Under 64-bit, FastMM_LoadDebugSupportLibrary binds a stack tracing routine that cannot work there, so debug blocks are recorded with no stack trace at all. A leak report prints
This block was allocated on ..., and the stack trace (return addresses) at the time was:
The block is currently used for an object of class: Unknown
with nothing between the two lines. The same program built for 32-bit resolves the trace normally.
Cause
FastMM_LoadDebugSupportLibrary binds GetRawStackTrace on every target:
if (@FastMM_GetStackTrace = @FastMM_NoOpGetStackTrace)
and Assigned(DebugLibrary_GetRawStackTrace) then
begin
FastMM_GetStackTrace := DebugLibrary_GetRawStackTrace;
end;
That routine walks the RBP frame chain, and the x64 ABI does not maintain one, so the loop finds nothing and returns an empty buffer.
The support library already has a routine for this case - GetFrameBasedStackTrace, which under 64-bit is implemented on RtlCaptureStackBackTrace, with the comment "We use the Windows API to do frame based stack tracing under 64-bit". It is exported. It is simply never bound.
Measurement
Calling both entry points directly out of the library, bypassing FastMM, with a 20 entry buffer and ASkipFrames zero:
| Target |
GetRawStackTrace |
GetFrameBasedStackTrace |
| Win32 |
12 of 20 frames |
- |
| Win64 |
0 of 20 |
8 of 20 |
What fixes it
Preferring the frame based routine under 64-bit, keeping the raw one as the fallback for a support library that does not export it, and leaving 32-bit alone - the raw tracer works there and yields the deeper traces it exists for. With that, a Win64 leak report comes back as
00007FF6BECDD396 [FastMM5.pas][FastMM5][FastMM_DebugGetMem_GetDebugBlock][8255]
00007FF6BECC5834 [System][System][@GetMem]
00007FF6BECF6EBE [LeakCheck.dpr][LeakCheck][AllocateSomethingAndLeakIt][23]
Both binding paths need it, the GetProcAddress one and the statically bound one.
A detail worth mentioning: with ASkipFrames at zero the first captured frame is GetFrameBasedStackTrace itself, so one of the entries is spent on the tracer. Harmless, but it means the effective depth is one less than requested on 64-bit.
No pull request, per your note in #101. It is on win64-frame-based-stack-trace in my fork if you want to look; the test suite passes 18 of 18 runs with it and 32-bit reports are unchanged line for line. Happy to open a PR if you ask for one.
Under 64-bit,
FastMM_LoadDebugSupportLibrarybinds a stack tracing routine that cannot work there, so debug blocks are recorded with no stack trace at all. A leak report printswith nothing between the two lines. The same program built for 32-bit resolves the trace normally.
Cause
FastMM_LoadDebugSupportLibrarybindsGetRawStackTraceon every target:That routine walks the RBP frame chain, and the x64 ABI does not maintain one, so the loop finds nothing and returns an empty buffer.
The support library already has a routine for this case -
GetFrameBasedStackTrace, which under 64-bit is implemented onRtlCaptureStackBackTrace, with the comment "We use the Windows API to do frame based stack tracing under 64-bit". It is exported. It is simply never bound.Measurement
Calling both entry points directly out of the library, bypassing FastMM, with a 20 entry buffer and
ASkipFrameszero:GetRawStackTraceGetFrameBasedStackTraceWhat fixes it
Preferring the frame based routine under 64-bit, keeping the raw one as the fallback for a support library that does not export it, and leaving 32-bit alone - the raw tracer works there and yields the deeper traces it exists for. With that, a Win64 leak report comes back as
Both binding paths need it, the
GetProcAddressone and the statically bound one.A detail worth mentioning: with
ASkipFramesat zero the first captured frame isGetFrameBasedStackTraceitself, so one of the entries is spent on the tracer. Harmless, but it means the effective depth is one less than requested on 64-bit.No pull request, per your note in #101. It is on
win64-frame-based-stack-tracein my fork if you want to look; the test suite passes 18 of 18 runs with it and 32-bit reports are unchanged line for line. Happy to open a PR if you ask for one.