Uh oh!
There was an error while loading. Please reload this page.
Add as_ptr and as_mut_ptr inherent method to String - #97483
Conversation
rust-highfive
commented
May 28, 2022
Hey! It looks like you've submitted a new PR for the library teams! If this PR contains changes to any Examples of
|
rust-highfive
commented
May 28, 2022
r? @kennytm (rust-highfive has picked a reviewer for you, use r? to override) |
Noratrieb
commented
May 28, 2022
r? rust-lang/libs-api @rustbot label +T-libs-api -T-libs |
Before, they went through `&str` and `&mut str`, which created intermediary references, shrinking provenance to only the initialized parts. `Vec<T>` already has such inherent methods added in rust-lang#61114.
And I just found another case where this would have been helpful, compact_str#100 |
Noratrieb
commented
Jun 8, 2022
@RalfJung you might be interested as well, since you added the method to |
RalfJung
left a comment
There was a problem hiding this comment.
Makes sense to me. However, since this changes the libs API surface, I cannot approve it -- let's wait for the @rust-lang/libs-api team.
| /// Modifying the string may cause its buffer to be reallocated, | ||
| /// which would also make any pointers to it invalid. | ||
| /// | ||
| /// The caller must also ensure that the memory the pointer (non-transitively) points to |
There was a problem hiding this comment.
| /// The caller must also ensure that the memory the pointer (non-transitively) points to | |
| /// The caller must also ensure that the memory the pointer points to |
We know it points to u8 so we don't need the transitivity comment.
| /// which would also make any pointers to it invalid. | ||
| /// | ||
| /// The caller must also ensure that the memory the pointer (non-transitively) points to | ||
| /// is never written to (except inside an `UnsafeCell`) using this pointer or any pointer |
There was a problem hiding this comment.
| /// is never written to (except inside an `UnsafeCell`) using this pointer or any pointer | |
| /// is never written to using this pointer or any pointer |
There is no UnsafeCell here.
I'd definitely prefer if we could merge this unstably, though I'm not sure exactly what that would entail. If it's not much work though I think I'd prefer to gate this change on that functionality since it will help a lot in similar situations going forward. @rust-lang/compiler do y'all know how hard it would be to make it so we could merge this unstably without causing breakage? My guess is we'd need to change method resolution to try all non-nightly methods for all deref targets first before going back and considering resolving the method call with the nightly method which doesn't seem tooooo hard (she says naively). This also feels vaguely related to rust-lang/rfcs#3240 |
joshtriplett
commented
Jul 27, 2022
We discussed this in today's @rust-lang/libs-api meeting. Without suggesting that we have any consensus on the implied provenance handling here, we don't have objections to merging this unstably for now. However, since it doesn't sound like there's a way to do that yet, marking this as blocked. |
joshtriplett
commented
Jul 27, 2022
(Elaborating on the "implied provenance handling": these and the underlying |
I think the PR description understates the impact that this has on the API. I'm hoping that this helps explain all the other implications of implementing fnmain(){letmut s:Vec<u8> = Vec::with_capacity(10);
s.extend(b"hello");let ptr = s.as_ptr();// This pointer stays valid...let other = s.as_mut_ptr();// Across as as_mut_ptr()let v = s;// Across a move of the original containerunsafe{*other = b'b';// And across a write to an aliasing pointerdbg!(*ptr);}letmut s = String::with_capacity(10);
s.push_str("hello");let ptr = s.as_ptr();// This pointer...let other = s.as_mut_ptr();// Is invalidated here (though this case might be fixed, UCG 113)let v = s;// But wouldn't be invalidated here (this invalidates other with field retagging)unsafe{*other = b'b';// We can't even get a pointer to do this without invalidating `ptr`, and we// can't do this write by casting `ptr` because it doesn't have write// permission.dbg!(*ptr);}} |
yaahc
commented
Jul 28, 2022
@Nilstrieb what happens when you apply an |
Noratrieb
commented
Jul 28, 2022
error: an associated function with this name may be added to the standard library in the future
--> compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs:1499:25
|
1499 | vtable_name.as_ptr().cast(),
| ^^^^^^
|
= warning: once this associated item is added to the standard library, the ambiguity may cause an error or change in behavior!
= note:for more information, see issue #48919 <https://github.com/rust-lang/rust/issues/48919>
= help: call with fully qualified syntax `bitflags::core::str::<impl str>::as_ptr(...)` to keep using the current method
= help: add `#![feature(string_as_ptr)]` to the crate attributes to enable `std::string::String::as_ptr` |
davidtwco
commented
Jul 29, 2022
#99898 should enable this to be unblocked :) |
RalfJung
commented
Jul 30, 2022
(Nit: in terms of the Rust specification / abstract machine, they would not return the same values here, but values that differ in provenance. They just erase to the same bit pattern at runtime.) |
RalfJung
commented
Apr 26, 2023
As a possible argument not to have these methods, Tree Borrows makes this pretty much unnecessary -- the code in #106593 is accepted with Tree Borrows. |
It's probably also fair to say that this is something we want to be allowed (at least I would want that :)) |
RalfJung
commented
Apr 26, 2023
Now I worry about whether we can remove these inherent methods from |
Noratrieb
commented
Apr 26, 2023
That is probably lost hope. I guess we can say that they now exist because they are a tiny little less code than the deref path, making compilation faster :D |
Hm, maybe we should open this again, or at least track this in an issue? There are still examples which are UB according to Tree Borrows that we might want to allow: fnmain(){letmut s = String::with_capacity(10);
s.push('x');let ptr = s.as_mut_ptr();unsafe{ ptr.write(0x20)};let _ptr2 = s.as_mut_ptr();// creates a slice that aliases with `ptr`.// That is considered like a read access, and since `ptr` is derived from// a mutable reference such a foreign read access invalidates `ptr`.unsafe{ ptr.write(97)};// UBprintln!("{s:?}");} |
Before, they went through
&strand&mut str, which created intermediary references, shrinking provenance to only the initialized parts.Vec<T>already has such inherent methods added in #61114.beefran into this in beef#47.The docs are mostly copied from
Vec::{as_ptr, as_mut_ptr}, adapting the examples to something better fitting. The implementation simply forwards to the vec methods.I'm not entirely sure what the correct stability attributes are for this, but I think it needs to be insta-stable like the vec methods?