Skip to content

Detect repeated contract enforcement in goto-instrument#8754

Open
tautschnig wants to merge 1 commit into
diffblue:developfrom
tautschnig:fix-7830-contracts-twice
Open

Detect repeated contract enforcement in goto-instrument#8754
tautschnig wants to merge 1 commit into
diffblue:developfrom
tautschnig:fix-7830-contracts-twice

Conversation

@tautschnig
Copy link
Copy Markdown
Collaborator

goto-instrument must detect when it is being invoked again when contract enforcement has already been run as only one contract can be enforced at a time.

Fixes: #7830

  • Each commit message has a non-empty body, explaining why the change was made.
  • n/a Methods or procedures I have added are documented, following the guidelines provided in CODING_STANDARD.md.
  • n/a The feature or user visible behaviour I have added or modified has been documented in the User Guide in doc/cprover-manual/
  • Regression or unit tests are included, or existing tests cover the modified code (in this case I have detailed which ones those are in the commit message).
  • n/a My commit message includes data points confirming performance improvements (if claimed).
  • My PR is restricted to a single feature or bugfix.
  • n/a White-space or formatting changes outside the feature-related changed lines are in commits of their own.

@tautschnig tautschnig self-assigned this Feb 24, 2026
@tautschnig tautschnig force-pushed the fix-7830-contracts-twice branch from 6f45e45 to e1ff67c Compare March 18, 2026 10:12
@tautschnig tautschnig marked this pull request as ready for review March 18, 2026 10:29
Copilot AI review requested due to automatic review settings March 18, 2026 10:29
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds guards to prevent re-applying contract enforcement instrumentation when goto-instrument is run multiple times on already-instrumented binaries.

Changes:

  • Detect prior DFCC instrumentation via a marker symbol and abort with an exception.
  • Detect prior per-function contract enforcement by checking for the mangled “original” symbol and abort.
  • Reorder check_frame_conditions_function to run after the new “already enforced” guard.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
src/goto-instrument/contracts/dynamic-frames/dfcc.cpp Adds a binary-level “already enforced” check via a marker symbol and throws invalid_input_exceptiont.
src/goto-instrument/contracts/contracts.cpp Adds an “already enforced” check in enforce_contract by detecting the pre-existing mangled original symbol.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/goto-instrument/contracts/contracts.cpp
Comment thread src/goto-instrument/contracts/dynamic-frames/dfcc.cpp Outdated
Comment thread src/goto-instrument/contracts/dynamic-frames/dfcc.cpp Outdated
@codecov
Copy link
Copy Markdown

codecov Bot commented Mar 18, 2026

Codecov Report

❌ Patch coverage is 91.66667% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 80.55%. Comparing base (808dae2) to head (927af32).

Files with missing lines Patch % Lines
src/goto-instrument/contracts/contracts.cpp 83.33% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #8754      +/-   ##
===========================================
- Coverage    80.55%   80.55%   -0.01%     
===========================================
  Files         1707     1707              
  Lines       189051   189061      +10     
  Branches        73       73              
===========================================
+ Hits        152299   152307       +8     
- Misses       36752    36754       +2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@tautschnig tautschnig force-pushed the fix-7830-contracts-twice branch from e1ff67c to 6b74fab Compare May 26, 2026 13:05
@tautschnig tautschnig requested review from a team, kroening and peterschrammel as code owners May 26, 2026 13:05
@tautschnig tautschnig force-pushed the fix-7830-contracts-twice branch from 6b74fab to 6e62bc6 Compare May 26, 2026 13:10
When goto-instrument is invoked multiple times to enforce contracts on
the same goto binary, the semantics break: without dfcc it fails during
checking, and with dfcc it fails due to arity mismatches from prior
instrumentation. The two paths have different invariants and the
diagnostics reflect that:

  Non-dfcc path (contracts.cpp): the check is *per function*. A given
  function can only be enforced once across the lifetime of a goto
  binary; enforcing different functions across separate invocations
  remains supported (each function gets its own
  __CPROVER_contracts_original_<F> wrapper, so the wrappers do not
  conflict). Enforcing multiple distinct functions in a *single*
  invocation -- as exercised by regression/contracts/assigns_enforce_03
  -- continues to work.

  Dfcc path (dfcc.cpp): the check is *per binary*. The dfcc pipeline
  cannot be applied a second time to a binary it has already
  instrumented, regardless of which mode (--enforce-contract,
  --replace-call-with-contract, --apply-loop-contracts, ...) ran the
  first time.

For the non-dfcc path, check whether the mangled wrapper symbol
already exists for the function being enforced and throw an
invalid_input_exceptiont with a per-function error message.

For the dfcc path, check whether the marker symbol left by a prior
dfcc pass is present in the input goto binary, before constructing
the dfcct object. This check must happen before the dfcc library is
loaded, since the library constructor creates the marker as part of
normal operation. Use invalid_input_exceptiont for a user-friendly
error rather than PRECONDITION (which is for programming errors).
The error wording was kept generic ("DFCC instrumentation has already
been applied to this binary; only one DFCC pass per binary is
supported") because the guard fires for *any* prior dfcc pass, not
just contract enforcement.

Refactor: rename the marker symbol from "__dfcc_instrumented_functions"
to "__CPROVER_dfcc_instrumented_functions" to follow the reserved
namespace convention used elsewhere; expose its name as a public
constant `dfcc_libraryt::INSTRUMENTED_FUNCTIONS_MAP_NAME` and add a
public static helper `dfcc_libraryt::is_dfcc_instrumented(const
goto_modelt &)` so the check has a single source of truth and a
self-explanatory name.

Tests: add regression/contracts-repeat/ with a small custom chain.sh
that runs goto-instrument twice, and four test directories covering:

  * enforce-same-function: the same function on both passes; second
    pass must fail with the per-function error.
  * enforce-different-functions: different functions on each pass;
    both passes must succeed (locks in the asymmetric semantics).
  * dfcc-enforce-twice: dfcc + --enforce-contract on both passes;
    second pass must fail with the per-binary dfcc error.
  * dfcc-replace-then-replace: dfcc + --replace-call-with-contract on
    both passes (no --enforce-contract on either); confirms the dfcc
    guard fires for non-enforce dfcc passes too, validating the
    generic error wording.

Wire regression/contracts-repeat/ into regression/Makefile and
regression/CMakeLists.txt alongside contracts/ and contracts-dfcc/.

Fixes: diffblue#7830

Co-authored-by: Kiro <kiro-agent@users.noreply.github.com>
@tautschnig tautschnig force-pushed the fix-7830-contracts-twice branch from 6e62bc6 to 927af32 Compare May 26, 2026 17:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Safety feature] Error when enforcing contracts twice

4 participants