Skip to content

Commit 0c3cea7

Browse files
committed
Fix static exclude for recursion tracker
1 parent 64f7e5f commit 0c3cea7

File tree

4 files changed

+59
-76
lines changed

4 files changed

+59
-76
lines changed

kani-compiler/src/codegen_cprover_gotoc/compiler_interface.rs

Lines changed: 52 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ use tempfile::Builder as TempFileBuilder;
6161
use tracing::{debug, error, info};
6262

6363
pub type UnsupportedConstructs = FxHashMap<InternedString, Vec<Location>>;
64+
6465
#[derive(Clone)]
6566
pub struct GotocCodegenBackend {
6667
/// The query is shared with `KaniCompiler` and it is initialized as part of `rustc`
@@ -146,33 +147,7 @@ impl GotocCodegenBackend {
146147
}
147148
}
148149

149-
check_contract.map(|check_contract_def| {
150-
let check_contract_attrs = KaniAttributes::for_item(tcx, check_contract_def);
151-
let wrapper_def = check_contract_attrs.inner_check().unwrap().unwrap();
152-
153-
let mut instances_of_check = items.iter().copied().filter_map(|i| match i {
154-
MonoItem::Fn(instance @ Instance { def: InstanceDef::Item(did), .. }) => {
155-
(wrapper_def == did).then_some(instance)
156-
}
157-
_ => None,
158-
});
159-
let instance_of_check = instances_of_check.next().unwrap();
160-
assert!(instances_of_check.next().is_none());
161-
let attrs = KaniAttributes::for_item(tcx, instance_of_check.def_id());
162-
let assigns_contract = attrs.modifies_contract().unwrap_or_else(|| {
163-
debug!(?instance_of_check, "had no assigns contract specified");
164-
vec![]
165-
});
166-
gcx.attach_contract(instance_of_check, assigns_contract);
167-
168-
let tracker_def = check_contract_attrs.recursion_tracker().unwrap().unwrap();
169-
170-
let span = tcx.def_span(tracker_def);
171-
let location = SourceLocation::new(tcx, &span);
172-
let full_name = format!("{}:{}", location.filename, tcx.item_name(tracker_def));
173-
174-
(tcx.symbol_name(instance_of_check).to_string(), full_name)
175-
})
150+
check_contract.map(|check_id| gcx.handle_check_contract(check_id, &items))
176151
},
177152
"codegen",
178153
);
@@ -215,6 +190,51 @@ impl GotocCodegenBackend {
215190
}
216191
}
217192

193+
impl<'tcx> GotocCtx<'tcx> {
194+
fn handle_check_contract(
195+
&mut self,
196+
function_under_contract: DefId,
197+
items: &[MonoItem<'tcx>],
198+
) -> (String, String) {
199+
let tcx = self.tcx;
200+
let function_under_contract_attrs = KaniAttributes::for_item(tcx, function_under_contract);
201+
let wrapped_fn = function_under_contract_attrs.inner_check().unwrap().unwrap();
202+
203+
let mut instance_under_contract = items.iter().copied().filter_map(|i| match i {
204+
MonoItem::Fn(instance @ Instance { def: InstanceDef::Item(did), .. }) => {
205+
(wrapped_fn == did).then_some(instance)
206+
}
207+
_ => None,
208+
});
209+
let instance_of_check = instance_under_contract.next().unwrap();
210+
assert!(
211+
instance_under_contract.next().is_none(),
212+
"Only one instance of a checked function may be in scope"
213+
);
214+
let attrs_of_wrapped_fn = KaniAttributes::for_item(tcx, wrapped_fn);
215+
let assigns_contract = attrs_of_wrapped_fn.modifies_contract().unwrap_or_else(|| {
216+
debug!(?instance_of_check, "had no assigns contract specified");
217+
vec![]
218+
});
219+
self.attach_contract(instance_of_check, assigns_contract);
220+
221+
let wrapper_name = tcx.symbol_name(instance_of_check).to_string();
222+
223+
let recursion_wrapper_id =
224+
function_under_contract_attrs.checked_with_id().unwrap().unwrap();
225+
let span_of_recursion_wrapper = tcx.def_span(recursion_wrapper_id);
226+
let location_of_recursion_wrapper = SourceLocation::new(tcx, &span_of_recursion_wrapper);
227+
228+
let full_name = format!(
229+
"{}:{}::REENTRY",
230+
location_of_recursion_wrapper.filename,
231+
tcx.item_name(recursion_wrapper_id),
232+
);
233+
234+
(wrapper_name, full_name)
235+
}
236+
}
237+
218238
fn contract_metadata_for_harness(
219239
tcx: TyCtxt,
220240
def_id: DefId,
@@ -317,8 +337,11 @@ impl CodegenBackend for GotocCodegenBackend {
317337
results.extend(gcx, items, None);
318338

319339
for (test_fn, test_desc) in harnesses.iter().zip(descriptions.iter()) {
320-
let instance =
321-
if let MonoItem::Fn(instance) = test_fn { instance } else { continue };
340+
let instance = if let MonoItem::Fn(instance) = test_fn {
341+
instance
342+
} else {
343+
continue;
344+
};
322345
let metadata = gen_test_metadata(tcx, *test_desc, *instance, &base_filename);
323346
let test_model_path = &metadata.goto_file.as_ref().unwrap();
324347
std::fs::copy(&model_path, test_model_path).expect(&format!(

kani-compiler/src/kani_middle/attributes.rs

Lines changed: 2 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@ enum KaniAttributeKind {
6060
IsContractGenerated,
6161
Modifies,
6262
InnerCheck,
63-
RecursionTracker,
6463
}
6564

6665
impl KaniAttributeKind {
@@ -78,7 +77,6 @@ impl KaniAttributeKind {
7877
| KaniAttributeKind::ReplacedWith
7978
| KaniAttributeKind::CheckedWith
8079
| KaniAttributeKind::Modifies
81-
| KaniAttributeKind::RecursionTracker
8280
| KaniAttributeKind::InnerCheck
8381
| KaniAttributeKind::IsContractGenerated => false,
8482
}
@@ -225,34 +223,8 @@ impl<'tcx> KaniAttributes<'tcx> {
225223
}
226224

227225
/// Retrieves the global, static recursion tracker variable.
228-
pub fn recursion_tracker(&self) -> Option<Result<DefId, ErrorGuaranteed>> {
229-
self.expect_maybe_one(KaniAttributeKind::RecursionTracker).map(|target| {
230-
let name = expect_key_string_value(self.tcx.sess, target)?;
231-
let all_items = self.tcx.hir_crate_items(());
232-
let hir_map = self.tcx.hir();
233-
234-
// I don't like the way this is currently implemented. I search
235-
// through all items defined in the crate for one with the correct
236-
// name. That works but this should do something better like
237-
// `eval_sibling_attribute`, which is less likely to have any
238-
// conflicts or alternatively use resolution for a path.
239-
//
240-
// The efficient thing to do is figure out where (relative to the
241-
// annotated item) rustc actually stores the tracker (which `mod`)
242-
// and the retrieve it (like `eval_sibling_attribute` does).
243-
244-
let owner = all_items
245-
.items()
246-
.find(|it| hir_map.opt_name(it.hir_id()) == Some(name))
247-
.ok_or_else(|| {
248-
self.tcx.sess.span_err(
249-
self.tcx.def_span(self.item),
250-
format!("Could not find recursion tracker '{name}' in crate"),
251-
)
252-
})?;
253-
254-
Ok(owner.owner_id.def_id.to_def_id())
255-
})
226+
pub fn checked_with_id(&self) -> Option<Result<DefId, ErrorGuaranteed>> {
227+
self.eval_sibling_attribute(KaniAttributeKind::CheckedWith)
256228
}
257229

258230
fn eval_sibling_attribute(
@@ -373,9 +345,6 @@ impl<'tcx> KaniAttributes<'tcx> {
373345
KaniAttributeKind::InnerCheck => {
374346
self.inner_check();
375347
}
376-
KaniAttributeKind::RecursionTracker => {
377-
self.recursion_tracker();
378-
}
379348
}
380349
}
381350
}
@@ -479,7 +448,6 @@ impl<'tcx> KaniAttributes<'tcx> {
479448
| KaniAttributeKind::IsContractGenerated
480449
| KaniAttributeKind::Modifies
481450
| KaniAttributeKind::InnerCheck
482-
| KaniAttributeKind::RecursionTracker
483451
| KaniAttributeKind::ReplacedWith => {
484452
self.tcx.sess.span_err(self.tcx.def_span(self.item), format!("Contracts are not supported on harnesses. (Found the kani-internal contract attribute `{}`)", kind.as_ref()));
485453
}

kani-driver/src/call_goto_instrument.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ impl KaniSession {
178178
vec!["--dfcc".into(), (&harness.mangled_name).into()];
179179

180180
if let Some((function, recursion_tracker)) = check {
181-
println!("enforcing function contract for {function}");
181+
println!("enforcing function contract for {function} with tracker {recursion_tracker}");
182182
args.extend([
183183
"--enforce-contract".into(),
184184
function.into(),

library/kani_macros/src/sysroot/contracts.rs

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1003,11 +1003,6 @@ fn requires_ensures_main(
10031003
"recursion_wrapper",
10041004
item_hash,
10051005
);
1006-
let recursion_tracker_name = identifier_for_generated_function(
1007-
&original_function_name,
1008-
"recursion_tracker",
1009-
item_hash,
1010-
);
10111006

10121007
// Constructing string literals explicitly here, because `stringify!`
10131008
// doesn't work. Let's say we have an identifier `check_fn` and we were
@@ -1021,8 +1016,6 @@ fn requires_ensures_main(
10211016
syn::LitStr::new(&handler.make_wrapper_name().to_string(), Span::call_site());
10221017
let recursion_wrapper_name_str =
10231018
syn::LitStr::new(&recursion_wrapper_name.to_string(), Span::call_site());
1024-
let recursion_tracker_name_str =
1025-
syn::LitStr::new(&recursion_tracker_name.to_string(), Span::call_site());
10261019

10271020
// The order of `attrs` and `kanitool::{checked_with,
10281021
// is_contract_generated}` is important here, because macros are
@@ -1039,7 +1032,6 @@ fn requires_ensures_main(
10391032
#[kanitool::checked_with = #recursion_wrapper_name_str]
10401033
#[kanitool::replaced_with = #replace_fn_name_str]
10411034
#[kanitool::inner_check = #wrapper_fn_name_str]
1042-
#[kanitool::recursion_tracker = #recursion_tracker_name_str]
10431035
#vis #sig {
10441036
#block
10451037
}
@@ -1061,13 +1053,13 @@ fn requires_ensures_main(
10611053
#[allow(dead_code, unused_variables)]
10621054
#[kanitool::is_contract_generated(recursion_wrapper)]
10631055
#wrapper_sig {
1064-
static mut #recursion_tracker_name: bool = false;
1065-
if unsafe { #recursion_tracker_name } {
1056+
static mut REENTRY: bool = false;
1057+
if unsafe { REENTRY } {
10661058
#call_replace(#(#args),*)
10671059
} else {
1068-
unsafe { #recursion_tracker_name = true };
1060+
unsafe { REENTRY = true };
10691061
let result = #call_check(#(#also_args),*);
1070-
unsafe { #recursion_tracker_name = false };
1062+
unsafe { REENTRY = false };
10711063
result
10721064
}
10731065
}

0 commit comments

Comments
 (0)