From: "mghomn (Justin Peal)" Date: 2013-01-30T09:53:03+09:00 Subject: [ruby-core:51747] [ruby-trunk - Feature #7525] How to avoid memory leak when something gets wrong and throw exception when using win32api? Issue #7525 has been updated by mghomn (Justin Peal). Thank you for the resource release schema! ---------------------------------------- Feature #7525: How to avoid memory leak when something gets wrong and throw exception when using win32api? https://bugs.ruby-lang.org/issues/7525#change-35711 Author: mghomn (Justin Peal) Status: Rejected Priority: Normal Assignee: usa (Usaku NAKAMURA) Category: Target version: 2.0.0 require 'win32api' module Crypto # Common API NULL = 0 @GetLastError = Win32API.new('kernel32', 'GetLastError', '', 'I') @lstrlen = Win32API.new('kernel32', 'lstrlenW', 'L', 'I') # Memory API @RtlMoveMemory = Win32API.new('kernel32', 'RtlMoveMemory', 'PLL', 'I') @LocalFree = Win32API.new('kernel32', 'LocalFree', 'L', 'I') # Crypto API CRYPTPROTECT_UI_FORBIDDEN = 0x01 @CryptProtectData = Win32API.new('crypt32', 'CryptProtectData', 'PPPPPLP', 'I') @CryptUnprotectData = Win32API.new('crypt32', 'CryptUnprotectData', 'PPPPPLP', 'I') def self.error func puts "#{func} Error = #{@GetLastError.call()}" end def self.encrypt str, entropy, desc pDataIn = [str.bytesize, str].pack('Lp') szDataDescr = (desc + "\0").encode(Encoding::UTF_16LE) pOptionalEntropy = [entropy.bytesize, entropy].pack('Lp') pvReserved = pPromptStruct = NULL dwFlags = CRYPTPROTECT_UI_FORBIDDEN pDataOut = [0, ''].pack('Lp') return error('CryptProtectData') if @CryptProtectData.call(pDataIn, szDataDescr, pOptionalEntropy, pvReserved, pPromptStruct, dwFlags, pDataOut) == 0 cbData, pbData = pDataOut.unpack('LL') ret = ' '.encode(Encoding::BINARY) * cbData return error('RtlMoveMemory') if @RtlMoveMemory.call(ret, pbData, cbData) == 0 return error('LocalFree') if @LocalFree.call(pbData) != NULL ret end def self.decrypt str, entropy, desc pDataIn = [str.bytesize, str].pack('Lp') ppszDataDescr = [NULL].pack('L') pOptionalEntropy = [entropy.bytesize, entropy].pack('Lp') pvReserved = pPromptStruct = NULL dwFlags = CRYPTPROTECT_UI_FORBIDDEN pDataOut = [0, ''].pack('Lp') return error('CryptUnprotectData') if @CryptUnprotectData.call(pDataIn, ppszDataDescr, pOptionalEntropy, pvReserved, pPromptStruct, dwFlags, pDataOut) == 0 pszDataDescr = ppszDataDescr.unpack('L').first szDataDescr = ' '.encode(Encoding::UTF_16LE) * @lstrlen.call(pszDataDescr) return error('RtlMoveMemory') if @RtlMoveMemory.call(szDataDescr, pszDataDescr, szDataDescr.bytesize) == 0 return error('LocalFree') if @LocalFree.call(pszDataDescr) != NULL szDataDescr.encode!(Encoding::UTF_8) cbData, pbData = pDataOut.unpack('LL') ret = ' '.encode(Encoding::BINARY) * cbData return error('RtlMoveMemory') if @RtlMoveMemory.call(ret, pbData, cbData) == 0 return error('LocalFree') if @LocalFree.call(pbData) != NULL desc = '' unless desc return error('Unmatched description') unless desc == szDataDescr ret.force_encoding(Encoding::UTF_8) end end if $0 == __FILE__ def test plain, entropy, desc puts "plain = #{plain}, entropy = #{entropy}, desc = #{desc}" cipher = Crypto.encrypt(plain, entropy, desc) puts "cipher = #{cipher.unpack('H*').first}" recover = Crypto.decrypt(cipher, entropy, desc) puts "recover = #{recover}" end begin test('abcd', 'efgh', 'ijkl') rescue puts $!.to_s.force_encoding(Encoding::UTF_8), $!.backtrace.join($/) end end -- http://bugs.ruby-lang.org/