Vec::as_ptr()
contains the following nicely worded warning:
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 derived from it. If you need to mutate the contents of the slice, useas_mut_ptr
.
So I'm asking, am I really not allowed to write into it?
Of course there is an invariant here. The question is, is it a safety invariant or a validity invariant?
If it is a validity invariant (aka language UB), writing to the pointer is never safe, under any circumstances.
However, if this is a safety invariant, things get more complicated.
The standard library reserves the right to escalate a safety invariant to a validity invariant. I'm asking whether it can do that in this case too.
In other words, if I write into the pointer, but I always restore back the original value(s), and I promise to never call any Vec
methods before I do that - do I still have UB?
The documentation also says:
This method guarantees that for the purpose of the aliasing model, this method does not materialize a reference to the underlying slice, and thus the returned pointer will remain valid when mixed with other calls to
as_ptr
andas_mut_ptr
. Note that calling other methods that materialize mutable references to the slice, or mutable references to specific elements you are planning on accessing through this pointer, as well as writing to those elements, may still invalidate this pointer. See the second example below for how this guarantee can be used.
Which makes me think that this cannot be a validity invariant, but I'm not sure if this is guaranteed.
Context: I'm implementing a pycall!()
macro to conveniently call Python functions in the context of PyO3. This macro has the ability to unpack an iterable (or multiple iterables) into a call, and act as if all of the iterable's items were passed one-by-one (similar to unpacking in Python calls). I specialize unpacking for single slice/vec to pass the arguments directly without doing any conversion.
Now, Python has the nice flag called PY_VECTORCALL_ARGUMENTS_OFFSET
, that if added to a call, means that the interpreter is allowed to modify (but promises to restore) args[-1]
, or args[0]
in the case of a method call. This can help with the performance of bound method.
Now, in case of a function, I obviously cannot allow Python to modify args[-1]
, since I have no idea what's in there. But in case of a method, args[0]
is under my control. If I am passed a mutable reference (to a slice or a Vec
), everything is fine. If I am passed a shared reference to a slice, I cannot modify it, that will be language UB. But the question is, what happens if I am passed a shared reference of a Vec
?
This is exactly this question. Am I allowed to modify the pointer resulted from Vec::as_ptr()
?