diff --git a/CHANGELOG.md b/CHANGELOG.md index f4068ef5..60da1909 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -132,6 +132,16 @@ by default, on LLVM 17 / AppleClang 16 only with the CMake-added `-mllvm -basic- and there for scalar accesses, and not at all on GCC or clang before 17. For these 15 functions the promise measured no codegen change (the object form says nothing about a container's heap buffer), so there is no performance claim here: these are correctness contracts. +- **Six more aliasing contracts at function entry, completing the audit; one of them is the tree's only codegen row.** `waterFillRecallShares` + (`src/recall.h`) reads `demand[i]` while writing `alloc[i]` and never resizes either, so it takes the buffer form: + release codegen 309 → 301 instructions under the build's own flags. `splitNoteTail` (`src/notes.h`), + `takeAckNamedToken` and `computeDelta` (`src/quality.h`) take the object form, whose check runs in debug and whose + release residue is the `separate_storage` promise on the two objects (read on clang 18+ by default, on LLVM 17 / + AppleClang 16 only with the CMake-added flag and for scalar accesses, never on GCC or clang before 17); for these + it measured no codegen change. `computeDelta`'s two out-pointers both default to null, so its guard is a + null-safe `VERIFY_TEXT` rather than the object form. + `markCandidateFilesIncludingDecl` (`src/graph.h`) and `partitionByScope` (`src/verbs_quality.h`) take the last two + guards of the audit's apply list, which is now complete: 21 functions state their no-alias contract at entry. ## [0.6.0] — 2026-09-11 diff --git a/src/graph.h b/src/graph.h index 30e4431f..3371142c 100644 --- a/src/graph.h +++ b/src/graph.h @@ -4135,6 +4135,7 @@ inline std::size_t definitionCountOfName( const IngestResult& ing, NodeId focus inline void markCandidateFilesIncludingDecl( const IngestResult& ing, const std::vector& isDecl, const std::vector& isCand, std::vector& proven ) { + VERIFY_NO_ALIAS3( isDecl, isCand, proven ); // three same-role dense arrays: proven[] is written while isDecl[]/isCand[] are read // The index: ONE entry per DECLARATION file, keyed the way buildPreciseIncludeAdj keys its own // (lexicalNormalize on BOTH sides, so a `.`-rooted crawl's `./a/x.h` and a resolved `a/x.h` agree). HashMap declIndex; diff --git a/src/notes.h b/src/notes.h index b43d1ca7..e32f9dee 100644 --- a/src/notes.h +++ b/src/notes.h @@ -298,6 +298,7 @@ inline std::string shortSha( std::string_view sha ) // empty); a third but no fourth ⇒ a hand-edited 4-field oddity (sha only, degrade rather than reject). inline void splitNoteTail( std::string_view rest, std::string& text, std::string& sha, std::string& branch ) { + VERIFY_NO_ALIAS3( text, sha, branch ); const std::size_t t3 = rest.find( '\t' ); if( t3 == std::string_view::npos ) { text = std::string( rest ); return; } text = std::string( rest.substr( 0, t3 ) ); diff --git a/src/quality.h b/src/quality.h index 4ba91693..a264e59a 100644 --- a/src/quality.h +++ b/src/quality.h @@ -4805,6 +4805,7 @@ inline std::string normalizeLegacyAckKind( const std::string& kind, std::uint32_ // different language, and a caller that rejects the value restores `reason` itself. inline bool takeAckNamedToken( std::string& reason, std::string_view name, std::string& valueOut ) { + VERIFY_NO_ALIAS( reason, valueOut ); if( reason.size() < name.size() || reason.compare( 0, name.size(), name ) != 0 ) { return false; @@ -6099,6 +6100,8 @@ inline std::vector computeDelta( const IngestResult& ing, const Grap std::size_t* registerMacroExcludedOut = nullptr, // P2.2: honest disclosure count, additive+optional — see isDeadCandidate std::size_t* apiNewSurfaceOut = nullptr ) // Q-DIAL-4: the api-surface new-symbol COUNT that replaced N never-gating rows { + VERIFY_TEXT( registerMacroExcludedOut == nullptr || registerMacroExcludedOut != apiNewSurfaceOut, + "computeDelta: registerMacroExcludedOut and apiNewSurfaceOut must be distinct" ); // both default to nullptr, so the object form would dereference null std::vector regs; if( registerMacroExcludedOut ) { diff --git a/src/recall.h b/src/recall.h index 8c2bd084..b379b0a9 100644 --- a/src/recall.h +++ b/src/recall.h @@ -11,6 +11,7 @@ // best score of any symbol it holds (the markdown file-node, which indexes the whole body, dominates). The // graph half ([[links]]/PageRank) is intentionally NOT fused — the eval showed importance ≠ relatedness. +#include "infra/Diagnostics.h" // VERIFY_NO_ALIAS_BUF — waterFillRecallShares reads demand[] while writing alloc[] #include "docparse.h" // §P2b: the generated-document signals (marker / size+fences) + the ONE markdown // fence scanner — a doc-side property, computed from the file's own bytes #include "layout.h" // §L4.3: layout::lineOf — the ONE byte-offset-to-line-number helper (reused, not @@ -1611,6 +1612,7 @@ inline std::size_t recallServedPrefix( const std::vector& overhead, inline std::size_t waterFillRecallShares( const std::vector& demand, std::size_t served, std::size_t avail, std::vector& isSatisfied, std::vector& alloc ) { + VERIFY_NO_ALIAS_BUF( demand, alloc ); // read demand[i] / write alloc[i] in one loop; never resized here, so the buffer promise holds std::size_t remaining = avail; std::size_t unsatisfied = served; std::size_t share = 0; diff --git a/src/verbs_quality.h b/src/verbs_quality.h index 5fe1b7f8..230fb6ac 100644 --- a/src/verbs_quality.h +++ b/src/verbs_quality.h @@ -379,6 +379,7 @@ std::size_t partitionByScope( const rw::quality::Scope& scope, std::vector& outOfScope, const gtl::btree_map& acks ) { + VERIFY_NO_ALIAS( regs, outOfScope ); // push_back into outOfScope while iterating regs: the same vector twice is UB if( !scope.active() ) { return 0;