Menu

#785 cdescribe.c: stale static trk pointer survives LoadTracks(), can crash on file load (intermittent)

fixed
nobody
None
2026-09-08
2026-09-07
No

Investigate/fix a crash-on-file-load caused by CmdDescribe's module-static trk pointer surviving
across LoadTracks() -- root-caused via gdb on a real crash, but not yet reliably reproducible on
demand (see repro notes below before assuming any specific recipe always triggers it).

Root cause (confirmed via gdb on a real core dump): CmdDescribe() (app/bin/cdescribe.c)'s
C_REDRAW case has:

} else if (trk) {
    DrawTrack(trk,&tempD,wDrawColorPreviewSelected);
}

trk is a function-static (persists across calls) pointing at whatever track was last being
interactively described. Nothing resets it (or the related descTrk) when a new file is loaded.
LoadTracks() (app/bin/fileio.c) calls ClearTracks() (freeing/reinitializing the whole track
pool) then RecomputeElevations(), which synchronously triggers MainRedraw() ->
DrawTempContent() -> DoCurCommand() -> CmdDescribe()'s C_REDRAW case, before anything has
cleared the stale trk left over from the previous file. If it doesn't happen to compare equal
to NULL, DrawTrack() dereferences a track pointer into memory that's been freed/reused by the
new file's own track pool, and further down the call chain (IsTrack/QueryTrack/GetTrkType)
crashes -- observed as both a CHECK()-triggered SIGABRT and a straight SIGSEGV in different
capture attempts, consistent with reading garbage/reused memory rather than a single fixed bad
value.

Actual crash backtrace (one of two captured, gdb with full debug symbols against a matching
build):

#0 QueryTrack (trk=0x41199930, query=14) at track.c:2609
#1 IsTrack at track.c:2619
#2 DrawTrack at track.c:2951
#3 CmdDescribe at cdescribe.c:683 -- DrawTrack(trk,&tempD,wDrawColorPreviewSelected);
#4 DoCurCommand at command.c:413
#5 DrawTempContent at draw.c:278
#6 MainRedraw at draw.c:464
#7 RecomputeElevations at elev.c:1005
#8 LoadTracks at fileio.c:669
#9 wFilSelect -> DoLoad -> Confirm -> ChkLoad -> pushMenuItem (File > Open)

Not yet reliably reproducible on demand. Manual GUI repro (open a file, interact with a track
via Describe, Save, File > Open a different file) crashed twice, but repeated attempts afterward
-- on the exact same build, on an unrelated/unmodified build, and with the interacting-with-a-track
step varied -- did not reproduce it every time, including under a clean AddressSanitizer-
instrumented run of what should have been the same scenario (ASan reported nothing). This suggests
either a more specific trigger condition than "any described track + any file load" (a particular
track type, a particular prior command state, or genuine memory-layout-dependent timing), or that
the bug is real but only manifests when the freed memory happens to get reused in an
attacker/user-visible way before the redraw runs.

Suggested fix direction for next investigation pass: reset trk (and confirm descTrk's
lifecycle too) whenever a new file is loaded -- either inside CmdDescribe on a
C_CANCEL/explicit reset action invoked from LoadTracks()/ClearTracks(), or by having
ClearTracks() itself notify/callback into any "current command" holding stale track_p state.
Before landing a fix, get a deterministic repro (ideally via ASan, since manual GUI clicking has
proven unreliable) so the fix can actually be verified rather than merely inferred from a
one-time gdb backtrace.

Found while investigating unrelated user testing of the Layer Groups feature (SF #782); confirmed
via clean-room testing that this bug is unrelated to Layer Groups' own code (cdescribe.c is
untouched by that branch, and the crash reproduced -- when it did -- on an unmodified build too).

Discussion

  • Allen D Byrne

    Allen D Byrne - 2026-09-07

    Fixed as part of the #782 (Layer Groups) branch/PR -- found live-testing that feature. Root cause: CmdDescribe()'s static trk is set on every mouse move over a track while Describe is the active command, not just on a click, and is otherwise never cleared; a stale pointer from a previous file survives if a new file loads while Describe is still active, and the post-load redraw dereferences it into freed memory. Deterministically reproduced two ways (a live gdb attach during a real user crash, and independently via an automated repro: select Describe, move the mouse over any track with no click, Save As, then File > Open a different file) and confirmed the fix eliminates it against the same repro. git PR #181 merged (27/27 CI green), Hg branch pushed to SF. Holding out of Hg mainline for the normal review window alongside #782.

     
  • Allen D Byrne

    Allen D Byrne - 2026-09-08

    Correction: merged into Hg mainline (GTK3V2MAIN) separately from #782 via hg graft, not as part of that branch's merge -- #782 (Layer Groups) is being held back for further review while this fix lands on its own. Pushed to SF.

     

Anonymous
Anonymous

Add attachments
Cancel