Feature #7525
closedHow to avoid memory leak when something gets wrong and throw exception when using win32api?
Description
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
Updated by mame (Yusuke Endoh) about 12 years ago
- Status changed from Open to Assigned
- Assignee set to usa (Usaku NAKAMURA)
- Target version set to 2.0.0
Is this really a feature request? Or bug report?
Assigning to usa.
Usa-san, if this is a feature, please set the target to next minor.
If this is a bug report, please consider how to fix.
--
Yusuke Endoh mame@tsg.ne.jp
Updated by usa (Usaku NAKAMURA) almost 12 years ago
- Status changed from Assigned to Rejected
This is not a feature request nor a bug report. Only quetion.¶
Generically, you can use begin-ensure-end syntax to release resources.
For example:
begin
foo = get_some_resource
do_something_and_raises_exception
ensure
release_the_resource(foo) if foo
end
Updated by mghomn (Justin Peal) almost 12 years ago
Thank you for the resource release schema!