Repository navigation
feat!: guard every access by default - #46
Merged
Merged
Conversation
Implements RFC 0035 (docs/rfcs/0035-guard-by-default.md). weavec-cc now guards every load, store, atomic, memory intrinsic and library-call memory argument through ASan-style shadow memory, with redzones around stack frames, globals and heap blocks. A guard is removed only where a local rule proves it redundant, monitored by -fweavec-checks=verify. The ownership analysis is advisory: it runs in weavec and under -fweavec-diagnose and never changes generated code. BREAKING CHANGE: inserted checks, require levels, unit records, the link step and the analysis ledger are deleted, with their flags; the enforcement ledger is version 3; the runtime must be built by Clang.
The runtime reserves its shadow in a constructor on every target: on Linux nothing did before main, which kept the empty descriptor and passed every guard. A release of a stack or global object is reported before it reaches glibc. Reports name the call site of an artificial function, such as glibc's fortified wrappers (RFC 0035 amendment 14). Also: clang-tidy findings in the new passes, glibc's missing gets declaration and ELF's dso_local in the lit tests, and an ASan oracle that depended on the machine.
The record predated the last wip changes to the passes (late redirect of read-only calls, inline library guards only for exact constants, loop unrolling), so CI's quick gate failed on cJSON's proven share. Recorded from a full --quick run; adds the configs that had no record.
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
Implements RFC 0035, Guard by default. The order is reversed:
weavec-ccnow guards every memory access, and removes a guard only where a local rule proves it redundant. The ownership analysis no longer decides what is checked. It is advisory, runs inweavecand under-fweavec-diagnose, and never changes generated code.After RFC 0034, only 2 of 10 new projects built and passed, three classes of wrong proof had been found, and the guards were doing the catching anyway. Now:
fresh35projects build with their own builds andCC=weavec-cc, and pass their test suites in trap, report and verify mode: git, tcpdump and libpcap, libtiff, BearSSL, YARA, gawk, libarchive, Tcl, json-c and MicroPython. json-c needs itsVALGRINDoption and MicroPython a one-line#ifchange so Clang sees itsno_sanitize_address. ASan needs both too.sscanf, is fixed by the scanf wrappers.reallocarrayon Darwin and astrlenthat read past a page. Every workload in the set runs below ASan's ratio.weavec.provenreport in verify mode on any case, suite or benchmark.Design notes
GuardInsert(PipelineStartEP) puts a marker before each access, before the optimizer can exploit the bug's undefined behaviour.GuardPrune(PeepholeEP) removes in-bounds accesses to locals and globals after inlining.GuardLoop(VectorizerStartEP) versions affine loops with a trip count of at least 16 behind one range check. It also fully unrolls small guarded loops with a constant trip count.GuardExpand(OptimizerLastEP) applies rules 6.1–6.3 (in bounds, dominated, merged within 64 bytes), lays out frames and globals with redzones, and expands each remaining marker into an inline shadow check.preserve_all.wrapper(NAME)rows go through checked runtime wrappers, which check what the call actually read or wrote:strcpy,strcatand theprintffamily (including%s,%nand positional arguments);memchr,strchrand thestr[n][case]cmpfamily;scanffamily;gets,mmapandmunmap.no_sanitize("address")functions count as unsafe regions.weavec-ledgerversion 3 records each access asguarded,provenorunguarded, with a reason.weavec --whole-programstay. Inweavec, a confirmed definite finding is an error; under-fweavec-diagnoseevery finding is a warning.Not met, carried forward: run time (G7). These are ratios of instructions retired over the reference compiler's:
zlib meets its gate. Lua and cJSON are below ASan but above their gates, and brotli is above ASan. Geometric means: 1.5× (fresh35 set A) and 1.76× (set B). fresh34 is 2.04× on instructions and 1.49× on the gate's CPU measure. cJSON's remaining cost is a guard per byte in loops that exit on data, and Lua's is three guards per bytecode instruction.
Not met, carried forward: build time (G9). gawk (1.51×), chibi (1.52×) and several older-set builds measured under load are over 1.5×. Nine units are over 3×:
tif_pixarlog.c,lpc.c,compress_fragment.c,yyjson.c,pcre2_match.c,scanners.c,jchuff.c,grammar.cand wolfSSL'sapi.c. Instruction selection and register allocation over the guards' slow paths dominate. Smaller slow paths are the next step.Size (H1). The library is 55,992 lines, against RFC 0034's limit of 72,000. This PR adds 19.3K lines and deletes 48.1K.
Breaking changes:
.weavec), the link step and the analysis ledger (weavec --ledger);libweavec_chk.a.-fno-weavec-runtime;-f[no-]weavec-stack-objectsand-f[no-]weavec-global-objects;-fweavec-require=,-fweavec-link=and-fweavec-link-budget=;-fweavec-ledger-format=and-fweavec-print-prelude;-Wweavec-possible.weavec-ccbuild. Use-fweavec-diagnose, with-Werror=weavecto make its findings errors.weavec-ledgerversion 3, and its outcomes areguarded,provenandunguarded.preserve_all.weavec-ccmust be linked byweavec-cc.Test plan
ctest -R '^runtime$': 21 tests.lit build/dev/test: 130 tests.scripts/run-cases.py: 705 cases pass in trap, verify and--asan(detection 112 of 117; ASan 103).scripts/check-hygiene.py,scripts/check-format.sh.npm testandnpm run buildindocs/.scripts/corpus-gate.py --fullon the RFC 0033 and 0034 sets (G3), plus fresh35 and sealed35 by hand (G1, G2).