@@ -35,8 +35,46 @@ impl<'tcx> GotocCtx<'tcx> {
35
35
) -> AssignsContract {
36
36
let tcx = self . tcx ;
37
37
let function_under_contract_attrs = KaniAttributes :: for_item ( tcx, function_under_contract) ;
38
- let wrapped_fn = function_under_contract_attrs. inner_check ( ) . unwrap ( ) . unwrap ( ) ;
39
38
39
+ let recursion_wrapper_id =
40
+ function_under_contract_attrs. checked_with_id ( ) . unwrap ( ) . unwrap ( ) ;
41
+ let expected_name = format ! ( "{}::REENTRY" , tcx. item_name( recursion_wrapper_id) ) ;
42
+ let mut recursion_tracker = items. iter ( ) . filter_map ( |i| match i {
43
+ MonoItem :: Static ( recursion_tracker)
44
+ if ( * recursion_tracker) . name ( ) . contains ( expected_name. as_str ( ) ) =>
45
+ {
46
+ Some ( * recursion_tracker)
47
+ }
48
+ _ => None ,
49
+ } ) ;
50
+ let recursion_tracker_def = recursion_tracker
51
+ . next ( )
52
+ . expect ( "There should be at least one recursion tracker (REENTRY) in scope" ) ;
53
+ assert ! (
54
+ recursion_tracker. next( ) . is_none( ) ,
55
+ "Only one recursion tracker (REENTRY) may be in scope"
56
+ ) ;
57
+
58
+ let span_of_recursion_wrapper = tcx. def_span ( recursion_wrapper_id) ;
59
+ let location_of_recursion_wrapper = self . codegen_span ( & span_of_recursion_wrapper) ;
60
+ // The name and location for the recursion tracker should match the exact information added
61
+ // to the symbol table, otherwise our contract instrumentation will silently failed.
62
+ // This happens because Kani relies on `--nondet-static-exclude` from CBMC to properly
63
+ // handle this tracker. CBMC silently fails if there is no match in the symbol table
64
+ // that correspond to the argument of this flag.
65
+ // More details at https://github.com/model-checking/kani/pull/3045.
66
+ let full_recursion_tracker_name = format ! (
67
+ "{}:{}" ,
68
+ location_of_recursion_wrapper
69
+ . filename( )
70
+ . expect( "recursion location wrapper should have a file name" ) ,
71
+ // We must use the pretty name of the tracker instead of the mangled name.
72
+ // This restrictions comes from `--nondet-static-exclude` in CBMC.
73
+ // Mode details at https://github.com/diffblue/cbmc/issues/8225.
74
+ recursion_tracker_def. name( ) ,
75
+ ) ;
76
+
77
+ let wrapped_fn = function_under_contract_attrs. inner_check ( ) . unwrap ( ) . unwrap ( ) ;
40
78
let mut instance_under_contract = items. iter ( ) . filter_map ( |i| match i {
41
79
MonoItem :: Fn ( instance @ Instance { def, .. } )
42
80
if wrapped_fn == rustc_internal:: internal ( tcx, def. def_id ( ) ) =>
@@ -56,23 +94,12 @@ impl<'tcx> GotocCtx<'tcx> {
56
94
vec ! [ ]
57
95
} ) ;
58
96
self . attach_modifies_contract ( instance_of_check, assigns_contract) ;
59
-
60
97
let wrapper_name = self . symbol_name_stable ( instance_of_check) ;
61
98
62
- let recursion_wrapper_id =
63
- function_under_contract_attrs. checked_with_id ( ) . unwrap ( ) . unwrap ( ) ;
64
- let span_of_recursion_wrapper = tcx. def_span ( recursion_wrapper_id) ;
65
- let location_of_recursion_wrapper = self . codegen_span ( & span_of_recursion_wrapper) ;
66
-
67
- let full_name = format ! (
68
- "{}:{}::REENTRY" ,
69
- location_of_recursion_wrapper
70
- . filename( )
71
- . expect( "recursion location wrapper should have a file name" ) ,
72
- tcx. item_name( recursion_wrapper_id) ,
73
- ) ;
74
-
75
- AssignsContract { recursion_tracker : full_name, contracted_function_name : wrapper_name }
99
+ AssignsContract {
100
+ recursion_tracker : full_recursion_tracker_name,
101
+ contracted_function_name : wrapper_name,
102
+ }
76
103
}
77
104
78
105
/// Convert the Kani level contract into a CBMC level contract by creating a
0 commit comments