Skip to content

fix(build): avoid jt9 SIGSEGV from gfortran stack trampolines - #53

Open
cjkjellander wants to merge 1 commit into
WSJTX:masterfrom
cjkjellander:gfortran-stack-trampolines
Open

fix(build): avoid jt9 SIGSEGV from gfortran stack trampolines#53
cjkjellander wants to merge 1 commit into
WSJTX:masterfrom
cjkjellander:gfortran-stack-trampolines

Conversation

@cjkjellander

Copy link
Copy Markdown

On Linux, jt9 segfaults inside ft8_decode (SIGSEGV) with gfortran and
hardened toolchains. The FT8 decoder callback is an internal procedure passed
as an actual argument, which gfortran implements as a trampoline placed on
the stack
. The -Wa,--noexecstack hardening added for certain Linux builds
marks the stack non-executable, so the trampoline can no longer run and the
process crashes as soon as a decode is produced.

This is a build-time-vs-run-time trade-off: noexecstack keeps strict linkers
happy but breaks the decoder at run time; an executable stack runs but trips a
linker warning on hardened distros.

The clean resolution is to stop putting the trampoline on the stack at all.
gfortran 14 added -ftrampoline-impl=heap, which allocates trampolines on the
heap and lets the stack stay non-executable. This PR:

  • detects -ftrampoline-impl=heap with check_fortran_compiler_flag;
  • if supported (gfortran >= 14): uses it and keeps -Wa,--noexecstack
    (no crash, no warning, stack stays non-executable);
  • otherwise (gfortran <= 13): falls back to -Wa,--execstack so the
    trampoline can run, rather than crashing.

The fallback re-introduces the non-fatal ld: warning: ... requires executable stack on older compilers — that is the correct trade-off (a warning beats a
run-time crash), and modern toolchains avoid both paths.

Verified on gfortran 13.3 (Ubuntu 24.04): without this, jt9's GNU_STACK is
RW and it SIGSEGVs in ft8_decode; with the fallback it is RWE and decoding
works. gfortran >= 14 selects the heap-trampoline path.

gfortran compiles the FT8 decoder callback (an internal procedure passed
as an actual argument) into a trampoline placed on the stack. Combined
with the -Wa,--noexecstack hardening this crashes at run time (jt9
SIGSEGV in ft8_decode) on gfortran and hardened toolchains, because the
trampoline cannot execute on a non-executable stack.

Prefer heap-allocated trampolines when the compiler supports them
(gfortran >= 14, -ftrampoline-impl=heap), which keeps the stack
non-executable. On older compilers that lack the option, mark the stack
executable so the trampoline runs instead of crashing.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant