Repository navigation
Run every test program under ThreadSanitizer every night - #137
Open
SwayamInSync wants to merge 22 commits into
Open
SwayamInSync wants to merge 22 commits into
SwayamInSync wants to merge 22 commits into
Conversation
…y and exit hooks, which overflow its shadow stack.
…an's shadow stack.
…and report programs without a result.
…w stack in ARCHITECTURE.md.
…timed wait under ThreadSanitizer.
… bug in ARCHITECTURE.md.
This branch has not been deployed
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.
Plan item T3, the ThreadSanitizer half. Builds on #133 (
ci/sanitizers, the sanitizer option, script, and workflow) and on #136 (the race this sweep found), both merged; main is merged into this branch.Why TSan failed
#133 dropped its TSan job because TSan's runtime crashed or hung in 66 of 69 runs of
suite/spec_automation.cppwith four jobs. The cause is neither the partial instrumentation nor the counterexample checker's thread per check: TSan keeps each thread's calls on a shadow stack of 64 Ki frames (kShadowStackSize) that only a debug runtime bounds, and the checker nests up toCertifyLimits::Frames(50000) evaluations of several frames each, so it writes past it into the runtime's own memory.spec_automation.cpp,--jobs=4, fresh proof cacheCHECKotherwise)__tsan_func_entrywrapper that stops at the limitBackend/Certify.cppCertify.cppwithout entry/exit hooks, either instrumentationA standalone program recursing 65,600 calls deep beside threads that start and stop failed in 3 of 6 runs, at 65,000 in 0 of 6.
Change
Backend/Certify.cppis compiled with-fno-sanitize-thread-func-entry-exitunder TSan (LLVM_USE_SANITIZER=ThreadorCPPVERIFY_SANITIZERwiththread): its accesses are still checked, its frames are missing from reported stacks.tools/cpp-verify/ShadowStackGuard.cpp, linked into TSan builds only (uninstrumented,--wrap=__tsan_func_entry,--wrap=__tsan_func_exit), stops a run that reaches the limit withcpp-verify: ThreadSanitizer shadow stack full: N nested callsand its stack. With the hooks put back inCertify.cpp, 6 of 6 runs stopped so.CppVerifyZ3.cmakebuilds the vendored Z3 with-fsanitize=threadunderLLVM_USE_SANITIZER=Thread, so TSan sees Z3's synchronization and accesses.cppverify-sanitize.sh BUILD address|thread [PARALLEL]: thread mode runs each program with--jobs=4, a proof cache of its own, and--backend=racewhere its RUN lines use it. Both modes skip programs lit never runs (UNSUPPORTED: true:llvm_uleb128_decoder_exhaustive.cpp, which needed 17.6 GB under TSan) and report a program without a result within 900 s, since a hung runtime prints nothing.cppverify-tsan.supp: three races and a lock order inside Z3 4.13.4 (global verbose stream, statistics read of the allocation counters, the timeout handler's flag, the timer pool), and LLVM's crash-time backtrace (crash_report_url.cppcrashes on purpose). Each with its reason.cppverify-sanitizers.yml: aThreadSanitizerjob, clang-18 against GCC 13's libstdc++ (below), everything instrumented, two programs at once.The C++ library on CI's runner
The first CI run failed in Z3's build:
scoped_timer.cpp:64,m_mutex.try_lock_until(end)with asteady_clocktime,error: no member named '_M_clocklock' in 'std::timed_mutex'in/usr/include/c++/14/mutex:205. Clang 18 onubuntu-24.04compiles against the libstdc++ of the image's newest GCC, 14.2, and that is GCC PR 121496: GCC 14 defines_GLIBCXX_USE_PTHREAD_MUTEX_CLOCKLOCKas(_GLIBCXX_TSAN==0), so 0 under TSan, and<mutex>tests it with#ifwheretimed_mutex::_M_clocklockis declared (line 300) but with#ifdefwhere the steady-clock_M_try_lock_untilthat calls it is defined (line 191). The#ifdefs are in 14.3.0 and 15.2.0 and gone in 14.4.0 and 15.3.0. GCC 13 defines the macro as 1, and its wait callspthread_mutex_clocklock, which clang-18's TSan runtime intercepts (nm libclang_rt.tsan-x86_64.a). This machine has only GCC 13, so local builds never hit it; with Ubuntu'slibstdc++-14-dev14.2.0-4ubuntu2~24.04.1 selected through--gcc-install-dir, the same error appears, and nothing else in LLVM, Clang, or the verifier uses a timed mutex.--gcc-install-dir=/usr/lib/gcc/x86_64-linux-gnu/13asCMAKE_C_FLAGSandCMAKE_CXX_FLAGS.CppVerifyZ3.cmakegives Z3's ExternalProject the cache'sCMAKE_C_FLAGS,CMAKE_CXX_FLAGS, andCMAKE_EXE_LINKER_FLAGS(as configured, without LLVM's additions), then TSan's. Z3 got only the compilers before, so a flag that selects the C++ library reached LLVM and the verifier but not Z3. With no flags configured nothing more is passed, as before.CPPVERIFY_TSAN_TIMED_MUTEX_WAIT) and otherwise stops with the cause and the flags to use; a failed check is not cached, so it is rerun after the flags change.scoped_timer.cppno member named '_M_clocklock'A full configure of LLVM with TSan and GCC 14.2's headers stops at the check as well.
Instrumenting only the verifier is still accepted but not used: it reported a race on LLVM's
RemoveFileOnSignallist that the full build, seeing LLVM's atomics, does not, and it cannot see a race on Z3 objects.Results
The nightly's configuration (vendored Z3 through the ExternalProject) on all 465 programs with this branch plus #136:
thread: no reports in 465 programs, 4800 CPU seconds (20 minutes on four cores here), at most 3.3 GB a program. Without #136 the sweep reports the source manager race ingetLineNumber(calls_in_expressions.cpp,inductive_counterexamples.cpp,pointer_origins.cpp,range_for.cpp, and #136's test), so this PR's own TSan job fails until #136 is merged in.After merging #133's fresh stacks for the certifier (
ci/sanitizersat eb7b64d) and running at the default 8 MiB stack limit, as the script now does: 30 of 30 runs ofspec_automation.cppfinished with no runtime failure; the sweep (4300 CPU seconds) reported only that source manager race, in 6 programs; and with the hooks put back inCertify.cpp, 6 of 6 runs still stopped at the guard, since half of a 256 MiB stack holds more than 65536 frames.After merging main (#136, #138, #139, #133) and with the job's flags (
--gcc-install-dir=/usr/lib/gcc/x86_64-linux-gnu/13), the job's build and script with eight programs at once:thread: no reports in 468 programs, 3900 CPU seconds, at most 3.5 GB a program.Two of 20 runs of the partly instrumented build with the manual wrapper stalled once, under heavy machine load, after storing every proof; 80 more runs of that binary under gdb did not reproduce it, and the fully instrumented builds never stalled (220 runs). The no-result check would report such a stall in CI.
Docs
ARCHITECTURE ("Regression and Coverage"), the tooling reference (the build, the script, the guard's exact output), and the release notes ("Testing").