Fix native control-flow and symbol miscompiles and complete the fuzz campaign inventory - #28
Merged
Merged
Conversation
…ied frontend input across optimizer modes; require measured execution and RSS evidence in campaign reports; strengthen deterministic oracle smoke tests and document sanitizer boundaries
… fuzz campaign inventory The native Core-to-CorePrep adapter built loop and logical-operator control flow that diverged from the Haskell CorePrep lowering: - a for-loop update region fell through to its own entry instead of the condition, so every for loop that reached its update never terminated; - a while condition was folded into the incoming block, so each back-edge re-executed the statements preceding the loop, including its initializers; - the canonicalizing comparison of a numeric for condition was dropped, which made valid programs fail CorePrep verification; - && and || were lowered as eager two-operand instructions, so a guarded division trapped and a guarded recursion overflowed the stack. The adapter now threads one block cursor through expressions and statements. Loop headers are dedicated blocks, the fallthrough successor of a loop region is separate from its continue target, and short-circuit operators become a branch with an initialized Boolean result slot, matching the Haskell lowering. Regression coverage asserts exact CorePrep edges for for, while, do/while, nested loops and short-circuit operators, and executes each form through CorePrep, Xpp, Xmm and LLVM with both native optimizer settings against values computed by host code. One existing test that pinned the eager LogicalAnd shape now checks the per-operand canonical comparisons in the lazy shape. The differential oracle gains while and guarded-recursion shapes, and the source smoke sweeps every shape across trip counts 0 through 11. Fuzzing: add component-owned CLI, project registry, REPL and AARC ownership libFuzzer targets with versioned seed corpora, a bounded project registry decoder entry point with its tests, and an HPC-guided Haskell frontend engine with feedback and mutation policy tests. The developer helper shares one target inventory, terminates the whole process tree when a smoke, libFuzzer or HPC process exceeds its watchdog, isolates the HPC tick file per stage, reads the HPC report from the engine's report file, and adds fuzz-thread, a separate ThreadSanitizer campaign for threaded targets that fails on hosts without a ThreadSanitizer runtime. CI runs the ThreadSanitizer ownership campaign on macOS and native Ubuntu and the fuzz feedback tests with the Haskell layers. The fuzzing, Core IR, testing and developer recipe documents describe the verified inventory, limits and remaining coverage boundaries. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…idence Fix two failures the first hosted run of the new fuzz inventory exposed: - OwnershipFuzzer used std::jthread, which Apple libc++ does not provide. It now uses std::thread and joins every worker before the destructor oracle runs. - The process-tree watchdog test reported a surviving descendant inside the Fedora container. The watchdog had killed it; the orphan stayed a zombie because the container's first process never reaped it, and signal 0 still succeeds for a zombie. The Unix liveness probe now treats a zombie or dead procfs state as terminated. Campaign scheduling: targets and HPC stages run through one bounded scheduler. Concurrency is not free evidence: on a two-core, four-thread host two concurrent targets executed 40 to 90 percent fewer inputs each, so the default is one job per four logical processors, at most four, which keeps such hosts and four-vCPU runners sequential. VXS_FUZZ_JOBS overrides it, targets with a 4096 MiB RSS limit never overlap, and the ThreadSanitizer campaign always runs one target at a time. Budgets, limits, timeouts and watchdogs are identical at every job count, the report keeps inventory order, and the earliest failing target is reported regardless of scheduling. Build time: outside CI the helper adds a persistent content-addressed Bazel disk cache, limited to 8 GiB, to its build invocations. The plain, sanitizer and fuzz configurations share one output tree, and every switch previously recompiled all owned translation units. Measured on the same sources, a bounded campaign dropped from 910 to 436 seconds with unchanged or higher executed-input counts. VXS_BAZEL_DISK_CACHE selects another absolute directory or disables the cache. The fuzzing guide documents the job policy, the measurement behind it and the cache.
…aign Both inputs are valid programs that passed Core verification and were then rejected inside the native pipeline. Module-wide symbol allocation: the Core-to-CorePrep adapter numbered generated temporaries from the highest identity of the function being lowered and lifted closure names from a separate counter. Identities are unique across a module, so a temporary of one function reused another function's identity and CorePrep verification reported one identity with conflicting spellings and types. Temporaries, condition and short-circuit slots, and closure names now come from one counter that starts above every identity in the module and is never reset, as the Haskell lowering does. Reserved LLVM prefix: a function in a namespace named llvm produced a global whose name began with the prefix LLVM reserves for intrinsics, and module verification failed. Such symbols are emitted with a leading dollar sign, which cannot occur in a source identifier; declarations in other per-source objects follow the same rule. Each defect has a failing-first component test, and both crashing inputs join the versioned source corpus. The Core IR and LLVM backend documents state the allocation and naming rules.
A hosted AddressSanitizer run aborted the differential smoke with 'IMAGE_REL_AMD64_ADDR32NB relocation requires an ordered section layout' while the same commit passed in a parallel run. On Windows LLJIT links with RuntimeDyld, whose default memory manager maps code and data sections separately. Win64 unwind tables use image-relative relocations that can only be applied when no section of an object lies below the lowest one, so the operating system's choice of addresses decided whether linking succeeded. The ORC session now gives each object a single pre-reserved block on COFF hosts and keeps LLJIT's COFF symbol-flag handling; other hosts keep the default linking layer. The failure depends on address layout and was not reproduced locally, so a test samples 400 independent sessions and the interactive guide states that the evidence for the fix is indirect.
The contiguous-reservation linking layer introduced for COFF hosts used a SectionMemoryManager constructor that only newer LLVM releases provide. The block was selected at run time but compiled on every host, so builds against distribution LLVM releases on macOS, Ubuntu and Fedora failed with 'no matching constructor for initialization of llvm::SectionMemoryManager'. The linking-layer setup and its two headers are now inside a Windows-only preprocessor block. Other hosts compile the same session setup as before that change and keep LLJIT's default linking layer.
Leitwolf11
marked this pull request as ready for review
October 2, 2026 00:51
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.
Compiler defects fixed
All of these were valid programs that the frontend accepted and the native pipeline then miscompiled or rejected.
forupdate region fell through to its own entryinstead of the condition, so the loop never terminated. A
whilecondition was folded into the incoming block, soeach back-edge re-ran the statements before the loop. The canonicalizing comparison of a numeric
forconditionwas dropped.
&&and||were lowered as eager two-operand instructions; a guarded divisiontrapped and a guarded recursion overflowed the stack. They are now control flow, as in the Haskell lowering.
identity. Found by the hosted source fuzz campaign.
llvmproduced a symbol in LLVM's intrinsic namespaceand failed module verification. Found by the hosted source fuzz campaign.
IMAGE_REL_AMD64_ADDR32NBlayouterror. Windows ORC sessions now link each object into one contiguous reservation. This failure was not reproduced
locally; the change removes its cause and the evidence for it is indirect.
Each fix except the last has a failing-first regression test: exact CorePrep edge assertions in
Compiler/Core/Testsand executable tests inCompiler/Backend/LLVM/Teststhat run both optimizer settings againstvalues computed by host code.
Fuzzing and tooling
whileand guarded-recursion shapesand the smoke sweeps every shape across trip counts 0 through 11.
frontend engine and a ThreadSanitizer campaign (
fuzz-thread) for threaded targets on macOS and native Linux.smoke, libFuzzer or HPC process exceeds its watchdog.
with unchanged or higher executed-input counts. Concurrent targets are off by default because they reduced executed
inputs on a two-core host.
Verification
ASan/UBSan suites, the bounded fuzz campaigns and the ThreadSanitizer ownership campaign.
verify-helpers,verify-docs, and a bounded 9-target libFuzzer plus 3-stage HPC campaign.Known limits
continueinside aforupdate region still targets the update entry in both lowerings. The frontend cannotproduce it; the verifier does not reject it.
run locally.