fix(bb): fix out-of-bounds read behind the nightly debug build failure - #25129
Draft
AztecBot wants to merge 1 commit into
Draft
fix(bb): fix out-of-bounds read behind the nightly debug build failure#25129AztecBot wants to merge 1 commit into
AztecBot wants to merge 1 commit into
Conversation
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.
The Nightly Debug Build fails on
AcirComponentsCheckTest.DetectsUnconstrainedWitnesseswith SIGABRT (exit 134) — run #170, CI log:Root cause
The test fabricated an "unconstrained witness" by truncating the builder's index table:
builder.real_variable_index.resize(9);create_circuitsizes the builder frommax_witness_index(9 here), so ACIR witnesses 0–9 become variables 0–9 and the builder's internal constants start at 10 (zero_idx() == 10; 19 variables in total). Truncating to 9 entries leaves the builder's own gates wired to variables past the end of that table, andComponentsCheckerhands the builder tocdg::StaticAnalyzer_, which resolves every gate wire throughreal_variable_index. Gate 0 of the arithmetic block wireszero_idx, so the walk read index 10 of a 9-element vector.Under the debug preset's
-D_GLIBCXX_DEBUGthe checked vector aborts; in every other build it is a silent past-the-end read (UB), which is why the test passed everywhere else. Any truncation small enough to hide witness 9 also drops variables the builder's gates reference, so the corruption could never be made consistent — it describes a builder state that cannot exist.Changes
The test no longer corrupts the builder. It expresses "this ACIR component has no circuit-side placement" the way the checker actually supports it: the ACIR handed to
ComponentsCheckerlinks a second pair of witnesses (w1000/w1001) thatcreate_circuitnever allocated variables for. That exercises the existingwitness >= real_variable_index.size()guard inbuild_circuit_component_mapand yields exactly oneUNCONSTRAINEDerror, with the builder left self-consistent.StaticAnalyzer_::to_realbounds-checks the index. Every gate wire is resolved through it, so it is where an inconsistent builder surfaces. ABB_ASSERT_LTreports the problem instead of reading past the end of the table, in release builds as well as debug. The two other rawreal_variable_index[...]subscripts ingraph.cppnow go through the same accessor, so there is a single checked path.ComponentsChecker_::checkasserts the builder invariant up front, so a caller passing a builder whose index table does not cover its variables gets an actionable message at the API boundary rather than a failure deep inside the analyzer. ACIR witnesses beyond the builder's variables remain a legitimate input — those are reported asUNCONSTRAINED, which is the checker's job.The result: the invalid state is no longer created, and if it is ever created again the failure is a legible assertion rather than an out-of-bounds read. With the old
resize(9)reintroduced on top of this change, the test now fails cleanly with:Verification
All with the debug preset (
cmake --preset debug, i.e.-D_GLIBCXX_DEBUG), on the same commit the nightly failed at:acir_components_check_tests— SIGABRT before, all 10 tests pass after.boomerang_value_detection_tests— all 96 tests pass, so the newto_realassertion does not fire on any real analyzer input.goblin_tests,stdlib_honk_verifier_tests,stdlib_translator_vm_verifier_tests,vm2_tests).Note that the nightly's test phase fail-fasts, so it aborted 14s in at this failure; other debug-only failures may still be hiding behind it.
Created by claudebox · group:
slackbot· requested by ludamad (@ludamad) · Slack thread