ESBMC
Efficient SMT-based Context-Bounded Model Checker
Loading...
Searching...
No Matches
bmc.cpp File Reference
#include <csignal>
#include <memory>
#include <sys/types.h>
#include <algorithm>
#include <cctype>
#include <cstdlib>
#include <mutex>
#include <thread>
#include <chrono>
#include <unistd.h>
#include <sched.h>
#include <filesystem>
#include <fmt/format.h>
#include <regex>
#include <ac_config.h>
#include <esbmc/bmc.h>
#include <esbmc/property_report.h>
#include <fstream>
#include <goto-programs/goto_loops.h>
#include <goto-symex/trace/build_goto_trace.h>
#include <goto-symex/symex_invariant.h>
#include <goto-symex/trace/goto_trace.h>
#include <goto-symex/equation/features.h>
#include <goto-symex/trace/sarif.h>
#include <goto-symex/equation/symex_symmetry.h>
#include <goto-symex/trace/xml_goto_trace.h>
#include <langapi/language_util.h>
#include <langapi/languages.h>
#include <langapi/mode.h>
#include <solvers/smt/smt_conv.h>
#include <sstream>
#include <util/base/i2string.h>
#include <irep2/irep2.h>
#include <util/irep/location.h>
#include <util/irep/migrate.h>
#include <util/base/cwe_mapping.h>
#include <util/symtab/show_symbol_table.h>
#include <util/base/time_stopping.h>
#include <util/ssa/cache.h>
#include <util/ssa/fingerprint.h>
#include <util/ssa/proof_cache.h>
#include <esbmc/globals.h>
#include <atomic>
#include <vector>
#include <nlohmann/json.hpp>
Include dependency graph for bmc.cpp:

Functions

static std::string ctest_output_dir (const optionst &options)
static std::string pytest_output_dir (const optionst &options)
void note_cov_incomplete (const std::string &reason)
 Record why a coverage measurement is not exhaustive; the reason is listed under the closing COVERAGE ANALYSIS INCOMPLETE line.
static void note_cov_suppressed_violation (const std::string &claim)
static void note_undecided_cov_goal (const std::string &reason)
static bool strategy_owns_property_table (const optionst &options)
 Whether the k-step strategy driver owns the run's property table: it clears the store before its first phase, every phase records into it, and it is printed once where the run concludes (W3b of docs/roadmap/multi-property-strategy-plan.md).
static bool reports_multi_property_verdict (const optionst &options)
 Whether this phase may report a –multi-property result of its own.
static void record_discharge (bool withhold_proofs, const std::string &property, property_verdictt verdict, const property_locationt &loc, const std::string &note="")
 Record what a solver's UNSAT earned property.
static void print_partial_report_note ()
 The closing line of a report that does not account for every property.
static bool run_fully_proved (const optionst &options)
 Whether the table a k-step run accumulated says the program holds.
static bool phase_left_properties_undecided (bool report_incomplete, smt_resultt res)
 Whether a phase left properties undecided that a later one must not take for proved: it skipped some claim, died before its per-claim loop, or only emitted a formula.
static bool is_bounded_round (const optionst &options)
 Whether this phase is a k-step strategy's base case, which opens and completes a round and discharges a claim only within the current k (withholds_proofs()).
static bool is_loop_invariant_obligation (const locationt &location)
static bool is_vacuity_probe_candidate (const std::string &claim_property)
static std::string prettify_solidity_expr (const std::string &expr)
static nlohmann::json parse_claim_location (const std::string &loc)
static bool is_kpath_maximal (const std::string &claim_sig)
static void report_dead_code (const optionst &options, const std::unordered_set< std::string > &reached_claims, const std::vector< dead_store_advisoryt > &dead_stores)
static size_t count_reached_goals (const std::unordered_set< std::string > &reached_claims)
 Coverage numerator over the branch instrumentation.
void report_coverage (const optionst &options, std::unordered_set< std::string > &reached_claims, const std::unordered_multiset< std::string > &reached_mul_claims, pytest_generator &pytest_gen, ctest_generator &ctest_gen)
void report_coverage_completeness ()
 Closing line of a coverage run: whether every goal was actually decided, and if not, why.
static void prepare_property_verdicts (const optionst &options)
 A k-step strategy clears the store once, before its first phase, and starts a round at each base case.
static bool proof_cache_hit (proof_cachet *cache, bool verify, const symex_target_equationt::SSA_stepst &steps, std::string &cone_key, bool &hit)
 Look the claim's cone up in the cache.
static void proof_cache_store (proof_cachet *cache, const std::string &cone_key, bool hit, smt_resultt solver_result, bool is_vacuous, const std::string &claim, smt_resultt &final_result, std::mutex &result_mutex)
 Store a fresh proof, or fail the run over a stored one the solver has just refuted.
static bool coverage_silences_claim (bool goto_cov, bool dead_code, const std::string &prop)
 A dead-code probe is advisory and a non-probe claim in a coverage run is not being reported, so neither prints a per-claim solve (issue #4495).
static bool is_coverage_goal (bool cov_run, const std::string &prop)
 A coverage probe: SAT means "this location is reachable".
static const std::string & proof_cache_identity ()
 Which ESBMC this is.
static std::unique_ptr< proof_cachet > make_proof_cache (const optionst &options, const std::string &dir, const BigInt &interleaving_number)
 Build the cache only where a stored proof would be sound; nullptr disables every cache interaction downstream.
static void log_proof_cache_summary (const proof_cachet *cache)
 A warm run solves nothing, so without this the report shows no solver activity at all and gives no sign of where the verdicts came from.
static void dump_claim_fingerprint (const std::string &path, const symex_target_equationt::SSA_stepst &cone, smt_resultt result, const std::string &loc, const std::string &msg)
 One line per solved claim, digesting its cone under each normalisation: the instrument for measuring what –proof-cache can reuse.
static void print_property_rows (const std::vector< property_rowt > &rows, const property_countst &counts, bool is_color)
static void print_property_summary (size_t total, const property_countst &counts, bool is_color)
static property_countst print_property_table (const std::map< std::string, property_resultt > &verdicts, const std::set< std::string > &library_files, bool is_color, bool unchecked_is_unknown, bool decided_only, const std::function< std::string(const expr2tc &)> &render_condition)
 Build, order and print one property table.
void report_k_step_property_table (const optionst &options, const goto_functionst &goto_functions, const namespacet &ns)
 Print the property table a k-step strategy accumulated across its phases, once, where the strategy concludes without a phase of its own having reported (the k steps ran out).

Variables

static std::atomic< size_t > undecided_cov_goals {0}
static std::set< std::string > cov_incomplete_reasons
static std::set< std::string > cov_suppressed_violations
static std::mutex cov_report_mutex
static std::atomic< bool > cov_block_reported {false}
static const char *const weak_invariant_note

Function Documentation

◆ count_reached_goals()

size_t count_reached_goals ( const std::unordered_set< std::string > & reached_claims)
static

Coverage numerator over the branch instrumentation.

reached_claims records every claim symex refuted, including ones outside the instrumentation (an uncaught exception, say), so its raw size can exceed the goal count and report over 100% (#7296). all_claims is the instrumented set.

◆ coverage_silences_claim()

bool coverage_silences_claim ( bool goto_cov,
bool dead_code,
const std::string & prop )
static

A dead-code probe is advisory and a non-probe claim in a coverage run is not being reported, so neither prints a per-claim solve (issue #4495).

◆ ctest_output_dir()

std::string ctest_output_dir ( const optionst & options)
static

◆ dump_claim_fingerprint()

void dump_claim_fingerprint ( const std::string & path,
const symex_target_equationt::SSA_stepst & cone,
smt_resultt result,
const std::string & loc,
const std::string & msg )
static

One line per solved claim, digesting its cone under each normalisation: the instrument for measuring what –proof-cache can reuse.

No-op when –claim-fingerprint-dump was not given.

◆ is_bounded_round()

bool is_bounded_round ( const optionst & options)
static

Whether this phase is a k-step strategy's base case, which opens and completes a round and discharges a claim only within the current k (withholds_proofs()).

◆ is_coverage_goal()

bool is_coverage_goal ( bool cov_run,
const std::string & prop )
static

A coverage probe: SAT means "this location is reachable".

It is not a property, so it must not be reported as one (issue #6387).

◆ is_kpath_maximal()

bool is_kpath_maximal ( const std::string & claim_sig)
static

◆ is_loop_invariant_obligation()

bool is_loop_invariant_obligation ( const locationt & location)
static

◆ is_vacuity_probe_candidate()

bool is_vacuity_probe_candidate ( const std::string & claim_property)
static

◆ log_proof_cache_summary()

void log_proof_cache_summary ( const proof_cachet * cache)
static

A warm run solves nothing, so without this the report shows no solver activity at all and gives no sign of where the verdicts came from.

◆ make_proof_cache()

std::unique_ptr< proof_cachet > make_proof_cache ( const optionst & options,
const std::string & dir,
const BigInt & interleaving_number )
static

Build the cache only where a stored proof would be sound; nullptr disables every cache interaction downstream.

A cached proof is only sound where the claim's sliced cone is everything its verdict depends on. The k-induction phases and –incremental-bmc qualify: each sets its phase flags and unwind on this optionst before running, so both are already part of a claim's key.

◆ note_cov_incomplete()

void note_cov_incomplete ( const std::string & reason)

Record why a coverage measurement is not exhaustive; the reason is listed under the closing COVERAGE ANALYSIS INCOMPLETE line.

◆ note_cov_suppressed_violation()

void note_cov_suppressed_violation ( const std::string & claim)
static

◆ note_undecided_cov_goal()

void note_undecided_cov_goal ( const std::string & reason)
static

◆ parse_claim_location()

nlohmann::json parse_claim_location ( const std::string & loc)
static

◆ phase_left_properties_undecided()

bool phase_left_properties_undecided ( bool report_incomplete,
smt_resultt res )
static

Whether a phase left properties undecided that a later one must not take for proved: it skipped some claim, died before its per-claim loop, or only emitted a formula.

◆ prepare_property_verdicts()

void prepare_property_verdicts ( const optionst & options)
static

A k-step strategy clears the store once, before its first phase, and starts a round at each base case.

◆ prettify_solidity_expr()

std::string prettify_solidity_expr ( const std::string & expr)
static

◆ print_partial_report_note()

void print_partial_report_note ( )
static

The closing line of a report that does not account for every property.

◆ print_property_rows()

void print_property_rows ( const std::vector< property_rowt > & rows,
const property_countst & counts,
bool is_color )
static

◆ print_property_summary()

void print_property_summary ( size_t total,
const property_countst & counts,
bool is_color )
static

◆ print_property_table()

property_countst print_property_table ( const std::map< std::string, property_resultt > & verdicts,
const std::set< std::string > & library_files,
bool is_color,
bool unchecked_is_unknown,
bool decided_only,
const std::function< std::string(const expr2tc &)> & render_condition )
static

Build, order and print one property table.

unchecked_is_unknown renames the rows a k-step run never decided: the run did check them, at every k it reached, so "not checked" would understate what was tried.

◆ proof_cache_hit()

bool proof_cache_hit ( proof_cachet * cache,
bool verify,
const symex_target_equationt::SSA_stepst & steps,
std::string & cone_key,
bool & hit )
static

Look the claim's cone up in the cache.

Returns true when the stored proof stands in for solving; cone_key and hit are set for the store step.

◆ proof_cache_identity()

const std::string & proof_cache_identity ( )
static

Which ESBMC this is.

Hashing the executable is the fallback when the build ID does not name one build, so it is computed once and held.

◆ proof_cache_store()

void proof_cache_store ( proof_cachet * cache,
const std::string & cone_key,
bool hit,
smt_resultt solver_result,
bool is_vacuous,
const std::string & claim,
smt_resultt & final_result,
std::mutex & result_mutex )
static

Store a fresh proof, or fail the run over a stored one the solver has just refuted.

hit can only be set here under –proof-cache-verify: a hit short-circuits the solve otherwise.

◆ pytest_output_dir()

std::string pytest_output_dir ( const optionst & options)
static

◆ record_discharge()

void record_discharge ( bool withhold_proofs,
const std::string & property,
property_verdictt verdict,
const property_locationt & loc,
const std::string & note = "" )
static

Record what a solver's UNSAT earned property.

Only a proof needs backing: where withholds_proofs() says the phase cannot make one, the claim stays undecided. A vacuous discharge is not a proof but a diagnosis of the path, which a bounded round establishes as well as a conclusive one, so it is recorded either way – and it has to be, since a k-step run reports the vacuity nowhere else.

◆ report_coverage()

void report_coverage ( const optionst & options,
std::unordered_set< std::string > & reached_claims,
const std::unordered_multiset< std::string > & reached_mul_claims,
pytest_generator & pytest_gen,
ctest_generator & ctest_gen )

the reached_claims might not be empty (due to unwinding assertions)

Might got incorrect total number when using –k-induction due to that the symex->goto_functions has been simplified

◆ report_coverage_completeness()

void report_coverage_completeness ( )

Closing line of a coverage run: whether every goal was actually decided, and if not, why.

Printed by the driver once, after the last [Coverage] block (k-induction prints one per phase).

◆ report_dead_code()

void report_dead_code ( const optionst & options,
const std::unordered_set< std::string > & reached_claims,
const std::vector< dead_store_advisoryt > & dead_stores )
static

◆ report_k_step_property_table()

void report_k_step_property_table ( const optionst & options,
const goto_functionst & goto_functions,
const namespacet & ns )

Print the property table a k-step strategy accumulated across its phases, once, where the strategy concludes without a phase of its own having reported (the k steps ran out).

Rows the run never decided print as UNKNOWN: every base case checked them, none settled them. A no-op on a run that keeps a table per phase.

◆ reports_multi_property_verdict()

bool reports_multi_property_verdict ( const optionst & options)
static

Whether this phase may report a –multi-property result of its own.

Under a k-step strategy it may not: its phases deepen the search rather than conclude it, and the strategy reports for all of them.

◆ run_fully_proved()

bool run_fully_proved ( const optionst & options)
static

Whether the table a k-step run accumulated says the program holds.

The run's verdict follows its table, so a row left undecided – never settled within max-k, or discharged only vacuously – is not a proof, and the phase that closes the search must not call it one. Vacuously true elsewhere: a single run's phase speaks for itself.

◆ strategy_owns_property_table()

bool strategy_owns_property_table ( const optionst & options)
static

Whether the k-step strategy driver owns the run's property table: it clears the store before its first phase, every phase records into it, and it is printed once where the run concludes (W3b of docs/roadmap/multi-property-strategy-plan.md).

Variable Documentation

◆ cov_block_reported

std::atomic<bool> cov_block_reported {false}
static

◆ cov_incomplete_reasons

std::set<std::string> cov_incomplete_reasons
static

◆ cov_report_mutex

std::mutex cov_report_mutex
static

◆ cov_suppressed_violations

std::set<std::string> cov_suppressed_violations
static

◆ undecided_cov_goals

std::atomic<size_t> undecided_cov_goals {0}
static

◆ weak_invariant_note

const char* const weak_invariant_note
static
Initial value:
=
"loop invariant too weak to prove this claim: the counterexample is against "
"the havoc abstraction, not a reachable state of the program"