@@ -35,8 +35,46 @@ impl<'tcx> GotocCtx<'tcx> {
3535 ) -> AssignsContract {
3636 let tcx = self . tcx ;
3737 let function_under_contract_attrs = KaniAttributes :: for_item ( tcx, function_under_contract) ;
38- let wrapped_fn = function_under_contract_attrs. inner_check ( ) . unwrap ( ) . unwrap ( ) ;
3938
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 ( ) ;
4078 let mut instance_under_contract = items. iter ( ) . filter_map ( |i| match i {
4179 MonoItem :: Fn ( instance @ Instance { def, .. } )
4280 if wrapped_fn == rustc_internal:: internal ( tcx, def. def_id ( ) ) =>
@@ -56,23 +94,12 @@ impl<'tcx> GotocCtx<'tcx> {
5694 vec ! [ ]
5795 } ) ;
5896 self . attach_modifies_contract ( instance_of_check, assigns_contract) ;
59-
6097 let wrapper_name = self . symbol_name_stable ( instance_of_check) ;
6198
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+ }
76103 }
77104
78105 /// Convert the Kani level contract into a CBMC level contract by creating a
0 commit comments