Skip to content

FullDebugMode support library destroys source paths outside the ANSI code page #105

Description

@TetzkatLipHoka

The FullDebugMode support library hands its stack trace text over as PAnsiChar, and FastMM widens it again assuming Latin-1. Both halves lose data, and the loss is not limited to exotic setups.

Where it happens

  1. FastMM_FullDebugMode.dpr, in the JCL branch of LogStackTrace:

    LPInfo := LReturnAddressInfoCache.AddEntry(LAddress, AnsiString(LTempStr));

    LTempStr is a string. Casting it to AnsiString replaces everything the system ANSI code page cannot represent with question marks, permanently.

  2. FastMM5.pas, in FastMM_DebugLibrary_LegacyLogStackTrace_Wrapper:

    Result^ := WideChar(LPCurPos^); //Assume it is Latin-1 text

    The library produced that text in the ANSI code page, not in Latin-1. On a Russian system a Cyrillic path fits into the AnsiString perfectly well and is then mangled here. On a Western system the two agree except for 0x80..0x9F, which is where , and the typographic quotes live.

So a path survives only if it is pure ASCII, or if the system code page is 1252 and the path avoids that range.

Reproducing it

A unit whose file name mixes scripts, so no single code page can hold it:

Проект日本Grösse.pas

Built with -GD, traced through the support library, the frame comes back as

before:  ÐÑÐ¾ÐµÐºÑæ¥æ¬Grösse.pas

Five characters are simply gone. They are the ones that land in 0x80..0x9F on the way down and become control characters on the way back up.

A second thing, while in here

TFastMM_LegacyConvertStackTraceToText has no buffer end parameter, so the library cannot know where the caller's buffer stops - the wrapper just trusts it with a 16 KB stack buffer. TFastMM_ConvertStackTraceToText, which FastMM already uses for custom handlers, does carry one.

Not a FastMM bug, but visible in the same output

The remaining mojibake above is the JCL: Delphi writes the .map file as UTF-8 and the JCL reads it as ANSI. I verified that against the raw bytes (D0 9F D1 80 D0 BE ... = Проект in UTF-8). That belongs upstream in the JCL and I intend to take it there; I mention it only so the sample output above is not mistaken for something FastMM could fix.

What I did on my side

No pull request, per your note in #101. For what it is worth, the shape that worked was: export LogStackTraceW from the library using the existing TFastMM_ConvertStackTraceToText signature, prefer it in FastMM_LoadDebugSupportLibrary and keep the legacy lookup as the fallback, so an older support library keeps working untouched. That removes the wrapper and its stack buffer entirely rather than adding to them. The info cache becomes WideChar, which doubles it in memory (~900 KB at the default 4096 entries) but costs about 512 bytes in the file, since it is uninitialised data.

For the third party backends it differs: madExcept exposes StackAddrToStr, which returns a UnicodeString per address, so that build needs no code page at all. EurekaLog and the map file reader only offer ANSI, so the best available there is converting through the actual code page instead of assuming Latin-1 - enough for a single script non-Western system, not for mixed scripts.

It is on fulldebugmode-unicode-stacktrace in my fork if you want to look, and it builds on Delphi 7, 2009 and 13.1. 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