Skip to content

Commit eca2c52

Browse files
tedinskiavanhatt
andcommitted
Switch --restrict-vtable to use CBMC labels instead of wrapper functions (rust-lang#767)
Co-authored-by: Alexa VanHattum <[email protected]>
1 parent 45216f8 commit eca2c52

File tree

6 files changed

+39
-89
lines changed

6 files changed

+39
-89
lines changed

library/kani_restrictions/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ pub struct TraitDefinedMethod {
1919
pub struct CallSite {
2020
pub trait_method: TraitDefinedMethod,
2121
pub function_name: InternedString,
22+
pub label: InternedString,
2223
}
2324

2425
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]

src/kani-compiler/rustc_codegen_kani/src/codegen/statement.rs

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -139,17 +139,17 @@ impl<'tcx> GotocCtx<'tcx> {
139139
let self_ref =
140140
self_ref.cast_to(trait_fat_ptr.typ().clone().to_pointer());
141141

142-
let call = if self.vtable_ctx.emit_vtable_restrictions {
142+
let call =
143+
fn_ptr.dereference().call(vec![self_ref]).as_stmt(Location::none());
144+
if self.vtable_ctx.emit_vtable_restrictions {
143145
self.virtual_call_with_restricted_fn_ptr(
144146
trait_fat_ptr.typ().clone(),
145147
VtableCtx::drop_index(),
146-
fn_ptr,
147-
vec![self_ref],
148+
call,
148149
)
149150
} else {
150-
fn_ptr.dereference().call(vec![self_ref])
151-
};
152-
call.as_stmt(Location::none())
151+
call
152+
}
153153
}
154154
_ => {
155155
// Non-virtual, direct drop call
@@ -436,17 +436,14 @@ impl<'tcx> GotocCtx<'tcx> {
436436
let assert_nonnull = Stmt::assert(call_is_nonnull, &assert_msg, loc.clone());
437437

438438
// Virtual function call and corresponding nonnull assertion.
439-
let call = if self.vtable_ctx.emit_vtable_restrictions {
440-
self.virtual_call_with_restricted_fn_ptr(
441-
trait_fat_ptr.typ().clone(),
442-
idx,
443-
fn_ptr,
444-
fargs.to_vec(),
445-
)
439+
let call = fn_ptr.dereference().call(fargs.to_vec());
440+
let call_stmt = self.codegen_expr_to_place(place, call).with_location(loc.clone());
441+
let call_stmt = if self.vtable_ctx.emit_vtable_restrictions {
442+
self.virtual_call_with_restricted_fn_ptr(trait_fat_ptr.typ().clone(), idx, call_stmt)
446443
} else {
447-
fn_ptr.dereference().call(fargs.to_vec())
444+
call_stmt
448445
};
449-
vec![assert_nonnull, self.codegen_expr_to_place(place, call).with_location(loc.clone())]
446+
vec![assert_nonnull, call_stmt]
450447
}
451448

452449
/// A place is similar to the C idea of a LHS. For example, the returned value of a function call is stored to a place.

src/kani-compiler/rustc_codegen_kani/src/context/vtable_ctx.rs

Lines changed: 15 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,8 @@
1616
/// For the current CBMC implementation of function restrictions, see:
1717
/// http://cprover.diffblue.com/md__home_travis_build_diffblue_cbmc_doc_architectural_restrict-function-pointer.html
1818
use crate::GotocCtx;
19-
use cbmc::goto_program::{Expr, Location, Stmt, Symbol, Type};
19+
use cbmc::goto_program::{Stmt, Type};
2020
use cbmc::InternedString;
21-
use cbmc::NO_PRETTY_NAME;
2221
use kani_restrictions::{CallSite, PossibleMethodEntry, TraitDefinedMethod, VtableCtxResults};
2322
use rustc_data_structures::stable_map::FxHashMap;
2423
use tracing::debug;
@@ -92,98 +91,44 @@ impl VtableCtx {
9291
trait_name: InternedString,
9392
method: usize,
9493
function_name: InternedString,
94+
label: InternedString,
9595
) {
9696
assert!(self.emit_vtable_restrictions);
9797
let site = CallSite {
9898
trait_method: TraitDefinedMethod { trait_name, vtable_idx: method },
9999
function_name: function_name,
100+
label: label,
100101
};
101102
self.call_sites.push(site);
102103
}
103104
}
104105

105106
impl<'tcx> GotocCtx<'tcx> {
106-
/// Wrap a virtual call through a function pointer and restrict the
107-
/// possible targets.
108-
///
109-
/// We need to wrap because for the current implemention, CBMC employs
110-
/// a hard-to-get-right naming scheme for restrictions: the call site is
111-
/// named for its index in a given function. We don't have a good way to
112-
/// track _all_ function pointers within the function, so wrapping the call
113-
/// to a function that makes a single virtual function pointer call makes
114-
/// the naming unambiguous.
115-
///
116-
/// This can be simplified if CBMC implemented label-based restrictions.
117-
/// Kani tracking: https://github.com/model-checking/kani/issues/651
118-
/// CBMC tracking: https://github.com/diffblue/cbmc/issues/6464
107+
/// Create a label to the virtual call site
119108
pub fn virtual_call_with_restricted_fn_ptr(
120109
&mut self,
121110
trait_ty: Type,
122111
vtable_idx: usize,
123-
fn_ptr: Expr,
124-
args: Vec<Expr>,
125-
) -> Expr {
112+
body: Stmt,
113+
) -> Stmt {
126114
assert!(self.vtable_ctx.emit_vtable_restrictions);
127115

128-
// Crate-based naming scheme for wrappers
129-
let full_crate_name = self.full_crate_name().to_string().replace("::", "_");
130-
let wrapper_name: InternedString = format!(
131-
"restricted_call_{}_{}",
132-
full_crate_name,
133-
self.vtable_ctx.get_call_site_global_idx()
134-
)
135-
.into();
116+
let label: InternedString =
117+
format!("restricted_call_label_{}", self.vtable_ctx.get_call_site_global_idx()).into();
136118

137119
// We only have the Gotoc type, we need to normalize to match the MIR type.
138120
assert!(trait_ty.is_struct_tag());
139121
let mir_name =
140122
self.normalized_trait_name(*self.type_map.get(&trait_ty.tag().unwrap()).unwrap());
141-
self.vtable_ctx.add_call_site(mir_name.into(), vtable_idx, wrapper_name);
142-
143-
// Declare the wrapper's parameters
144-
let func_exp: Expr = fn_ptr.dereference();
145-
let fn_type = func_exp.typ().clone();
146-
let parameters: Vec<Symbol> = fn_type
147-
.parameters()
148-
.unwrap()
149-
.iter()
150-
.enumerate()
151-
.map(|(i, parameter)| {
152-
let name = format!("{}_{}", wrapper_name, i);
153-
let param =
154-
Symbol::variable(name.clone(), name, parameter.typ().clone(), Location::none());
155-
self.symbol_table.insert(param.clone());
156-
param
157-
})
158-
.collect();
159-
160-
// Finish constructing the wrapper type
161-
let ret_typ = fn_type.return_type().unwrap().clone();
162-
let param_typs = parameters.clone().iter().map(|p| p.to_function_parameter()).collect();
163-
let new_typ = if fn_type.is_code() {
164-
Type::code(param_typs, ret_typ.clone())
165-
} else if fn_type.is_variadic_code() {
166-
Type::variadic_code(param_typs, ret_typ.clone())
167-
} else {
168-
unreachable!("Function type must be Code or VariadicCode")
169-
};
170123

171-
// Build the body: call the original function pointer
172-
let body = func_exp
173-
.clone()
174-
.call(parameters.iter().map(|p| p.to_expr()).collect())
175-
.ret(Location::none());
176-
177-
// Build and insert the wrapper function itself
178-
let sym = Symbol::function(
179-
wrapper_name,
180-
new_typ,
181-
Some(Stmt::block(vec![body], Location::none())),
182-
NO_PRETTY_NAME,
183-
Location::none(),
124+
// Label
125+
self.vtable_ctx.add_call_site(
126+
mir_name.into(),
127+
vtable_idx,
128+
self.current_fn().name().into(),
129+
label,
184130
);
185-
self.symbol_table.insert(sym.clone());
186-
sym.to_expr().call(args.to_vec())
131+
body.with_label(label)
187132
}
188133
}
189134

tests/kani/DynTrait/any_cast_int.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
22
// SPDX-License-Identifier: Apache-2.0 OR MIT
33

4+
// kani-flags: --no-restrict-vtable
5+
// Tracking issue for the need for this flag:
6+
// https://github.com/model-checking/kani/issues/802
7+
48
use std::any::Any;
59

610
// Cast one dynamic trait object type to another, which is legal because Send

tests/kani/DynTrait/any_cast_int_fail.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
22
// SPDX-License-Identifier: Apache-2.0 OR MIT
33

4+
// kani-flags: --no-restrict-vtable
5+
// Tracking issue for the need for this flag:
6+
// https://github.com/model-checking/kani/issues/802
7+
48
use std::any::Any;
59

610
// Cast one dynamic trait object type to another, which is legal because Send

tools/kani-link-restrictions/src/main.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,9 @@ fn link_function_pointer_restrictions(data_per_crate: Vec<VtableCtxResults>) ->
2323
// Iterate call sites
2424
for crate_data in data_per_crate {
2525
for call_site in crate_data.call_sites {
26-
// CBMC index is 1-indexed:
27-
// http://cprover.diffblue.com/md__home_travis_build_diffblue_cbmc_doc_architectural_restrict-function-pointer.html
28-
let cbmc_call_site_name =
29-
format!("{}.function_pointer_call.1", call_site.function_name);
26+
// CBMC Now supports referencing callsites by label:
27+
// https://github.com/diffblue/cbmc/pull/6508
28+
let cbmc_call_site_name = format!("{}.{}", call_site.function_name, call_site.label);
3029
let trait_def = call_site.trait_method;
3130

3231
// Look up all possibilities, defaulting to the empty set

0 commit comments

Comments
 (0)