Open teskje opened 4 years ago
I thought about the use of StableDeref
a bit more. The guarantees it provides with regard to DerefMut
are a bit hard to grasp. For example, Vec
implements StableDeref
, even though it can re-allocate if you push to it. My understanding is that the stable address guarantee for DerefMut
types only holds as long as you don't call &mut self
methods on the type itself. But the documentation doesn't explicitly state that.
Let's take a step back. Here is what I gather are the minimum requirements a generic safe DMA buffer type has to fulfill:
Transfer
struct and move around with it on the stack, which we cannot allow (see 3).Requirements 2 and 3 must be true even if we take mem::forget
into account: If the Transfer
is mem::forget
ten, we won't be able to stop the DMA since the destructor is not run. So the buffer needs to stay valid and stable afterwards.
Looking at the types StableDeref
is implemented for out of the box, it looks like all of them fulfill the above requirements. So provided I'm not missing an essential requirement above, using StableDeref
for DMA buffers should be fine. In fact, it seems to be exactly what we need in terms of guarantees.
It appears that the DMA API described in Chapter 8 - DMA is unsafe.
Consider this example. It is basically the motivating example from the "Immovable buffers" section, but with the complete
read_exact
API from the end of the chapter, includingPin
ing and the'static
bound. The example shows that it is still possible to pass a stack-allocated array into this (supposedly safe)read_exact
function, which means the DMA operation will corrupt the stack. All you need to do is wrap the array in a newtype and implDerefMut
for it.I believe the root of the issue is a misunderstanding of the
Pin
API. Contrary to intuition,Pin
does in most cases not pin the pointed-to data in memory: If the target type implementsUnpin
,Pin
does nothing at all:Basically all types we care about implement
Unpin
(I believe only self-referential types are supposed not to?). Which meansPin
ing the buffer passed into the DMA doesn't help us make the code safe.The DMA chapter also mentions the
StableDeref
trait as an alternative. As far as I see, using this would actually lead to a safe API, so we should change the chapter accordingly.