Skip to content

Debug mode captures no stack trace at all under 64-bit #106

Description

@TetzkatLipHoka

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions