Hey there, I'm doing some FFI code and noticed &mut CStr
does not have a as_mut_ptr
method like &mut str
does.
What exactly are you trying to do? Any writes to an &mut CStr
would have to ensure that the length of the C string doesn't change as &mut CStr
is a fat pointer consisting of both a pointer to the string itself and a usize
containing the length of the C string. If the FFI code modifies the length, you would get UB.
I'm not writing the length, nor am I giving direct access to &CStr
to the C code, I'm just giving a *mut i8
pointer to code I'm 100% sure does not modify the string but did not annotate as such. C is opposite to Rust in the sense that it is mutable by default, so some code out there probably does not modify the string content, but it does not tell that using the type system.
For context, CString
has a into_raw
that consumes itself and returns a mut pointer. What I'm doing currently, is turning a CString
into a Pin<Box<CStr>>
, hence why I need to get a *mut i8
from a &mut CStr
If you're certain that the FFI code does not modify the string, then you can .as_ptr() as *mut c_char
just fine. If the FFI code will not ever mutate the string, then requiring &mut
access is overly restrictive and not a correct wrapping of the call in the first place.
Pin
does nothing in this situation. CStr
is Unpin
, thus Pin<Box<CStr>>
is no different from Box<CStr>
.
If you're certain that the FFI code does not modify the string, then you can
.as_ptr() as *mut c_char
just fine.
My point is, it does not make sense to allow CString
-> * mut c_char
but disallow CString
-> Box<CStr>
-> *mut c_char
. Regardless of my problem at hand, you should be allow to get a *mut c_char
from a &mut CStr
. At least for Box<CStr>
, it should be possible, because it is an owned pointer.
Pin
does nothing in this situation.CStr
isUnpin
, thusPin<Box<CStr>>
is no different fromBox<CStr>
.
I'm still getting my head around what Pin
means. Even if the type is Unpin
, shouldn't Pin
guarantee it's not moved in memory?
CString
-> *mut c_char
consumes the CString
, so there's nothing that remembers the length. You could technically do the same for Box<CStr>
-> *mut c_char
, but the reasoning doesn't hold for &mut CStr
because you still have the CStr
even after turning it into a pointer.
No, Unpin
is defined as being implemented by "Types that can be safely moved after being pinned.". It effectively cancels the effect of Pin
.
CString
does have an essentially no-op impl From<Box<CStr, Global>>
, so maybe you could just do CString::from(boxed).into_raw()
?
Is the possibility of writing a 0-byte within it the only issue with a mutable CStr
? That is, could we have a safe &mut CStr -> &mut [NonZeroU8]
(which doesn't include the nul-terminator)? Clearly the current API is exclusively geared towards non-mutable uses, as there's no way to use a &mut CStr
and the only way to get one is from a Box<CStr>
.
This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.