Skip to content

Commit 3490b49

Browse files
committed
ci: defer to libsanitizer + filter jit note from parity diff
Two latent CI matrix failures after v0.255.15: mino's install_crash_handler unconditionally installs SIGSEGV / SIGABRT / SIGBUS handlers. Under libasan (gcc, Linux) those run BEFORE libasan's own handlers, so a sanitizer trap produces an opaque "[mino] fatal SIGSEGV" line with no AddressSanitizer preamble -- the diagnostic libasan formatted gets swallowed. Apple clang's ASan on macos was permissive enough not to surface this. Skip the crash handler entirely when any sanitizer is built in; the sanitizer's reports are strictly better than mino's minimal preamble. test-jit-parity builds four variants and asserts byte-identical stdout across them. On hosts where the JIT is not available (every non-arm64-darwin runner: arm64-linux, x86_64-linux, etc), --jit=on prints a one-line stderr note that the build can't honor the flag. sh captures stderr via 2>&1, so the note lands in :out and breaks the diff. Strip it before comparing. Local release-gate 17/17 green; tests/run.clj 1274/4557 green.
1 parent e284387 commit 3490b49

4 files changed

Lines changed: 93 additions & 2 deletions

File tree

CHANGELOG.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,52 @@
11
# Changelog
22

3+
## v0.255.16 — Fix: Defer to libsanitizer + filter JIT note from parity diff
4+
5+
Two remaining CI matrix failures after v0.255.15:
6+
7+
- **ubuntu-24.04 (x86_64) ASan SEGV.** mino's `install_crash_handler`
8+
unconditionally installs SIGSEGV / SIGABRT / SIGBUS handlers via
9+
`sigaction`. Under libasan (gcc) those run BEFORE libasan's own
10+
handlers, so a sanitizer-driven trap (red-zone read or any other
11+
ASan-flagged access) produces an opaque
12+
`[mino] fatal SIGSEGV (signal 11)` line with no `==XXX==ERROR:
13+
AddressSanitizer:` preamble -- the actual diagnostic libasan
14+
formatted gets swallowed. Apple clang's ASan on macos was permissive
15+
enough not to surface this. Skip the crash handler entirely when any
16+
sanitizer (ASan / TSan / UBSan) is built in; the sanitizer's
17+
reports are strictly better than mino's minimal preamble.
18+
19+
- **ubuntu-24.04-arm jit-parity warning leak.** `test-jit-parity`
20+
builds four variants (`--jit=auto`, `--jit=on`, `--jit=off`,
21+
`mino-lean`) and asserts every variant's stdout is byte-identical.
22+
On hosts where the JIT is not available (every non-arm64-darwin
23+
runner in this matrix), `--jit=on` prints a one-line note to stderr
24+
that the build can't honor the flag. `sh` captures stderr via
25+
`2>&1`, so the note lands in `:out` and breaks the diff. The note
26+
is informational and orthogonal to the parity contract (which is
27+
about the evaluator's stdout). Strip it before comparing.
28+
29+
### Changes
30+
31+
- `main.c::install_crash_handler`: dual-path early-return when
32+
`__has_feature(address_sanitizer)` (clang) or
33+
`__SANITIZE_ADDRESS__` / `__SANITIZE_THREAD__` /
34+
`__SANITIZE_UNDEFINED__` (gcc).
35+
- `lib/mino/tasks/builtin.clj::run-parity-variant`: filter the
36+
"this build has the JIT compiled out" line out of each variant's
37+
`:out` before the byte-identity comparison. Line-based filter
38+
because mino's `clojure.string/replace` doesn't accept regex.
39+
- `src/mino.h`: `MINO_VERSION_PATCH` bumped to 16.
40+
41+
### Verification
42+
43+
- Local `release-gate` 17/17 green.
44+
- Local `tests/run.clj` 1274 tests / 4557 assertions green.
45+
- On ubuntu-24.04 x86_64 the v0.255.16 ASan run will either pass
46+
(if the previous SEGV was an instrumentation false positive only
47+
masked by the handler) or surface the real ASan report (if there
48+
IS a real OOB). Either is a step forward from the silent SEGV.
49+
350
## v0.255.15 — Fix: Free dyn_frame on eval_try unwind path
451

552
With v0.255.14's ASan stack-scan attribute fix letting the ASan

lib/mino/tasks/builtin.clj

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,10 +313,33 @@
313313
(apply sh! args)
314314
(println " lean build -> mino-lean")))
315315

316+
(def ^:private jit-disabled-warning-prefix
317+
"mino: note: this build has the JIT compiled out")
318+
319+
(defn- strip-jit-disabled-warning [s]
320+
;; mino prints a one-line stderr note when --jit=on or MINO_JIT=on is
321+
;; requested on a build/host where the JIT isn't available (e.g. all
322+
;; non-arm64-darwin matrix entries: arm64-linux, x86_64-linux,
323+
;; x86_64-windows). sh captures stderr via 2>&1, so the note lands in
324+
;; the variant's :out and breaks the byte-identity diff against
325+
;; jit-auto (which doesn't trip the warning). The note is informational
326+
;; and not part of the parity contract -- jit-parity is about the
327+
;; runtime evaluator's stdout, not about which CLI flags this build
328+
;; honors. Strip it before comparing.
329+
;;
330+
;; Implemented line-by-line because mino's clojure.string/replace
331+
;; requires a string match; regex matching is unavailable on this path.
332+
(if (nil? s)
333+
s
334+
(str/join "\n"
335+
(remove (fn [line]
336+
(str/starts-with? line jit-disabled-warning-prefix))
337+
(str/split s "\n")))))
338+
316339
(defn- run-parity-variant [bin-args label parity-test]
317340
(let [result (apply sh (concat bin-args [parity-test]))]
318341
{:label label
319-
:out (get result :out)
342+
:out (strip-jit-disabled-warning (get result :out))
320343
:exit (get result :exit)}))
321344

322345
(defn test-jit-parity

main.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -760,6 +760,27 @@ static void install_crash_handler(mino_state_t *S)
760760
if (disabled != NULL && disabled[0] != '\0' && disabled[0] != '0') {
761761
return;
762762
}
763+
/* Skip when running under a sanitizer: libasan / libtsan / libubsan
764+
* install their own SIGSEGV / SIGABRT handlers and produce far more
765+
* detailed reports (red-zone diagnosis, allocation backtraces, leak
766+
* graphs). Mino's handler intercepting SIGSEGV first means the
767+
* sanitizer's report path never runs -- on ubuntu-24.04 x86_64 a
768+
* conservative-stack-scan false positive surfaced as an opaque
769+
* "[mino] fatal SIGSEGV" line with no ASan preamble, masking the
770+
* actual diagnostic. Detect clang via __has_feature and gcc via
771+
* __SANITIZE_*__ predefined macros (same dual-path used in
772+
* gc/internal.h's MINO_GC_PIN_LOUD_ASSERT). */
773+
#if defined(__has_feature)
774+
# if __has_feature(address_sanitizer) \
775+
|| __has_feature(thread_sanitizer) \
776+
|| __has_feature(undefined_behavior_sanitizer)
777+
return;
778+
# endif
779+
#elif defined(__SANITIZE_ADDRESS__) \
780+
|| defined(__SANITIZE_THREAD__) \
781+
|| defined(__SANITIZE_UNDEFINED__)
782+
return;
783+
#endif
763784
crash_handler_state = S;
764785
#ifndef _WIN32
765786
{

src/mino.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
*/
2929
#define MINO_VERSION_MAJOR 0
3030
#define MINO_VERSION_MINOR 255
31-
#define MINO_VERSION_PATCH 15
31+
#define MINO_VERSION_PATCH 16
3232

3333
/*
3434
* Human-readable version string of the *linked* runtime, e.g. "0.48.0".

0 commit comments

Comments
 (0)