Skip to content

Commit 325c9e4

Browse files
authored
Fix ICE due to mishandling of Aggregate rvalue for raw pointers to trait objects (#3636)
Add a match arm for the `AggregateKind::RawPtr(TyKind::RigidTy(RigidTy::Dynamic(..)))` case. Pointers to trait objects [are fat](https://github.com/rust-lang/rust/blob/master/library/core/src/ptr/metadata.rs#L20-#L27), so generate a fat pointer for the rvalue. Resolves #3631 By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses.
1 parent 8c9ee58 commit 325c9e4

File tree

2 files changed

+57
-0
lines changed
  • kani-compiler/src/codegen_cprover_gotoc/codegen
  • tests/kani/CodegenAggregateRawPtrTraitObject

2 files changed

+57
-0
lines changed

kani-compiler/src/codegen_cprover_gotoc/codegen/rvalue.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -726,6 +726,17 @@ impl GotocCtx<'_> {
726726
dynamic_fat_ptr(typ, data_cast, vtable_expr, &self.symbol_table)
727727
}
728728
}
729+
TyKind::RigidTy(RigidTy::Dynamic(..)) => {
730+
let pointee_goto_typ = self.codegen_ty_stable(pointee_ty);
731+
let data_cast =
732+
data.cast_to(Type::Pointer { typ: Box::new(pointee_goto_typ) });
733+
let meta = self.codegen_operand_stable(&operands[1]);
734+
let vtable_expr = meta
735+
.member("_vtable_ptr", &self.symbol_table)
736+
.member("pointer", &self.symbol_table)
737+
.cast_to(typ.lookup_field_type("vtable", &self.symbol_table).unwrap());
738+
dynamic_fat_ptr(typ, data_cast, vtable_expr, &self.symbol_table)
739+
}
729740
_ => {
730741
let pointee_goto_typ = self.codegen_ty_stable(pointee_ty);
731742
data.cast_to(Type::Pointer { typ: Box::new(pointee_goto_typ) })
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// Copyright Kani Contributors
2+
// SPDX-License-Identifier: Apache-2.0 OR MIT
3+
// Test that Kani can verify code that produces a aggregate raw pointer to trait objects
4+
// c.f. https://github.com/model-checking/kani/issues/3631
5+
6+
#![feature(ptr_metadata)]
7+
8+
use std::ptr::NonNull;
9+
10+
trait SampleTrait {
11+
fn get_value(&self) -> i32;
12+
}
13+
14+
struct SampleStruct {
15+
value: i32,
16+
}
17+
18+
impl SampleTrait for SampleStruct {
19+
fn get_value(&self) -> i32 {
20+
self.value
21+
}
22+
}
23+
24+
#[cfg(kani)]
25+
#[kani::proof]
26+
fn check_nonnull_dyn_from_raw_parts() {
27+
// Create a SampleTrait object from SampleStruct
28+
let sample_struct = SampleStruct { value: kani::any() };
29+
let trait_object: &dyn SampleTrait = &sample_struct;
30+
31+
// Get the raw data pointer and metadata for the trait object
32+
let trait_ptr = NonNull::new(trait_object as *const dyn SampleTrait as *mut ()).unwrap();
33+
let metadata = std::ptr::metadata(trait_object);
34+
35+
// Create NonNull<dyn SampleTrait> from the data pointer and metadata
36+
let nonnull_trait_object: NonNull<dyn SampleTrait> =
37+
NonNull::from_raw_parts(trait_ptr, metadata);
38+
39+
unsafe {
40+
// Ensure trait method and member is preserved
41+
kani::assert(
42+
trait_object.get_value() == nonnull_trait_object.as_ref().get_value(),
43+
"trait method and member must correctly preserve",
44+
);
45+
}
46+
}

0 commit comments

Comments
 (0)