Skip to content

Commit 3d0d12a

Browse files
avanhatttedinski
authored andcommitted
Codegen drop_in_place type and vtable pointer (rust-lang#222)
* Add vtable drop_in_place * Fix __VERIFIER_expect_fail
1 parent b4657d4 commit 3d0d12a

File tree

7 files changed

+75
-64
lines changed

7 files changed

+75
-64
lines changed

compiler/rustc_codegen_llvm/src/gotoc/rvalue.rs

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -712,26 +712,23 @@ impl<'tcx> GotocCtx<'tcx> {
712712
}
713713
}
714714

715-
fn codegen_vtable_drop_in_place(&self) -> Expr {
716-
// TODO: The following still needs to be done for the destructor (drop_in_place method), but before that
717-
// the right type for drop_in_place needs to be set in typ.rs in codegen_ty_ref method as well.
718-
// Atm we pass a nullpointer instead (Type::empty().pointer(ctx.ptr_width()).null() in vtable_base)
719-
// This is sound, because CBMC will give a pointer error if we ever actually use it.
720-
//
721-
// let drop_instance =
722-
// Instance::resolve_drop_in_place(ctx.tcx, operand_type);
723-
// let drop_method_name = self.symbol_name(drop_instance);
724-
// let drop_inst_type =
725-
// drop_instance.ty(self.tcx, ty::ParamEnv::reveal_all());
726-
// let drop_irep = data::Variable {
727-
// data: drop_method_name.clone(),
728-
// typ: self.codegen_ty(drop_inst_type),
729-
// // typ: output_type,
730-
// location: data::Irep::nil(),
731-
// }
732-
// .to_expr()
733-
// .address_of();
734-
Type::void_pointer().null()
715+
/// Generate a function pointer to drop_in_place for entry into the vtable
716+
fn codegen_vtable_drop_in_place(
717+
&mut self,
718+
ty: Ty<'tcx>,
719+
trait_ty: &'tcx ty::TyS<'tcx>,
720+
) -> Expr {
721+
let drop_instance = Instance::resolve_drop_in_place(self.tcx, ty);
722+
let drop_sym_name = self.symbol_name(drop_instance);
723+
let drop_sym = self.symbol_table.lookup(&drop_sym_name).unwrap().clone();
724+
725+
// The drop instance has the concrete object type, for consistency with
726+
// type codegen we need the trait type for the function parameter.
727+
let trait_fn_ty =
728+
Type::code_with_unnamed_parameters(vec![self.codegen_ty(trait_ty)], Type::unit())
729+
.to_pointer();
730+
731+
Expr::symbol_expression(drop_sym_name, drop_sym.typ).address_of().cast_to(trait_fn_ty)
735732
}
736733

737734
fn codegen_vtable_methods(
@@ -825,7 +822,7 @@ impl<'tcx> GotocCtx<'tcx> {
825822
|ctx, var| {
826823
// Build the vtable
827824
// See compiler/rustc_codegen_llvm/src/gotoc/typ.rs `trait_vtable_field_types` for field order
828-
let drop_irep = ctx.codegen_vtable_drop_in_place();
825+
let drop_irep = ctx.codegen_vtable_drop_in_place(&src_mir_type, trait_type);
829826
let (vt_size, vt_align) = ctx.codegen_vtable_size_and_align(&src_mir_type);
830827
let size_assert = ctx.check_vtable_size(&src_mir_type, vt_size.clone());
831828
let mut vtable_fields = vec![drop_irep, vt_size, vt_align];

compiler/rustc_codegen_llvm/src/gotoc/statement.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ impl<'tcx> GotocCtx<'tcx> {
9696
}
9797

9898
// TODO: this function doesn't handle unwinding which begins if the destructor panics
99+
// https://github.com/model-checking/rmc/issues/221
99100
fn codegen_drop(&mut self, location: &Place<'tcx>, target: &BasicBlock) -> Stmt {
100101
// instance for drop function
101102
let loc_ty = self.place_ty(location);

compiler/rustc_codegen_llvm/src/gotoc/typ.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -175,13 +175,14 @@ impl<'tcx> GotocCtx<'tcx> {
175175
/// The order of fields (i.e., the layout of a vtable) is not guaranteed by the compiler.
176176
/// We follow the order implemented by the compiler in compiler/rustc_codegen_ssa/src/meth.rs
177177
/// `get_vtable`.
178-
///
179-
/// Currently, we also add a well-formed flag field to the end of the struct.
180178
fn trait_vtable_field_types(&mut self, t: &'tcx ty::TyS<'tcx>) -> Vec<DatatypeComponent> {
179+
// `drop_in_place` is a function with type t -> (), the vtable needs a
180+
// pointer to it
181+
let drop_ty =
182+
Type::code_with_unnamed_parameters(vec![self.codegen_ty(t)], Type::unit()).to_pointer();
183+
181184
let mut vtable_base = vec![
182-
// TODO: get the correct type for the drop in place. For now, just use void*
183-
// https://github.com/model-checking/rmc/issues/11
184-
Type::datatype_component("drop", Type::void_pointer()),
185+
Type::datatype_component("drop", drop_ty),
185186
Type::datatype_component("size", Type::size_t()),
186187
Type::datatype_component("align", Type::size_t()),
187188
];

src/test/cbmc/DynTrait/vtable_size_align.rs renamed to src/test/cbmc/DynTrait/vtable_size_align_drop.rs

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

4-
// This test checks the `size` and `align` fields of vtables, for a
4+
// This test checks the `size` and `align` fields of vtables, for a
55
// dynamic trait where two implementing structs have different sizes.
66
// The strategy is to cast the dyn trait object to a raw::TraitObject
77
// then do some unsafe pointer math.
@@ -12,6 +12,7 @@
1212

1313
use std::intrinsics::size_of;
1414
use std::mem::transmute;
15+
use std::ptr::drop_in_place;
1516
use std::raw::TraitObject;
1617

1718
include!("../Helpers/vtable_utils_ignore.rs");
@@ -45,18 +46,16 @@ impl Animal for Cow {
4546

4647
// Returns some struct that implements Animal, but we don't know which one at compile time.
4748
fn random_animal(random_number: i64) -> Box<dyn Animal> {
48-
if random_number < 5 {
49-
Box::new(Sheep { sheep_num : 7 })
50-
} else {
51-
Box::new(Cow { cow_num : 9 })
49+
if random_number < 5 {
50+
Box::new(Sheep { sheep_num: 7 })
51+
} else {
52+
Box::new(Cow { cow_num: 9 })
5253
}
5354
}
5455

5556
fn main() {
56-
let ptr_size = size_of::<&usize>() as isize;
57-
5857
// The vtable is laid out as the right hand side here:
59-
//
58+
//
6059
// +-------+------------------+
6160
// | size | value |
6261
// +-------+------------------+
@@ -65,8 +64,8 @@ fn main() {
6564
// | usize | align in bytes |
6665
// | ? | function ptrs... |
6766
// +-------+------------------+
68-
//
69-
// This layout taken from miri's handling:
67+
//
68+
// This layout taken from miri's handling:
7069
// https://github.com/rust-lang/rust/blob/ec487bf3cfc9ce386da25169509fae8f2b4d4eec/compiler/rustc_mir/src/interpret/traits.rs#L155
7170

7271
// Check layout/values for Sheep
@@ -81,17 +80,17 @@ fn main() {
8180

8281
// Note: i32 ptr cast
8382
assert!(*(data_ptr as *mut i32) == 7); // From Sheep
84-
83+
8584
let vtable_ptr = trait_object.vtable as *mut usize;
8685

8786
// Drop pointer
88-
assert!(!vtable_ptr.is_null());
87+
assert!(drop_from_vtrable(vtable_ptr) == drop_in_place::<Sheep> as *mut ());
8988

9089
// Size and align as usizes
9190
assert!(size_from_vtable(vtable_ptr) == size_of::<i32>());
9291
assert!(align_from_vtable(vtable_ptr) == size_of::<i32>());
9392
}
94-
// Check layout/values for Cow
93+
// Check layout/values for Cow
9594
unsafe {
9695
let animal_cow = random_animal(6);
9796

@@ -103,15 +102,14 @@ fn main() {
103102

104103
// Note: i8 ptr cast
105104
assert!(*(data_ptr as *mut i8) == 9); // From Cow
106-
105+
107106
let vtable_ptr = trait_object.vtable as *mut usize;
108107

109108
// Drop pointer
110-
assert!(!vtable_ptr.is_null());
109+
assert!(drop_from_vtrable(vtable_ptr) == drop_in_place::<Cow> as *mut ());
111110

112111
// Size and align as usizes
113112
assert!(size_from_vtable(vtable_ptr) == size_of::<i8>());
114113
assert!(align_from_vtable(vtable_ptr) == size_of::<i8>());
115114
}
116115
}
117-

src/test/cbmc/DynTrait/vtable_size_align_fail.rs renamed to src/test/cbmc/DynTrait/vtable_size_align_drop_fail.rs

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

4-
// This test checks the `size` and `align` fields of vtables, for a
4+
// This test checks the `size` and `align` fields of vtables, for a
55
// dynamic trait where two implementing structs have different sizes.
66
// The strategy is to cast the dyn trait object to a raw::TraitObject
77
// then do some unsafe pointer math.
@@ -14,9 +14,11 @@
1414

1515
use std::intrinsics::size_of;
1616
use std::mem::transmute;
17+
use std::ptr::drop_in_place;
1718
use std::raw::TraitObject;
1819

1920
include!("../Helpers/vtable_utils_ignore.rs");
21+
include!("../../rmc-prelude.rs");
2022

2123
// Different sized data fields on each struct
2224
struct Sheep {
@@ -47,18 +49,18 @@ impl Animal for Cow {
4749

4850
// Returns some struct that implements Animal, but we don't know which one at compile time.
4951
fn random_animal(random_number: i64) -> Box<dyn Animal> {
50-
if random_number < 5 {
51-
Box::new(Sheep { sheep_num : 7 })
52-
} else {
53-
Box::new(Cow { cow_num : 9 })
52+
if random_number < 5 {
53+
Box::new(Sheep { sheep_num: 7 })
54+
} else {
55+
Box::new(Cow { cow_num: 9 })
5456
}
5557
}
5658

5759
fn main() {
5860
let ptr_size = size_of::<&usize>() as isize;
5961

6062
// The vtable is laid out as the right hand side here:
61-
//
63+
//
6264
// +-------+------------------+
6365
// | size | value |
6466
// +-------+------------------+
@@ -67,8 +69,8 @@ fn main() {
6769
// | usize | align in bytes |
6870
// | ? | function ptrs... |
6971
// +-------+------------------+
70-
//
71-
// This layout taken from miri's handling:
72+
//
73+
// This layout taken from miri's handling:
7274
// https://github.com/rust-lang/rust/blob/ec487bf3cfc9ce386da25169509fae8f2b4d4eec/compiler/rustc_mir/src/interpret/traits.rs#L155
7375

7476
// Check layout/values for Sheep
@@ -82,18 +84,21 @@ fn main() {
8284
let data_ptr = trait_object.data;
8385

8486
// Note: i32 ptr cast
85-
assert!(*(data_ptr as *mut i32) != 7); // From Sheep
86-
87+
__VERIFIER_expect_fail(*(data_ptr as *mut i32) != 7, "Wrong data"); // From Sheep
88+
8789
let vtable_ptr = trait_object.vtable as *mut usize;
8890

8991
// Drop pointer
90-
assert!(vtable_ptr.is_null());
91-
92+
__VERIFIER_expect_fail(
93+
drop_from_vtrable(vtable_ptr) != drop_in_place::<Sheep> as *mut (),
94+
"Wrong drop",
95+
);
96+
9297
// Size and align as usizes
93-
assert!(size_from_vtable(vtable_ptr) != size_of::<i32>());
94-
assert!(align_from_vtable(vtable_ptr) != size_of::<i32>());
98+
__VERIFIER_expect_fail(size_from_vtable(vtable_ptr) != size_of::<i32>(), "Wrong size");
99+
__VERIFIER_expect_fail(align_from_vtable(vtable_ptr) != size_of::<i32>(), "Wrong align");
95100
}
96-
// Check layout/values for Cow
101+
// Check layout/values for Cow
97102
unsafe {
98103
let animal_cow = random_animal(6);
99104

@@ -104,16 +109,18 @@ fn main() {
104109
let data_ptr = trait_object.data;
105110

106111
// Note: i8 ptr cast
107-
assert!(*(data_ptr as *mut i8) != 9); // From Cow
108-
112+
__VERIFIER_expect_fail(*(data_ptr as *mut i8) != 9, "Wrong data"); // From Cow
113+
109114
let vtable_ptr = trait_object.vtable as *mut usize;
110115

111116
// Drop pointer
112-
assert!(vtable_ptr.is_null());
117+
__VERIFIER_expect_fail(
118+
drop_from_vtrable(vtable_ptr) != drop_in_place::<Cow> as *mut (),
119+
"Wrong drop",
120+
);
113121

114122
// Size and align as usizes
115-
assert!(size_from_vtable(vtable_ptr) != size_of::<i8>());
116-
assert!(align_from_vtable(vtable_ptr) != size_of::<i8>());
123+
__VERIFIER_expect_fail(size_from_vtable(vtable_ptr) != size_of::<i8>(), "Wrong size");
124+
__VERIFIER_expect_fail(align_from_vtable(vtable_ptr) != size_of::<i8>(), "Wrong align");
117125
}
118126
}
119-

src/test/cbmc/Helpers/vtable_utils_ignore.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,13 @@
33

44
// Because each regression test does not share a crate, we just use
55
// an import! to share this code across test directories.
6+
fn drop_from_vtrable(vtable_ptr : *mut usize) -> *mut () {
7+
// 1st pointer-sized position
8+
unsafe {
9+
*vtable_ptr as *mut ()
10+
}
11+
}
12+
613
fn size_from_vtable(vtable_ptr : *mut usize) -> usize {
714
// 2nd usize-sized position
815
unsafe {

src/test/rmc-prelude.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ fn __VERIFIER_assume(cond: bool) {
55
unimplemented!()
66
}
77

8-
fn __VERIFIER_expect_fail(cond: bool) {
8+
fn __VERIFIER_expect_fail(cond: bool, message: &str) {
99
unimplemented!()
1010
}
1111

0 commit comments

Comments
 (0)