Skip to content

test(acir_components_check): fix out-of-bounds abort in DetectsUnconstrainedWitnesses under debug build - #24955

Draft
AztecBot wants to merge 1 commit into
nextfrom
cb/fix-acir-components-check-debug-oob-2
Draft

test(acir_components_check): fix out-of-bounds abort in DetectsUnconstrainedWitnesses under debug build#24955
AztecBot wants to merge 1 commit into
nextfrom
cb/fix-acir-components-check-debug-oob-2

Conversation

@AztecBot

Copy link
Copy Markdown
Collaborator

Problem

The Nightly Debug Build failed with exit code 134 (SIGABRT) in acir_components_check_tests:

AcirComponentsCheckTest.DetectsUnconstrainedWitnesses
/usr/include/c++/13/debug/vector:442:
Error: attempt to subscript container with out-of-bounds index 10, but container only holds 9 elements.
    reference std::vector<unsigned int>::operator[](size_type)

The nightly build compiles with -D_GLIBCXX_DEBUG (libstdc++ debug mode), which bounds-checks std::vector::operator[]. Regular release/default builds do not, so this defect was silent there — the test "passed" on undefined behavior.

Root cause

DetectsUnconstrainedWitnesses corrupted the builder with:

builder.real_variable_index.resize(9);

This left the builder internally inconsistent: its gates still reference variable indices ≥ 9, but real_variable_index was truncated to 9 elements. When ComponentsChecker::check() runs the static analyzer (build_circuit_component_mapStaticAnalyzer::find_connected_components), the analyzer walks the builder's gate wires and calls to_real(wire) = real_variable_index[wire]. A gate wire referencing variable index 10 then reads real_variable_index[10] on a 9-element vector — out of bounds. Release builds read adjacent memory (UB) and happen to produce the expected result; the debug build correctly aborts.

The truncation was a blunt way to simulate "an ACIR witness with no circuit-side component". It can't occur with a real builder — real_variable_index is always sized to hold every variable the gates reference.

Fix

Exercise the same UNCONSTRAINED detection path with a consistent builder — the scenario the checker actually exists to catch (the ACIR graph expects a constraint the circuit does not carry):

  • The ACIR view links witnesses 8 ↔ 9 into one component.
  • The circuit links witness 8 ↔ 10 instead, leaving witness 9 allocated but touched by no gate.

Witness 9 therefore legitimately maps to no circuit component (hitting the NO_CIRCUIT_CC path in build_circuit_component_map), and the checker reports exactly one UNCONSTRAINED error. No real_variable_index truncation, no out-of-bounds read.

Testing

Built and ran the target with the debug preset (-D_GLIBCXX_DEBUG), matching the nightly:

cmake --preset debug && ninja -C build-debug acir_components_check_tests
  • Before: DetectsUnconstrainedWitnesses aborts (index 10, 9 elements).
  • After: all 10 AcirComponentsCheckTest tests pass under the debug build.

Created by claudebox · group: slackbot · Slack thread

@AztecBot AztecBot added ci-barretenberg Run all barretenberg/cpp checks. ci-draft Run CI on draft PRs. ci-no-fail-fast Sets NO_FAIL_FAST in the CI so the run is not aborted on the first failure claudebox Owned by claudebox. it can push to this PR. labels Jul 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci-barretenberg Run all barretenberg/cpp checks. ci-draft Run CI on draft PRs. ci-no-fail-fast Sets NO_FAIL_FAST in the CI so the run is not aborted on the first failure claudebox Owned by claudebox. it can push to this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant