[英]ZDecompressStream() causes memory leak
I've been using ZLib
functions to compress/uncompress streams in memory. 我一直在使用
ZLib
函数来压缩/解压缩内存中的流。 In case when I try to uncompress invalid stream, it leaks memory. 如果我尝试解压缩无效流,它会泄漏内存。 The following code would leak memory:
以下代码会泄漏内存:
uses
Winapi.Windows, System.Classes, System.ZLib;
function DecompressStream(const AStream: TMemoryStream): Boolean;
var
ostream: TMemoryStream;
begin
ostream := TMemoryStream.Create;
try
AStream.Position := 0;
// ISSUE: Memory leak happening here
try
ZDecompressStream(AStream, ostream);
except
Exit(FALSE);
end;
AStream.Clear;
ostream.Position := 0;
AStream.CopyFrom(ostream, ostream.Size);
result := TRUE;
finally
ostream.Free;
end;
end;
var
s: TMemoryStream;
begin
ReportMemoryLeaksOnShutdown := TRUE;
s := TMemoryStream.Create;
try
DecompressStream(s);
finally
s.Free;
end;
end.
I try to decompress empty TMemoryStream
here and at the end of execution it shows that memory leak happened. 我尝试在这里解压缩空
TMemoryStream
,并在执行结束时显示内存泄漏发生。 Testing on Delphi XE2. 在Delphi XE2上进行测试。
Any ideas how to prevent this leak to happen, because in real world there would be a chance for my application to try to decompress invalid stream and leak the memory there. 任何想法如何防止这种泄漏发生,因为在现实世界中,我的应用程序有可能尝试解压缩无效流并泄漏内存。
QC: http://qc.embarcadero.com/wc/qcmain.aspx?d=120329 - claimed fixed starting with XE6 质量控制: http : //qc.embarcadero.com/wc/qcmain.aspx?d = 120329 - 声称从XE6开始固定
It's a bug in the Delphi RTL code. 这是Delphi RTL代码中的一个错误。 The implementation of
ZDecompressStream
raises exceptions and then fails to perform tidy up. ZDecompressStream
的实现引发异常,然后无法执行整理。 Let's look at the code: 我们来看看代码:
procedure ZDecompressStream(inStream, outStream: TStream);
const
bufferSize = 32768;
var
zstream: TZStreamRec;
zresult: Integer;
inBuffer: TBytes;
outBuffer: TBytes;
inSize: Integer;
outSize: Integer;
begin
SetLength(inBuffer, BufferSize);
SetLength(outBuffer, BufferSize);
FillChar(zstream, SizeOf(TZStreamRec), 0);
ZCompressCheck(InflateInit(zstream)); <--- performs heap allocation
inSize := inStream.Read(inBuffer, bufferSize);
while inSize > 0 do
begin
zstream.next_in := @inBuffer[0];
zstream.avail_in := inSize;
repeat
zstream.next_out := @outBuffer[0];
zstream.avail_out := bufferSize;
ZCompressCheck(inflate(zstream, Z_NO_FLUSH));
// outSize := zstream.next_out - outBuffer;
outSize := bufferSize - zstream.avail_out;
outStream.Write(outBuffer, outSize);
until (zstream.avail_in = 0) and (zstream.avail_out > 0);
inSize := inStream.Read(inBuffer, bufferSize);
end;
repeat
zstream.next_out := @outBuffer[0];
zstream.avail_out := bufferSize;
zresult := ZCompressCheck(inflate(zstream, Z_FINISH));
// outSize := zstream.next_out - outBuffer;
outSize := bufferSize - zstream.avail_out;
outStream.Write(outBuffer, outSize);
until (zresult = Z_STREAM_END) and (zstream.avail_out > 0);
ZCompressCheck(inflateEnd(zstream)); <--- tidy up, frees heap allocation
end;
I've taken this from my XE3, but I believe that it is essentially the same in all versions. 我从我的XE3中获取了这个,但我相信它在所有版本中基本相同。 I've highlighted the problem.
我突出了这个问题。 The call to
inflateInit
allocates memory off the heap. 对
inflateInit
的调用会从inflateInit
分配内存。 It needs to be paired with a call to inflateEnd
. 它需要与对
inflateEnd
的调用配对。 Because ZCompressCheck
raises exceptions in the face of errors, the call to inflateEnd
never happens. 因为
ZCompressCheck
在遇到错误时会引发异常,所以对inflateEnd
的调用永远不会发生。 And hence the code leaks. 因此代码泄漏。
The other calls to inflateInit
and inflateEnd
in that unit are correctly protected with try/finally. 使用try / finally正确保护该单元中的
inflateInit
和inflateEnd
的其他调用。 It just appears to be the use in this function that is erroneous. 它似乎只是在这个函数中使用是错误的。
My recommendation is that you replace the Zlib
unit with a version that is implemented correctly. 我的建议是用正确实现的版本替换
Zlib
单元。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.