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

Drop for dynamic objects #402

Merged
merged 3 commits into from
Aug 30, 2021

Conversation

avanhatt
Copy link
Contributor

@avanhatt avanhatt commented Aug 6, 2021

Description of changes:

RMC does not current codegen calls to drop for dynamic objects. This PR does that, inserting vtable calls as necessary.

Resolved issues:

Resolves #66
Should also resolve #435

Call-outs:

  • Known issue with the SizeAndAlignOfDst tests. This patch has a workaround to insert a codegen_unimplemented call in the case that drop fails to typecheck, which maintains soundness (the current implementation is not sound because it does not call drop at all).

Testing:

  • How is this change tested?

Existing plus 7 new regressions.

  • Is this a refactor change?

Not really.

Checklist

  • Each commit message has a non-empty body, explaining why the change was made
  • Methods or procedures are documented
  • Regression or unit tests are included, or existing tests cover the modified code
  • My PR is restricted to a single feature or bugfix

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses.

@avanhatt avanhatt changed the base branch from main-154-2021-08-02 to main-154-2021-08-06 August 6, 2021 19:14
@avanhatt avanhatt force-pushed the dyn-drop branch 2 times, most recently from db28d0b to bb160fc Compare August 11, 2021 13:47
@avanhatt avanhatt changed the title (draft) Drop for dynamic objects Drop for dynamic objects Aug 16, 2021
@avanhatt avanhatt marked this pull request as ready for review August 16, 2021 14:38
@avanhatt avanhatt changed the base branch from main-154-2021-08-06 to main-154-2021-08-17 August 19, 2021 13:13
let type_from_mir = ctx.codegen_ty(t);
if expr_ty != type_from_mir { Some((expr_ty, type_from_mir)) } else { None }
}
TypeOrVariant::Variant(_) => None, //TODO, what to do here?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to create an issue for this ? Not sure if this is tracked somewhere..

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added

@avanhatt avanhatt force-pushed the dyn-drop branch 3 times, most recently from 15388e3 to 671b741 Compare August 24, 2021 13:33
format!("drop_in_place for {}", drop_sym_name).as_str(),
trait_fn_ty,
Location::none(),
"https://github.com/model-checking/rmc/issues/202",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this the right link? #202

Copy link
Contributor Author

@avanhatt avanhatt Aug 25, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops no it should actually be #281.

The problem is when we skip functions in should_skip_current_fn, the thing we're skipping could be a drop that's called elsewhere. #202 is the first function we skip but bridge::client, #281, is where we actually see it

self.readable_instance_name(drop_instance),
);
Type::void_pointer().null().cast_to(trait_fn_ty)
self.codegen_unimplemented(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this typecheck? We want a pointer to an unimplemented function, and instead we're getting an unimplemented function that returns a fn pointer.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does type check, we cast to the same type in the if case. I don't think we have any unit tests that hit this, only the standard library regression.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The issue is that this code is called in a constructor, so it will always fail at CBMC time (which is sound, but not helpful). I think what we want is to make a function whose body is unimplemented, and put a pointer to that function into the vtable.

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) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we still need the hook here? Or could we just move its logic inside the regular codegen?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without it, we fail on:

failures:
    [expected] expected/replace-hashmap/main.rs
    [expected] expected/replace-vec/main.rs

}
_ => {
// Non-virtual, direct drop call
assert!(!matches!(drop_instance.def, InstanceDef::Virtual(_, _)));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we assert this above? Would that be a better check than matching on loc_ty.kind()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The conditional doesn't work as a check, because asserting the inverse in the dynamic case fails whenever the instance def is InstanceDef::DropGlue instead of ::Virtual. This structure also matches how the Cranelift backend handles this case.

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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would be in the case of dropping a slice?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We've also seen it be a fat pointer to a nested dynamic object.

let _nested: Box<dyn Send> = Box::new(x);
}
unsafe {
assert!(CELL == 2); // Should fail
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use the expect_fail macro

@danielsn danielsn changed the base branch from main-154-2021-08-17 to main-154-2021-08-24 August 25, 2021 18:04
@danielsn danielsn merged commit ef758e2 into model-checking:main-154-2021-08-24 Aug 30, 2021
@avanhatt avanhatt deleted the dyn-drop branch September 14, 2021 15:23
tedinski pushed a commit to tedinski/rmc that referenced this pull request Apr 22, 2022
tedinski pushed a commit to tedinski/rmc that referenced this pull request Apr 25, 2022
tedinski pushed a commit to tedinski/rmc that referenced this pull request Apr 26, 2022
tedinski pushed a commit that referenced this pull request Apr 27, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants