Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix ICE due to mishandling of Aggregate rvalue for raw pointers to trait objects #3636

Merged
merged 2 commits into from
Oct 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions kani-compiler/src/codegen_cprover_gotoc/codegen/rvalue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -726,6 +726,17 @@ impl GotocCtx<'_> {
dynamic_fat_ptr(typ, data_cast, vtable_expr, &self.symbol_table)
}
}
TyKind::RigidTy(RigidTy::Dynamic(..)) => {
let pointee_goto_typ = self.codegen_ty_stable(pointee_ty);
let data_cast =
data.cast_to(Type::Pointer { typ: Box::new(pointee_goto_typ) });
let meta = self.codegen_operand_stable(&operands[1]);
let vtable_expr = meta
.member("_vtable_ptr", &self.symbol_table)
.member("pointer", &self.symbol_table)
.cast_to(typ.lookup_field_type("vtable", &self.symbol_table).unwrap());
dynamic_fat_ptr(typ, data_cast, vtable_expr, &self.symbol_table)
}
_ => {
let pointee_goto_typ = self.codegen_ty_stable(pointee_ty);
data.cast_to(Type::Pointer { typ: Box::new(pointee_goto_typ) })
Expand Down
46 changes: 46 additions & 0 deletions tests/kani/CodegenAggregateRawPtrTraitObject/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright Kani Contributors
// SPDX-License-Identifier: Apache-2.0 OR MIT
// Test that Kani can verify code that produces a aggregate raw pointer to trait objects
// c.f. https://github.com/model-checking/kani/issues/3631

#![feature(ptr_metadata)]

use std::ptr::NonNull;

trait SampleTrait {
fn get_value(&self) -> i32;
}

struct SampleStruct {
value: i32,
}

impl SampleTrait for SampleStruct {
fn get_value(&self) -> i32 {
self.value
}
}

#[cfg(kani)]
#[kani::proof]
fn check_nonnull_dyn_from_raw_parts() {
// Create a SampleTrait object from SampleStruct
let sample_struct = SampleStruct { value: kani::any() };
let trait_object: &dyn SampleTrait = &sample_struct;

// Get the raw data pointer and metadata for the trait object
let trait_ptr = NonNull::new(trait_object as *const dyn SampleTrait as *mut ()).unwrap();
let metadata = std::ptr::metadata(trait_object);

// Create NonNull<dyn SampleTrait> from the data pointer and metadata
let nonnull_trait_object: NonNull<dyn SampleTrait> =
NonNull::from_raw_parts(trait_ptr, metadata);

unsafe {
// Ensure trait method and member is preserved
kani::assert(
trait_object.get_value() == nonnull_trait_object.as_ref().get_value(),
"trait method and member must correctly preserve",
);
}
}
Loading