diff --git a/core/embed/rust/src/micropython/buffer.rs b/core/embed/rust/src/micropython/buffer.rs index 8d44136651..498f0082a2 100644 --- a/core/embed/rust/src/micropython/buffer.rs +++ b/core/embed/rust/src/micropython/buffer.rs @@ -31,6 +31,19 @@ impl StrBuffer { Self::from("") } + // SAFETY: + // Caller is responsible for ensuring that data under `ptr` is valid for the + // whole lifetime of the result, plus possible copies/clones/offsets. + // This generally holds for GC-managed pointers and for static data. + // Dangerous with anything else. + pub unsafe fn from_ptr_and_len(ptr: *const u8, len: usize) -> Self { + Self { + ptr, + len: unwrap!(len.try_into()), + off: 0, + } + } + pub fn alloc(val: &str) -> Result { unsafe { Self::alloc_with(val.len(), |buffer| { @@ -63,11 +76,8 @@ impl StrBuffer { // Null-terminate the string for C ASCIIZ compatibility. This will not be // reflected in Rust-visible slice, the zero byte is after the end. raw.add(len).write(0); - Ok(Self { - ptr: raw, - len: unwrap!(len.try_into()), - off: 0, - }) + // SAFETY: pointer is GC-managed. + Ok(Self::from_ptr_and_len(raw, len)) } } @@ -107,11 +117,8 @@ impl TryFrom for StrBuffer { fn try_from(obj: Obj) -> Result { if obj.is_str() { let bufinfo = get_buffer_info(obj, ffi::MP_BUFFER_READ)?; - let new = Self { - ptr: bufinfo.buf as _, - len: bufinfo.len.try_into()?, - off: 0, - }; + // SAFETY: bufinfo.buf should point to a GC head pointer or static data. + let new = unsafe { Self::from_ptr_and_len(bufinfo.buf as _, bufinfo.len) }; // MicroPython _should_ ensure that values of type `str` are UTF-8. // Rust seems to be stricter in what it considers UTF-8 though. @@ -151,11 +158,9 @@ impl AsRef for StrBuffer { impl From<&'static str> for StrBuffer { fn from(val: &'static str) -> Self { - Self { - ptr: val.as_ptr(), - len: unwrap!(val.len().try_into()), - off: 0, - } + // SAFETY: Safe for &'static strs. + // Do not try to do it with arbitrary &'a str. + unsafe { Self::from_ptr_and_len(val.as_ptr(), val.len()) } } }