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

Correctly construct Region to uphold deallocation safety invariant #2062

Merged
merged 6 commits into from
Mar 21, 2024

Conversation

aumetra
Copy link
Member

@aumetra aumetra commented Mar 19, 2024

Closes #2061

To cite from the comments of the patch:

Shrinking the buffer down to the length is important to uphold a safety invariant by the dealloc method.
Passing in a differing size into the dealloc layout is considered undefined behaviour.

See: https://doc.rust-lang.org/stable/alloc/alloc/trait.GlobalAlloc.html#safety-2

@webmaster128
Copy link
Member

Yeah, I now understand why this fix is correct, thank you! However, this will create a pointless clone of the data in many cases. I think there are two potential other ways to address it:

  1. Don't call build_region(&buffer) but create a region of the entire buffer capacity
  2. We only have this problem when buffers are created by the contract and then destroyed by the VM (see fn call_raw<A, S, Q>). But the whole instance.deallocate(res_region_ptr)?;is pointless because we dropinstance` one line later. This is like cleaning the house before demolishing it.

@aumetra
Copy link
Member Author

aumetra commented Mar 20, 2024

Don't call build_region(&buffer) but create a region of the entire buffer capacity

Since all of the logic is private, I felt free to update the API of build_region.
Instead of taking a raw byte slice, it now takes something that implements the new unsafe trait RegionSource which is, by default, implemented for &[u8] and Vec<u8>.

The trait exposes the function capacity which has to, as documented in the trait safety section, return the full capacity of the memory region.
I wanna change the trait a bit, but yeah, this is roughly what I envisioned.

And testing against the latest nightly compiler, it fixes it.

@aumetra
Copy link
Member Author

aumetra commented Mar 20, 2024

The AsRef<[u8]> bound was very Vec<u8> centric since other types which might implement this API only point to a sub-region of the allocated memory with a different starting pointer and so on and so forth..

So this is a better API.

@aumetra aumetra force-pushed the aw/fix-dealloc-ub branch from 140549b to c688732 Compare March 20, 2024 09:58
@aumetra aumetra changed the title Shrink buffer down to length to uphold safety invariant Correctly construct Region to uphold deallocation safety invariant Mar 20, 2024
Copy link
Member

@webmaster128 webmaster128 left a comment

Choose a reason for hiding this comment

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

That's beautiful, thanks!

packages/std/src/memory.rs Outdated Show resolved Hide resolved
packages/std/src/memory.rs Outdated Show resolved Hide resolved
S: RegionSource,
{
// Well, this technically violates pointer provenance rules.
// But there isn't a stable API for it, so that's the best we can do, I guess.
Copy link
Member

Choose a reason for hiding this comment

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

Which provenance rules are you referring to?

The whole memory module is wasm32 only, such that we know

  • The memory is a Wasm linear memory where memory can be addressed by offsets
  • usize is 32 bit long

Copy link
Member Author

@aumetra aumetra Mar 21, 2024

Choose a reason for hiding this comment

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

Yeah, makes sense, but it's just internally a bunch of hints for the compiler and miri.
It contains stuff like the address space, address, and some other metadata which a usize can technically not accurately represent since it's just a pointer somewhere in memory.

It's technically just an experiment but they also wanna explore if it makes sense for the compiler to enforce provenance at some point AFAIK.

https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance

But as the docs say

The following text is non-normative, insufficiently formal, and is an extremely strict interpretation of provenance. It’s ok if your code doesn’t strictly conform to it.

Just something that was on my mind and I commented in ¯\_(ツ)_/¯
We can remove the comment, too.

Copy link
Member

Choose a reason for hiding this comment

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

Thanks, all good, no worries. I was just not sure if there is anything practically relevant we need to be careful of.

aumetra and others added 2 commits March 21, 2024 10:01
Co-authored-by: Simon Warta <2603011+webmaster128@users.noreply.github.com>
@aumetra aumetra marked this pull request as ready for review March 21, 2024 09:06
@aumetra aumetra requested a review from webmaster128 March 21, 2024 11:04
Copy link
Member

@webmaster128 webmaster128 left a comment

Choose a reason for hiding this comment

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

Sweet! Could you add a CHANGELOG entry for this?

S: RegionSource,
{
// Well, this technically violates pointer provenance rules.
// But there isn't a stable API for it, so that's the best we can do, I guess.
Copy link
Member

Choose a reason for hiding this comment

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

Thanks, all good, no worries. I was just not sure if there is anything practically relevant we need to be careful of.

@aumetra
Copy link
Member Author

aumetra commented Mar 21, 2024

Damn it, I always forget the changelog..

@aumetra aumetra force-pushed the aw/fix-dealloc-ub branch from 8db21a0 to e0f963d Compare March 21, 2024 11:40
@aumetra
Copy link
Member Author

aumetra commented Mar 21, 2024

I was just not sure if there is anything practically relevant we need to be careful of

No, not really. It's just something they are experimenting with to give the compiler more information about raw pointers.
Because the more info compilers have about the code, the more assumptions they can make, the more optimization tricks they can do (prime example: Fortran)

@aumetra aumetra requested a review from webmaster128 March 21, 2024 12:16
@webmaster128 webmaster128 merged commit 5671d6e into main Mar 21, 2024
29 checks passed
@webmaster128 webmaster128 deleted the aw/fix-dealloc-ub branch March 21, 2024 12:52
@aumetra
Copy link
Member Author

aumetra commented Mar 21, 2024

@Mergifyio backport release/1.5

Copy link
Contributor

mergify bot commented Mar 21, 2024

backport release/1.5

✅ Backports have been created

aumetra added a commit that referenced this pull request Mar 21, 2024
Correctly construct `Region` to uphold deallocation safety invariant (backport #2062)
@aumetra
Copy link
Member Author

aumetra commented Mar 26, 2024

@Mergifyio backport release/2.0

Copy link
Contributor

mergify bot commented Mar 26, 2024

backport release/2.0

✅ Backports have been created

aumetra added a commit that referenced this pull request Mar 26, 2024
Correctly construct `Region` to uphold deallocation safety invariant (backport #2062)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

dealloc error with dlmalloc >= 2.5
2 participants