-
Notifications
You must be signed in to change notification settings - Fork 142
Drop for dynamic objects #402
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -721,26 +721,26 @@ impl<'tcx> GotocCtx<'tcx> { | |
| ty: Ty<'tcx>, | ||
| trait_ty: &'tcx ty::TyS<'tcx>, | ||
| ) -> Expr { | ||
| let drop_instance = Instance::resolve_drop_in_place(self.tcx, ty); | ||
| let drop_instance = Instance::resolve_drop_in_place(self.tcx, ty).polymorphize(self.tcx); | ||
| let drop_sym_name = self.symbol_name(drop_instance); | ||
| let param_types = vec![self.codegen_ty(trait_ty)]; | ||
|
|
||
| // The drop instance has the concrete object type, for consistency with | ||
| // type codegen we need the trait type for the function parameter. | ||
| let trait_fn_ty = | ||
| Type::code_with_unnamed_parameters(param_types, Type::unit()).to_pointer(); | ||
| let trait_fn_ty = self.trait_vtable_drop_type(trait_ty); | ||
|
|
||
| if let Some(drop_sym) = self.symbol_table.lookup(&drop_sym_name) { | ||
| Expr::symbol_expression(drop_sym_name, drop_sym.clone().typ) | ||
| .address_of() | ||
| .cast_to(trait_fn_ty) | ||
| } else { | ||
| // TODO: check why in https://github.com/model-checking/rmc/issues/66 | ||
| debug!( | ||
| "WARNING: drop_in_place not found for {:?}", | ||
| self.readable_instance_name(drop_instance), | ||
| ); | ||
| Type::void_pointer().null().cast_to(trait_fn_ty) | ||
| // We skip an entire submodule of the standard library, so drop is missing | ||
| // for it. | ||
| self.codegen_unimplemented( | ||
|
||
| format!("drop_in_place for {}", drop_sym_name).as_str(), | ||
| trait_fn_ty, | ||
| Location::none(), | ||
| "https://github.com/model-checking/rmc/issues/281", | ||
| ) | ||
| } | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -99,27 +99,74 @@ impl<'tcx> GotocCtx<'tcx> { | |
| // TODO: this function doesn't handle unwinding which begins if the destructor panics | ||
| // https://github.com/model-checking/rmc/issues/221 | ||
| fn codegen_drop(&mut self, location: &Place<'tcx>, target: &BasicBlock) -> Stmt { | ||
| // instance for drop function | ||
| let loc_ty = self.place_ty(location); | ||
| let instance = Instance::resolve_drop_in_place(self.tcx, loc_ty); | ||
| if let Some(hk) = self.hooks.hook_applies(self.tcx, instance) { | ||
| let drop_instance = Instance::resolve_drop_in_place(self.tcx, loc_ty); | ||
| if let Some(hk) = self.hooks.hook_applies(self.tcx, drop_instance) { | ||
|
||
| let le = self.codegen_place(location).goto_expr; | ||
| hk.handle(self, instance, vec![le], None, Some(*target), None) | ||
| hk.handle(self, drop_instance, vec![le], None, Some(*target), None) | ||
| } else { | ||
| let drop_implementation = match instance.def { | ||
| InstanceDef::Virtual(..) => self | ||
| .codegen_unimplemented( | ||
| "drop_in_place for dynamic argument", | ||
| Type::Empty, | ||
| Location::none(), | ||
| "https://github.com/model-checking/rmc/issues/11", | ||
| ) | ||
| .as_stmt(Location::none()), | ||
| InstanceDef::DropGlue(..) => Stmt::skip(Location::none()), | ||
| let drop_implementation = match drop_instance.def { | ||
| InstanceDef::DropGlue(_, None) => { | ||
| // We can skip empty DropGlue functions | ||
| Stmt::skip(Location::none()) | ||
| } | ||
| _ => { | ||
| let func = self.codegen_func_expr(instance, None); | ||
| func.call(vec![self.codegen_place(location).goto_expr.address_of()]) | ||
| .as_stmt(Location::none()) | ||
| match loc_ty.kind() { | ||
| ty::Dynamic(..) => { | ||
| // Virtual drop via a vtable lookup | ||
| let trait_fat_ptr = | ||
| self.codegen_place(location).fat_ptr_goto_expr.unwrap(); | ||
|
|
||
| // Pull the function off of the fat pointer's vtable pointer | ||
| let vtable_ref = | ||
| trait_fat_ptr.to_owned().member("vtable", &self.symbol_table); | ||
| let vtable = vtable_ref.dereference(); | ||
| let fn_ptr = vtable.member("drop", &self.symbol_table); | ||
|
|
||
| // Pull the self argument off of the fat pointer's data pointer | ||
| let self_ref = | ||
| trait_fat_ptr.to_owned().member("data", &self.symbol_table); | ||
| let self_ref = | ||
| self_ref.cast_to(trait_fat_ptr.typ().clone().to_pointer()); | ||
|
|
||
| let func_exp: Expr = fn_ptr.dereference(); | ||
| func_exp.call(vec![self_ref]).as_stmt(Location::none()) | ||
| } | ||
| _ => { | ||
| // Non-virtual, direct drop call | ||
| assert!(!matches!(drop_instance.def, InstanceDef::Virtual(_, _))); | ||
|
||
|
|
||
| let func = self.codegen_func_expr(drop_instance, None); | ||
| let place = self.codegen_place(location); | ||
| let arg = if let Some(fat_ptr) = place.fat_ptr_goto_expr { | ||
| // Drop takes the fat pointer if it exists | ||
|
||
| fat_ptr | ||
| } else { | ||
| place.goto_expr.address_of() | ||
| }; | ||
| // The only argument should be a self reference | ||
| let args = vec![arg]; | ||
|
|
||
| // We have a known issue where nested Arc and Mutex objects result in | ||
| // drop_in_place call implementations that fail to typecheck. Skipping | ||
| // drop entirely causes unsound verification results in common cases | ||
| // like vector extend, so for now, add a sound special case workaround | ||
| // for calls that fail the typecheck. | ||
| // https://github.com/model-checking/rmc/issues/426 | ||
| // Unblocks: https://github.com/model-checking/rmc/issues/435 | ||
| if Expr::typecheck_call(&func, &args) { | ||
| func.call(args) | ||
| } else { | ||
| self.codegen_unimplemented( | ||
| format!("drop_in_place call for {:?}", func).as_str(), | ||
| func.typ().return_type().unwrap().clone(), | ||
| Location::none(), | ||
| "https://github.com/model-checking/rmc/issues/426", | ||
| ) | ||
| } | ||
| .as_stmt(Location::none()) | ||
| } | ||
| } | ||
| } | ||
| }; | ||
| let goto_target = Stmt::goto(self.current_fn().find_label(target), Location::none()); | ||
|
|
@@ -310,7 +357,7 @@ impl<'tcx> GotocCtx<'tcx> { | |
| // should be a fat pointer for the trait | ||
| let trait_fat_ptr = fargs[0].to_owned(); | ||
|
|
||
| //Check the Gotoc-level fat pointer type | ||
| // Check the Gotoc-level fat pointer type | ||
| assert!(trait_fat_ptr.typ().is_rust_trait_fat_ptr(&self.symbol_table)); | ||
|
|
||
| self.codegen_virtual_funcall( | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
| // SPDX-License-Identifier: Apache-2.0 OR MIT | ||
|
|
||
| // Check drop implementation for a boxed dynamic trait object. | ||
|
|
||
| include!("../../rmc-prelude.rs"); | ||
|
|
||
| static mut CELL: i32 = 0; | ||
|
|
||
| trait T { | ||
| fn t(&self) {} | ||
| } | ||
|
|
||
| struct Concrete1; | ||
|
|
||
| impl T for Concrete1 {} | ||
|
|
||
| impl Drop for Concrete1 { | ||
| fn drop(&mut self) { | ||
| unsafe { | ||
| CELL = 1; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| struct Concrete2; | ||
|
|
||
| impl T for Concrete2 {} | ||
|
|
||
| impl Drop for Concrete2 { | ||
| fn drop(&mut self) { | ||
| unsafe { | ||
| CELL = 2; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| fn main() { | ||
| { | ||
| let x: Box<dyn T>; | ||
| if __nondet() { | ||
| x = Box::new(Concrete1 {}); | ||
| } else { | ||
| x = Box::new(Concrete2 {}); | ||
| } | ||
| } | ||
| unsafe { | ||
| assert!(CELL == 1 || CELL == 2); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
| // SPDX-License-Identifier: Apache-2.0 OR MIT | ||
|
|
||
| // Check drop implementation for a concrete, non-trait object. | ||
|
|
||
| static mut CELL: i32 = 0; | ||
|
|
||
| struct Concrete1; | ||
|
|
||
| impl Drop for Concrete1 { | ||
| fn drop(&mut self) { | ||
| unsafe { | ||
| CELL = 1; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| fn main() { | ||
| { | ||
| let _x1 = Concrete1 {}; | ||
| } | ||
| unsafe { | ||
| assert!(CELL == 1); | ||
| } | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.