Sorry, ended up replying to this using my personal email. Sending it again. ————— Hi Benno, > On 17 Jul 2024, at 19:12, Benno Lossin <benno.lossin@xxxxxxxxx> wrote: > > Add examples of good and bad safety documentation. > > There aren't many examples at the moment, as I hope to add more during > discussions, since coming up with examples on my own is very difficult. > > Signed-off-by: Benno Lossin <benno.lossin@xxxxxxxxx> > --- > .../rust/safety-standard/examples.rst | 70 +++++++++++++++++++ > Documentation/rust/safety-standard/index.rst | 23 ++++-- > 2 files changed, 86 insertions(+), 7 deletions(-) > create mode 100644 Documentation/rust/safety-standard/examples.rst > > diff --git a/Documentation/rust/safety-standard/examples.rst b/Documentation/rust/safety-standard/examples.rst > new file mode 100644 > index 000000000000..d66ef3f8954a > --- /dev/null > +++ b/Documentation/rust/safety-standard/examples.rst > @@ -0,0 +1,70 @@ > +.. SPDX-License-Identifier: GPL-2.0 > +.. highlight:: rust > + > +Examples > +======== > + > +Unsound APIs > +------------ > + > +Simple Unsound Function > +*********************** > +:: > + > + struct Data { > + a: usize, > + } > + > + fn access_a(data: *mut Data) -> usize { > + unsafe { (*data).a } > + } > + > +One would normally call this function as follows, which does not trigger UB:: > + > + fn main() { > + let mut d = Data { a: 42 }; > + println!("{}", access_a(&mut d)); > + } > + > +However, a caller could also call it like this, which triggers UB using only safe code:: > + > + fn main() { > + println!("{}", access_a(core::ptr::null_mut())); > + } > + > +And this would result in a dereference of a null pointer. > + > + > +Sound ``unsafe`` Code > +--------------------- > + > +The Importance of the API Boundary > +********************************** > + > +Is the following API sound?:: > + > + fn foo(r: &mut u32) { > + let ptr: *mut u32 = r; > + let val; > + unsafe { > + val = *ptr; > + *ptr = 0; > + } > + } > + > +It better be sound, but one could argue that it is unsound, since one could replace the ptr > +initialization by ``ptr = core::ptr::null_mut()``:: > + > + fn foo(r: &mut u32) { > + let ptr: *mut u32 = core::ptr::null_mut(); > + let val; > + unsafe { > + val = *ptr; > + *ptr = 0; > + } > + } > + > +But this modification is not allowed, since it goes beyond the API boundary of ``foo``. This way > +any ``unsafe`` code that relies on surrounding safe code could be shown to be unsound. Instead one > +should only consider safe code using the API, in this case, there is no way to make the code > +incorrect, since a reference is always valid to dereference during its lifetime. I find this paragraph a bit confusing. Maybe this can be clarified a bit further? — Daniel