简体   繁体   English

ZDecompressStream()导致内存泄漏

[英]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正确保护该单元中的inflateInitinflateEnd的其他调用。 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM