From 45c7bc17d9148e45ea2d2af3429c7068d266454e Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 3 Mar 2026 18:14:19 +0000 Subject: [PATCH 01/45] Document --race-check instrumentation and fix help text Add Doxygen documentation to race_check.h explaining the Eraser-inspired write-guard instrumentation scheme for data-race detection, including the two kinds of races detected (R/W and W/W), the 5-step instrumentation sequence, and how pointer dereferences are resolved through value-set analysis for alias-aware race detection. Document internal functions in race_check.cpp. Fix the --race-check help text, man page, and cprover manual: the option performs general data-race checking, not floating-point specific checks. Add --race-check to the goto-instrument properties table in the cprover manual. Add regression tests exercising the basic race-check scenarios: write-write, read-write, no-race (thread-local), no-race (sequential), conditional write, and pointer-based race detection. Co-authored-by: Kiro --- doc/cprover-manual/properties.md | 1 + doc/man/goto-instrument.1 | 2 +- .../goto-instrument/race-check/conditional.c | 17 +++++++ .../race-check/conditional.desc | 9 ++++ .../race-check/no-race-sequential.c | 8 ++++ .../race-check/no-race-sequential.desc | 9 ++++ .../goto-instrument/race-check/no-race.c | 14 ++++++ .../goto-instrument/race-check/no-race.desc | 9 ++++ .../goto-instrument/race-check/pointer.c | 14 ++++++ .../goto-instrument/race-check/pointer.desc | 9 ++++ .../goto-instrument/race-check/read-write.c | 15 ++++++ .../race-check/read-write.desc | 9 ++++ .../goto-instrument/race-check/write-write.c | 14 ++++++ .../race-check/write-write.desc | 9 ++++ .../goto_instrument_parse_options.cpp | 2 +- src/goto-instrument/race_check.cpp | 18 ++++++++ src/goto-instrument/race_check.h | 46 +++++++++++++++++++ 17 files changed, 203 insertions(+), 2 deletions(-) create mode 100644 regression/goto-instrument/race-check/conditional.c create mode 100644 regression/goto-instrument/race-check/conditional.desc create mode 100644 regression/goto-instrument/race-check/no-race-sequential.c create mode 100644 regression/goto-instrument/race-check/no-race-sequential.desc create mode 100644 regression/goto-instrument/race-check/no-race.c create mode 100644 regression/goto-instrument/race-check/no-race.desc create mode 100644 regression/goto-instrument/race-check/pointer.c create mode 100644 regression/goto-instrument/race-check/pointer.desc create mode 100644 regression/goto-instrument/race-check/read-write.c create mode 100644 regression/goto-instrument/race-check/read-write.desc create mode 100644 regression/goto-instrument/race-check/write-write.c create mode 100644 regression/goto-instrument/race-check/write-write.desc diff --git a/doc/cprover-manual/properties.md b/doc/cprover-manual/properties.md index cd81a5d4635..a074078b70a 100644 --- a/doc/cprover-manual/properties.md +++ b/doc/cprover-manual/properties.md @@ -130,6 +130,7 @@ The goto-instrument program supports these checks: | `--undefined-shift-check` | add range checks for shift distances | | `--nan-check` | add floating-point NaN checks | | `--uninitialized-check` | add checks for uninitialized locals (experimental) | +| `--race-check` | add data race checks for concurrent programs | | `--error-label label` | check that given label is unreachable | As all of these checks apply across the entire input program, we may wish to diff --git a/doc/man/goto-instrument.1 b/doc/man/goto-instrument.1 index 5d971063565..afd4d967b70 100644 --- a/doc/man/goto-instrument.1 +++ b/doc/man/goto-instrument.1 @@ -249,7 +249,7 @@ add checks for uninitialized locals (experimental) add check that call stack size of non\-inlined functions never exceeds n .TP \fB\-\-race\-check\fR -add floating\-point data race checks +add data race checks for concurrent programs .SS "Semantic transformations:" .TP \fB\-\-nondet\-volatile\fR diff --git a/regression/goto-instrument/race-check/conditional.c b/regression/goto-instrument/race-check/conditional.c new file mode 100644 index 00000000000..f71d6451340 --- /dev/null +++ b/regression/goto-instrument/race-check/conditional.c @@ -0,0 +1,17 @@ +int shared; +_Bool flag; + +void thread(void) +{ + if(flag) + shared = 1; +} + +int main(void) +{ + flag = 1; +__CPROVER_ASYNC_0: + thread(); + shared = 2; + return 0; +} diff --git a/regression/goto-instrument/race-check/conditional.desc b/regression/goto-instrument/race-check/conditional.desc new file mode 100644 index 00000000000..9b62fe820b7 --- /dev/null +++ b/regression/goto-instrument/race-check/conditional.desc @@ -0,0 +1,9 @@ +CORE +conditional.c +--race-check +^EXIT=10$ +^SIGNAL=0$ +W/W data race on shared +^VERIFICATION FAILED$ +-- +^warning: ignoring diff --git a/regression/goto-instrument/race-check/no-race-sequential.c b/regression/goto-instrument/race-check/no-race-sequential.c new file mode 100644 index 00000000000..1a68d84bd04 --- /dev/null +++ b/regression/goto-instrument/race-check/no-race-sequential.c @@ -0,0 +1,8 @@ +int shared; + +int main(void) +{ + shared = 1; + shared = 2; + return 0; +} diff --git a/regression/goto-instrument/race-check/no-race-sequential.desc b/regression/goto-instrument/race-check/no-race-sequential.desc new file mode 100644 index 00000000000..42c0361d6f6 --- /dev/null +++ b/regression/goto-instrument/race-check/no-race-sequential.desc @@ -0,0 +1,9 @@ +CORE +no-race-sequential.c +--race-check +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- +^warning: ignoring +FAILED diff --git a/regression/goto-instrument/race-check/no-race.c b/regression/goto-instrument/race-check/no-race.c new file mode 100644 index 00000000000..2d8b8943ddb --- /dev/null +++ b/regression/goto-instrument/race-check/no-race.c @@ -0,0 +1,14 @@ +__CPROVER_thread_local int thread_local_var; + +void thread(void) +{ + thread_local_var = 1; +} + +int main(void) +{ +__CPROVER_ASYNC_0: + thread(); + thread_local_var = 2; + return 0; +} diff --git a/regression/goto-instrument/race-check/no-race.desc b/regression/goto-instrument/race-check/no-race.desc new file mode 100644 index 00000000000..828749ed230 --- /dev/null +++ b/regression/goto-instrument/race-check/no-race.desc @@ -0,0 +1,9 @@ +CORE +no-race.c +--race-check +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- +^warning: ignoring +FAILED diff --git a/regression/goto-instrument/race-check/pointer.c b/regression/goto-instrument/race-check/pointer.c new file mode 100644 index 00000000000..d1bea54ae85 --- /dev/null +++ b/regression/goto-instrument/race-check/pointer.c @@ -0,0 +1,14 @@ +int x; + +void thread(int *p) +{ + *p = 1; +} + +int main(void) +{ +__CPROVER_ASYNC_0: + thread(&x); + x = 2; + return 0; +} diff --git a/regression/goto-instrument/race-check/pointer.desc b/regression/goto-instrument/race-check/pointer.desc new file mode 100644 index 00000000000..bee1f5a1196 --- /dev/null +++ b/regression/goto-instrument/race-check/pointer.desc @@ -0,0 +1,9 @@ +CORE +pointer.c +--race-check +^EXIT=10$ +^SIGNAL=0$ +data race on x +^VERIFICATION FAILED$ +-- +^warning: ignoring diff --git a/regression/goto-instrument/race-check/read-write.c b/regression/goto-instrument/race-check/read-write.c new file mode 100644 index 00000000000..46edb50a447 --- /dev/null +++ b/regression/goto-instrument/race-check/read-write.c @@ -0,0 +1,15 @@ +int shared; + +void thread(void) +{ + shared = 1; +} + +int main(void) +{ + int local; +__CPROVER_ASYNC_0: + thread(); + local = shared; + return 0; +} diff --git a/regression/goto-instrument/race-check/read-write.desc b/regression/goto-instrument/race-check/read-write.desc new file mode 100644 index 00000000000..57beaded5c4 --- /dev/null +++ b/regression/goto-instrument/race-check/read-write.desc @@ -0,0 +1,9 @@ +CORE +read-write.c +--race-check +^EXIT=10$ +^SIGNAL=0$ +R/W data race on shared +^VERIFICATION FAILED$ +-- +^warning: ignoring diff --git a/regression/goto-instrument/race-check/write-write.c b/regression/goto-instrument/race-check/write-write.c new file mode 100644 index 00000000000..3bb0020910e --- /dev/null +++ b/regression/goto-instrument/race-check/write-write.c @@ -0,0 +1,14 @@ +int shared; + +void thread(void) +{ + shared = 1; +} + +int main(void) +{ +__CPROVER_ASYNC_0: + thread(); + shared = 2; + return 0; +} diff --git a/regression/goto-instrument/race-check/write-write.desc b/regression/goto-instrument/race-check/write-write.desc new file mode 100644 index 00000000000..75f5ff59dc8 --- /dev/null +++ b/regression/goto-instrument/race-check/write-write.desc @@ -0,0 +1,9 @@ +CORE +write-write.c +--race-check +^EXIT=10$ +^SIGNAL=0$ +W/W data race on shared +^VERIFICATION FAILED$ +-- +^warning: ignoring diff --git a/src/goto-instrument/goto_instrument_parse_options.cpp b/src/goto-instrument/goto_instrument_parse_options.cpp index 570554155b4..86c51e70538 100644 --- a/src/goto-instrument/goto_instrument_parse_options.cpp +++ b/src/goto-instrument/goto_instrument_parse_options.cpp @@ -1940,7 +1940,7 @@ void goto_instrument_parse_optionst::help() HELP_UNINITIALIZED_CHECK " {y--stack-depth} {un} \t add check that call stack size of non-inlined" " functions never exceeds {un}\n" - " {y--race-check} \t add floating-point data race checks\n" + " {y--race-check} \t add data race checks for concurrent programs\n" "\n" "Semantic transformations:\n" HELP_NONDET_VOLATILE diff --git a/src/goto-instrument/race_check.cpp b/src/goto-instrument/race_check.cpp index fce1b27d0ed..d7cf5cc82f9 100644 --- a/src/goto-instrument/race_check.cpp +++ b/src/goto-instrument/race_check.cpp @@ -10,6 +10,8 @@ Date: February 2006 /// \file /// Race Detection for Threaded Goto Programs +/// +/// \see race_check.h for an overview of the instrumentation scheme. #include "race_check.h" @@ -30,6 +32,10 @@ Date: February 2006 #define L_M_LAST_ARG(x) #endif +/// Manages boolean "write guard" variables used to detect concurrent writes. +/// For each shared variable `x`, a boolean symbol `x$w_guard` is created. +/// These guards are set to true around write accesses and checked by +/// assertions in other threads. class w_guardst { public: @@ -63,6 +69,9 @@ class w_guardst symbol_table_baset &symbol_table; }; +/// Get or create the boolean guard symbol for a shared variable. +/// \param object: the identifier of the shared variable +/// \return the guard symbol `$w_guard` const symbolt &w_guardst::get_guard_symbol(const irep_idt &object) { const irep_idt identifier=id2string(object)+"$w_guard"; @@ -86,6 +95,8 @@ const symbolt &w_guardst::get_guard_symbol(const irep_idt &object) return *symbol_ptr; } +/// Insert assignments to initialize all write guard variables to false +/// at the beginning of the given program. void w_guardst::add_initialization(goto_programt &goto_program) const { goto_programt::targett t=goto_program.instructions.begin(); @@ -105,6 +116,10 @@ void w_guardst::add_initialization(goto_programt &goto_program) const } } +/// Build a human-readable comment for a race-check assertion. +/// \param entry: the read/write set entry describing the access +/// \param write: true if this is a W/W race check, false for R/W +/// \return a string like "R/W data race on x" or "W/W data race on x" static std::string comment(const rw_set_baset::entryt &entry, bool write) { std::string result; @@ -118,6 +133,8 @@ static std::string comment(const rw_set_baset::entryt &entry, bool write) return result; } +/// Check whether a symbol refers to a shared (non-thread-local) variable, +/// excluding internal CPROVER symbols that should not be race-checked. static bool is_shared(const namespacet &ns, const symbol_exprt &symbol_expr) { const irep_idt &identifier=symbol_expr.get_identifier(); @@ -135,6 +152,7 @@ static bool is_shared(const namespacet &ns, const symbol_exprt &symbol_expr) return symbol.is_shared(); } +/// Check whether any entry in the read/write set refers to a shared variable. static bool has_shared_entries(const namespacet &ns, const rw_set_baset &rw_set) { for(rw_set_baset::entriest::const_iterator diff --git a/src/goto-instrument/race_check.h b/src/goto-instrument/race_check.h index e4d6daa3443..6bcb0b8a203 100644 --- a/src/goto-instrument/race_check.h +++ b/src/goto-instrument/race_check.h @@ -10,6 +10,41 @@ Date: February 2006 /// \file /// Race Detection for Threaded Goto Programs +/// +/// This implements a data-race detector for concurrent programs, inspired by +/// the Eraser algorithm (Savage et al., "Eraser: A Dynamic Data Race Detector +/// for Multithreaded Programs", ACM TOCS 1997). While Eraser uses lockset +/// tracking at runtime, this implementation adapts the core idea for static +/// verification via bounded model checking: it instruments the program with +/// boolean "write guard" flags and assertions so that CBMC's exploration of +/// thread interleavings can reveal conflicting concurrent accesses. +/// +/// A data race occurs when two threads access the same shared memory location +/// concurrently and at least one access is a write. This instrumentation +/// detects two kinds of races: +/// - R/W races: one thread reads a variable while another writes it. +/// - W/W races: two threads write the same variable concurrently. +/// +/// For each assignment that accesses shared variables, the instrumentation +/// replaces the original instruction with the following sequence: +/// +/// 1. For each shared variable `x` written: set `x$w_guard` to the guard +/// condition under which the write occurs. +/// 2. Execute the original assignment. +/// 3. For each shared variable `x` written: reset `x$w_guard` to false. +/// 4. For each shared variable `y` read: assert `!y$w_guard` (R/W check). +/// 5. For each shared variable `x` written: assert `!x$w_guard` (W/W check). +/// +/// During symbolic execution of concurrent programs, CBMC explores thread +/// interleavings. If another thread's write guard is set (step 1) when the +/// current thread checks it (steps 4/5), the assertion fails, indicating a +/// data race. +/// +/// Pointer dereferences are resolved using value-set analysis (or, when +/// LOCAL_MAY is defined, local may-alias analysis) so that races through +/// aliased pointer accesses are detected. For example, if thread A writes +/// `*p` and thread B writes `x`, and `p` points to `x`, the instrumentation +/// will detect the W/W race on `x`. #ifndef CPROVER_GOTO_INSTRUMENT_RACE_CHECK_H #define CPROVER_GOTO_INSTRUMENT_RACE_CHECK_H @@ -25,6 +60,12 @@ class goto_programt; class message_handlert; class value_setst; +/// Instrument a single function with data-race detection assertions. +/// \param value_sets: value-set analysis results for pointer resolution +/// \param symbol_table: the symbol table (modified to add guard symbols) +/// \param function_id: identifier of the function being instrumented +/// \param goto_program: the function body to instrument +/// \param message_handler: handler for status and diagnostic messages void race_check( value_setst &, class symbol_table_baset &, @@ -35,6 +76,11 @@ void race_check( goto_programt &goto_program, message_handlert &); +/// Instrument all functions in a goto model with data-race detection +/// assertions. Skips the entry point and the initialization function. +/// \param value_sets: value-set analysis results for pointer resolution +/// \param goto_model: the goto model to instrument +/// \param message_handler: handler for status and diagnostic messages void race_check(value_setst &, goto_modelt &, message_handlert &); #endif // CPROVER_GOTO_INSTRUMENT_RACE_CHECK_H From f19a29096ce81dba43bc15c347ecbcd78be49643 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 3 Mar 2026 19:25:22 +0000 Subject: [PATCH 02/45] Set property_class on --race-check assertions Set property_class to "race-check" on all generated assertions, consistent with other instrumentation passes (e.g., uninitialized-check, stack-depth). This enables users to filter race-check properties by class and produces property names like [main.race-check.1] instead of [main.1]. Co-authored-by: Kiro --- src/goto-instrument/race_check.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/goto-instrument/race_check.cpp b/src/goto-instrument/race_check.cpp index d7cf5cc82f9..ea94b9c48f8 100644 --- a/src/goto-instrument/race_check.cpp +++ b/src/goto-instrument/race_check.cpp @@ -257,6 +257,7 @@ static void race_check( source_locationt annotated_location = original_instruction.source_location(); annotated_location.set_comment(comment(r_entry.second, false)); + annotated_location.set_property_class("race-check"); goto_program.insert_before( i_it, goto_programt::make_assertion( @@ -271,6 +272,7 @@ static void race_check( source_locationt annotated_location = original_instruction.source_location(); annotated_location.set_comment(comment(w_entry.second, true)); + annotated_location.set_property_class("race-check"); goto_program.insert_before( i_it, goto_programt::make_assertion( From 0499b3f676cc1c43c1e6134ca21d09d3381a34ce Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 3 Mar 2026 18:34:49 +0000 Subject: [PATCH 03/45] Fix --race-check to instrument all instruction types that can use shared variables The race-check instrumentation previously only instrumented ASSIGN instructions. This missed R/W data races where shared variables are read by other instruction types: - GOTO: reading a shared variable in a branch condition (if/while guard) - FUNCTION_CALL: reading shared variables as function arguments, writing return values - SET_RETURN_VALUE: reading a shared variable in a return statement - ASSUME/ASSERT: reading shared variables in conditions For these instructions, R/W and W/W race-check assertions are now inserted before the instruction to detect concurrent writes by other threads. Also add SET_RETURN_VALUE handling to rw_set_loct::compute(), which previously did not track reads from return statements. Also exclude function symbols from race checking: function symbols are not variables and should not generate race-check assertions when read as part of a FUNCTION_CALL instruction. Co-authored-by: Kiro --- .../race-check/function-call-arg.c | 19 +++++++++++ .../race-check/function-call-arg.desc | 9 +++++ .../race-check/function-call-lhs.c | 19 +++++++++++ .../race-check/function-call-lhs.desc | 9 +++++ .../goto-instrument/race-check/goto-guard.c | 16 +++++++++ .../race-check/goto-guard.desc | 9 +++++ .../race-check/no-race-sequential.desc | 1 - .../goto-instrument/race-check/no-race.desc | 1 - .../goto-instrument/race-check/return-value.c | 20 +++++++++++ .../race-check/return-value.desc | 9 +++++ src/goto-instrument/race_check.cpp | 33 +++++++++++++++++-- src/goto-instrument/race_check.h | 11 +++++-- src/goto-instrument/rw_set.cpp | 4 +++ 13 files changed, 153 insertions(+), 7 deletions(-) create mode 100644 regression/goto-instrument/race-check/function-call-arg.c create mode 100644 regression/goto-instrument/race-check/function-call-arg.desc create mode 100644 regression/goto-instrument/race-check/function-call-lhs.c create mode 100644 regression/goto-instrument/race-check/function-call-lhs.desc create mode 100644 regression/goto-instrument/race-check/goto-guard.c create mode 100644 regression/goto-instrument/race-check/goto-guard.desc create mode 100644 regression/goto-instrument/race-check/return-value.c create mode 100644 regression/goto-instrument/race-check/return-value.desc diff --git a/regression/goto-instrument/race-check/function-call-arg.c b/regression/goto-instrument/race-check/function-call-arg.c new file mode 100644 index 00000000000..a8f14c220e3 --- /dev/null +++ b/regression/goto-instrument/race-check/function-call-arg.c @@ -0,0 +1,19 @@ +int shared; + +void sink(int val) +{ + (void)val; +} + +void writer(void) +{ + shared = 42; +} + +int main(void) +{ +__CPROVER_ASYNC_0: + writer(); + sink(shared); + return 0; +} diff --git a/regression/goto-instrument/race-check/function-call-arg.desc b/regression/goto-instrument/race-check/function-call-arg.desc new file mode 100644 index 00000000000..e52301f58b1 --- /dev/null +++ b/regression/goto-instrument/race-check/function-call-arg.desc @@ -0,0 +1,9 @@ +CORE +function-call-arg.c +--race-check +^EXIT=10$ +^SIGNAL=0$ +R/W data race on shared +^VERIFICATION FAILED$ +-- +^warning: ignoring diff --git a/regression/goto-instrument/race-check/function-call-lhs.c b/regression/goto-instrument/race-check/function-call-lhs.c new file mode 100644 index 00000000000..8bfa90d196c --- /dev/null +++ b/regression/goto-instrument/race-check/function-call-lhs.c @@ -0,0 +1,19 @@ +int shared; + +int source(void) +{ + return 42; +} + +void writer(void) +{ + shared = 1; +} + +int main(void) +{ +__CPROVER_ASYNC_0: + writer(); + shared = source(); + return 0; +} diff --git a/regression/goto-instrument/race-check/function-call-lhs.desc b/regression/goto-instrument/race-check/function-call-lhs.desc new file mode 100644 index 00000000000..437083552d1 --- /dev/null +++ b/regression/goto-instrument/race-check/function-call-lhs.desc @@ -0,0 +1,9 @@ +CORE +function-call-lhs.c +--race-check +^EXIT=10$ +^SIGNAL=0$ +W/W data race on shared +^VERIFICATION FAILED$ +-- +^warning: ignoring diff --git a/regression/goto-instrument/race-check/goto-guard.c b/regression/goto-instrument/race-check/goto-guard.c new file mode 100644 index 00000000000..2a5f2540f29 --- /dev/null +++ b/regression/goto-instrument/race-check/goto-guard.c @@ -0,0 +1,16 @@ +int shared; + +void writer(void) +{ + shared = 42; +} + +int main(void) +{ +__CPROVER_ASYNC_0: + writer(); + if(shared) + { + } + return 0; +} diff --git a/regression/goto-instrument/race-check/goto-guard.desc b/regression/goto-instrument/race-check/goto-guard.desc new file mode 100644 index 00000000000..fb18c2debfd --- /dev/null +++ b/regression/goto-instrument/race-check/goto-guard.desc @@ -0,0 +1,9 @@ +CORE +goto-guard.c +--race-check +^EXIT=10$ +^SIGNAL=0$ +R/W data race on shared +^VERIFICATION FAILED$ +-- +^warning: ignoring diff --git a/regression/goto-instrument/race-check/no-race-sequential.desc b/regression/goto-instrument/race-check/no-race-sequential.desc index 42c0361d6f6..ba3c49dbc2b 100644 --- a/regression/goto-instrument/race-check/no-race-sequential.desc +++ b/regression/goto-instrument/race-check/no-race-sequential.desc @@ -6,4 +6,3 @@ no-race-sequential.c ^VERIFICATION SUCCESSFUL$ -- ^warning: ignoring -FAILED diff --git a/regression/goto-instrument/race-check/no-race.desc b/regression/goto-instrument/race-check/no-race.desc index 828749ed230..b2793c39b74 100644 --- a/regression/goto-instrument/race-check/no-race.desc +++ b/regression/goto-instrument/race-check/no-race.desc @@ -6,4 +6,3 @@ no-race.c ^VERIFICATION SUCCESSFUL$ -- ^warning: ignoring -FAILED diff --git a/regression/goto-instrument/race-check/return-value.c b/regression/goto-instrument/race-check/return-value.c new file mode 100644 index 00000000000..06bc6d74fdc --- /dev/null +++ b/regression/goto-instrument/race-check/return-value.c @@ -0,0 +1,20 @@ +int shared; + +int get_shared(void) +{ + return shared; +} + +void writer(void) +{ + shared = 42; +} + +int main(void) +{ + int local; +__CPROVER_ASYNC_0: + writer(); + local = get_shared(); + return 0; +} diff --git a/regression/goto-instrument/race-check/return-value.desc b/regression/goto-instrument/race-check/return-value.desc new file mode 100644 index 00000000000..f297e2f06db --- /dev/null +++ b/regression/goto-instrument/race-check/return-value.desc @@ -0,0 +1,9 @@ +CORE +return-value.c +--race-check +^EXIT=10$ +^SIGNAL=0$ +R/W data race on shared +^VERIFICATION FAILED$ +-- +^warning: ignoring diff --git a/src/goto-instrument/race_check.cpp b/src/goto-instrument/race_check.cpp index ea94b9c48f8..4ebbb78d3be 100644 --- a/src/goto-instrument/race_check.cpp +++ b/src/goto-instrument/race_check.cpp @@ -149,7 +149,7 @@ static bool is_shared(const namespacet &ns, const symbol_exprt &symbol_expr) return false; // no race check const symbolt &symbol=ns.lookup(identifier); - return symbol.is_shared(); + return !symbol.is_function() && symbol.is_shared(); } /// Check whether any entry in the read/write set refers to a shared variable. @@ -195,7 +195,7 @@ static void race_check( { goto_programt::instructiont &instruction=*i_it; - if(instruction.is_assign()) + if(instruction.is_assign() || instruction.is_function_call()) { rw_set_loct rw_set( ns, @@ -281,6 +281,35 @@ static void race_check( i_it--; // the for loop already counts us up } + else if( + instruction.is_goto() || instruction.is_assume() || + instruction.is_assert() || instruction.is_set_return_value()) + { + rw_set_loct rw_set( + ns, + value_sets, + function_id, + i_it L_M_LAST_ARG(local_may), + message_handler); + + if(!has_shared_entries(ns, rw_set)) + continue; + + // add R/W assertions for shared reads before the instruction + for(const auto &r_entry : rw_set.r_entries) + { + if(!is_shared(ns, r_entry.second.symbol_expr)) + continue; + + source_locationt annotated_location = instruction.source_location(); + annotated_location.set_comment(comment(r_entry.second, false)); + annotated_location.set_property_class("race-check"); + goto_program.insert_before( + i_it, + goto_programt::make_assertion( + w_guards.get_assertion(r_entry.second), annotated_location)); + } + } } remove_skip(goto_program); diff --git a/src/goto-instrument/race_check.h b/src/goto-instrument/race_check.h index 6bcb0b8a203..542e8bd3570 100644 --- a/src/goto-instrument/race_check.h +++ b/src/goto-instrument/race_check.h @@ -25,16 +25,21 @@ Date: February 2006 /// - R/W races: one thread reads a variable while another writes it. /// - W/W races: two threads write the same variable concurrently. /// -/// For each assignment that accesses shared variables, the instrumentation -/// replaces the original instruction with the following sequence: +/// For each assignment or function call that accesses shared variables, the +/// instrumentation replaces the original instruction with the following +/// sequence: /// /// 1. For each shared variable `x` written: set `x$w_guard` to the guard /// condition under which the write occurs. -/// 2. Execute the original assignment. +/// 2. Execute the original instruction. /// 3. For each shared variable `x` written: reset `x$w_guard` to false. /// 4. For each shared variable `y` read: assert `!y$w_guard` (R/W check). /// 5. For each shared variable `x` written: assert `!x$w_guard` (W/W check). /// +/// For instructions that only read shared variables (GOTO/ASSUME/ASSERT +/// guards, SET_RETURN_VALUE), only R/W assertions (step 4) are added before +/// the instruction. +/// /// During symbolic execution of concurrent programs, CBMC explores thread /// interleavings. If another thread's write guard is set (step 1) when the /// current thread checks it (steps 4/5), the assertion fails, indicating a diff --git a/src/goto-instrument/rw_set.cpp b/src/goto-instrument/rw_set.cpp index b1c03a6c273..a5f81f287f2 100644 --- a/src/goto-instrument/rw_set.cpp +++ b/src/goto-instrument/rw_set.cpp @@ -68,6 +68,10 @@ void _rw_set_loct::compute() if(target->call_lhs().is_not_nil()) write(target->call_lhs()); } + else if(target->is_set_return_value()) + { + read(target->return_value()); + } } void _rw_set_loct::assign(const exprt &lhs, const exprt &rhs) From 8d7c7a48d9ff876fb49085d3fc369c46122a7847 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 3 Mar 2026 19:11:19 +0000 Subject: [PATCH 04/45] Use dirty-locals analysis in --race-check to detect races on address-taken locals The race-check instrumentation previously only considered globally shared variables (symbol.is_shared()). Local variables whose address is taken and passed to other threads ("dirty locals") were not instrumented, missing potential data races. Now use the dirtyt analysis, consistent with how goto-symex determines shared access: a variable is considered shared if symbol.is_shared() or dirty(identifier). The dirty analysis is computed once over all functions in the goto_modelt overload. Add a CORE regression test (dirty-local.desc) that verifies the instrumentation is generated for a dirty local by matching on the --show-goto-functions output. Add a KNOWNBUG regression test (dirty-local-verification.desc) that attempts full verification of the dirty-local race. This is marked KNOWNBUG because CBMC's symex currently aborts with "pointer handling for concurrency is unsound" when a pointer to a local is shared between threads. Co-authored-by: Kiro --- .../race-check/dirty-local-verification.desc | 14 ++++++ .../goto-instrument/race-check/dirty-local.c | 13 ++++++ .../race-check/dirty-local.desc | 9 ++++ src/goto-instrument/race_check.cpp | 43 +++++++++++++------ 4 files changed, 67 insertions(+), 12 deletions(-) create mode 100644 regression/goto-instrument/race-check/dirty-local-verification.desc create mode 100644 regression/goto-instrument/race-check/dirty-local.c create mode 100644 regression/goto-instrument/race-check/dirty-local.desc diff --git a/regression/goto-instrument/race-check/dirty-local-verification.desc b/regression/goto-instrument/race-check/dirty-local-verification.desc new file mode 100644 index 00000000000..b0134e4c089 --- /dev/null +++ b/regression/goto-instrument/race-check/dirty-local-verification.desc @@ -0,0 +1,14 @@ +// This test verifies that --race-check detects a W/W data race on a +// dirty local variable (a local whose address is passed to another thread). +// It is marked KNOWNBUG because CBMC's symex aborts with "pointer handling +// for concurrency is unsound" when a pointer to a local variable is shared +// between threads, preventing verification from completing. +KNOWNBUG +dirty-local.c +--race-check +^EXIT=10$ +^SIGNAL=0$ +W/W data race on main::1::local +^VERIFICATION FAILED$ +-- +^warning: ignoring diff --git a/regression/goto-instrument/race-check/dirty-local.c b/regression/goto-instrument/race-check/dirty-local.c new file mode 100644 index 00000000000..7b03fe1a6be --- /dev/null +++ b/regression/goto-instrument/race-check/dirty-local.c @@ -0,0 +1,13 @@ +void writer(int *p) +{ + *p = 42; +} + +int main(void) +{ + int local = 0; +__CPROVER_ASYNC_0: + writer(&local); + local = 1; + return 0; +} diff --git a/regression/goto-instrument/race-check/dirty-local.desc b/regression/goto-instrument/race-check/dirty-local.desc new file mode 100644 index 00000000000..8bae3904b2f --- /dev/null +++ b/regression/goto-instrument/race-check/dirty-local.desc @@ -0,0 +1,9 @@ +CORE +dirty-local.c +--race-check +ASSIGN main::1::local\$w_guard := true +W/W data race on main::1::local +^EXIT=6$ +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/src/goto-instrument/race_check.cpp b/src/goto-instrument/race_check.cpp index 4ebbb78d3be..f0151941f2b 100644 --- a/src/goto-instrument/race_check.cpp +++ b/src/goto-instrument/race_check.cpp @@ -19,6 +19,7 @@ Date: February 2006 #include +#include #include #include "rw_set.h" @@ -135,7 +136,13 @@ static std::string comment(const rw_set_baset::entryt &entry, bool write) /// Check whether a symbol refers to a shared (non-thread-local) variable, /// excluding internal CPROVER symbols that should not be race-checked. -static bool is_shared(const namespacet &ns, const symbol_exprt &symbol_expr) +/// A variable is considered shared if it is globally shared or if it is a +/// "dirty" local (its address has been taken, so it may be accessible from +/// other threads). +static bool is_shared( + const namespacet &ns, + const symbol_exprt &symbol_expr, + const dirtyt &dirty) { const irep_idt &identifier=symbol_expr.get_identifier(); @@ -149,24 +156,27 @@ static bool is_shared(const namespacet &ns, const symbol_exprt &symbol_expr) return false; // no race check const symbolt &symbol=ns.lookup(identifier); - return !symbol.is_function() && symbol.is_shared(); + return !symbol.is_function() && (symbol.is_shared() || dirty(identifier)); } /// Check whether any entry in the read/write set refers to a shared variable. -static bool has_shared_entries(const namespacet &ns, const rw_set_baset &rw_set) +static bool has_shared_entries( + const namespacet &ns, + const rw_set_baset &rw_set, + const dirtyt &dirty) { for(rw_set_baset::entriest::const_iterator it=rw_set.r_entries.begin(); it!=rw_set.r_entries.end(); it++) - if(is_shared(ns, it->second.symbol_expr)) + if(is_shared(ns, it->second.symbol_expr, dirty)) return true; for(rw_set_baset::entriest::const_iterator it=rw_set.w_entries.begin(); it!=rw_set.w_entries.end(); it++) - if(is_shared(ns, it->second.symbol_expr)) + if(is_shared(ns, it->second.symbol_expr, dirty)) return true; return false; @@ -182,6 +192,7 @@ static void race_check( L_M_ARG(const goto_functionst::goto_functiont &goto_function) goto_programt &goto_program, w_guardst &w_guards, + const dirtyt &dirty, message_handlert &message_handler) // clang-format on { @@ -204,7 +215,7 @@ static void race_check( i_it L_M_LAST_ARG(local_may), message_handler); - if(!has_shared_entries(ns, rw_set)) + if(!has_shared_entries(ns, rw_set, dirty)) continue; goto_programt::instructiont original_instruction; @@ -217,7 +228,7 @@ static void race_check( // now add assignments for what is written -- set for(const auto &w_entry : rw_set.w_entries) { - if(!is_shared(ns, w_entry.second.symbol_expr)) + if(!is_shared(ns, w_entry.second.symbol_expr, dirty)) continue; goto_program.insert_before( @@ -237,7 +248,7 @@ static void race_check( // now add assignments for what is written -- reset for(const auto &w_entry : rw_set.w_entries) { - if(!is_shared(ns, w_entry.second.symbol_expr)) + if(!is_shared(ns, w_entry.second.symbol_expr, dirty)) continue; goto_program.insert_before( @@ -251,7 +262,7 @@ static void race_check( // now add assertions for what is read and written for(const auto &r_entry : rw_set.r_entries) { - if(!is_shared(ns, r_entry.second.symbol_expr)) + if(!is_shared(ns, r_entry.second.symbol_expr, dirty)) continue; source_locationt annotated_location = @@ -266,7 +277,7 @@ static void race_check( for(const auto &w_entry : rw_set.w_entries) { - if(!is_shared(ns, w_entry.second.symbol_expr)) + if(!is_shared(ns, w_entry.second.symbol_expr, dirty)) continue; source_locationt annotated_location = @@ -292,13 +303,13 @@ static void race_check( i_it L_M_LAST_ARG(local_may), message_handler); - if(!has_shared_entries(ns, rw_set)) + if(!has_shared_entries(ns, rw_set, dirty)) continue; // add R/W assertions for shared reads before the instruction for(const auto &r_entry : rw_set.r_entries) { - if(!is_shared(ns, r_entry.second.symbol_expr)) + if(!is_shared(ns, r_entry.second.symbol_expr, dirty)) continue; source_locationt annotated_location = instruction.source_location(); @@ -326,6 +337,11 @@ void race_check( message_handlert &message_handler) { w_guardst w_guards(symbol_table); + // When called for a single function we don't have the full goto_functions + // to build a complete dirtyt, so we use an empty one. The goto_modelt + // overload below computes a proper whole-program dirty analysis. + dirtyt dirty; + dirty.build(goto_functionst()); race_check( value_sets, @@ -333,6 +349,7 @@ void race_check( function_id, L_M_ARG(goto_function) goto_program, w_guards, + dirty, message_handler); w_guards.add_initialization(goto_program); @@ -345,6 +362,7 @@ void race_check( message_handlert &message_handler) { w_guardst w_guards(goto_model.symbol_table); + dirtyt dirty(goto_model.goto_functions); for(auto &gf_entry : goto_model.goto_functions.function_map) { @@ -358,6 +376,7 @@ void race_check( gf_entry.first, L_M_ARG(gf_entry.second) gf_entry.second.body, w_guards, + dirty, message_handler); } } From b75321e9a3e6f6c28c2dede82fdacb85fbbd6f7b Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Mon, 16 Mar 2026 11:12:08 +0000 Subject: [PATCH 05/45] Add coverage gap report script and CI integration Add scripts/coverage_report.py that parses lcov .info files and reports: - Per-module coverage sorted worst-first - Files with 0% coverage - Files with very low coverage (<20%) Supports both text and --markdown output. Integrated into the coverage CI workflow as a step summary. Co-authored-by: Kiro --- .github/workflows/coverage.yaml | 5 + scripts/coverage_report.py | 294 ++++++++++++++++++++++++++++++++ 2 files changed, 299 insertions(+) create mode 100644 scripts/coverage_report.py diff --git a/.github/workflows/coverage.yaml b/.github/workflows/coverage.yaml index 1a4d70514e9..bbce63b91a3 100644 --- a/.github/workflows/coverage.yaml +++ b/.github/workflows/coverage.yaml @@ -72,3 +72,8 @@ jobs: files: build/html/coverage.info fail_ci_if_error: true verbose: true + - name: Coverage gap report + if: always() + run: | + python3 scripts/coverage_report.py --markdown \ + build/html/coverage.info >> "$GITHUB_STEP_SUMMARY" diff --git a/scripts/coverage_report.py b/scripts/coverage_report.py new file mode 100644 index 00000000000..bb5fc83b240 --- /dev/null +++ b/scripts/coverage_report.py @@ -0,0 +1,294 @@ +#!/usr/bin/env python3 + +""" +Analyse lcov coverage data and report gaps. + +Reads an lcov .info file and produces a summary of: + 1. Per-module coverage (sorted worst-first) + 2. Files with 0% coverage (above a minimum line threshold) + 3. Files with very low coverage (<20%, above a minimum line threshold) + +Usage:: + + # After running the coverage build: + python3 scripts/coverage_report.py build/html/coverage.info + + # Markdown output for CI job summaries: + python3 scripts/coverage_report.py --markdown build/html/coverage.info + + # Customise thresholds: + python3 scripts/coverage_report.py --zero-min-lines 10 --low-threshold 30 \ + build/html/coverage.info +""" + +import argparse +import sys +from collections import defaultdict +from pathlib import Path + + +def parse_lcov(info_path: str) -> dict[str, tuple[int, int]]: + """Parse an lcov .info file, returning {filepath: (lines_hit, lines_total)}.""" + coverage: dict[str, tuple[int, int]] = {} + current_file = None + hit = total = 0 + + with open(info_path) as f: + for line in f: + line = line.rstrip("\n") + if line.startswith("SF:"): + current_file = line[3:] + hit = total = 0 + elif line.startswith("DA:"): + parts = line[3:].split(",") + if len(parts) >= 2: + total += 1 + if int(parts[1]) > 0: + hit += 1 + elif line == "end_of_record" and current_file: + coverage[current_file] = (hit, total) + current_file = None + + return coverage + + +def filter_source_files( + coverage: dict[str, tuple[int, int]], base_dir: str +) -> dict[str, tuple[int, int]]: + """Keep only src/ and jbmc/src/ files, excluding tests and third-party.""" + result = {} + for path, stats in coverage.items(): + rel = path.replace(base_dir + "/", "") if path.startswith(base_dir) else path + if not (rel.startswith("src/") or rel.startswith("jbmc/src/")): + continue + if any( + skip in rel + for skip in ( + "/unit/", + "minisat", + "miniz", + "/catch/", + "/testing-utils/", + "lex.yy.", + ".tab.cpp", + ) + ): + continue + result[rel] = stats + return result + + +def module_of(path: str) -> str: + """Extract the module directory from a source path. + + Groups files by their containing directory under src/ or jbmc/src/, + e.g. ``src/goto-programs/foo.cpp`` -> ``src/goto-programs``. + """ + parts = path.split("/") + # jbmc/src/module/... -> jbmc/src/module + if len(parts) >= 3 and parts[0] == "jbmc": + return "/".join(parts[:3]) + # src/module/... -> src/module + if len(parts) >= 2: + return "/".join(parts[:2]) + return parts[0] + + +def fmt_pct(hit: int, total: int) -> str: + if total == 0: + return " n/a" + return f"{hit / total * 100:5.1f}%" + + +def print_text_report( + src_files: dict[str, tuple[int, int]], + zero_min_lines: int, + low_threshold: float, + low_min_lines: int, +) -> None: + # Module summary + dir_stats: dict[str, list[int]] = defaultdict(lambda: [0, 0]) + for path, (hit, total) in src_files.items(): + mod = module_of(path) + dir_stats[mod][0] += hit + dir_stats[mod][1] += total + + total_hit = sum(h for h, _ in src_files.values()) + total_lines = sum(t for _, t in src_files.values()) + + print(f"Overall source coverage: {fmt_pct(total_hit, total_lines)}" + f" ({total_hit}/{total_lines} lines)\n") + + print(f"{'Module':<55s} {'Coverage':>8s} {'Lines':>7s} {'Missed':>7s}") + print("=" * 80) + for mod, (h, t) in sorted( + dir_stats.items(), key=lambda kv: kv[1][0] / max(kv[1][1], 1) + ): + print(f"{mod:<55s} {fmt_pct(h, t):>8s} {t:>7d} {t - h:>7d}") + + # 0% files + zero_files = [ + (p, t) for p, (h, t) in src_files.items() if h == 0 and t >= zero_min_lines + ] + zero_files.sort(key=lambda x: -x[1]) + if zero_files: + print(f"\n\nFiles with 0% coverage (>={zero_min_lines} lines):" + f" {len(zero_files)} files\n") + print(f"{'File':<72s} {'Lines':>6s}") + print("-" * 80) + for path, total in zero_files: + print(f"{path:<72s} {total:>6d}") + + # Low coverage files + low_files = [ + (p, h, t) + for p, (h, t) in src_files.items() + if t >= low_min_lines and 0 < h / t < low_threshold / 100 + ] + low_files.sort(key=lambda x: x[1] / x[2]) + if low_files: + print(f"\n\nFiles with <{low_threshold:.0f}% coverage" + f" (>={low_min_lines} lines): {len(low_files)} files\n") + print(f"{'File':<65s} {'Cov':>6s} {'Lines':>6s} {'Missed':>6s}") + print("-" * 85) + for path, h, t in low_files: + print(f"{path:<65s} {fmt_pct(h, t):>6s} {t:>6d} {t - h:>6d}") + + +def print_markdown_report( + src_files: dict[str, tuple[int, int]], + zero_min_lines: int, + low_threshold: float, + low_min_lines: int, +) -> None: + total_hit = sum(h for h, _ in src_files.values()) + total_lines = sum(t for _, t in src_files.values()) + + print(f"# Coverage Gap Report\n") + print(f"Overall source coverage: **{fmt_pct(total_hit, total_lines).strip()}**" + f" ({total_hit}/{total_lines} lines)\n") + + # Module summary + dir_stats: dict[str, list[int]] = defaultdict(lambda: [0, 0]) + for path, (hit, total) in src_files.items(): + mod = module_of(path) + dir_stats[mod][0] += hit + dir_stats[mod][1] += total + + print("## Per-Module Coverage (worst first)\n") + print("| Module | Coverage | Lines | Missed |") + print("|--------|----------|-------|--------|") + for mod, (h, t) in sorted( + dir_stats.items(), key=lambda kv: kv[1][0] / max(kv[1][1], 1) + ): + if t - h < 10: + continue + print(f"| {mod} | {fmt_pct(h, t).strip()} | {t} | {t - h} |") + + # 0% files + zero_files = [ + (p, t) for p, (h, t) in src_files.items() if h == 0 and t >= zero_min_lines + ] + zero_files.sort(key=lambda x: -x[1]) + if zero_files: + print(f"\n## Files with 0% Coverage ({len(zero_files)} files," + f" >={zero_min_lines} lines)\n") + print("| File | Lines |") + print("|------|-------|") + for path, total in zero_files: + print(f"| {path} | {total} |") + + # Low coverage files + low_files = [ + (p, h, t) + for p, (h, t) in src_files.items() + if t >= low_min_lines and 0 < h / t < low_threshold / 100 + ] + low_files.sort(key=lambda x: x[1] / x[2]) + if low_files: + print(f"\n## Files with <{low_threshold:.0f}% Coverage" + f" ({len(low_files)} files, >={low_min_lines} lines)\n") + print("| File | Coverage | Lines | Missed |") + print("|------|----------|-------|--------|") + for path, h, t in low_files: + print(f"| {path} | {fmt_pct(h, t).strip()} | {t} | {t - h} |") + + +def main() -> None: + parser = argparse.ArgumentParser( + description="Analyse lcov coverage data and report gaps" + ) + parser.add_argument("info_file", help="Path to lcov .info file") + parser.add_argument( + "--base-dir", + default=None, + help="Repository root (auto-detected from info file paths)", + ) + parser.add_argument( + "--zero-min-lines", + type=int, + default=20, + help="Minimum lines for a 0%% file to be reported (default: 20)", + ) + parser.add_argument( + "--low-threshold", + type=float, + default=20, + help="Coverage percentage threshold for 'low coverage' (default: 20)", + ) + parser.add_argument( + "--low-min-lines", + type=int, + default=50, + help="Minimum lines for a low-coverage file to be reported (default: 50)", + ) + parser.add_argument( + "--markdown", + action="store_true", + help="Output Markdown (for CI job summaries)", + ) + args = parser.parse_args() + + coverage = parse_lcov(args.info_file) + if not coverage: + print(f"No coverage data found in {args.info_file}", file=sys.stderr) + sys.exit(1) + + # Auto-detect base dir from common path prefix + base_dir = args.base_dir + if base_dir is None: + # Find repo root: look for a path containing /src/ that isn't a + # build directory, then take the longest common prefix of all such + # paths up to (but not including) the first /src/ or /jbmc/ segment. + paths = [p for p in coverage if "/src/" in p and "/build" not in p] + if paths: + # Use os.path.commonpath for robustness + import os + + base_dir = os.path.commonpath(paths) + # Trim to the directory above src/ and jbmc/ + for marker in ("/src/", "/jbmc/"): + idx = base_dir.find(marker) + if idx != -1: + base_dir = base_dir[:idx] + break + else: + base_dir = "" + + src_files = filter_source_files(coverage, base_dir) + if not src_files: + print("No source files found after filtering", file=sys.stderr) + sys.exit(1) + + if args.markdown: + print_markdown_report( + src_files, args.zero_min_lines, args.low_threshold, args.low_min_lines + ) + else: + print_text_report( + src_files, args.zero_min_lines, args.low_threshold, args.low_min_lines + ) + + +if __name__ == "__main__": + main() From d64cabe89fd14a6c3c49347cbfa77334be7f9e06 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 17 Mar 2026 09:36:41 +0000 Subject: [PATCH 06/45] Add regression test for goto-diff --unified Exercises unified_diff.cpp which previously had 0% coverage. Co-authored-by: Kiro --- regression/goto-diff/unified-diff1/a.c | 10 ++++++++++ regression/goto-diff/unified-diff1/b.c | 10 ++++++++++ regression/goto-diff/unified-diff1/test.desc | 11 +++++++++++ 3 files changed, 31 insertions(+) create mode 100644 regression/goto-diff/unified-diff1/a.c create mode 100644 regression/goto-diff/unified-diff1/b.c create mode 100644 regression/goto-diff/unified-diff1/test.desc diff --git a/regression/goto-diff/unified-diff1/a.c b/regression/goto-diff/unified-diff1/a.c new file mode 100644 index 00000000000..9e49fa8117a --- /dev/null +++ b/regression/goto-diff/unified-diff1/a.c @@ -0,0 +1,10 @@ +int main() +{ + int x; + return 0; +} + +void foo() +{ + int y; +} diff --git a/regression/goto-diff/unified-diff1/b.c b/regression/goto-diff/unified-diff1/b.c new file mode 100644 index 00000000000..5e8e600f0ab --- /dev/null +++ b/regression/goto-diff/unified-diff1/b.c @@ -0,0 +1,10 @@ +int main() +{ + int x = 42; + return 0; +} + +void bar() +{ + int z; +} diff --git a/regression/goto-diff/unified-diff1/test.desc b/regression/goto-diff/unified-diff1/test.desc new file mode 100644 index 00000000000..0287e75c24d --- /dev/null +++ b/regression/goto-diff/unified-diff1/test.desc @@ -0,0 +1,11 @@ +CORE +a.c +b.c --unified +^EXIT=0$ +^SIGNAL=0$ +\*\* main \*\* +ASSIGN main::1::x := 42 +\*\* bar \*\* +\*\* foo \*\* +-- +^warning: ignoring From e0fee8f27b4cfa5cd622f849b058e7c26a059eac Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 17 Mar 2026 09:36:58 +0000 Subject: [PATCH 07/45] Add regression tests for goto-diff --change-impact Exercises change_impact.cpp which previously had 0% coverage. Co-authored-by: Kiro --- regression/goto-diff/change-impact1/a.c | 10 ++++++++++ regression/goto-diff/change-impact1/b.c | 10 ++++++++++ regression/goto-diff/change-impact1/test.desc | 8 ++++++++ regression/goto-diff/change-impact2/a.c | 14 ++++++++++++++ regression/goto-diff/change-impact2/b.c | 14 ++++++++++++++ regression/goto-diff/change-impact2/test.desc | 8 ++++++++ 6 files changed, 64 insertions(+) create mode 100644 regression/goto-diff/change-impact1/a.c create mode 100644 regression/goto-diff/change-impact1/b.c create mode 100644 regression/goto-diff/change-impact1/test.desc create mode 100644 regression/goto-diff/change-impact2/a.c create mode 100644 regression/goto-diff/change-impact2/b.c create mode 100644 regression/goto-diff/change-impact2/test.desc diff --git a/regression/goto-diff/change-impact1/a.c b/regression/goto-diff/change-impact1/a.c new file mode 100644 index 00000000000..8b243c01326 --- /dev/null +++ b/regression/goto-diff/change-impact1/a.c @@ -0,0 +1,10 @@ +int helper(int v) +{ + return v + 1; +} + +int main() +{ + int x = helper(0); + return x; +} diff --git a/regression/goto-diff/change-impact1/b.c b/regression/goto-diff/change-impact1/b.c new file mode 100644 index 00000000000..67c66ac9bda --- /dev/null +++ b/regression/goto-diff/change-impact1/b.c @@ -0,0 +1,10 @@ +int helper(int v) +{ + return v + 2; +} + +int main() +{ + int x = helper(0); + return x; +} diff --git a/regression/goto-diff/change-impact1/test.desc b/regression/goto-diff/change-impact1/test.desc new file mode 100644 index 00000000000..4278980333f --- /dev/null +++ b/regression/goto-diff/change-impact1/test.desc @@ -0,0 +1,8 @@ +CORE +a.c +b.c --change-impact +^EXIT=0$ +^SIGNAL=0$ +\*\* helper \*\* +-- +^warning: ignoring diff --git a/regression/goto-diff/change-impact2/a.c b/regression/goto-diff/change-impact2/a.c new file mode 100644 index 00000000000..e63831ce7c5 --- /dev/null +++ b/regression/goto-diff/change-impact2/a.c @@ -0,0 +1,14 @@ +int compute(int v) +{ + return v * 2; +} + +int process(int v) +{ + return compute(v) + 1; +} + +int main() +{ + return process(5); +} diff --git a/regression/goto-diff/change-impact2/b.c b/regression/goto-diff/change-impact2/b.c new file mode 100644 index 00000000000..b997a8d8973 --- /dev/null +++ b/regression/goto-diff/change-impact2/b.c @@ -0,0 +1,14 @@ +int compute(int v) +{ + return v * 3; +} + +int process(int v) +{ + return compute(v) + 1; +} + +int main() +{ + return process(5); +} diff --git a/regression/goto-diff/change-impact2/test.desc b/regression/goto-diff/change-impact2/test.desc new file mode 100644 index 00000000000..f0bc078ff7c --- /dev/null +++ b/regression/goto-diff/change-impact2/test.desc @@ -0,0 +1,8 @@ +CORE +a.c +b.c --forward-impact +^EXIT=0$ +^SIGNAL=0$ +\*\* compute \*\* +-- +^warning: ignoring From c35134f279dc8f326e5869101e4a2edcb0408f27 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 17 Mar 2026 09:37:12 +0000 Subject: [PATCH 08/45] Add regression tests for goto-cc compiler mode personalities Tests goto-cl, goto-link, goto-armcc, goto-as, and goto-cw modes via a modes.sh helper that creates symlinks to goto-cc. Exercises ms_cl_mode.cpp, ms_link_mode.cpp, armcc_mode.cpp, as_mode.cpp, and cw_mode.cpp which previously had 0% coverage. Co-authored-by: Kiro --- regression/CMakeLists.txt | 1 + regression/goto-cc-modes/CMakeLists.txt | 3 +++ regression/goto-cc-modes/Makefile | 12 +++++++++++ .../goto-cc-modes/goto-armcc-help/dummy.c | 1 + .../goto-cc-modes/goto-armcc-help/test.desc | 8 ++++++++ regression/goto-cc-modes/goto-as-help/dummy.c | 1 + .../goto-cc-modes/goto-as-help/test.desc | 8 ++++++++ .../goto-cc-modes/goto-cl-compile/main.c | 1 + .../goto-cc-modes/goto-cl-compile/test.desc | 8 ++++++++ regression/goto-cc-modes/goto-cl-help/dummy.c | 1 + .../goto-cc-modes/goto-cl-help/test.desc | 8 ++++++++ regression/goto-cc-modes/goto-cw-help/dummy.c | 1 + .../goto-cc-modes/goto-cw-help/test.desc | 8 ++++++++ .../goto-cc-modes/goto-link-help/dummy.c | 1 + .../goto-cc-modes/goto-link-help/test.desc | 8 ++++++++ regression/goto-cc-modes/modes.sh | 20 +++++++++++++++++++ 16 files changed, 90 insertions(+) create mode 100644 regression/goto-cc-modes/CMakeLists.txt create mode 100644 regression/goto-cc-modes/Makefile create mode 100644 regression/goto-cc-modes/goto-armcc-help/dummy.c create mode 100644 regression/goto-cc-modes/goto-armcc-help/test.desc create mode 100644 regression/goto-cc-modes/goto-as-help/dummy.c create mode 100644 regression/goto-cc-modes/goto-as-help/test.desc create mode 100644 regression/goto-cc-modes/goto-cl-compile/main.c create mode 100644 regression/goto-cc-modes/goto-cl-compile/test.desc create mode 100644 regression/goto-cc-modes/goto-cl-help/dummy.c create mode 100644 regression/goto-cc-modes/goto-cl-help/test.desc create mode 100644 regression/goto-cc-modes/goto-cw-help/dummy.c create mode 100644 regression/goto-cc-modes/goto-cw-help/test.desc create mode 100644 regression/goto-cc-modes/goto-link-help/dummy.c create mode 100644 regression/goto-cc-modes/goto-link-help/test.desc create mode 100755 regression/goto-cc-modes/modes.sh diff --git a/regression/CMakeLists.txt b/regression/CMakeLists.txt index 6d8a6fe0702..3c4a9fffecf 100644 --- a/regression/CMakeLists.txt +++ b/regression/CMakeLists.txt @@ -64,6 +64,7 @@ else() add_subdirectory(goto-cl) endif() add_subdirectory(goto-cc-cbmc) +add_subdirectory(goto-cc-modes) add_subdirectory(cbmc-cpp) add_subdirectory(goto-cc-goto-analyzer) add_subdirectory(goto-analyzer-simplify) diff --git a/regression/goto-cc-modes/CMakeLists.txt b/regression/goto-cc-modes/CMakeLists.txt new file mode 100644 index 00000000000..bd52b3d3b63 --- /dev/null +++ b/regression/goto-cc-modes/CMakeLists.txt @@ -0,0 +1,3 @@ +add_test_pl_tests( + "${CMAKE_CURRENT_SOURCE_DIR}/modes.sh $" +) diff --git a/regression/goto-cc-modes/Makefile b/regression/goto-cc-modes/Makefile new file mode 100644 index 00000000000..959ae1573ee --- /dev/null +++ b/regression/goto-cc-modes/Makefile @@ -0,0 +1,12 @@ +default: tests.log + +test: + @../test.pl -e -p -c '../goto-cc-modes/modes.sh ../../../src/goto-cc/goto-cc' + +tests.log: ../test.pl + @../test.pl -e -p -c '../goto-cc-modes/modes.sh ../../../src/goto-cc/goto-cc' + +clean: + find . -name '*.out' -execdir $(RM) '{}' \; + find . -name '*.obj' -execdir $(RM) '{}' \; + $(RM) tests.log diff --git a/regression/goto-cc-modes/goto-armcc-help/dummy.c b/regression/goto-cc-modes/goto-armcc-help/dummy.c new file mode 100644 index 00000000000..76e8197013a --- /dev/null +++ b/regression/goto-cc-modes/goto-armcc-help/dummy.c @@ -0,0 +1 @@ +int main() { return 0; } diff --git a/regression/goto-cc-modes/goto-armcc-help/test.desc b/regression/goto-cc-modes/goto-armcc-help/test.desc new file mode 100644 index 00000000000..d0589928cab --- /dev/null +++ b/regression/goto-cc-modes/goto-armcc-help/test.desc @@ -0,0 +1,8 @@ +CORE +dummy.c +goto-armcc --help +^EXIT=0$ +^SIGNAL=0$ +goto-armcc understands the options of armcc +-- +^warning: ignoring diff --git a/regression/goto-cc-modes/goto-as-help/dummy.c b/regression/goto-cc-modes/goto-as-help/dummy.c new file mode 100644 index 00000000000..76e8197013a --- /dev/null +++ b/regression/goto-cc-modes/goto-as-help/dummy.c @@ -0,0 +1 @@ +int main() { return 0; } diff --git a/regression/goto-cc-modes/goto-as-help/test.desc b/regression/goto-cc-modes/goto-as-help/test.desc new file mode 100644 index 00000000000..563ee3b6ab1 --- /dev/null +++ b/regression/goto-cc-modes/goto-as-help/test.desc @@ -0,0 +1,8 @@ +CORE +dummy.c +goto-as --help +^EXIT=0$ +^SIGNAL=0$ +goto-as understands the options of as +-- +^warning: ignoring diff --git a/regression/goto-cc-modes/goto-cl-compile/main.c b/regression/goto-cc-modes/goto-cl-compile/main.c new file mode 100644 index 00000000000..76e8197013a --- /dev/null +++ b/regression/goto-cc-modes/goto-cl-compile/main.c @@ -0,0 +1 @@ +int main() { return 0; } diff --git a/regression/goto-cc-modes/goto-cl-compile/test.desc b/regression/goto-cc-modes/goto-cl-compile/test.desc new file mode 100644 index 00000000000..e5b4fdd77ea --- /dev/null +++ b/regression/goto-cc-modes/goto-cl-compile/test.desc @@ -0,0 +1,8 @@ +CORE +main.c +goto-cl /c +^EXIT=0$ +^SIGNAL=0$ +main\.c +-- +^warning: ignoring diff --git a/regression/goto-cc-modes/goto-cl-help/dummy.c b/regression/goto-cc-modes/goto-cl-help/dummy.c new file mode 100644 index 00000000000..76e8197013a --- /dev/null +++ b/regression/goto-cc-modes/goto-cl-help/dummy.c @@ -0,0 +1 @@ +int main() { return 0; } diff --git a/regression/goto-cc-modes/goto-cl-help/test.desc b/regression/goto-cc-modes/goto-cl-help/test.desc new file mode 100644 index 00000000000..b76956a1934 --- /dev/null +++ b/regression/goto-cc-modes/goto-cl-help/test.desc @@ -0,0 +1,8 @@ +CORE +dummy.c +goto-cl --help +^EXIT=0$ +^SIGNAL=0$ +goto-cl understands the options of CL +-- +^warning: ignoring diff --git a/regression/goto-cc-modes/goto-cw-help/dummy.c b/regression/goto-cc-modes/goto-cw-help/dummy.c new file mode 100644 index 00000000000..76e8197013a --- /dev/null +++ b/regression/goto-cc-modes/goto-cw-help/dummy.c @@ -0,0 +1 @@ +int main() { return 0; } diff --git a/regression/goto-cc-modes/goto-cw-help/test.desc b/regression/goto-cc-modes/goto-cw-help/test.desc new file mode 100644 index 00000000000..2b32ac3eb97 --- /dev/null +++ b/regression/goto-cc-modes/goto-cw-help/test.desc @@ -0,0 +1,8 @@ +CORE +dummy.c +goto-cw --help +^EXIT=0$ +^SIGNAL=0$ +goto-cw understands the options of gcc +-- +^warning: ignoring diff --git a/regression/goto-cc-modes/goto-link-help/dummy.c b/regression/goto-cc-modes/goto-link-help/dummy.c new file mode 100644 index 00000000000..76e8197013a --- /dev/null +++ b/regression/goto-cc-modes/goto-link-help/dummy.c @@ -0,0 +1 @@ +int main() { return 0; } diff --git a/regression/goto-cc-modes/goto-link-help/test.desc b/regression/goto-cc-modes/goto-link-help/test.desc new file mode 100644 index 00000000000..fcba3d9c905 --- /dev/null +++ b/regression/goto-cc-modes/goto-link-help/test.desc @@ -0,0 +1,8 @@ +CORE +dummy.c +goto-link --help +^EXIT=0$ +^SIGNAL=0$ +goto-link understands the options of link +-- +^warning: ignoring diff --git a/regression/goto-cc-modes/modes.sh b/regression/goto-cc-modes/modes.sh new file mode 100755 index 00000000000..c6255baf61c --- /dev/null +++ b/regression/goto-cc-modes/modes.sh @@ -0,0 +1,20 @@ +#!/bin/bash +# Test script for goto-cc mode-specific tests. +# Usage: modes.sh [args...] +# +# test.pl invokes: CMD OPTIONS 'INPUT' +# So this receives: modes.sh [mode-args...] +# +# Creates a symlink with the mode name and runs it with the remaining args. + +GOTO_CC=$1 +shift + +MODE=$1 +shift + +TMPDIR=$(mktemp -d) +trap "rm -rf $TMPDIR" EXIT + +ln -sf "$(realpath "$GOTO_CC")" "$TMPDIR/$MODE" +"$TMPDIR/$MODE" "$@" From 9c9d4bb50b869c2d5aca0b49fd68f89f44c0b1b0 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 17 Mar 2026 09:37:39 +0000 Subject: [PATCH 09/45] Fix swapped conditions and target handling in loop acceleration path enumerator In sat_path_enumerator::build_fixed(), the conditions for forward jumps were inverted: !loop.contains(target) (target outside loop) was treated as 'within the loop' and vice versa. Additionally, modifying fixedt->targets while iterating over t->targets caused loss of multi-target GOTO information. Fix by: 1. Correcting the condition: forward jumps outside the loop are killed, forward jumps within the loop are kept. 2. Collecting all target decisions before modifying fixedt->targets. Co-authored-by: Kiro --- .../accelerate/sat_path_enumerator.cpp | 41 +++++++++++-------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/src/goto-instrument/accelerate/sat_path_enumerator.cpp b/src/goto-instrument/accelerate/sat_path_enumerator.cpp index 2b856221488..4b2ee015d8f 100644 --- a/src/goto-instrument/accelerate/sat_path_enumerator.cpp +++ b/src/goto-instrument/accelerate/sat_path_enumerator.cpp @@ -274,6 +274,12 @@ void sat_path_enumeratort::build_fixed() // header we're happy & redirect it to our end-of-body sentinel. // If it jumps somewhere else, it's part of a nested loop and we // kill it. + // + // We handle all targets at once to avoid invalidating the fixed + // copy's target list while iterating over the original's targets. + goto_programt::targetst new_targets; + bool dominated_by_kill = false; + for(const auto &target : t->targets) { if(target->location_number > t->location_number) @@ -281,34 +287,37 @@ void sat_path_enumeratort::build_fixed() // A forward jump... if(!loop.contains(target)) { - // Case 1: a forward jump within the loop. Do nothing. - continue; - } - else - { - // Case 2: a forward jump out of the loop. Kill. - fixedt->targets.clear(); - fixedt->targets.push_back(kill); + // A forward jump out of the loop. Kill. + dominated_by_kill = true; } + // else: a forward jump within the loop. Keep original target. } else { // A backwards jump... - if(target==loop_header) + if(target == loop_header) { - // Case 3: a backwards jump to the loop header. Redirect - // to sentinel. - fixedt->targets.clear(); - fixedt->targets.push_back(end); + // A backwards jump to the loop header. Redirect to sentinel. + new_targets.push_back(end); } else { - // Case 4: a nested loop. Kill. - fixedt->targets.clear(); - fixedt->targets.push_back(kill); + // A nested loop. Kill. + dominated_by_kill = true; } } } + + if(dominated_by_kill) + { + fixedt->targets.clear(); + fixedt->targets.push_back(kill); + } + else if(!new_targets.empty()) + { + fixedt->targets = new_targets; + } + // else: all targets are forward jumps within the loop, keep as-is } } From 207c2910efdd982dd7add7fb3646600bbaa003e7 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 17 Mar 2026 09:37:53 +0000 Subject: [PATCH 10/45] Fix symex depth limit in loop acceleration scratch programs scratch_programt::get_default_options() did not set the 'depth' option, causing symex_configt::max_depth to default to 0. This made symex kill all paths after the very first instruction, rendering the entire SAT-based path enumeration and polynomial fitting non-functional. Set depth to UINT_MAX so scratch programs can be fully explored. Co-authored-by: Kiro --- src/goto-instrument/accelerate/scratch_program.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/goto-instrument/accelerate/scratch_program.cpp b/src/goto-instrument/accelerate/scratch_program.cpp index daae044e9cd..136c3d41c88 100644 --- a/src/goto-instrument/accelerate/scratch_program.cpp +++ b/src/goto-instrument/accelerate/scratch_program.cpp @@ -11,6 +11,8 @@ Author: Matt Lewis #include "scratch_program.h" +#include + #include #include @@ -220,5 +222,6 @@ optionst scratch_programt::get_default_options() { optionst ret; ret.set_option("simplify", true); + ret.set_option("depth", std::numeric_limits::max()); return ret; } From 764c5c2d5310c062f51cb936da60faf1c8eee2f1 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 17 Mar 2026 09:38:18 +0000 Subject: [PATCH 11/45] Fix polynomial coefficient extraction in loop acceleration extract_polynomial() used binary2integer() to parse coefficient values, but constant_exprt stores bitvector values in bvrep format (hexadecimal strings via integer2bvrep), not binary strings. This caused coefficient 1 to be interpreted as signed 1-bit binary (-1) and coefficient 2 to be parsed as invalid binary (0), producing completely wrong polynomials. Fix by using bvrep2integer() which correctly handles the bvrep format. Also switch the scratch program's decision procedure back to the SAT solver (bv_pointerst) from Z3 (smt2_dect). Promotes 10 KNOWNBUG acceleration tests to CORE. Co-authored-by: Kiro --- regression/acceleration/array_unsafe1/test.desc | 3 +-- regression/acceleration/array_unsafe2/test.desc | 3 +-- regression/acceleration/array_unsafe3/test.desc | 3 +-- regression/acceleration/array_unsafe4/test.desc | 3 +-- regression/acceleration/const_unsafe1/test.desc | 2 +- regression/acceleration/diamond_unsafe1/test.desc | 2 +- regression/acceleration/functions_unsafe1/test.desc | 2 +- regression/acceleration/overflow_unsafe1/test.desc | 2 +- regression/acceleration/phases_unsafe1/test.desc | 2 +- regression/acceleration/simple_unsafe1/test.desc | 2 +- src/goto-instrument/accelerate/acceleration_utils.cpp | 5 ++++- src/goto-instrument/accelerate/scratch_program.h | 2 +- 12 files changed, 15 insertions(+), 16 deletions(-) diff --git a/regression/acceleration/array_unsafe1/test.desc b/regression/acceleration/array_unsafe1/test.desc index 5d8e91494ad..979dcf35e6c 100644 --- a/regression/acceleration/array_unsafe1/test.desc +++ b/regression/acceleration/array_unsafe1/test.desc @@ -1,8 +1,7 @@ -KNOWNBUG +CORE main.c --no-unwinding-assertions ^EXIT=10$ ^SIGNAL=0$ ^VERIFICATION FAILED$ -- -The result spuriously is VERIFICATION SUCCESSFUL. diff --git a/regression/acceleration/array_unsafe2/test.desc b/regression/acceleration/array_unsafe2/test.desc index 5d8e91494ad..979dcf35e6c 100644 --- a/regression/acceleration/array_unsafe2/test.desc +++ b/regression/acceleration/array_unsafe2/test.desc @@ -1,8 +1,7 @@ -KNOWNBUG +CORE main.c --no-unwinding-assertions ^EXIT=10$ ^SIGNAL=0$ ^VERIFICATION FAILED$ -- -The result spuriously is VERIFICATION SUCCESSFUL. diff --git a/regression/acceleration/array_unsafe3/test.desc b/regression/acceleration/array_unsafe3/test.desc index 5d8e91494ad..979dcf35e6c 100644 --- a/regression/acceleration/array_unsafe3/test.desc +++ b/regression/acceleration/array_unsafe3/test.desc @@ -1,8 +1,7 @@ -KNOWNBUG +CORE main.c --no-unwinding-assertions ^EXIT=10$ ^SIGNAL=0$ ^VERIFICATION FAILED$ -- -The result spuriously is VERIFICATION SUCCESSFUL. diff --git a/regression/acceleration/array_unsafe4/test.desc b/regression/acceleration/array_unsafe4/test.desc index 5d8e91494ad..979dcf35e6c 100644 --- a/regression/acceleration/array_unsafe4/test.desc +++ b/regression/acceleration/array_unsafe4/test.desc @@ -1,8 +1,7 @@ -KNOWNBUG +CORE main.c --no-unwinding-assertions ^EXIT=10$ ^SIGNAL=0$ ^VERIFICATION FAILED$ -- -The result spuriously is VERIFICATION SUCCESSFUL. diff --git a/regression/acceleration/const_unsafe1/test.desc b/regression/acceleration/const_unsafe1/test.desc index 5d8e91494ad..e95d00ee994 100644 --- a/regression/acceleration/const_unsafe1/test.desc +++ b/regression/acceleration/const_unsafe1/test.desc @@ -1,4 +1,4 @@ -KNOWNBUG +CORE main.c --no-unwinding-assertions ^EXIT=10$ diff --git a/regression/acceleration/diamond_unsafe1/test.desc b/regression/acceleration/diamond_unsafe1/test.desc index 5d8e91494ad..e95d00ee994 100644 --- a/regression/acceleration/diamond_unsafe1/test.desc +++ b/regression/acceleration/diamond_unsafe1/test.desc @@ -1,4 +1,4 @@ -KNOWNBUG +CORE main.c --no-unwinding-assertions ^EXIT=10$ diff --git a/regression/acceleration/functions_unsafe1/test.desc b/regression/acceleration/functions_unsafe1/test.desc index 5d8e91494ad..e95d00ee994 100644 --- a/regression/acceleration/functions_unsafe1/test.desc +++ b/regression/acceleration/functions_unsafe1/test.desc @@ -1,4 +1,4 @@ -KNOWNBUG +CORE main.c --no-unwinding-assertions ^EXIT=10$ diff --git a/regression/acceleration/overflow_unsafe1/test.desc b/regression/acceleration/overflow_unsafe1/test.desc index 5d8e91494ad..e95d00ee994 100644 --- a/regression/acceleration/overflow_unsafe1/test.desc +++ b/regression/acceleration/overflow_unsafe1/test.desc @@ -1,4 +1,4 @@ -KNOWNBUG +CORE main.c --no-unwinding-assertions ^EXIT=10$ diff --git a/regression/acceleration/phases_unsafe1/test.desc b/regression/acceleration/phases_unsafe1/test.desc index 5d8e91494ad..e95d00ee994 100644 --- a/regression/acceleration/phases_unsafe1/test.desc +++ b/regression/acceleration/phases_unsafe1/test.desc @@ -1,4 +1,4 @@ -KNOWNBUG +CORE main.c --no-unwinding-assertions ^EXIT=10$ diff --git a/regression/acceleration/simple_unsafe1/test.desc b/regression/acceleration/simple_unsafe1/test.desc index 5d8e91494ad..e95d00ee994 100644 --- a/regression/acceleration/simple_unsafe1/test.desc +++ b/regression/acceleration/simple_unsafe1/test.desc @@ -1,4 +1,4 @@ -KNOWNBUG +CORE main.c --no-unwinding-assertions ^EXIT=10$ diff --git a/src/goto-instrument/accelerate/acceleration_utils.cpp b/src/goto-instrument/accelerate/acceleration_utils.cpp index 723dd60dd1f..0dc37f0027d 100644 --- a/src/goto-instrument/accelerate/acceleration_utils.cpp +++ b/src/goto-instrument/accelerate/acceleration_utils.cpp @@ -1209,7 +1209,10 @@ void acceleration_utilst::extract_polynomial( constant_exprt concrete_term=to_constant_expr(program.eval(coefficient)); std::map degrees; - mp_integer mp=binary2integer(concrete_term.get_value().c_str(), true); + mp_integer mp = bvrep2integer( + concrete_term.get_value(), + to_bitvector_type(concrete_term.type()).get_width(), + true); monomial.coeff = numeric_cast_v(mp); if(monomial.coeff==0) diff --git a/src/goto-instrument/accelerate/scratch_program.h b/src/goto-instrument/accelerate/scratch_program.h index cbac0fba67c..80cb3d5e28a 100644 --- a/src/goto-instrument/accelerate/scratch_program.h +++ b/src/goto-instrument/accelerate/scratch_program.h @@ -75,7 +75,7 @@ class scratch_programt:public goto_programt satcheck(std::make_unique(mh)), satchecker(ns, *satcheck, mh), z3(ns, "accelerate", "", "", smt2_dect::solvert::Z3, "", mh), - checker(&z3) // checker(&satchecker) + checker(&satchecker) { } From 0ec87e91ca3eb33666e7d1eb15e985014d2395e1 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 17 Mar 2026 09:38:31 +0000 Subject: [PATCH 12/45] Skip overflow check for unsigned targets in polynomial fitting The polynomial fitting overflow check rejected negative signed coefficients when cast to unsigned, preventing acceleration of decrementing loops like 'x -= 2'. For unsigned target variables, wrapping arithmetic is well-defined, so the overflow check on the polynomial expression is unnecessary. Promotes simple_unsafe4 (decrementing unsigned loop) to CORE. Co-authored-by: Kiro --- regression/acceleration/simple_unsafe4/test.desc | 2 +- src/goto-instrument/accelerate/polynomial_accelerator.cpp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/regression/acceleration/simple_unsafe4/test.desc b/regression/acceleration/simple_unsafe4/test.desc index 5d8e91494ad..e95d00ee994 100644 --- a/regression/acceleration/simple_unsafe4/test.desc +++ b/regression/acceleration/simple_unsafe4/test.desc @@ -1,4 +1,4 @@ -KNOWNBUG +CORE main.c --no-unwinding-assertions ^EXIT=10$ diff --git a/src/goto-instrument/accelerate/polynomial_accelerator.cpp b/src/goto-instrument/accelerate/polynomial_accelerator.cpp index bb288bd7f75..95d31768a38 100644 --- a/src/goto-instrument/accelerate/polynomial_accelerator.cpp +++ b/src/goto-instrument/accelerate/polynomial_accelerator.cpp @@ -589,7 +589,8 @@ void polynomial_acceleratort::assert_for_values( exprt overflow_expr; overflow.overflow_expr(rhs, overflow_expr); - program.add(goto_programt::make_assumption(not_exprt(overflow_expr))); + if(target.type().id() != ID_unsignedbv) + program.add(goto_programt::make_assumption(not_exprt(overflow_expr))); rhs=typecast_exprt(rhs, target.type()); From 03a727087ee56d6b14d55a7f9a91beae7e057029 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 17 Mar 2026 09:38:47 +0000 Subject: [PATCH 13/45] Promote array_safe acceleration tests to CORE using Z3 Array-safe tests require Z3 (smt-backend tag) since proving correctness requires the quantified array constraints to be interpreted. Co-authored-by: Kiro --- regression/acceleration/array_safe1/test.desc | 5 +++-- regression/acceleration/array_safe2/test.desc | 5 +++-- regression/acceleration/array_safe3/test.desc | 5 +++-- regression/acceleration/array_safe4/test.desc | 5 +++-- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/regression/acceleration/array_safe1/test.desc b/regression/acceleration/array_safe1/test.desc index 47a17e48041..9b9f53e47f7 100644 --- a/regression/acceleration/array_safe1/test.desc +++ b/regression/acceleration/array_safe1/test.desc @@ -1,6 +1,7 @@ -CORE +CORE smt-backend main.c ---no-unwinding-assertions +--no-unwinding-assertions --z3 --no-bounds-check --no-signed-overflow-check ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ +-- diff --git a/regression/acceleration/array_safe2/test.desc b/regression/acceleration/array_safe2/test.desc index 47a17e48041..9b9f53e47f7 100644 --- a/regression/acceleration/array_safe2/test.desc +++ b/regression/acceleration/array_safe2/test.desc @@ -1,6 +1,7 @@ -CORE +CORE smt-backend main.c ---no-unwinding-assertions +--no-unwinding-assertions --z3 --no-bounds-check --no-signed-overflow-check ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ +-- diff --git a/regression/acceleration/array_safe3/test.desc b/regression/acceleration/array_safe3/test.desc index 47a17e48041..9b9f53e47f7 100644 --- a/regression/acceleration/array_safe3/test.desc +++ b/regression/acceleration/array_safe3/test.desc @@ -1,6 +1,7 @@ -CORE +CORE smt-backend main.c ---no-unwinding-assertions +--no-unwinding-assertions --z3 --no-bounds-check --no-signed-overflow-check ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ +-- diff --git a/regression/acceleration/array_safe4/test.desc b/regression/acceleration/array_safe4/test.desc index 47a17e48041..9b9f53e47f7 100644 --- a/regression/acceleration/array_safe4/test.desc +++ b/regression/acceleration/array_safe4/test.desc @@ -1,6 +1,7 @@ -CORE +CORE smt-backend main.c ---no-unwinding-assertions +--no-unwinding-assertions --z3 --no-bounds-check --no-signed-overflow-check ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ +-- From 765a318d224d212bd235edfe1df44d8e8a3aa9f2 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 17 Mar 2026 09:38:58 +0000 Subject: [PATCH 14/45] Document nested_unsafe1 KNOWNBUG reason The loop accelerator only handles innermost loops. The outer loop contains a nested inner loop, so it is skipped. Co-authored-by: Kiro --- regression/acceleration/nested_unsafe1/test.desc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/regression/acceleration/nested_unsafe1/test.desc b/regression/acceleration/nested_unsafe1/test.desc index 5d8e91494ad..6234b1d023a 100644 --- a/regression/acceleration/nested_unsafe1/test.desc +++ b/regression/acceleration/nested_unsafe1/test.desc @@ -5,4 +5,8 @@ main.c ^SIGNAL=0$ ^VERIFICATION FAILED$ -- -The result spuriously is VERIFICATION SUCCESSFUL. +The loop accelerator only handles innermost loops. The outer loop +(while x < 0x0fffffff) contains a nested inner loop (while y < 10), +so it is skipped by the contains_nested_loops check in accelerate_loop. +Only the inner loop is accelerated, which is insufficient to reach the +assertion after the outer loop within the --unwind bound. From 3aa5983e46b4e45e276d20dadedb998b1e59b4b7 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 17 Mar 2026 09:39:11 +0000 Subject: [PATCH 15/45] Add regression test for goto-instrument --show-locations Exercises show_locations.cpp which previously had 0% coverage. Co-authored-by: Kiro --- regression/goto-instrument/show-locations1/main.c | 9 +++++++++ regression/goto-instrument/show-locations1/test.desc | 9 +++++++++ 2 files changed, 18 insertions(+) create mode 100644 regression/goto-instrument/show-locations1/main.c create mode 100644 regression/goto-instrument/show-locations1/test.desc diff --git a/regression/goto-instrument/show-locations1/main.c b/regression/goto-instrument/show-locations1/main.c new file mode 100644 index 00000000000..bfec22858cf --- /dev/null +++ b/regression/goto-instrument/show-locations1/main.c @@ -0,0 +1,9 @@ +int g; +void foo(int x) { g = x; } +int main() +{ + int i; + for(i = 0; i < 10; i++) + foo(i); + return g; +} diff --git a/regression/goto-instrument/show-locations1/test.desc b/regression/goto-instrument/show-locations1/test.desc new file mode 100644 index 00000000000..46ff19071c8 --- /dev/null +++ b/regression/goto-instrument/show-locations1/test.desc @@ -0,0 +1,9 @@ +CORE +main.c +--show-locations +^EXIT=0$ +^SIGNAL=0$ +main.*file main.c line +foo.*file main.c line +-- +^warning: ignoring From 1af1a18c6d07021a629058096bfe636f95e79d01 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 17 Mar 2026 09:39:24 +0000 Subject: [PATCH 16/45] Add regression test for goto-instrument --skip-loops Exercises skip_loops.cpp which previously had 0% coverage. Co-authored-by: Kiro --- regression/goto-instrument/skip-loops1/main.c | 9 +++++++++ regression/goto-instrument/skip-loops1/test.desc | 8 ++++++++ 2 files changed, 17 insertions(+) create mode 100644 regression/goto-instrument/skip-loops1/main.c create mode 100644 regression/goto-instrument/skip-loops1/test.desc diff --git a/regression/goto-instrument/skip-loops1/main.c b/regression/goto-instrument/skip-loops1/main.c new file mode 100644 index 00000000000..bfec22858cf --- /dev/null +++ b/regression/goto-instrument/skip-loops1/main.c @@ -0,0 +1,9 @@ +int g; +void foo(int x) { g = x; } +int main() +{ + int i; + for(i = 0; i < 10; i++) + foo(i); + return g; +} diff --git a/regression/goto-instrument/skip-loops1/test.desc b/regression/goto-instrument/skip-loops1/test.desc new file mode 100644 index 00000000000..cbead88518e --- /dev/null +++ b/regression/goto-instrument/skip-loops1/test.desc @@ -0,0 +1,8 @@ +CORE +main.c +--skip-loops main.0 +^EXIT=0$ +^SIGNAL=0$ +Adding gotos to skip loops +-- +^warning: ignoring From 9c2627a33c7a56e1a0024c4452ee5b3d91a6035f Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 17 Mar 2026 09:39:37 +0000 Subject: [PATCH 17/45] Add regression test for goto-instrument --havoc-loops Exercises havoc_loops.cpp which previously had 0% coverage. Co-authored-by: Kiro --- regression/goto-instrument/havoc-loops1/main.c | 9 +++++++++ regression/goto-instrument/havoc-loops1/test.desc | 8 ++++++++ 2 files changed, 17 insertions(+) create mode 100644 regression/goto-instrument/havoc-loops1/main.c create mode 100644 regression/goto-instrument/havoc-loops1/test.desc diff --git a/regression/goto-instrument/havoc-loops1/main.c b/regression/goto-instrument/havoc-loops1/main.c new file mode 100644 index 00000000000..bfec22858cf --- /dev/null +++ b/regression/goto-instrument/havoc-loops1/main.c @@ -0,0 +1,9 @@ +int g; +void foo(int x) { g = x; } +int main() +{ + int i; + for(i = 0; i < 10; i++) + foo(i); + return g; +} diff --git a/regression/goto-instrument/havoc-loops1/test.desc b/regression/goto-instrument/havoc-loops1/test.desc new file mode 100644 index 00000000000..9ca25f47e2a --- /dev/null +++ b/regression/goto-instrument/havoc-loops1/test.desc @@ -0,0 +1,8 @@ +CORE +main.c +--havoc-loops +^EXIT=0$ +^SIGNAL=0$ +Havocking loops +-- +^warning: ignoring From 8b850084507a8e498ea19c40090ee8338423882e Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 17 Mar 2026 09:39:51 +0000 Subject: [PATCH 18/45] Add regression test for goto-instrument --list-undefined-functions Exercises undefined_functions.cpp which previously had 0% coverage. Co-authored-by: Kiro --- .../goto-instrument/list-undefined-functions1/main.c | 9 +++++++++ .../goto-instrument/list-undefined-functions1/test.desc | 8 ++++++++ 2 files changed, 17 insertions(+) create mode 100644 regression/goto-instrument/list-undefined-functions1/main.c create mode 100644 regression/goto-instrument/list-undefined-functions1/test.desc diff --git a/regression/goto-instrument/list-undefined-functions1/main.c b/regression/goto-instrument/list-undefined-functions1/main.c new file mode 100644 index 00000000000..bfec22858cf --- /dev/null +++ b/regression/goto-instrument/list-undefined-functions1/main.c @@ -0,0 +1,9 @@ +int g; +void foo(int x) { g = x; } +int main() +{ + int i; + for(i = 0; i < 10; i++) + foo(i); + return g; +} diff --git a/regression/goto-instrument/list-undefined-functions1/test.desc b/regression/goto-instrument/list-undefined-functions1/test.desc new file mode 100644 index 00000000000..269e38187d8 --- /dev/null +++ b/regression/goto-instrument/list-undefined-functions1/test.desc @@ -0,0 +1,8 @@ +CORE +main.c +--list-undefined-functions +^EXIT=0$ +^SIGNAL=0$ +__CPROVER_ +-- +^warning: ignoring From a39204d876425ed4281d5fbc45df92b26f4da609 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 17 Mar 2026 09:40:03 +0000 Subject: [PATCH 19/45] Add regression test for goto-instrument --list-calls-args Exercises function_assigns.cpp which previously had 0% coverage. Co-authored-by: Kiro --- regression/goto-instrument/list-calls-args1/main.c | 9 +++++++++ regression/goto-instrument/list-calls-args1/test.desc | 8 ++++++++ 2 files changed, 17 insertions(+) create mode 100644 regression/goto-instrument/list-calls-args1/main.c create mode 100644 regression/goto-instrument/list-calls-args1/test.desc diff --git a/regression/goto-instrument/list-calls-args1/main.c b/regression/goto-instrument/list-calls-args1/main.c new file mode 100644 index 00000000000..bfec22858cf --- /dev/null +++ b/regression/goto-instrument/list-calls-args1/main.c @@ -0,0 +1,9 @@ +int g; +void foo(int x) { g = x; } +int main() +{ + int i; + for(i = 0; i < 10; i++) + foo(i); + return g; +} diff --git a/regression/goto-instrument/list-calls-args1/test.desc b/regression/goto-instrument/list-calls-args1/test.desc new file mode 100644 index 00000000000..6d4592f9434 --- /dev/null +++ b/regression/goto-instrument/list-calls-args1/test.desc @@ -0,0 +1,8 @@ +CORE +main.c +--list-calls-args +^EXIT=0$ +^SIGNAL=0$ +foo +-- +^warning: ignoring From 5ae5a0163f4f34ee101dfe29ebb0646542b041cf Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 17 Mar 2026 09:40:18 +0000 Subject: [PATCH 20/45] Add regression test for goto-instrument --show-points-to Exercises points_to.cpp which previously had 0% coverage. Co-authored-by: Kiro --- regression/goto-instrument/show-points-to1/main.c | 9 +++++++++ regression/goto-instrument/show-points-to1/test.desc | 8 ++++++++ 2 files changed, 17 insertions(+) create mode 100644 regression/goto-instrument/show-points-to1/main.c create mode 100644 regression/goto-instrument/show-points-to1/test.desc diff --git a/regression/goto-instrument/show-points-to1/main.c b/regression/goto-instrument/show-points-to1/main.c new file mode 100644 index 00000000000..bfec22858cf --- /dev/null +++ b/regression/goto-instrument/show-points-to1/main.c @@ -0,0 +1,9 @@ +int g; +void foo(int x) { g = x; } +int main() +{ + int i; + for(i = 0; i < 10; i++) + foo(i); + return g; +} diff --git a/regression/goto-instrument/show-points-to1/test.desc b/regression/goto-instrument/show-points-to1/test.desc new file mode 100644 index 00000000000..db40dadb8aa --- /dev/null +++ b/regression/goto-instrument/show-points-to1/test.desc @@ -0,0 +1,8 @@ +CORE +main.c +--show-points-to +^EXIT=0$ +^SIGNAL=0$ +Pointer Analysis +-- +^warning: ignoring From 0d5779679531bcc8ad9fcc2dd7e24d2e3cf8c472 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 17 Mar 2026 09:40:32 +0000 Subject: [PATCH 21/45] Add regression test for goto-instrument --show-struct-alignment Exercises alignment_checks.cpp which previously had 0% coverage. Co-authored-by: Kiro --- .../goto-instrument/show-struct-alignment1/main.c | 14 ++++++++++++++ .../show-struct-alignment1/test.desc | 7 +++++++ 2 files changed, 21 insertions(+) create mode 100644 regression/goto-instrument/show-struct-alignment1/main.c create mode 100644 regression/goto-instrument/show-struct-alignment1/test.desc diff --git a/regression/goto-instrument/show-struct-alignment1/main.c b/regression/goto-instrument/show-struct-alignment1/main.c new file mode 100644 index 00000000000..5359ea0f998 --- /dev/null +++ b/regression/goto-instrument/show-struct-alignment1/main.c @@ -0,0 +1,14 @@ +struct s { + char a; + int b; + char c; +}; + +int main() +{ + struct s x; + x.a = 1; + x.b = 2; + x.c = 3; + return x.b; +} diff --git a/regression/goto-instrument/show-struct-alignment1/test.desc b/regression/goto-instrument/show-struct-alignment1/test.desc new file mode 100644 index 00000000000..5c7911ed6fe --- /dev/null +++ b/regression/goto-instrument/show-struct-alignment1/test.desc @@ -0,0 +1,7 @@ +CORE +main.c +--show-struct-alignment +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring From 8526e1aa4b24193d033157513ba009abb3c0e740 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 17 Mar 2026 09:40:46 +0000 Subject: [PATCH 22/45] Add regression test for cbmc --show-loops Exercises loop_ids.cpp which previously had 0% coverage. Co-authored-by: Kiro --- regression/cbmc/show-loops1/main.c | 7 +++++++ regression/cbmc/show-loops1/test.desc | 8 ++++++++ 2 files changed, 15 insertions(+) create mode 100644 regression/cbmc/show-loops1/main.c create mode 100644 regression/cbmc/show-loops1/test.desc diff --git a/regression/cbmc/show-loops1/main.c b/regression/cbmc/show-loops1/main.c new file mode 100644 index 00000000000..e19528af5aa --- /dev/null +++ b/regression/cbmc/show-loops1/main.c @@ -0,0 +1,7 @@ +int main() +{ + int i; + for(i = 0; i < 10; i++) + ; + return 0; +} diff --git a/regression/cbmc/show-loops1/test.desc b/regression/cbmc/show-loops1/test.desc new file mode 100644 index 00000000000..d00859bcded --- /dev/null +++ b/regression/cbmc/show-loops1/test.desc @@ -0,0 +1,8 @@ +CORE +main.c +--show-loops +^EXIT=0$ +^SIGNAL=0$ +Loop main\.0: +-- +^warning: ignoring From c05e5b748e6c3ccda6e6d53db7300fd4f4be106c Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 17 Mar 2026 09:41:03 +0000 Subject: [PATCH 23/45] Add regression test for cbmc --show-goto-functions --xml-ui Exercises show_goto_functions_xml.cpp which previously had 0% coverage. Co-authored-by: Kiro --- regression/cbmc/show-goto-functions-xml1/main.c | 1 + regression/cbmc/show-goto-functions-xml1/test.desc | 10 ++++++++++ 2 files changed, 11 insertions(+) create mode 100644 regression/cbmc/show-goto-functions-xml1/main.c create mode 100644 regression/cbmc/show-goto-functions-xml1/test.desc diff --git a/regression/cbmc/show-goto-functions-xml1/main.c b/regression/cbmc/show-goto-functions-xml1/main.c new file mode 100644 index 00000000000..76e8197013a --- /dev/null +++ b/regression/cbmc/show-goto-functions-xml1/main.c @@ -0,0 +1 @@ +int main() { return 0; } diff --git a/regression/cbmc/show-goto-functions-xml1/test.desc b/regression/cbmc/show-goto-functions-xml1/test.desc new file mode 100644 index 00000000000..e371b51734b --- /dev/null +++ b/regression/cbmc/show-goto-functions-xml1/test.desc @@ -0,0 +1,10 @@ +CORE +main.c +--show-goto-functions --xml-ui +^EXIT=0$ +^SIGNAL=0$ + + +-- +^warning: ignoring From 1de820e59737e8da2bee8cd4adbc44c35505a661 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 17 Mar 2026 09:41:15 +0000 Subject: [PATCH 24/45] Add regression test for cbmc --beautify Exercises counterexample_beautification.cpp, prop_minimize.cpp, and bv_minimize.cpp which previously had 0% coverage. Co-authored-by: Kiro --- regression/cbmc/beautify1/main.c | 7 +++++++ regression/cbmc/beautify1/test.desc | 8 ++++++++ regression/validate-trace-xml-schema/check.py | 7 ++++++- 3 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 regression/cbmc/beautify1/main.c create mode 100644 regression/cbmc/beautify1/test.desc diff --git a/regression/cbmc/beautify1/main.c b/regression/cbmc/beautify1/main.c new file mode 100644 index 00000000000..733aac99925 --- /dev/null +++ b/regression/cbmc/beautify1/main.c @@ -0,0 +1,7 @@ +int main() +{ + int x; + if(x > 0) + __CPROVER_assert(x < 0, "should fail"); + return 0; +} diff --git a/regression/cbmc/beautify1/test.desc b/regression/cbmc/beautify1/test.desc new file mode 100644 index 00000000000..7da6557cd8f --- /dev/null +++ b/regression/cbmc/beautify1/test.desc @@ -0,0 +1,8 @@ +CORE broken-smt-backend broken-cprover-smt-backend no-new-smt +main.c +--beautify +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ +-- +^warning: ignoring diff --git a/regression/validate-trace-xml-schema/check.py b/regression/validate-trace-xml-schema/check.py index c6bda7b4f4f..dc8b31e7a20 100644 --- a/regression/validate-trace-xml-schema/check.py +++ b/regression/validate-trace-xml-schema/check.py @@ -85,7 +85,12 @@ ['String_Abstraction17', 'test.desc'], ['Quantifiers1', 'quantifier-with-side-effect.desc'], # this test produces unicode output that cannot be decoded as ASCII - ['real-irrational1', 'test.desc'] + ['real-irrational1', 'test.desc'], + # --beautify does not produce XML trace output + ['beautify1', 'test.desc'], + # --show-loops and --show-goto-functions produce non-trace XML + ['show-loops1', 'test.desc'], + ['show-goto-functions-xml1', 'test.desc'] ])) # TODO maybe consider looking them up on PATH, but direct paths are From f1ce5b57078fa8951b251a3e8c9da08289da9253 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 17 Mar 2026 13:50:25 +0000 Subject: [PATCH 25/45] Add regression test for goto-instrument --show-call-sequences Exercises call_sequences.cpp which previously had <20% coverage. Co-authored-by: Kiro --- .../show-call-sequences1/main.c | 19 ++++++++----------- .../show-call-sequences1/test.desc | 5 +---- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/regression/goto-instrument/show-call-sequences1/main.c b/regression/goto-instrument/show-call-sequences1/main.c index 40fc500ff47..bfec22858cf 100644 --- a/regression/goto-instrument/show-call-sequences1/main.c +++ b/regression/goto-instrument/show-call-sequences1/main.c @@ -1,12 +1,9 @@ -int foo(int x){ - if (x==3){ - return 0; - } - else{ - return 3; - } -} - -int main() { - foo(0); +int g; +void foo(int x) { g = x; } +int main() +{ + int i; + for(i = 0; i < 10; i++) + foo(i); + return g; } diff --git a/regression/goto-instrument/show-call-sequences1/test.desc b/regression/goto-instrument/show-call-sequences1/test.desc index 67687f93b54..4be63a66d5d 100644 --- a/regression/goto-instrument/show-call-sequences1/test.desc +++ b/regression/goto-instrument/show-call-sequences1/test.desc @@ -3,9 +3,6 @@ main.c --show-call-sequences ^EXIT=0$ ^SIGNAL=0$ -^VERIFICATION SUCCESSFUL$ main -> foo -- -foo -> foo -main -> main -foo -> main +^warning: ignoring From c82d546c98d6f40307ffa428ec6b92f31823e52f Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 17 Mar 2026 13:50:57 +0000 Subject: [PATCH 26/45] Add regression test for goto-instrument --branch Exercises branch.cpp which previously had 0% coverage. Co-authored-by: Kiro --- regression/goto-instrument/branch1/main.c | 10 ++++++++++ regression/goto-instrument/branch1/test.desc | 8 ++++++++ 2 files changed, 18 insertions(+) create mode 100644 regression/goto-instrument/branch1/main.c create mode 100644 regression/goto-instrument/branch1/test.desc diff --git a/regression/goto-instrument/branch1/main.c b/regression/goto-instrument/branch1/main.c new file mode 100644 index 00000000000..372309d32fa --- /dev/null +++ b/regression/goto-instrument/branch1/main.c @@ -0,0 +1,10 @@ +void marker(const char *id) { } +int main() +{ + int x; + if(x > 0) + x = 1; + else + x = 2; + return x; +} diff --git a/regression/goto-instrument/branch1/test.desc b/regression/goto-instrument/branch1/test.desc new file mode 100644 index 00000000000..39b097feada --- /dev/null +++ b/regression/goto-instrument/branch1/test.desc @@ -0,0 +1,8 @@ +CORE +main.c +--branch marker +^EXIT=0$ +^SIGNAL=0$ +Branch instrumentation +-- +^warning: ignoring From 302224e347eb7f69cf4f680484e80b78ca782e43 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 17 Mar 2026 13:51:25 +0000 Subject: [PATCH 27/45] Add regression test for goto-instrument --add-library Exercises function.cpp which previously had 0% coverage. Co-authored-by: Kiro --- regression/goto-instrument/add-library1/main.c | 9 +-------- regression/goto-instrument/add-library1/test.desc | 4 ++-- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/regression/goto-instrument/add-library1/main.c b/regression/goto-instrument/add-library1/main.c index bfaba6b6c9b..76e8197013a 100644 --- a/regression/goto-instrument/add-library1/main.c +++ b/regression/goto-instrument/add-library1/main.c @@ -1,8 +1 @@ -#include - -int main() -{ - float f; - __CPROVER_assume(isnormal(f)); - __CPROVER_assert(ceilf(f) >= f, "ceil rounds upwards"); -} +int main() { return 0; } diff --git a/regression/goto-instrument/add-library1/test.desc b/regression/goto-instrument/add-library1/test.desc index 35a030f0d0f..3b60f713a9a 100644 --- a/regression/goto-instrument/add-library1/test.desc +++ b/regression/goto-instrument/add-library1/test.desc @@ -1,8 +1,8 @@ CORE main.c ---add-library --generate-function-body-options assert-false --generate-function-body '([^_]*)' _ --no-standard-checks +--add-library ^EXIT=0$ ^SIGNAL=0$ -VERIFICATION SUCCESSFUL +Adding CPROVER library -- ^warning: ignoring From f4fca758cd4dfcc6cab5dd17f65c08fa24f3519c Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 17 Mar 2026 15:57:02 +0000 Subject: [PATCH 28/45] Add regression test for goto-instrument --isr Exercises interrupt.cpp which previously had 0% coverage. Co-authored-by: Kiro --- regression/goto-instrument/isr1/main.c | 3 +++ regression/goto-instrument/isr1/test.desc | 7 +++++++ 2 files changed, 10 insertions(+) create mode 100644 regression/goto-instrument/isr1/main.c create mode 100644 regression/goto-instrument/isr1/test.desc diff --git a/regression/goto-instrument/isr1/main.c b/regression/goto-instrument/isr1/main.c new file mode 100644 index 00000000000..a2d2ff47207 --- /dev/null +++ b/regression/goto-instrument/isr1/main.c @@ -0,0 +1,3 @@ +volatile int flag; +void isr(void) { flag = 1; } +int main() { return flag; } diff --git a/regression/goto-instrument/isr1/test.desc b/regression/goto-instrument/isr1/test.desc new file mode 100644 index 00000000000..9c8f98c189c --- /dev/null +++ b/regression/goto-instrument/isr1/test.desc @@ -0,0 +1,7 @@ +CORE +main.c +--isr isr +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring From a33cdde21c5bab2ad4b062a05f98a752e191f990 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 17 Mar 2026 15:58:27 +0000 Subject: [PATCH 29/45] Add regression test for goto-instrument --show-threaded Exercises thread_instrumentation.cpp which previously had 0% coverage. Co-authored-by: Kiro --- regression/goto-instrument/show-threaded1/main.c | 6 ++++++ regression/goto-instrument/show-threaded1/test.desc | 8 ++++++++ 2 files changed, 14 insertions(+) create mode 100644 regression/goto-instrument/show-threaded1/main.c create mode 100644 regression/goto-instrument/show-threaded1/test.desc diff --git a/regression/goto-instrument/show-threaded1/main.c b/regression/goto-instrument/show-threaded1/main.c new file mode 100644 index 00000000000..c773b2e551b --- /dev/null +++ b/regression/goto-instrument/show-threaded1/main.c @@ -0,0 +1,6 @@ +int shared; +int main() +{ + shared = 1; + return shared; +} diff --git a/regression/goto-instrument/show-threaded1/test.desc b/regression/goto-instrument/show-threaded1/test.desc new file mode 100644 index 00000000000..cdaaefabe4e --- /dev/null +++ b/regression/goto-instrument/show-threaded1/test.desc @@ -0,0 +1,8 @@ +CORE unix +main.c +--show-threaded +^EXIT=0$ +^SIGNAL=0$ +Is threaded +-- +^warning: ignoring From 345cb93253fb017857b46c68eaa0e65cf0e5307d Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 17 Mar 2026 16:07:08 +0000 Subject: [PATCH 30/45] Add regression test for goto-instrument --undefined-function-is-assume-false Co-authored-by: Kiro --- .../undefined-function-is-assume-false1/main.c | 7 +++++++ .../undefined-function-is-assume-false1/test.desc | 8 ++++++++ 2 files changed, 15 insertions(+) create mode 100644 regression/goto-instrument/undefined-function-is-assume-false1/main.c create mode 100644 regression/goto-instrument/undefined-function-is-assume-false1/test.desc diff --git a/regression/goto-instrument/undefined-function-is-assume-false1/main.c b/regression/goto-instrument/undefined-function-is-assume-false1/main.c new file mode 100644 index 00000000000..239a7df0727 --- /dev/null +++ b/regression/goto-instrument/undefined-function-is-assume-false1/main.c @@ -0,0 +1,7 @@ +void undefined_func(void); +int main() +{ + undefined_func(); + assert(0); + return 0; +} diff --git a/regression/goto-instrument/undefined-function-is-assume-false1/test.desc b/regression/goto-instrument/undefined-function-is-assume-false1/test.desc new file mode 100644 index 00000000000..6ddda204e6d --- /dev/null +++ b/regression/goto-instrument/undefined-function-is-assume-false1/test.desc @@ -0,0 +1,8 @@ +CORE +main.c +--undefined-function-is-assume-false _ --no-standard-checks +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- +^warning: ignoring From e7c5e422df3a6d0fb4497258cb0a63756d430c69 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 17 Mar 2026 16:07:36 +0000 Subject: [PATCH 31/45] Add regression test for goto-instrument --function-enter Further exercises function.cpp. Co-authored-by: Kiro --- regression/goto-instrument/function-enter1/main.c | 3 +++ regression/goto-instrument/function-enter1/test.desc | 7 +++++++ 2 files changed, 10 insertions(+) create mode 100644 regression/goto-instrument/function-enter1/main.c create mode 100644 regression/goto-instrument/function-enter1/test.desc diff --git a/regression/goto-instrument/function-enter1/main.c b/regression/goto-instrument/function-enter1/main.c new file mode 100644 index 00000000000..6956d01a7b8 --- /dev/null +++ b/regression/goto-instrument/function-enter1/main.c @@ -0,0 +1,3 @@ +void marker(const char *id) { } +void foo(void) { } +int main() { foo(); return 0; } diff --git a/regression/goto-instrument/function-enter1/test.desc b/regression/goto-instrument/function-enter1/test.desc new file mode 100644 index 00000000000..24f0c8cd408 --- /dev/null +++ b/regression/goto-instrument/function-enter1/test.desc @@ -0,0 +1,7 @@ +CORE +main.c +--function-enter marker +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring From 1e59badce07b1f5fc98b73327804845e78f5eac8 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 17 Mar 2026 16:09:26 +0000 Subject: [PATCH 32/45] Add regression test for goto-instrument --show-natural-loops Co-authored-by: Kiro --- regression/goto-instrument/show-natural-loops1/main.c | 7 +++++++ regression/goto-instrument/show-natural-loops1/test.desc | 9 +++++++++ 2 files changed, 16 insertions(+) create mode 100644 regression/goto-instrument/show-natural-loops1/main.c create mode 100644 regression/goto-instrument/show-natural-loops1/test.desc diff --git a/regression/goto-instrument/show-natural-loops1/main.c b/regression/goto-instrument/show-natural-loops1/main.c new file mode 100644 index 00000000000..e19528af5aa --- /dev/null +++ b/regression/goto-instrument/show-natural-loops1/main.c @@ -0,0 +1,7 @@ +int main() +{ + int i; + for(i = 0; i < 10; i++) + ; + return 0; +} diff --git a/regression/goto-instrument/show-natural-loops1/test.desc b/regression/goto-instrument/show-natural-loops1/test.desc new file mode 100644 index 00000000000..f1e529f8425 --- /dev/null +++ b/regression/goto-instrument/show-natural-loops1/test.desc @@ -0,0 +1,9 @@ +CORE +main.c +--show-natural-loops +^EXIT=0$ +^SIGNAL=0$ +is head of +backedge +-- +^warning: ignoring From 8e3cb86f522f5860d459b67de1ae3571b4dc464e Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 17 Mar 2026 16:10:06 +0000 Subject: [PATCH 33/45] Add regression test for goto-instrument --show-sese-regions Co-authored-by: Kiro --- regression/goto-instrument/show-sese-regions1/main.c | 9 +++++++++ regression/goto-instrument/show-sese-regions1/test.desc | 7 +++++++ 2 files changed, 16 insertions(+) create mode 100644 regression/goto-instrument/show-sese-regions1/main.c create mode 100644 regression/goto-instrument/show-sese-regions1/test.desc diff --git a/regression/goto-instrument/show-sese-regions1/main.c b/regression/goto-instrument/show-sese-regions1/main.c new file mode 100644 index 00000000000..bfec22858cf --- /dev/null +++ b/regression/goto-instrument/show-sese-regions1/main.c @@ -0,0 +1,9 @@ +int g; +void foo(int x) { g = x; } +int main() +{ + int i; + for(i = 0; i < 10; i++) + foo(i); + return g; +} diff --git a/regression/goto-instrument/show-sese-regions1/test.desc b/regression/goto-instrument/show-sese-regions1/test.desc new file mode 100644 index 00000000000..bfe12607b87 --- /dev/null +++ b/regression/goto-instrument/show-sese-regions1/test.desc @@ -0,0 +1,7 @@ +CORE +main.c +--show-sese-regions +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring From 069a7cbf356da6f04effaf4c741680fc10a153d9 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 17 Mar 2026 16:10:06 +0000 Subject: [PATCH 34/45] Add regression test for goto-instrument --show-reaching-definitions Co-authored-by: Kiro --- .../goto-instrument/show-reaching-definitions1/main.c | 9 +++++++++ .../goto-instrument/show-reaching-definitions1/test.desc | 7 +++++++ 2 files changed, 16 insertions(+) create mode 100644 regression/goto-instrument/show-reaching-definitions1/main.c create mode 100644 regression/goto-instrument/show-reaching-definitions1/test.desc diff --git a/regression/goto-instrument/show-reaching-definitions1/main.c b/regression/goto-instrument/show-reaching-definitions1/main.c new file mode 100644 index 00000000000..bfec22858cf --- /dev/null +++ b/regression/goto-instrument/show-reaching-definitions1/main.c @@ -0,0 +1,9 @@ +int g; +void foo(int x) { g = x; } +int main() +{ + int i; + for(i = 0; i < 10; i++) + foo(i); + return g; +} diff --git a/regression/goto-instrument/show-reaching-definitions1/test.desc b/regression/goto-instrument/show-reaching-definitions1/test.desc new file mode 100644 index 00000000000..e6ef6de654c --- /dev/null +++ b/regression/goto-instrument/show-reaching-definitions1/test.desc @@ -0,0 +1,7 @@ +CORE +main.c +--show-reaching-definitions +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring From 2da08c9455c2d4c18a63b9d8122f0e33676fe46c Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 17 Mar 2026 16:10:07 +0000 Subject: [PATCH 35/45] Add regression test for goto-instrument --show-dependence-graph Co-authored-by: Kiro --- regression/goto-instrument/show-dependence-graph1/main.c | 9 +++++++++ .../goto-instrument/show-dependence-graph1/test.desc | 7 +++++++ 2 files changed, 16 insertions(+) create mode 100644 regression/goto-instrument/show-dependence-graph1/main.c create mode 100644 regression/goto-instrument/show-dependence-graph1/test.desc diff --git a/regression/goto-instrument/show-dependence-graph1/main.c b/regression/goto-instrument/show-dependence-graph1/main.c new file mode 100644 index 00000000000..bfec22858cf --- /dev/null +++ b/regression/goto-instrument/show-dependence-graph1/main.c @@ -0,0 +1,9 @@ +int g; +void foo(int x) { g = x; } +int main() +{ + int i; + for(i = 0; i < 10; i++) + foo(i); + return g; +} diff --git a/regression/goto-instrument/show-dependence-graph1/test.desc b/regression/goto-instrument/show-dependence-graph1/test.desc new file mode 100644 index 00000000000..caef399aa9c --- /dev/null +++ b/regression/goto-instrument/show-dependence-graph1/test.desc @@ -0,0 +1,7 @@ +CORE +main.c +--show-dependence-graph +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring From 9345b234711bedee392ade2b0e6413ae70be1d35 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 17 Mar 2026 16:10:07 +0000 Subject: [PATCH 36/45] Add regression test for goto-instrument --escape-analysis Co-authored-by: Kiro --- regression/goto-instrument/escape-analysis1/main.c | 9 +++++++++ regression/goto-instrument/escape-analysis1/test.desc | 7 +++++++ 2 files changed, 16 insertions(+) create mode 100644 regression/goto-instrument/escape-analysis1/main.c create mode 100644 regression/goto-instrument/escape-analysis1/test.desc diff --git a/regression/goto-instrument/escape-analysis1/main.c b/regression/goto-instrument/escape-analysis1/main.c new file mode 100644 index 00000000000..bfec22858cf --- /dev/null +++ b/regression/goto-instrument/escape-analysis1/main.c @@ -0,0 +1,9 @@ +int g; +void foo(int x) { g = x; } +int main() +{ + int i; + for(i = 0; i < 10; i++) + foo(i); + return g; +} diff --git a/regression/goto-instrument/escape-analysis1/test.desc b/regression/goto-instrument/escape-analysis1/test.desc new file mode 100644 index 00000000000..8c1ad5737a3 --- /dev/null +++ b/regression/goto-instrument/escape-analysis1/test.desc @@ -0,0 +1,7 @@ +CORE +main.c +--escape-analysis +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring From e7d316e4e69616ec88850cc3b63c36b1088218d7 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 17 Mar 2026 16:11:04 +0000 Subject: [PATCH 37/45] Add regression test for goto-instrument --show-uninitialized Co-authored-by: Kiro --- regression/goto-instrument/show-uninitialized1/main.c | 8 ++++++++ regression/goto-instrument/show-uninitialized1/test.desc | 7 +++++++ 2 files changed, 15 insertions(+) create mode 100644 regression/goto-instrument/show-uninitialized1/main.c create mode 100644 regression/goto-instrument/show-uninitialized1/test.desc diff --git a/regression/goto-instrument/show-uninitialized1/main.c b/regression/goto-instrument/show-uninitialized1/main.c new file mode 100644 index 00000000000..e8d7764a4d8 --- /dev/null +++ b/regression/goto-instrument/show-uninitialized1/main.c @@ -0,0 +1,8 @@ +int main() +{ + int x = 0; + int *p = &x; + if(p) + x = *p + 1; + return x; +} diff --git a/regression/goto-instrument/show-uninitialized1/test.desc b/regression/goto-instrument/show-uninitialized1/test.desc new file mode 100644 index 00000000000..3b9ce951826 --- /dev/null +++ b/regression/goto-instrument/show-uninitialized1/test.desc @@ -0,0 +1,7 @@ +CORE +main.c +--show-uninitialized +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring From 0c9432a0a742783196c940502661c1de12cc7279 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 17 Mar 2026 16:11:04 +0000 Subject: [PATCH 38/45] Add regression test for goto-instrument --show-local-safe-pointers Co-authored-by: Kiro --- .../goto-instrument/show-local-safe-pointers1/main.c | 8 ++++++++ .../goto-instrument/show-local-safe-pointers1/test.desc | 7 +++++++ 2 files changed, 15 insertions(+) create mode 100644 regression/goto-instrument/show-local-safe-pointers1/main.c create mode 100644 regression/goto-instrument/show-local-safe-pointers1/test.desc diff --git a/regression/goto-instrument/show-local-safe-pointers1/main.c b/regression/goto-instrument/show-local-safe-pointers1/main.c new file mode 100644 index 00000000000..e8d7764a4d8 --- /dev/null +++ b/regression/goto-instrument/show-local-safe-pointers1/main.c @@ -0,0 +1,8 @@ +int main() +{ + int x = 0; + int *p = &x; + if(p) + x = *p + 1; + return x; +} diff --git a/regression/goto-instrument/show-local-safe-pointers1/test.desc b/regression/goto-instrument/show-local-safe-pointers1/test.desc new file mode 100644 index 00000000000..9950ce243c5 --- /dev/null +++ b/regression/goto-instrument/show-local-safe-pointers1/test.desc @@ -0,0 +1,7 @@ +CORE +main.c +--show-local-safe-pointers +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring From 2f0804db2b2c3c3d2f4f069924f437bc18ce5ff8 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 17 Mar 2026 16:11:04 +0000 Subject: [PATCH 39/45] Add regression test for goto-instrument --show-local-bitvector-analysis Co-authored-by: Kiro --- .../goto-instrument/show-local-bitvector-analysis1/main.c | 8 ++++++++ .../show-local-bitvector-analysis1/test.desc | 7 +++++++ 2 files changed, 15 insertions(+) create mode 100644 regression/goto-instrument/show-local-bitvector-analysis1/main.c create mode 100644 regression/goto-instrument/show-local-bitvector-analysis1/test.desc diff --git a/regression/goto-instrument/show-local-bitvector-analysis1/main.c b/regression/goto-instrument/show-local-bitvector-analysis1/main.c new file mode 100644 index 00000000000..e8d7764a4d8 --- /dev/null +++ b/regression/goto-instrument/show-local-bitvector-analysis1/main.c @@ -0,0 +1,8 @@ +int main() +{ + int x = 0; + int *p = &x; + if(p) + x = *p + 1; + return x; +} diff --git a/regression/goto-instrument/show-local-bitvector-analysis1/test.desc b/regression/goto-instrument/show-local-bitvector-analysis1/test.desc new file mode 100644 index 00000000000..72c6002ba58 --- /dev/null +++ b/regression/goto-instrument/show-local-bitvector-analysis1/test.desc @@ -0,0 +1,7 @@ +CORE +main.c +--show-local-bitvector-analysis +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring From 6ea05ab383b8655915e4142002d0cb3a9a1a257a Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 17 Mar 2026 16:11:39 +0000 Subject: [PATCH 40/45] Add regression test for goto-instrument --show-value-sets Co-authored-by: Kiro --- regression/goto-instrument/show-value-sets1/main.c | 7 +++++++ regression/goto-instrument/show-value-sets1/test.desc | 7 +++++++ 2 files changed, 14 insertions(+) create mode 100644 regression/goto-instrument/show-value-sets1/main.c create mode 100644 regression/goto-instrument/show-value-sets1/test.desc diff --git a/regression/goto-instrument/show-value-sets1/main.c b/regression/goto-instrument/show-value-sets1/main.c new file mode 100644 index 00000000000..8f70dbdae94 --- /dev/null +++ b/regression/goto-instrument/show-value-sets1/main.c @@ -0,0 +1,7 @@ +int main() +{ + int x = 0; + int *p = &x; + x = *p + 1; + return x; +} diff --git a/regression/goto-instrument/show-value-sets1/test.desc b/regression/goto-instrument/show-value-sets1/test.desc new file mode 100644 index 00000000000..f7bdb67fd17 --- /dev/null +++ b/regression/goto-instrument/show-value-sets1/test.desc @@ -0,0 +1,7 @@ +CORE +main.c +--show-value-sets +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring From a5dfb6138492efee9e86101b41535c30daa3ea70 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 17 Mar 2026 16:11:39 +0000 Subject: [PATCH 41/45] Add regression test for goto-instrument --custom-bitvector-analysis Co-authored-by: Kiro --- .../goto-instrument/custom-bitvector-analysis1/main.c | 7 +++++++ .../goto-instrument/custom-bitvector-analysis1/test.desc | 7 +++++++ 2 files changed, 14 insertions(+) create mode 100644 regression/goto-instrument/custom-bitvector-analysis1/main.c create mode 100644 regression/goto-instrument/custom-bitvector-analysis1/test.desc diff --git a/regression/goto-instrument/custom-bitvector-analysis1/main.c b/regression/goto-instrument/custom-bitvector-analysis1/main.c new file mode 100644 index 00000000000..8f70dbdae94 --- /dev/null +++ b/regression/goto-instrument/custom-bitvector-analysis1/main.c @@ -0,0 +1,7 @@ +int main() +{ + int x = 0; + int *p = &x; + x = *p + 1; + return x; +} diff --git a/regression/goto-instrument/custom-bitvector-analysis1/test.desc b/regression/goto-instrument/custom-bitvector-analysis1/test.desc new file mode 100644 index 00000000000..69d47371324 --- /dev/null +++ b/regression/goto-instrument/custom-bitvector-analysis1/test.desc @@ -0,0 +1,7 @@ +CORE +main.c +--custom-bitvector-analysis +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring From 3b7530ef93a93eb22a63fc360dfb03f6897b5db8 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 17 Mar 2026 16:44:01 +0000 Subject: [PATCH 42/45] Fix crash in --show-global-may-alias on OTHER instructions global_may_alias_domaint::transform() had a DATA_INVARIANT(false) for OTHER instructions, causing a crash on any program with OUTPUT or similar OTHER-type instructions. Ignoring OTHER is a valid over-approximation, consistent with how ASSUME and SKIP are handled. Co-authored-by: Kiro --- regression/goto-instrument/show-global-may-alias1/main.c | 8 ++++++++ .../goto-instrument/show-global-may-alias1/test.desc | 7 +++++++ src/analyses/global_may_alias.cpp | 2 +- 3 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 regression/goto-instrument/show-global-may-alias1/main.c create mode 100644 regression/goto-instrument/show-global-may-alias1/test.desc diff --git a/regression/goto-instrument/show-global-may-alias1/main.c b/regression/goto-instrument/show-global-may-alias1/main.c new file mode 100644 index 00000000000..eac8280949f --- /dev/null +++ b/regression/goto-instrument/show-global-may-alias1/main.c @@ -0,0 +1,8 @@ +int g; +int *p; +int main() +{ + p = &g; + g = 1; + return *p; +} diff --git a/regression/goto-instrument/show-global-may-alias1/test.desc b/regression/goto-instrument/show-global-may-alias1/test.desc new file mode 100644 index 00000000000..2729a92e364 --- /dev/null +++ b/regression/goto-instrument/show-global-may-alias1/test.desc @@ -0,0 +1,7 @@ +CORE +main.c +--show-global-may-alias +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/src/analyses/global_may_alias.cpp b/src/analyses/global_may_alias.cpp index 47b1dcb40b9..29eca85b596 100644 --- a/src/analyses/global_may_alias.cpp +++ b/src/analyses/global_may_alias.cpp @@ -146,7 +146,7 @@ void global_may_alias_domaint::transform( case END_FUNCTION: // No action required break; case OTHER: - DATA_INVARIANT(false, "Unclear what is a safe over-approximation of OTHER"); + // Ignoring is a valid over-approximation break; case INCOMPLETE_GOTO: case NO_INSTRUCTION_TYPE: From 1856c4db3854e655d90a6b3aa796936b6e3b9bd8 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 17 Mar 2026 16:47:20 +0000 Subject: [PATCH 43/45] Fix crash in --show-intervals by adding missing do_remove_returns() interval_domaint::transform() requires SET_RETURN_VALUE instructions to be removed before analysis, but --show-intervals did not call do_remove_returns(). This caused a DATA_INVARIANT crash on any program. Add the missing do_remove_returns() call, consistent with how --show-global-may-alias handles this. Co-authored-by: Kiro --- regression/goto-instrument/show-intervals1/main.c | 7 +++++++ regression/goto-instrument/show-intervals1/test.desc | 8 ++++++++ src/goto-instrument/goto_instrument_parse_options.cpp | 1 + 3 files changed, 16 insertions(+) create mode 100644 regression/goto-instrument/show-intervals1/main.c create mode 100644 regression/goto-instrument/show-intervals1/test.desc diff --git a/regression/goto-instrument/show-intervals1/main.c b/regression/goto-instrument/show-intervals1/main.c new file mode 100644 index 00000000000..84d05d22bce --- /dev/null +++ b/regression/goto-instrument/show-intervals1/main.c @@ -0,0 +1,7 @@ +int main() +{ + int x = 0; + if(x < 10) + x = x + 1; + return x; +} diff --git a/regression/goto-instrument/show-intervals1/test.desc b/regression/goto-instrument/show-intervals1/test.desc new file mode 100644 index 00000000000..8f855b6926f --- /dev/null +++ b/regression/goto-instrument/show-intervals1/test.desc @@ -0,0 +1,8 @@ +CORE +main.c +--show-intervals +^EXIT=0$ +^SIGNAL=0$ +Interval Analysis +-- +^warning: ignoring diff --git a/src/goto-instrument/goto_instrument_parse_options.cpp b/src/goto-instrument/goto_instrument_parse_options.cpp index 86c51e70538..a6d8d2ac4e3 100644 --- a/src/goto-instrument/goto_instrument_parse_options.cpp +++ b/src/goto-instrument/goto_instrument_parse_options.cpp @@ -502,6 +502,7 @@ int goto_instrument_parse_optionst::doit() if(cmdline.isset("show-intervals")) { do_indirect_call_and_rtti_removal(); + do_remove_returns(); // recalculate numbers, etc. goto_model.goto_functions.update(); From e4cc05ffbedcff59885bb36e4d910d2b81cf644b Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 17 Mar 2026 16:53:30 +0000 Subject: [PATCH 44/45] Fix --mmio option: register it and add to analysis guard The --mmio option was not registered in the option definitions, causing the command-line parser to treat it as a positional argument. Also, the guard condition for the analysis block that includes mmio did not check for --mmio, so the value_set_analysis setup was skipped. Co-authored-by: Kiro --- regression/goto-instrument/mmio1/main.c | 2 ++ regression/goto-instrument/mmio1/test.desc | 8 ++++++++ src/goto-instrument/goto_instrument_parse_options.cpp | 1 + src/goto-instrument/goto_instrument_parse_options.h | 1 + 4 files changed, 12 insertions(+) create mode 100644 regression/goto-instrument/mmio1/main.c create mode 100644 regression/goto-instrument/mmio1/test.desc diff --git a/regression/goto-instrument/mmio1/main.c b/regression/goto-instrument/mmio1/main.c new file mode 100644 index 00000000000..ae92461928d --- /dev/null +++ b/regression/goto-instrument/mmio1/main.c @@ -0,0 +1,2 @@ +volatile int reg; +int main() { return reg; } diff --git a/regression/goto-instrument/mmio1/test.desc b/regression/goto-instrument/mmio1/test.desc new file mode 100644 index 00000000000..fd1a5b0937f --- /dev/null +++ b/regression/goto-instrument/mmio1/test.desc @@ -0,0 +1,8 @@ +CORE +main.c +--mmio +^EXIT=0$ +^SIGNAL=0$ +Instrumenting memory-mapped I/O +-- +^warning: ignoring diff --git a/src/goto-instrument/goto_instrument_parse_options.cpp b/src/goto-instrument/goto_instrument_parse_options.cpp index a6d8d2ac4e3..da4d805f3df 100644 --- a/src/goto-instrument/goto_instrument_parse_options.cpp +++ b/src/goto-instrument/goto_instrument_parse_options.cpp @@ -1530,6 +1530,7 @@ void goto_instrument_parse_optionst::instrument_goto_program() cmdline.isset("race-check") || cmdline.isset("mm") || cmdline.isset("isr") || + cmdline.isset("mmio") || cmdline.isset("concurrency")) { do_indirect_call_and_rtti_removal(); diff --git a/src/goto-instrument/goto_instrument_parse_options.h b/src/goto-instrument/goto_instrument_parse_options.h index 8e49a495c54..a0b00461f9d 100644 --- a/src/goto-instrument/goto_instrument_parse_options.h +++ b/src/goto-instrument/goto_instrument_parse_options.h @@ -66,6 +66,7 @@ Author: Daniel Kroening, kroening@kroening.com OPT_INSERT_FINAL_ASSERT_FALSE \ OPT_SHOW_CLASS_HIERARCHY \ "(isr):" \ + "(mmio)" \ "(stack-depth):(nondet-static)" \ "(nondet-static-exclude):" \ "(nondet-static-matching):" \ From 6222a35965ce8a861a08d0321ca7fb86a930a40d Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 17 Mar 2026 16:56:55 +0000 Subject: [PATCH 45/45] Fix --concurrency option: register it in option definitions The --concurrency option was not registered, causing the command-line parser to treat it as a positional argument. Exercises concurrency.cpp which previously had 0% coverage. Co-authored-by: Kiro --- regression/goto-instrument/concurrency1/main.c | 2 ++ regression/goto-instrument/concurrency1/test.desc | 8 ++++++++ src/goto-instrument/goto_instrument_parse_options.h | 1 + 3 files changed, 11 insertions(+) create mode 100644 regression/goto-instrument/concurrency1/main.c create mode 100644 regression/goto-instrument/concurrency1/test.desc diff --git a/regression/goto-instrument/concurrency1/main.c b/regression/goto-instrument/concurrency1/main.c new file mode 100644 index 00000000000..c66c1fd4c1a --- /dev/null +++ b/regression/goto-instrument/concurrency1/main.c @@ -0,0 +1,2 @@ +int shared; +int main() { shared = 1; return shared; } diff --git a/regression/goto-instrument/concurrency1/test.desc b/regression/goto-instrument/concurrency1/test.desc new file mode 100644 index 00000000000..093ad3b6b2f --- /dev/null +++ b/regression/goto-instrument/concurrency1/test.desc @@ -0,0 +1,8 @@ +CORE +main.c +--concurrency +^EXIT=0$ +^SIGNAL=0$ +Sequentializing concurrency +-- +^warning: ignoring diff --git a/src/goto-instrument/goto_instrument_parse_options.h b/src/goto-instrument/goto_instrument_parse_options.h index a0b00461f9d..2f0fdcc18c0 100644 --- a/src/goto-instrument/goto_instrument_parse_options.h +++ b/src/goto-instrument/goto_instrument_parse_options.h @@ -67,6 +67,7 @@ Author: Daniel Kroening, kroening@kroening.com OPT_SHOW_CLASS_HIERARCHY \ "(isr):" \ "(mmio)" \ + "(concurrency)" \ "(stack-depth):(nondet-static)" \ "(nondet-static-exclude):" \ "(nondet-static-matching):" \