Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / lazarus / 2021-10

Debugger stops in c dll even when no breakpoint set

13 messages · 3 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Luca Olivetti

I'm using a quite complex c dll (pascal headers here: https://github.com/fluisgirardi./fpopen62541).
For logging purposes, this dll can call a function but it needs to support varargs, so I wrote a simple c source
(https://github.com/fluisgirardi/fpopen62541/blob/main/pascallog/pascallog.c), compiled into a dll, that writes the message in a buffer then calls a pascal function without varargs.

The problem is that every time the main dll calls the function UA_Log_Pascal_clear (which just frees the pointer passed to it), the debugger stops inside the function

ntdll!RtlpNtMakeTemporaryKey

even with no breakpoints set.

This is under win32, lazarus 2.0.12, fpc 3.2.0. the debugger is gdb 8.2 (I don't remember where I got it).

It's quite annoying since it disrupts my debugging session, any way to avoid it?

The stack trace is

#0 ntdll!RtlpNtMakeTemporaryKey at :0
#1 ntdll!RtlImageRvaToVa at :0
#2 ntdll!EtwSetMark at :0
#3 ntdll!RtlpNtMakeTemporaryKey at :0
#4 ntdll!EtwSetMark at :0
#5 wcsnicmp at :0
#6 msvcrt!free at :0
#7 ?? at :0
#8 UA_Log_Pascal_clear(0x6b74a28) at D:\open62541\extlog\pascallog.c:53 #9 UA_ClientConfig_clear(0x100000) at
\home\travis\build\open62541\open62541\src\client\ua_client.c:75 #10 UA_Client_delete(0x72dec78) at
\home\travis\build\open62541\open62541\src\client\ua_client.c:103 #11 TOPCUARFID__DISCONNECT(0x2dec150) at opcuarfid.pas:1129 #12 TOPCUARFID__CHECKSTATUSCODE(0xbb4c18 'Error en UA_Client_connec'..., 2158886912, 0x2dec150) at opcuarfid.pas:1200
#13 TOPCUARFID__CONNECT(0x314076c '192.168.1.46', 0x2dec150) at opcuarfid.pas:1102
#14 TRF185C__EXECUTE(0x28c4e0) at rf185c.pas:214
#15 CLASSES$_$TSTRINGLIST_$__$$_SORT at :0
#16 ?? at :0
#17 _FPC_except_safecall at :0
#18 ?? at :0
#19 KERNEL32!BaseThreadInitThunk at :0
#20 ntdll!RtlInitializeExceptionChain at :0
#21 ntdll!RtlInitializeExceptionChain at :0
#22 ?? at :0

and this is what the assembler window shows:

77045A9F 90 nop
77045AA0 90 nop
77045AA1 8bff mov %edi,%edi 77045AA3 55 push %ebp
77045AA4 8bec mov %esp,%ebp 77045AA6 64a118000000 mov %fs:0x18,%eax 77045AAC 8b4030 mov 0x30(%eax),%eax 77045AAF 80780200 cmpb $0x0,0x2(%eax) 77045AB3 7417 je 0x77045acc <ntdll!RtlpNtMakeTemporaryKey+14541>
77045AB5 8b4508 mov 0x8(%ebp),%eax 77045AB8 c605a510067701 movb $0x1,0x770610a5 77045ABF a3a0100677 mov %eax,0x770610a0 77045AC4 cc int3
77045AC5 c605a510067700 movb $0x0,0x770610a5 <<<<here 77045ACC 5d pop %ebp
77045ACD c20400 ret $0x4
77045AD0 90 nop
77045AD1 90 nop
77045AD2 90 nop
77045AD3 90 nop
77045AD4 90 nop
77045AD5 8bff mov %edi,%edi 77045AD7 55 push %ebp
77045AD8 8bec mov %esp,%ebp 77045ADA 83ec1c sub $0x1c,%esp 77045ADD 56 push %esi
77045ADE 8b7510 mov 0x10(%ebp),%esi 77045AE1 57 push %edi

Bye

Luca Olivetti Wetron Automation Technology http://www.wetron.es/ Tel. +34 93 5883004 (Ext.3010) Fax +34 93 5883007

Reply by email

Christo Crause
to Luca Olivetti

On Thu, Oct 28, 2021 at 2:01 PM Luca Olivetti via lazarus <

wrote: 77045AC4 cc int3

The Int3 instruction means break, so this is the expected behaviour. If there is no debugger inserted break point for this location, it must be compiled into the dll code. This means not stopping here will be problematic, unless you use some kind of script to step over this break instruction automatically. I do not think it is possible from inside Lazarus, but haven't actually tried to work around something similar before. -------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus-ide.org/pipermail/lazarus/attachments/20211028/fc27d13c/attachment.html>

Reply by email

Martin Frb
to Christo Crause
Christo Crause wrote 16 lines
On Thu, Oct 28, 2021 at 2:01 PM Luca Olivetti via lazarus wrote: 77045AC4 cc                       int3 The Int3 instruction means break, so this is the expected behaviour.  If there is no debugger inserted break point for this location, it must be compiled into the dll code.  This means not stopping here will be problematic, unless you use some kind of script to step over this break instruction automatically.  I do not think it is possible from inside Lazarus, but haven't actually tried to work around something similar before.

FpDebug refers unknown "int3" back to the application, and lets the application handle them itself.

At least FpDebug does this by default. There is an option in the global settings to stop.
But if the dll expects the int3, and therefore wants to handle it itself.....
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus-ide.org/pipermail/lazarus/attachments/20211028/3eab2eca/attachment.html>

Reply by email

Luca Olivetti
to Christo Crause: On Thu, Oct 28, 2021 at 2:01 PM Luca Olivetti via lazarus < The Int3 instruction means…

El 28/10/21 a les 14:28, Christo Crause ha escrit:

Show quoted text 12 lines
On Thu, Oct 28, 2021 at 2:01 PM Luca Olivetti via lazarus < <mailto:>> wrote: 77045AC4 cc                       int3 The Int3 instruction means break, so this is the expected behaviour.  If there is no debugger inserted break point for this location, it must be compiled into the dll code.

Thank you, that's interesting, but that's inside the ntdll!RtlpNtMakeTemporaryKey (i.e. presumably in ntdll.dll) function, not in my code.
I just removed the "free" call in my code, it will cause a memory leak but that's ok for testing.

Bye

Luca Olivetti Wetron Automation Technology http://www.wetron.es/ Tel. +34 93 5883004 (Ext.3010) Fax +34 93 5883007

Reply by email

Luca Olivetti
to Martin Frb: FpDebug refers unknown "int3" back to the application, and lets the application handle…

El 28/10/21 a les 14:46, Martin Frb via lazarus ha escrit:

Show quoted text 26 lines
On 28/10/2021 14:28, Christo Crause via lazarus wrote: > > On Thu, Oct 28, 2021 at 2:01 PM Luca Olivetti via lazarus > wrote: > > > 77045AC4 cc                       int3 > > > The Int3 instruction means break, so this is the expected behaviour. > If there is no debugger inserted break point for this location, it > must be compiled into the dll code.  This means not stopping here will > be problematic, unless you use some kind of script to step over this > break instruction automatically.  I do not think it is possible from > inside Lazarus, but haven't actually tried to work around something > similar before. > FpDebug refers unknown "int3" back to the application, and lets the application handle them itself. At least FpDebug does this by default. There is an option in the global settings to stop. But if the dll expects the int3, and therefore wants to handle it itself.....

Any hint on why it hits that int3?

Now I recompiled pascallog.c (I changed its location, no wonder lazarus complained it couldn't find it), and lazarus instead of showing the assembler window shows the c file stopping at the call to "free".

I checked and the pointer passed to "free" is the same that "malloc" returned.

malloc ->
https://github.com/fluisgirardi/fpopen62541/blob/d95839c908657f58bf2fde4533625a61cbccb8c7/pascallog/pascallog.c#L59

free ->
https://github.com/fluisgirardi/fpopen62541/blob/d95839c908657f58bf2fde4533625a61cbccb8c7/pascallog/pascallog.c#L51

Bye

Luca Olivetti Wetron Automation Technology http://www.wetron.es/ Tel. +34 93 5883004 (Ext.3010) Fax +34 93 5883007

Reply by email

Luca Olivetti
to Luca Olivetti

El 29/10/21 a les 10:15, Luca Olivetti via lazarus ha escrit:

Show quoted text 44 lines
El 28/10/21 a les 14:46, Martin Frb via lazarus ha escrit: > On 28/10/2021 14:28, Christo Crause via lazarus wrote: >> >> On Thu, Oct 28, 2021 at 2:01 PM Luca Olivetti via lazarus >> wrote: >> >> >>     77045AC4 cc                       int3 >> >> >> The Int3 instruction means break, so this is the expected behaviour. >> If there is no debugger inserted break point for this location, it >> must be compiled into the dll code.  This means not stopping here >> will be problematic, unless you use some kind of script to step over >> this break instruction automatically.  I do not think it is possible >> from inside Lazarus, but haven't actually tried to work around >> something similar before. >> > > > FpDebug refers unknown "int3" back to the application, and lets the > application handle them itself. > > At least FpDebug does this by default. There is an option in the > global settings to stop. > But if the dll expects the int3, and therefore wants to handle it > itself..... Any hint on why it hits that int3? Now I recompiled pascallog.c (I changed its location, no wonder lazarus complained it couldn't find it), and lazarus instead of showing the assembler window shows the c file stopping at the call to "free". I checked and the pointer passed to "free" is the same that "malloc" returned. malloc -> https://github.com/fluisgirardi/fpopen62541/blob/d95839c908657f58bf2fde4533625a61cbccb8c7/pascallog/pascallog.c#L59 free -> https://github.com/fluisgirardi/fpopen62541/blob/d95839c908657f58bf2fde4533625a61cbccb8c7/pascallog/pascallog.c#L51

I now tested under windows 10 64 bits (the exe is 32 bits, the previous test was under windows 7 32 bits), and here instead of stopping once in ntdll!RtlpNtMakeTemporaryKey it stops twice: in ntdll!RtlZeroHeap and in ntdll!RtlCaptureStackContext.
The former (RtlZeroHeap) shows what it seems a bogus call stack (i.e. just two levels, the RtlZeroHeap itself and 00000000).

Bye

Luca Olivetti Wetron Automation Technology http://www.wetron.es/ Tel. +34 93 5883004 (Ext.3010) Fax +34 93 5883007

Reply by email

Christo Crause
to Luca Olivetti

On Fri, Oct 29, 2021 at 10:41 AM Luca Olivetti via lazarus <

Show quoted text 10 lines
wrote: I now tested under windows 10 64 bits (the exe is 32 bits, the previous test was under windows 7 32 bits), and here instead of stopping once in ntdll!RtlpNtMakeTemporaryKey it stops twice: in ntdll!RtlZeroHeap and in ntdll!RtlCaptureStackContext. The former (RtlZeroHeap) shows what it seems a bogus call stack (i.e. just two levels, the RtlZeroHeap itself and 00000000).

Searching around seems to suggest that RtlpNtMakeTemporaryKey is typically part of a stack trace involving memory/stack corruption or freeing an invalid reference or already freed pointer. See this example: https://stackoverflow.com/questions/45162248/calling-free-in-c-triggers-ntdlldbgbreakpoint-in-debug-but-crashes-in-rel/45247035

Since the code writes something to memory in the int3 branch, check errno to see if that reveals something.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus-ide.org/pipermail/lazarus/attachments/20211029/da929d43/attachment.html>

Reply by email

Luca Olivetti
to Christo Crause

El 29/10/21 a les 12:48, Christo Crause ha escrit:

Show quoted text 24 lines
On Fri, Oct 29, 2021 at 10:41 AM Luca Olivetti via lazarus < <mailto:>> wrote: I now tested under windows 10 64 bits (the exe is 32 bits, the previous test was under windows 7 32 bits), and here instead of stopping once in ntdll!RtlpNtMakeTemporaryKey it stops twice: in ntdll!RtlZeroHeap and in ntdll!RtlCaptureStackContext. The former (RtlZeroHeap) shows what it seems a bogus call stack (i.e. just two levels, the RtlZeroHeap itself and 00000000). Searching around seems to suggest that RtlpNtMakeTemporaryKey is typically part of a stack trace involving memory/stack corruption or freeing an invalid reference or already freed pointer.  See this example: https://stackoverflow.com/questions/45162248/calling-free-in-c-triggers-ntdlldbgbreakpoint-in-debug-but-crashes-in-rel/45247035 <https://stackoverflow.com/questions/45162248/calling-free-in-c-triggers-ntdlldbgbreakpoint-in-debug-but-crashes-in-rel/45247035> Since the code writes something to memory in the int3 branch, check errno to see if that reveals something.

OK, I added a

    printf("Error clear %d: %s\n", errno, strerror(errno));

after the call to free.
When run outside the debugger, it prints "Error clear 0: no error", when run from lazarus "Error clear 22: Invalid argument".

I then found this document
https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/free?view=msvc-160 it says that "when the application is linked with a debug version of the C run-time libraries, free resolves to _free_dbg", but I don't think it does that dynamically based on how the app is been called (directly or through a debugger), or does it?

In any case I checked the documentation for the "CRT Debug Heap"

https://docs.microsoft.com/en-us/visualstudio/debugger/crt-debug-heap-details?view=vs-2019

and the bytes surrounding my allocated data aren't the same as explained in that article and they are the same before calling free as they were after calling malloc.

Bye

Luca Olivetti Wetron Automation Technology http://www.wetron.es/ Tel. +34 93 5883004 (Ext.3010) Fax +34 93 5883007

Reply by email

Luca Olivetti
to Luca Olivetti

El 3/11/21 a les 15:56, Luca Olivetti via lazarus ha escrit:

A quick follow up: I used the wrong size when mallocing data (size of the pointer variable instead of the size of the struct it pointed to, d'oh!).
I found it by running the program under windbg and there I saw a message saying that I wrote to a memory area beyond the 4 bytes allocated. I wondered why 4 bytes when my struct is bigger and then I found the stupid error
https://github.com/olivluca/fpopen62541/commit/e5ec2cab8e97eeeba29e33b801de6e42a0084ca8

I don't know where that message came from, but is there a way to see it while debugging the application under lazarus?

Bye

Show quoted text 56 lines
El 29/10/21 a les 12:48, Christo Crause ha escrit: > > On Fri, Oct 29, 2021 at 10:41 AM Luca Olivetti via lazarus > < <mailto:>> > wrote: > > >     I now tested under windows 10 64 bits (the exe is 32 bits, the > previous >     test was under windows 7 32 bits), and here instead of stopping > once in >     ntdll!RtlpNtMakeTemporaryKey it stops twice: in ntdll!RtlZeroHeap >     and in >     ntdll!RtlCaptureStackContext. >     The former (RtlZeroHeap) shows what it seems a bogus call stack (i.e. >     just two levels, the RtlZeroHeap itself and 00000000). > > > Searching around seems to suggest that RtlpNtMakeTemporaryKey is > typically part of a stack trace involving memory/stack corruption or > freeing an invalid reference or already freed pointer.  See this > example: > https://stackoverflow.com/questions/45162248/calling-free-in-c-triggers-ntdlldbgbreakpoint-in-debug-but-crashes-in-rel/45247035 > <https://stackoverflow.com/questions/45162248/calling-free-in-c-triggers-ntdlldbgbreakpoint-in-debug-but-crashes-in-rel/45247035> > > > Since the code writes something to memory in the int3 branch, check > errno to see if that reveals something. OK, I added a    printf("Error clear %d: %s\n", errno, strerror(errno)); after the call to free. When run outside the debugger, it prints "Error clear 0: no error", when run from lazarus "Error clear 22: Invalid argument". I then found this document https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/free?view=msvc-160 it says that "when the application is linked with a debug version of the C run-time libraries, free resolves to _free_dbg", but I don't think it does that dynamically based on how the app is been called (directly or through a debugger), or does it? In any case I checked the documentation for the "CRT Debug Heap" https://docs.microsoft.com/en-us/visualstudio/debugger/crt-debug-heap-details?view=vs-2019 and the bytes surrounding my allocated data aren't the same as explained in that article and they are the same before calling free as they were after calling malloc. Bye
Luca Olivetti Wetron Automation Technology http://www.wetron.es/ Tel. +34 93 5883004 (Ext.3010) Fax +34 93 5883007

Reply by email

Martin Frb
to Luca Olivetti
Luca Olivetti wrote 13 lines
El 3/11/21 a les 15:56, Luca Olivetti via lazarus ha escrit: A quick follow up: I used the wrong size when mallocing data (size of the pointer variable instead of the size of the struct it pointed to, d'oh!). I found it by running the program under windbg and there I saw a message saying that I wrote to a memory area beyond the 4 bytes allocated. I wondered why 4 bytes when my struct is bigger and then I found the stupid error https://github.com/olivluca/fpopen62541/commit/e5ec2cab8e97eeeba29e33b801de6e42a0084ca8 I don't know where that message came from, but is there a way to see it while debugging the application under lazarus?

I would guess this is based on
https://docs.microsoft.com/de-de/windows-hardware/drivers/debugger/gflags-and-pageheap

Now there are 2 modes: "standard" and "full"
Note: this is only about mem on the heap. Local vars on the stack are not affected (except, if (like objects) they are pointers to the heap, then the heap part (and only that) will be affected)

"Standard" only detects, overruns when mem is freed. If I understand this correctly, in FPC you can enable -gh heaptrc, and this will do something similar, but limited...
This is hardcoded in HeapTrc
      { add a small footprint at the end of memory blocks, this         can check for memory overwrites at the end of a block }       add_tail : boolean = true;
      tail_size : longint = sizeof(ptruint);
Additionally
https://www.freepascal.org/docs-html/rtl/heaptrc/keepreleased.html

On Linux, you can also use valgrind memcheck => which is excellent at finding stuff like this.

"Full" (if I read it correctly) will get a separate mem-page for every (m)alloc.
As the doc says, that will strain your sys mem.... This want work with default FPC, because FPC does not use its own mem manager. Fpc gets a whole page, and splits it without windows knowing. So you need to see if there is an alternative mem manager that would work (maybe CMEM?).

If there is a mem manager, that works with "FULL", then gdb and fpdebug should stop with an access violation.

Reply by email

Luca Olivetti
to Martin Frb

El 24/11/21 a les 14:29, Martin Frb via lazarus ha escrit:

Show quoted text 15 lines
> I don't know where that message came from, but is there a way to see > it while debugging the application under lazarus? I would guess this is based on https://docs.microsoft.com/de-de/windows-hardware/drivers/debugger/gflags-and-pageheap Now there are 2 modes: "standard" and "full" Note: this is only about mem on the heap. Local vars on the stack are not affected (except, if (like objects) they are pointers to the heap, then the heap part (and only that) will be affected) "Standard" only detects, overruns when mem is freed. If I understand this correctly, in FPC you can enable -gh heaptrc, and this will do something similar, but limited...

Yes, I routinely do that, but it only works for pascal code. In this case it was a c dll (that I wrote as a bridge between another dll and my pascal code) so heaptrc wouldn't catch that error. I suppose the message comes from some windows core dll and windbg can display it, I don't know if and how gdb can (I'm not using fpdebug yet, maybe it can?).

Bye

Luca Olivetti Wetron Automation Technology http://www.wetron.es/ Tel. +34 93 5883004 (Ext.3010) Fax +34 93 5883007

Reply by email

Luca Olivetti
to Luca Olivetti

El 24/11/21 a les 14:38, Luca Olivetti via lazarus ha escrit:

Show quoted text 24 lines
El 24/11/21 a les 14:29, Martin Frb via lazarus ha escrit: >> I don't know where that message came from, but is there a way to see >> it while debugging the application under lazarus? > > I would guess this is based on > https://docs.microsoft.com/de-de/windows-hardware/drivers/debugger/gflags-and-pageheap > > > Now there are 2 modes: "standard" and "full" > Note: this is only about mem on the heap. Local vars on the stack are > not affected (except, if (like objects) they are pointers to the heap, > then the heap part (and only that) will be affected) > > "Standard" only detects, overruns when mem is freed. > If I understand this correctly, in FPC you can enable -gh heaptrc, and > this will do something similar, but limited... Yes, I routinely do that, but it only works for pascal code. In this case it was a c dll (that I wrote as a bridge between another dll and my pascal code) so heaptrc wouldn't catch that error. I suppose the message comes from some windows core dll and windbg can display it, I don't know if and how gdb can (I'm not using fpdebug yet, maybe it can?).

btw, I'm not sure that gflags was doing anything: I was getting the same result with every flag activated as with none of them. In fact when I sent the first message in this thread I had no windows debugging tool installed, yet the debugger stopped on the free, only I couldn't see or find that message.

Bye

Luca Olivetti Wetron Automation Technology http://www.wetron.es/ Tel. +34 93 5883004 (Ext.3010) Fax +34 93 5883007

Reply by email

Luca Olivetti
to Luca Olivetti: El 24/11/21 a les 14:29, Martin Frb via lazarus ha escrit: Yes, I routinely do that, but…

El 24/11/21 a les 14:38, Luca Olivetti via lazarus ha escrit: .

I suppose the message comes from some windows core dll and windbg can display it, I don't know if and how gdb can (I'm not using fpdebug yet, maybe it can?).

Well, call me stupid: the message is perfectly visible in the "Event Log" window.

Bye

Luca Olivetti Wetron Automation Technology http://www.wetron.es/ Tel. +34 93 5883004 (Ext.3010) Fax +34 93 5883007

Reply by email