From 5cbe1e6767d11aff3f14c7ad69a06b04e8d583c7 Mon Sep 17 00:00:00 2001 From: Andreas Molzer Date: Thu, 12 Nov 2020 13:05:34 +0100 Subject: [PATCH] Fix assembling mutable slice from const reference The pointer from which a mutable reference is created must have provenance for accessing the underlying elements of the struct and its fields (a single array here) mutably. A pointer acquired by slice::as_ptr does not have that provenance, it only allows shared read access. The `slice::as_ptr` method says: > 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, use as_mut_ptr. This fails MIRI which checks for this assertion but I'm not aware of mis-compilation resulting from it. In fact, consider: pub fn as_ptr(slice: &mut [u8]) -> *const u8 { slice.as_ptr() } pub fn as_mut_ptr(slice: &mut [u8]) -> *mut u8 { slice.as_mut_ptr() } Then llvm-IR in optimization will show that the functions are collapsed to a single one, hinting there is no semantic difference at that level. The difference in codegen is a readonly attribute on the slice::as_ptr argument but this is scoped to the particular function and argument, not the pointer value itself: > On a function, this attribute indicates that the function does not write through any pointer arguments Since the _outer_ function correctly takes a `&mut self` argument the restriction possibly no longer applies to our own method. Of course, a stricter codegen of Rust's memory model might not be as kind and exploit the MIR level UB here. --- src/color.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/color.rs b/src/color.rs index 3677473dc8..771e43fc1b 100644 --- a/src/color.rs +++ b/src/color.rs @@ -253,7 +253,7 @@ impl Pixel for $ident { } fn from_slice_mut(slice: &mut [T]) -> &mut $ident { assert_eq!(slice.len(), $channels); - unsafe { &mut *(slice.as_ptr() as *mut $ident) } + unsafe { &mut *(slice.as_mut_ptr() as *mut $ident) } } fn to_rgb(&self) -> Rgb {