[fpc-pascal] Are the TEncoding singletons thread-safe?

silvioprog silvioprog at gmail.com
Thu Aug 11 03:05:16 CEST 2016


Hello,

I've used the useful singletons available in the TEncoding class, and I
don't get any problem with them, unless using threads.

I have an application that does many tests in a code compilable in FPC and
Delphi, however, the FPC's tests raise memory leak at the finalization
tests. The problem can be a little bit hard to be reproduce, but I think
the code below can do that:

=== begin code [project1.dpr] ===

program project1;

{$IFDEF FPC}
{$MODE DELPHI}
{$ENDIF}
{$IFDEF MSWINDOWS}
{$APPTYPE CONSOLE}
{$ENDIF}

uses
//  HeapTrc, the FPC staff recomends to enable HeapTrc in the lpi or
passing the -gh compiler parameter
{$IFDEF UNIX}
  CThreads,
{$ENDIF} SysUtils, Classes;

type
  TTestThread = class(TThread)
  public
    constructor Create;
    procedure Execute; override;
  end;

  constructor TTestThread.Create;
  begin
    inherited Create(True);
    FreeOnTerminate := False;
  end;

  procedure TTestThread.Execute;
  begin
    WriteLn(TEncoding.Default.GetString(TBytes.Create(65, 66, 67)));
  end;

var
  VThread1, VThread2: TTestThread;
begin
{$IFNDEF FPC}
  ReportMemoryLeaksOnShutdown := True;
{$ENDIF}
  VThread1 := TTestThread.Create;
  VThread2 := TTestThread.Create;
  try
    Sleep(1000);
    VThread1.Start;
    VThread2.Start;
    VThread1.WaitFor;
    VThread2.WaitFor;
  finally
    VThread1.Free;
    VThread2.Free;
  end;
end.

=== end code ===

If you compile and run the code above, you may get the following trace:

=== begin log ===

ABC
ABC
Heap dump by heaptrc unit
44 memory blocks allocated : 2119/2144
43 memory blocks freed     : 2087/2112
1 unfreed memory blocks : 32
True heap size : 131072
True free heap : 131072
Should be : 130912
Call trace for block $00007FFFF7FAB0C0 size 32

=== end log ===

Researching the FPC's TEncoding implementation, I think it doesn't do any
lock before instantiate its singletons, so I decided to research how Delphi
implements it, because I can't get any error on it, and I've seen it
implements a "lock-free initialization" technique
<http://stackoverflow.com/a/24657705/3268398> using the XE's
AtomicCmpExchange() function before return any TEncoding global instance.

That memory leak can be really a problem, because I can't prevent how many
threads will call the TEncoding's singletons at same time, I could
initialize the TEncoding before starting any thread of my application, but
it doesn't sound good, because I can't prevent if the threads will
instantiate the ANSI or UTF8 singleton. The best way to solve this problem
would be making the TEncoding become thread-safe. I could send a patch to
solve it, but I don't know if FPC provides some global locker like
AtomicCmpExchange.

--
Silvio Clécio
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freepascal.org/pipermail/fpc-pascal/attachments/20160810/9036780f/attachment.html>


More information about the fpc-pascal mailing list