[yunqa.de] Re: YuOpenSSL : Memory leak when using library in thread

  • From: Delphi Inspiration <delphi@xxxxxxxx>
  • To: yunqa@xxxxxxxxxxxxx, "the_laser (Redacted sender the_laser for DMARC)" <dmarc-noreply@xxxxxxxxxxxxx>
  • Date: Thu, 28 Jan 2021 17:18:24 +0100


On 27.01.2021 19:44, the_laser (Redacted sender the_laser for DMARC) wrote:

when using YuOpenSSL with Synapse , multiple memory leak occurs on
each HTTPS request, if request done in thread.

OpenSSL allocates memory to thread-local storage (TLS) for some TSL/SSL
operations. This memory must be freed before exiting the thread.

The OpenSSL function to free the memory allocated to TLS is
OPENSSL_thread_stop(). Failing to call OPENSSL_thread_stop() results in
memory leaks which cannot be recovered.

if using standard openssl libraries ( YuOpenSSL NOT defined ) - no
memory leaks.

The memory leak is the same with the OpenSSL DLLs - it ist just not
logged by the FastMM memory tracker because the DLLs use their own
memory manager.

ICS (Internet Component Suite) was also affected by this:
https://en.delphipraxis.net/topic/3920-7-memory-leaks-in-overbyteicswsocketpas-with-fixes/

The code below (and attached) fixes the leak.

Ralf

-----------------------------------------------------------------------

program YuOpenSSL_THTTPSend_Thread;

{$APPTYPE CONSOLE}
{$I DICompilers.inc}
{$R ..\Yunqa.res}

uses
  {$IFDEF FastMM}{$I FastMM_uses.inc}{$ENDIF}
  SysUtils, Classes,
  httpsend, ssl_openssl, YuOpenSSL;

type
  THTTPSend_Thread = class(TThread)
    procedure Execute; override;
  end;

procedure THTTPSend_Thread.Execute;
var
  SynHttp: THTTPSend;
  SL: TStringList;
begin
  try
    try
      SynHttp := THTTPSend.Create;
      try
        SynHttp.HTTPMethod('GET', 'https://www.yunqa.de/delphi/');

        SL := TStringList.Create;
        try
          WriteLn(SynHttp.Document.Position);
          WriteLn(SynHttp.Document.Size);
          SL.LoadFromStream(SynHttp.Document);
          WriteLn(SL.Text);
        finally
          SL.Free;
        end;
      finally
        SynHttp.Free;
      end;

    finally
      { Free OpenSSL thread-local storage (TLS).

        THTTPSend may invoke OpenSSL TSL/SSL functions which allocate
memory to
        thread-local storage. OPENSSL_thread_stop() frees this memory.

        It is important to call OPENSSL_thread_stop() from the same
thread which
        allocated the thread-local storage. Failing to do so results in
memory
        leaks which cannot be recovered.

        If THTTPSend is used within the main thread, YuOpenSSL calls
        OPENSSL_thread_stop() automatically upon unit finalization. }
      OPENSSL_thread_stop;
    end;
  except
    on e: Exception do
      WriteLn(e.ClassName, ': ', e.Message);
  end;
end;

var
  RunThread: THTTPSend_Thread;
begin
  {$IFDEF FastMM}{$I FastMM_init.inc}{$ENDIF}

  RunThread := THTTPSend_Thread.Create(True);
  try
    {$IFDEF COMPILER_15_UP}
    RunThread.Start;
    {$ELSE COMPILER_15_UP}
    RunThread.Resume;
    {$ENDIF COMPILER_15_UP}

    RunThread.WaitFor;
  finally
    RunThread.Free;
  end;

  WriteLn('Done. Press ENTER to exit.');
  ReadLn;
end.
program YuOpenSSL_THTTPSend_Thread;

{$APPTYPE CONSOLE}
{$I DICompilers.inc}
{$R ..\Yunqa.res}

uses
  {$IFDEF FastMM}{$I FastMM_uses.inc}{$ENDIF}
  SysUtils, Classes,
  httpsend, ssl_openssl, YuOpenSSL;

type
  THTTPSend_Thread = class(TThread)
    procedure Execute; override;
  end;

procedure THTTPSend_Thread.Execute;
var
  SynHttp: THTTPSend;
  SL: TStringList;
begin
  try
    try
      SynHttp := THTTPSend.Create;
      try
        SynHttp.HTTPMethod('GET', 'https://www.yunqa.de/delphi/');

        SL := TStringList.Create;
        try
          WriteLn(SynHttp.Document.Position);
          WriteLn(SynHttp.Document.Size);
          SL.LoadFromStream(SynHttp.Document);
          WriteLn(SL.Text);
        finally
          SL.Free;
        end;
      finally
        SynHttp.Free;
      end;

    finally
      { Free OpenSSL thread-local storage (TLS).

        THTTPSend may invoke OpenSSL TSL/SSL functions which allocate memory to
        thread-local storage. OPENSSL_thread_stop() frees this memory.

        It is important to call OPENSSL_thread_stop() from the same thread which
        allocated the thread-local storage. Failing to do so results in memory
        leaks which cannot be recovered.

        If THTTPSend is used within the main thread, YuOpenSSL calls
        OPENSSL_thread_stop() automatically upon unit finalization. }
      OPENSSL_thread_stop;
    end;
  except
    on e: Exception do
      WriteLn(e.ClassName, ': ', e.Message);
  end;
end;

var
  RunThread: THTTPSend_Thread;
begin
  {$IFDEF FastMM}{$I FastMM_init.inc}{$ENDIF}

  RunThread := THTTPSend_Thread.Create(True);
  try
    {$IFDEF COMPILER_15_UP}
    RunThread.Start;
    {$ELSE COMPILER_15_UP}
    RunThread.Resume;
    {$ENDIF COMPILER_15_UP}

    RunThread.WaitFor;
  finally
    RunThread.Free;
  end;

  WriteLn('Done. Press ENTER to exit.');
  ReadLn;
end.

Other related posts: