From 7525dbc30e40911a690c49d6a9a166400e521fef Mon Sep 17 00:00:00 2001 From: ASDAlexander77 Date: Mon, 28 Sep 2026 18:40:45 +0100 Subject: [PATCH] A failing assert in a Linux JIT run is reported, not a compiler crash Off Windows the lowered assert calls glibc's __assert_fail, which ends in abort(). tslang's crash handler took that SIGABRT for a compiler crash and printed "PLEASE submit a bug report" and a "Stack dump" after the message. The JIT now binds __assert_fail to the handler that already answers _assert on Windows: it prints "file:line: assertion failed: msg" and exits with 3. The failing-assert JIT test runs on Linux too. Co-Authored-By: Claude Opus 5.5 --- tslang/test/tester/CMakeLists.txt | 19 ++++++++----------- tslang/tslang/jit.cpp | 24 ++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/tslang/test/tester/CMakeLists.txt b/tslang/test/tester/CMakeLists.txt index a45c1f43d..5a695e783 100644 --- a/tslang/test/tester/CMakeLists.txt +++ b/tslang/test/tester/CMakeLists.txt @@ -2546,17 +2546,14 @@ set_tests_properties(test-compile-specialization-cast-pair-error FAIL_REGULAR_EXPRESSION "Stack dump|Assertion failed") # A failing assert shows a message known only at run time, after the output printed before it. -# Windows only: that is where the JIT reports a failed assert; on Linux abort() reaches LLVM's -# crash handler. -if (WIN32) - add_test(NAME test-jit-assert-message-failing - COMMAND $ --emit=jit --no-default-lib - --shared-libs=$ - "${PROJECT_SOURCE_DIR}/test/tester/assert-message/failing.ts") - set_tests_properties(test-jit-assert-message-failing - PROPERTIES PASS_REGULAR_EXPRESSION "printed before.*assertion failed: n is 7" - FAIL_REGULAR_EXPRESSION "Stack dump|unlinked") -endif() +# The JIT reports it itself on every platform, so on Linux abort() never reaches the crash handler. +add_test(NAME test-jit-assert-message-failing + COMMAND $ --emit=jit --no-default-lib + --shared-libs=$ + "${PROJECT_SOURCE_DIR}/test/tester/assert-message/failing.ts") +set_tests_properties(test-jit-assert-message-failing + PROPERTIES PASS_REGULAR_EXPRESSION "printed before.*assertion failed: n is 7" + FAIL_REGULAR_EXPRESSION "Stack dump|unlinked") # --export=all exports the module's variables, not the locals of its functions. add_test(NAME test-compile-export-all-no-locals diff --git a/tslang/tslang/jit.cpp b/tslang/tslang/jit.cpp index 4785307a8..0d1db3d0b 100644 --- a/tslang/tslang/jit.cpp +++ b/tslang/tslang/jit.cpp @@ -327,6 +327,16 @@ static void jitAssertFailed(const char *message, const char *file, unsigned line _exit(3); } +#ifndef _WIN32 +// glibc's `__assert_fail`, which the lowering calls off Windows, ends in abort(). tslang's own +// crash handler takes that SIGABRT for a compiler crash and prints a "Stack dump" after the +// message. Report it as on Windows instead. +static void jitGlibcAssertFail(const char *assertion, const char *file, unsigned line, const char * /*function*/) +{ + jitAssertFailed(assertion, file, line); +} +#endif + #ifdef _WIN64 // MSVC x64 C++ EH encodes throw-site type information as image-relative offsets. // vcruntime's _CxxThrowException recovers the base with RtlPcToFileHeader on the @@ -904,6 +914,20 @@ int runJit(int argc, char **argv, mlir::ModuleOp module, CompileOptions &compile return -1; } } +#else + // see jitGlibcAssertFail above + { + llvm::orc::MangleAndInterner interner(jit->getExecutionSession(), jit->getDataLayout()); + llvm::orc::SymbolMap assertOverrides; + assertOverrides[interner("__assert_fail")] = { + llvm::orc::ExecutorAddr::fromPtr(&jitGlibcAssertFail), llvm::JITSymbolFlags::Exported}; + if (auto err = jit->getMainJITDylib().define(llvm::orc::absoluteSymbols(std::move(assertOverrides)))) + { + llvm::WithColor::error(llvm::errs(), "tslang") << "failed to define the assert handler, error: " << err << "\n"; + llvm::consumeError(std::move(err)); + return -1; + } + } #endif if (auto err = jit->addIRModule(llvm::orc::ThreadSafeModule(std::move(llvmModule), std::move(llvmContext))))