Jump to content
dkprojektai

Memory leak in UnicodeString to string conversion

Recommended Posts

Hello, I have a memory leak (EurekaLog): Memory Leak: Type=UnicodeString: Ref count - 1, Content: "Archive info"; Total size=78; Count=3;

It happens not every time.

 

It found in:

var
  result_text: IRecognitionResult;


procedure TWorkerThread.Execute;
begin
  
  ...
  OtlParallel.Parallel.For(0, 20,1).NumTasks(6).Execute(
  procedure (value: integer)
  var
    Recognition: string;
  begin
    ...
    Locking.EnterWriteLock;
    Try
      Recognition:= result_text.recognition_text >>>>> here is leak 
    Finally
      Locking.ExitWriteLock;
    End;
    ....
   end);
   ...

end;


  IRecognitionResult = interface(IDispatch)
    ....
    function Get_text: String; safecall;
    property recognition_text: String read Get_text;
  end;

Can somebody explain how to avoid this? I have tried to change line to this: Recognition := Copy(result_text.recognition_text,1,Pos(#0,result_text.recognition_text)-1)

because dll returns info like "Archive info#0aaa,bf;ddf...", but it does not help.

 

Thanks.

Share this post


Link to post

allocation number: 1804277
program up time: 3:04 min
type: UnicodeString
address: $da9db60
size: 26
access rights: read/write
code page: 1200
reference counter: 1
string length: 6
contents: Detected text

thread $85e8 (TOTPWorkerThread):
671a52b3 madExcept32.dll madExceptDbg    1736 GetMemCallback
004073e8 Main_program.exe    System          4758 @GetMem
0040bd86 Main_program.exe    System         24650 @NewUnicodeString
0040bfb7 Main_program.exe    System         25328 @UStrFromPWCharLen
01268b1f Main_program.exe    Unit1          14371 TWorkerThread.Execute$ActRec.$2$Body
0118353a Main_program.exe    OtlParallel     3440 TOmniParallelSimpleLoop.Execute[2]$ActRec.$0$Body
01183054 Main_program.exe    OtlParallel     3380 TOmniParallelSimpleLoop.CreateForTask$ActRec.$0$Body
0115b76f Main_program.exe    OtlTaskControl  1991 TOmniTaskExecutor.Asy_Execute
0115a51e Main_program.exe    OtlTaskControl  1584 TOmniTask.InternalExecute
0040a038 Main_program.exe    System         17320 TObject.GetInterface
0040a081 Main_program.exe    System         17327 TObject.GetInterface
00411d3b Main_program.exe    System         38375 TInterfacedObject.QueryInterface
00410916 Main_program.exe    System         37361 @IntfCast
0115a248 Main_program.exe    OtlTaskControl  1502 TOmniTask.Execute
0114c624 Main_program.exe    OtlThreadPool    889 TOTPWorkerThread.ExecuteWorkItem
0114c800 Main_program.exe    OtlThreadPool    918 TOTPWorkerThread.GetMsg
0114c19f Main_program.exe    OtlThreadPool    846 TOTPWorkerThread.Execute
004adbb7 Main_program.exe    madExcept            HookedTThreadExecute
0053ca51 Main_program.exe    System.Classes 14945 ThreadProc
0040bcd4 Main_program.exe    System         24423 ThreadWrapper
004ada9d Main_program.exe    madExcept            CallThreadProcSafe
004adb02 Main_program.exe    madExcept            ThreadExceptFrame
755e0417 KERNEL32.DLL                         BaseThreadInitThunk

 

 

I quess - convertion from widestring to string is the problem. But how to fix it?

 

Share this post


Link to post

Before knowing how to fix it, you need to know what causes the leak. That's where the minimal reproduction comes in. 

Share this post


Link to post

I'm now trying on - Finalize(result_text);

 

Leak detectors does not register leaks. Will write if it will help...

Share this post


Link to post

String is not an automation compatible data type. The IRecognitionResult.Get_text() method and IRecognition.recognition_text property need to be declared to use WideString instead of String.

IRecognitionResult = interface(IDispatch)
  function Get_text: WideString; safecall;
  property recognition_text: WideString read Get_text;
end;

 

Edited by Remy Lebeau
  • Like 1

Share this post


Link to post
   Locking.EnterWriteLock;
    Try
      Recognition:= String(result_text.recognition_text);
    Finally
      Locking.ExitWriteLock;
    End;

Remy - am I understand correctly? I should do like this?

Share this post


Link to post
On 1/9/2020 at 2:19 PM, dkprojektai said:

   Locking.EnterWriteLock;
    Try
      Recognition:= String(result_text.recognition_text);
    Finally
      Locking.ExitWriteLock;
    End;

Remy - am I understand correctly? I should do like this?

That type-cast is not necessary.  Assigning a String (or a WideString) to a String is handled automatically by the compiler.  This is not the source of your leaking.

 

Did you change the recognition_text property to return a WideString instead of a String, like I suggested 8 months ago?  What does the implementation of Get_text() actually look like?

  • Like 1

Share this post


Link to post
3 hours ago, dkprojektai said:

I can't change it - it's from third library 

Library, as in DLL?  You really can't pass a "string" from a DLL to an application, except when both projects are configured to use a shared memory manager ("uses sharemem").

 

 

 

 

 

Share this post


Link to post
On 1/12/2020 at 8:58 PM, dkprojektai said:

I can't change it - it's from third library 

Then you are going to have to ask the library author to change it, because this implementation is broken.  IRecognitionResult is derived from IDispatch, which is an OLE interface.  Pascal strings simply are not compatible with OLE - period.  The Pascal wrapper for the interface MUST use WideString instead, which uses the OLE BSTR string type.

  • Like 1

Share this post


Link to post

I'm very sorry. I double check. The IRecognitionResult is:

property recognition_text: WideString read Get_text;

Should I somehow transform Recognition: string; into WideString?

Share this post


Link to post
7 minutes ago, dkprojektai said:

I'm very sorry. I double check. The IRecognitionResult is:


property recognition_text: WideString read Get_text;

Should I somehow transform Recognition: string; into WideString?

If you want to solve a problem, the first step is to understand it fully. Guesswork is unlikely to be successful. 

 

If you want help from others, help them to be able to reproduce the issue. 

Share this post


Link to post
2 minutes ago, David Heffernan said:

If you want to solve a problem, the first step is to understand it fully. Guesswork is unlikely to be successful. 

 

If you want help from others, help them to be able to reproduce the issue. 

sorry, I can't crop some lines and make example from 15000 lines of code with treading and third party libraries.

Share this post


Link to post
50 minutes ago, dkprojektai said:

sorry, I can't crop some lines and make example from 15000 lines of code with treading and third party libraries.

Then you'll have to debug this yourself. 

Share this post


Link to post
20 hours ago, dkprojektai said:

I'm very sorry. I double check. The IRecognitionResult is:


property recognition_text: WideString read Get_text;

Then I don't see how there can possibly be a leak in the code you have shown.  Something else is going on.  You are just going to have to debug the code for yourself to see exactly where the real leak is.  What you described earlier suggests that the compiler is not freeing the 'Recognition: string' variable when your Parallel.For() procedure exits, and that is simply not how the compiler is supposed to work.

20 hours ago, dkprojektai said:

Should I somehow transform Recognition: string; into WideString?

That is not necessary.  As I stated earlier, you can assign a WideString directly to a String, and vice versa.  The compiler will handle everything for you, as WideString and String are both managed types that the compiler knows how to convert between, and free when they go out of scope.

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×