Fix callback function tests broken by modern GCC and Linux kernel NX protection#541
Open
mqcmd196 wants to merge 3 commits into
Open
Fix callback function tests broken by modern GCC and Linux kernel NX protection#541mqcmd196 wants to merge 3 commits into
mqcmd196 wants to merge 3 commits into
Conversation
…protection Three bugs prevented defun-c-callable / callback tests from working: 1. test/test_foreign.c: set_ifunc and set_ffunc lacked return statements. GCC -O2 generated no retq, causing fall-through from set_ifunc -> set_ffunc -> call_ifunc -> jmp *g where g was the integer argument (e.g. 12345), crashing at address 0x3039. Fixed by adding `return 0;` to both. 2. lisp/l/eusforeign.l: trampoline (podcode) lives in GC heap which is non-executable on Linux kernel >= 5.8 even with -z execstack. Fixed by adding defforeign for mprotect via sys::sysmod and calling it in foreign-pod :init to mark the trampoline page PROT_READ|PROT_WRITE|PROT_EXEC. Page address is computed with (* (floor (/ addr 4096)) 4096) to avoid a 32-bit truncation bug in (logand addr (lognot 4095)). 3. test/test-foreign.l: uncommented callback tests and restructured them as proper deftest forms. defun-c-callable must be at top level (not inside deftest) because it uninters and re-interns the symbol; quote-captured 'LISP-IFUNC inside a deftest body would hold the pre-unintern symbol. Use (intern "LISP-IFUNC") at runtime to look up the re-interned foreign-pod. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
macOS (Intel x86_64) CI failed because euscomp reads eusforeign.l at startup and the #+:x86_64 guard is true on macOS, but mprotect is not findable via (system::find-entry "mprotect" (sys::sysmod)) on Darwin. Fix: wrap defforeign in (when (system::find-entry ...)) so it is only defined when mprotect is actually available in sysmod. Similarly guard the mprotect call in foreign-pod :init with (fboundp 'c-mprotect) to skip it when the defforeign was not executed. ARM/i386/RISC-V CI failed because the new callback tests run on all platforms, but defun-c-callable trampolines are x86_64-specific machine code. Fix: add #+:x86_64 reader guards to both defun-c-callable and deftest forms for the callback tests. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
#+:x86_64 is also true on macOS Intel, but there mprotect is not available in sysmod so the GC heap cannot be made executable. The callback tests crash on macOS even though the build no longer fails. Use #+(and :x86_64 :linux) to limit them to Linux x86_64 only. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
test/test_foreign.c:set_ifuncandset_ffunclackedreturnstatements. GCC -O2 generated noretq, causing fall-through fromset_ifunc→set_ffunc→call_ifunc→jmp *gwheregheld the integer argument (e.g. 12345), crashing at address 0x3039.lisp/l/eusforeign.l: The trampoline (podcode) lives in GC heap, which is non-executable on Linux kernel ≥ 5.8 (NX protection), even with-z execstack. Addeddefforeign c-mprotectviasys::sysmodand call it inforeign-pod :initto mark the trampoline pagePROT_READ|PROT_WRITE|PROT_EXEC. Page address is computed with(* (floor (/ addr 4096)) 4096)to avoid a 32-bit truncation bug in(logand addr (lognot 4095)).test/test-foreign.l: Uncommented and restructured callback tests as properdeftestforms.defun-c-callablemust be at top level (not insidedeftest) because it uninterns and re-interns the symbol; use(intern "LISP-IFUNC")at runtime instead of'LISP-IFUNCto look up the re-internedforeign-pod.Test plan
test/test-foreign.lwitheusgon x86_64 Ubuntu 24.04 (GCC 13, kernel 6.17): all 19 tests pass includingtest-callback-integerandtest-callback-float🤖 Generated with Claude Code