ESBMC
Efficient SMT-based Context-Bounded Model Checker
Loading...
Searching...
No Matches
contracts.h
Go to the documentation of this file.
1/*
2 * This function is used to check function contracts.
3 *
4 * Verification Strategy: Abstraction and Hierarchical Verification
5 *
6 * Function contracts enable a manual abstraction approach to assist
7 * over-approximation verification logic. By splitting verification into
8 * system-level and function-level, we should be able to reduce verification
9 * complexity.
10 *
11 * 1. Function-level verification (enforce_contracts):
12 * - Verify each function independently against its contract
13 * - Use contract as specification: assume requires -> execute function ->
14 * assert ensures
15 * - This provides over-approximation: if function satisfies contract, it's
16 * correct
17 * - Complexity: O(n) where n is function size, not system size
18 *
19 * 2. System-level verification (replace_calls):
20 * - Replace function calls with contract semantics
21 * - Use contract as abstraction: assert requires -> havoc assigns -> assume
22 * ensures
23 * - This avoids exploring function body, reducing state space
24 * - Complexity: O(m) where m is call sites, not function implementations
25 *
26 * Benefits:
27 * - Modularity: Verify functions separately from system
28 * - Scalability: System verification doesn't need to explore function internals
29 * - Reusability: Once function is verified, contract can be used in any context
30 * - Over-approximation: Contract provides safe abstraction (may have false
31 * positives)
32 *
33 * This approach transforms a complex system verification problem into:
34 * - Multiple simpler function verification problems
35 * - One system verification problem using abstracted functions
36 *
37 * It takes phases:
38 * 1. Extract contract clauses (requires, ensures, assigns) from contract symbol
39 * 2. For contract checking: rename original function, generate wrapper with
40 * assume requires -> call -> assert ensures
41 * 3. For contract replacement: replace calls with assert requires -> havoc
42 * assigns -> assume ensures
43 */
44
45#ifndef ESBMC_CONTRACTS_H
46#define ESBMC_CONTRACTS_H
47
50#include <util/symtab/context.h>
52#include <functional>
53#include <map>
54#include <set>
55#include <string>
56
72{
73public:
74 // ========== __ESBMC_is_fresh support for ensures ==========
75
84
86 goto_functionst &goto_functions,
87 contextt &context,
88 const namespacet &ns);
89
103 std::set<std::string> enforce_contracts(
104 const std::set<std::string> &to_enforce,
105 const std::string &entry_function = "",
106 bool check_assigns_compliance = false);
107
120 void replace_calls(const std::set<std::string> &to_replace);
121
126
130 bool has_contracts(const goto_programt &function_body) const;
131
136 bool is_annotated_contract_function(const symbolt &func_sym) const;
137
140 std::string clause_call_callee(const goto_programt &body) const;
141
143 std::string clause_call_reason(const goto_programt &body) const;
144
148 bool declares_contracts(const symbolt &func_sym) const;
149
152 std::vector<symbolt *> short_name_candidates(
153 const std::string &short_name,
154 const std::function<bool(const symbolt &)> &accept);
155
167
186
201
218 {
221 bool from_is_fresh = false;
222 };
223
228 bool is_compiler_generated(const std::string &function_name) const;
229
245 std::string
246 diagnose_contract_target(const std::string &function_name, bool for_replace);
247
248private:
249 goto_functionst &goto_functions;
250 contextt &context;
251 const namespacet &ns;
252 frame_enforcert frame_enforcer;
253 size_t ptr_field_snap_counter =
254 0;
255 size_t ptr_deref_snap_counter =
256 0;
257 size_t arr_elem_snap_counter =
258 0;
259
267 static constexpr size_t WITNESS_IDX_FALLBACK_ELEMS = 100;
268
272 symbolt *find_function_symbol(const std::string &function_name);
273
277 void rename_function(const irep_idt &old_id, const irep_idt &new_id);
278
289 goto_programt generate_checking_wrapper(
290 const symbolt &original_func,
291 const expr2tc &requires_clause,
292 const expr2tc &ensures_clause,
293 const irep_idt &original_func_id,
294 const goto_programt &original_body,
295 const std::vector<is_fresh_mapping_t> &is_fresh_mappings,
296 bool alloc_ptr_params = false,
297 const std::vector<expr2tc> &assigns_targets = {},
298 bool check_assigns_compliance = false);
299
301 expr2tc
302 declare_local_symbol(const std::string &name, const type2tc &type) const;
303
310 expr2tc declare_call_result(
311 const symbolt &function_symbol,
312 const expr2tc &ret_val,
313 const locationt &call_location,
314 goto_programt &replacement) const;
315
321 void generate_replacement_at_call(
322 const symbolt &function_symbol,
323 const goto_programt &function_body,
324 goto_programt::targett call_instruction,
325 goto_programt &caller_body);
326
330 expr2tc extract_requires_clause(const symbolt &contract_symbol);
331
335 expr2tc extract_ensures_clause(const symbolt &contract_symbol);
336
341 expr2tc extract_requires_from_body(const goto_programt &function_body);
342
347 expr2tc extract_ensures_from_body(const goto_programt &function_body);
348
352 std::vector<expr2tc>
353 extract_assigns_from_body(const goto_programt &function_body);
354
358 expr2tc extract_assigns_clause(const symbolt &contract_symbol);
359
365 expr2tc replace_return_value_in_expr(
366 const expr2tc &expr,
367 const expr2tc &ret_val) const;
368
380 expr2tc extract_struct_members_to_temps(
381 const expr2tc &expr,
382 const expr2tc &ret_val,
383 goto_programt &wrapper,
384 const locationt &location);
385
391 expr2tc replace_symbol_in_expr(
392 const expr2tc &expr,
393 const expr2tc &old_symbol,
394 const expr2tc &new_expr) const;
395
404 expr2tc instantiate_assigns_target(
405 const expr2tc &target_expr,
406 const symbolt &function_symbol,
407 const std::vector<expr2tc> &actual_args,
408 bool &is_pointer_param) const;
409
410 // ========== __ESBMC_old support ==========
411
413 struct old_snapshot_t
414 {
415 expr2tc original_expr;
416 expr2tc snapshot_var;
417
425 bool is_ptr_region = false;
426 type2tc region_elem_type = type2tc();
427 };
428
432 bool is_old_call(const expr2tc &expr) const;
433
439 expr2tc create_snapshot_variable(
440 const expr2tc &expr,
441 const std::string &func_name,
442 size_t index) const;
443
446 static expr2tc find_snapshot_by_symbol(
447 const irep_idt &thename,
448 const std::vector<old_snapshot_t> &snapshots,
449 bool want_region);
450
455 static expr2tc try_replace_ptr_region_old(
456 const type2tc &result_type,
457 const expr2tc &ptr_expr,
458 const std::vector<old_snapshot_t> &snapshots,
459 const namespacet &ns);
460
465 expr2tc replace_old_in_expr(
466 const expr2tc &expr,
467 const std::vector<old_snapshot_t> &snapshots) const;
468
472 static void classify_ptr_region_snapshots(
473 std::vector<old_snapshot_t> &old_snapshots,
474 const goto_programt &function_body);
475
479 static void check_old_snapshot_pointer_ambiguity(
480 const std::vector<old_snapshot_t> &old_snapshots);
481
485 std::vector<old_snapshot_t>
486 collect_old_snapshots_from_body(const goto_programt &function_body) const;
487
498 std::vector<ptr_field_snapshot_t> materialize_ptr_field_snapshots(
499 const frame_enforcert::classified_assignst &classified,
500 const symbolt &original_func,
501 goto_programt &wrapper,
502 const locationt &location,
503 const std::string &func_name);
504
510 void emit_ptr_field_assertions(
511 const std::vector<ptr_field_snapshot_t> &snapshots,
512 goto_programt &wrapper,
513 const locationt &location);
514
515 // ========== Phase 2C: pointer-parameter dereference assigns compliance
516 // ==========
517
539 std::vector<ptr_deref_snapshot_t> materialize_ptr_deref_snapshots(
540 const frame_enforcert::classified_assignst &classified,
541 const std::vector<expr2tc> &assigns_targets,
542 const symbolt &original_func,
543 goto_programt &wrapper,
544 const locationt &location,
545 const std::string &func_name,
546 const std::map<irep_idt, param_extentt> &param_extents);
547
555 void materialize_ptr_deref_array_field(
556 const irep_idt &param_id,
557 const irep_idt &field,
558 const type2tc &ftype,
559 const type2tc &pointee,
560 const expr2tc &ptr_sym,
561 const expr2tc &deref_expr,
562 goto_programt &wrapper,
563 const locationt &location,
564 const std::string &func_name,
565 std::vector<ptr_deref_snapshot_t> &result);
566
573 void emit_ptr_deref_assertions(
574 const std::vector<ptr_deref_snapshot_t> &snapshots,
575 goto_programt &wrapper,
576 const locationt &location);
577
578 // ========== Phase 2B: array element assigns compliance ==========
579
596 std::vector<arr_elem_snapshot_t> materialize_arr_elem_snapshots(
597 const frame_enforcert::classified_assignst &classified,
598 const std::vector<expr2tc> &assigns_targets,
599 goto_programt &wrapper,
600 const locationt &location,
601 const std::string &func_name,
602 const std::map<irep_idt, param_extentt> &param_extents);
603
610 void emit_arr_elem_assertions(
611 const std::vector<arr_elem_snapshot_t> &snapshots,
612 goto_programt &wrapper,
613 const locationt &location);
614
637 expr2tc materialize_ptr_region_old_snapshot(
638 const expr2tc &original_expr,
639 const type2tc &region_elem_type,
640 goto_programt &wrapper,
641 const std::string &func_name,
642 const locationt &location,
643 const expr2tc &extent_bytes,
644 size_t snap_idx) const;
645
658 void materialize_old_snapshots_at_wrapper(
659 std::vector<old_snapshot_t> &old_snapshots,
660 goto_programt &wrapper,
661 const std::string &func_name,
662 const locationt &location,
663 const std::map<irep_idt, param_extentt> &param_extents) const;
664
682 std::vector<old_snapshot_t> materialize_old_snapshots_at_callsite(
683 const std::vector<old_snapshot_t> &old_snapshots,
684 const symbolt &function_symbol,
685 const goto_programt &function_body,
686 const expr2tc &requires_clause,
687 const std::vector<expr2tc> &actual_args,
688 goto_programt &replacement,
689 const locationt &call_location) const;
690
719 bool find_callsite_is_fresh_extent(
720 const goto_programt &function_body,
721 const expr2tc &target_param,
722 const expr2tc &requires_clause,
723 const code_typet::argumentst &params,
724 const std::vector<expr2tc> &actual_args,
725 expr2tc &out_size) const;
726
727 // ========== Type fixing for return value comparisons ==========
728
733 bool is_return_value_symbol(const symbol2t &sym) const;
734
739 expr2tc
740 remove_incorrect_casts(const expr2tc &expr, const expr2tc &ret_val) const;
741
747 expr2tc
748 fix_comparison_types(const expr2tc &expr, const expr2tc &ret_val) const;
749
755 expr2tc normalize_fp_add_in_ensures(const expr2tc &expr) const;
756
767 expr2tc normalize_ensures_guard_for_return_value(
768 const expr2tc &ensures_clause,
769 const expr2tc &ret_val) const;
770
771 // ========== __ESBMC_is_fresh support for ensures ==========
772
776 std::vector<is_fresh_mapping_t>
777 extract_is_fresh_mappings_from_body(const goto_programt &function_body) const;
778
787 expr2tc replace_is_fresh_temps(
788 const expr2tc &expr,
789 const std::vector<is_fresh_mapping_t> &mappings,
790 bool require_dynamic) const;
791
796 void havoc_assigns_targets(
797 const expr2tc &assigns_clause,
798 goto_programt &dest,
799 const locationt &location);
800
804 std::vector<expr2tc> extract_assigns_targets(const expr2tc &assigns_clause);
805
810 void havoc_function_parameters(
811 const symbolt &original_func,
812 goto_programt &dest,
813 const locationt &location);
814
818 void havoc_static_globals(goto_programt &dest, const locationt &location);
819
825 void havoc_globals_for_entry_harness(
826 goto_programt &dest,
827 const locationt &location,
828 bool is_entry_harness);
829
856 void add_pointer_validity_assumptions(
857 goto_programt &wrapper,
858 const symbolt &func,
859 const locationt &location,
860 const std::set<irep_idt> &skip_params,
861 const std::set<irep_idt> &separated_params,
862 std::vector<expr2tc> &allocated_ptrs,
863 std::map<irep_idt, param_extentt> &param_extents);
864
871 bool
872 param_extent_is_observable(const symbolt &func, const irep_idt &param) const;
873
879 expr2tc lower_is_fresh_in_requires(
880 const symbolt &function_symbol,
881 const goto_programt &function_body,
882 const std::vector<expr2tc> &actual_args,
883 expr2tc requires_clause,
884 std::vector<expr2tc> &separation);
885
892 void attach_alias_exemptions(
893 std::vector<ptr_deref_snapshot_t> &result,
894 const std::vector<expr2tc> &assigns_targets,
895 const symbolt &original_func,
896 goto_programt &wrapper,
897 const locationt &location,
898 const std::string &func_name);
899
910 expr2tc retain_allocation_for_free(
911 goto_programt &wrapper,
912 const expr2tc &allocated,
913 const std::string &name,
914 const symbolt &func,
915 const locationt &location);
916
929 void emit_pointer_param_aliasing(
930 goto_programt &wrapper,
931 const symbolt &func,
932 const locationt &location,
933 const std::vector<std::pair<expr2tc, std::string>> &params);
934
936 void emit_receiver_backing(
937 goto_programt &wrapper,
938 const expr2tc &p,
939 const std::string &param_name,
940 const type2tc &pointee,
941 const symbolt &func,
942 const locationt &location);
943
949 expr2tc emit_pointer_param_malloc(
950 goto_programt &wrapper,
951 const expr2tc &p,
952 const std::string &param_name,
953 const symbolt &func,
954 const locationt &location);
955};
956
957#endif // ESBMC_CONTRACTS_H
std::vector< symbolt * > short_name_candidates(const std::string &short_name, const std::function< bool(const symbolt &)> &accept)
Code symbols whose short name is short_name and which satisfy accept, in goto-function order.
Definition contracts.cpp:193
bool declares_contracts(const symbolt &func_sym) const
Whether func_sym has a body carrying contract clauses, or the __ESBMC_contract annotation.
Definition contracts.cpp:179
std::string clause_call_callee(const goto_programt &body) const
Name of the first non-intrinsic call a clause in body depends on, empty when there is none.
Definition contracts.cpp:451
code_contractst(goto_functionst &goto_functions, contextt &context, const namespacet &ns)
Definition contracts.cpp:137
bool is_compiler_generated(const std::string &function_name) const
Check if a function is compiler-generated and should be skipped.
Definition contracts.cpp:148
std::string diagnose_contract_target(const std::string &function_name, bool for_replace)
Say why function_name cannot be used by a contract flag.
Definition contracts.cpp:5076
bool has_contracts(const goto_programt &function_body) const
Quick check if function has any contracts.
Definition contracts.cpp:4995
void replace_calls(const std::set< std::string > &to_replace)
Replace function calls with contracts Replaces function calls with contract semantics:
Definition contracts.cpp:5122
void remove_inactive_clauses()
Drop the requires/ensures ASSUMEs of every function the passes above left in place: a clause of a fun...
Definition contracts.cpp:5259
std::string clause_call_reason(const goto_programt &body) const
Diagnostic for such a call, empty when there is none.
Definition contracts.cpp:481
bool is_annotated_contract_function(const symbolt &func_sym) const
Check if function is marked with attribute((annotate("__ESBMC_contract"))).
Definition contracts.cpp:5067
std::set< std::string > enforce_contracts(const std::set< std::string > &to_enforce, const std::string &entry_function="", bool check_assigns_compliance=false)
Enforce function contracts Renames function F to __ESBMC_contracts_original_F and generates a new wra...
Definition contracts.cpp:1429
std::vector< argumentt > argumentst
Definition std_types.h:283
Definition context.h:57
Definition frame_enforcer.h:39
Definition goto_functions.h:56
A generic container class for a control flow graph for one function, in the form of a goto-program.
Definition goto_program.h:63
instructionst::iterator targett
Definition goto_program.h:590
Definition irep_idt.h:12
Definition location.h:7
Definition namespace.h:10
Definition symbol.h:12
Observational frame-rule enforcement for verification.
irep_container< type2t > type2tc
Definition irep2.h:430
irep_container< expr2t > expr2tc
Definition irep2.h:431
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
Definition socket_lib.c:100
Snapshot for array element assigns compliance (Phase 2B).
Definition contracts.h:191
std::vector< expr2tc > declared_indices
Every index the clause names on this array: the witness assertion must excuse all of them,...
Definition contracts.h:197
expr2tc arr_ptr
Array pointer symbol (e.g. symbol2tc for "arr").
Definition contracts.h:192
type2tc elem_type
Element type (pointee of arr_ptr).
Definition contracts.h:194
expr2tc snapshot_sym
Snapshot symbol holding arr[j] pre-call value.
Definition contracts.h:199
expr2tc witness_idx
Nondet witness index symbol j.
Definition contracts.h:198
type2tc arr_add_type
Result type of (arr + j) pointer-arithmetic.
Definition contracts.h:193
Structure to store is_fresh mapping information.
Definition contracts.h:78
irep_idt temp_var_name
Temporary variable name (e.g., return_value$___ESBMC_is_fresh$1).
Definition contracts.h:79
expr2tc size_expr
Extent the contract asked for, in bytes; may be nil.
Definition contracts.h:82
expr2tc ptr_expr
Pointer expression (dereferenced from &ptr).
Definition contracts.h:81
Byte extent of a harness-allocated pointer parameter.
Definition contracts.h:218
bool justified
True when the backing may be dereferenced.
Definition contracts.h:220
bool from_is_fresh
True only when bytes is from is_fresh.
Definition contracts.h:221
expr2tc bytes
Byte-extent expression of the allocation.
Definition contracts.h:219
Snapshot for pointer-parameter dereference assigns compliance (Phase 2C).
Definition contracts.h:173
type2tc pointee_type
Resolved type pointed to by ptr_sym.
Definition contracts.h:175
expr2tc ptr_sym
Pointer parameter symbol.
Definition contracts.h:174
irep_idt field_name
Empty for scalars; field name for struct members.
Definition contracts.h:176
type2tc value_type
Type of the snapshotted value.
Definition contracts.h:177
expr2tc alias_exemption
Nil, or a guard under which this location is an assigns target reached by another name.
Definition contracts.h:183
type2tc member_type
Array-field member type (for indexing); nil otherwise.
Definition contracts.h:182
expr2tc snapshot_sym
Snapshot symbol holding the pre-call value.
Definition contracts.h:178
expr2tc array_index
Nil for scalars; nondet witness index for array fields.
Definition contracts.h:180
Per-field snapshot for pointer-struct-field assigns compliance.
Definition contracts.h:160
type2tc field_type
Type of that field.
Definition contracts.h:164
type2tc pointee_type
Resolved struct type pointed to by ptr_sym.
Definition contracts.h:162
expr2tc snapshot_sym
Snapshot symbol holding pre-call field value.
Definition contracts.h:165
irep_idt field_name
Field name not in assigns (e.g. "capacity").
Definition contracts.h:163
expr2tc ptr_sym
Pointer symbol (e.g. symbol2tc for "ctx").
Definition contracts.h:161