From b3dc199e6af9f6cf4a624082364665acad785697 Mon Sep 17 00:00:00 2001 From: sven-oxionics Date: Thu, 13 Jul 2023 14:05:26 +0100 Subject: [PATCH] Fix panic when receiving empty strings in rpc calls Receiving an empty string in an RPC call currently panics. When `length` is zero, a call to the `alloc` function (as implemented in `artiq/firmware/runtime/session.rs`) returns a null pointer. Constructing a `CMutSlice` from a null pointer panics. A `CMutSlice` consists of a pointer and the length. Rust's documentation of the `core::ptr` module states: "The canonical way to obtain a pointer that is valid for zero-sized accesses is `NonNull::dangling`." This commits adds a check for the length of a string received in an RPC call. Only for lengths greater than zero a memory allocation is performed. For zero-length strings, a dangling pointer is used. Test plan: Invoke the following experiment, which returns an empty string over RPC: ``` class ReturnEmptyString(artiq.experiment.EnvExperiment): def build(self): self.core: Core = self.get_device("core") @kernel def run(self): x = self.do_rpc() print(x) @rpc def do_rpc(self) -> TStr: return "" ``` Signed-off-by: Sven Over (Oxford Ionics) --- artiq/firmware/libproto_artiq/rpc_proto.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/libproto_artiq/rpc_proto.rs b/artiq/firmware/libproto_artiq/rpc_proto.rs index 49b78e633..cc567d7fb 100644 --- a/artiq/firmware/libproto_artiq/rpc_proto.rs +++ b/artiq/firmware/libproto_artiq/rpc_proto.rs @@ -112,8 +112,12 @@ unsafe fn recv_value(reader: &mut R, tag: Tag, data: &mut *mut (), Tag::String | Tag::Bytes | Tag::ByteArray => { consume_value!(CMutSlice, |ptr| { let length = reader.read_u32()? as usize; - *ptr = CMutSlice::new(alloc(length)? as *mut u8, length); - reader.read_exact((*ptr).as_mut())?; + if length > 0 { + *ptr = CMutSlice::new(alloc(length)? as *mut u8, length); + reader.read_exact((*ptr).as_mut())?; + } else { + *ptr = CMutSlice::new(core::ptr::NonNull::::dangling().as_ptr(), 0); + } Ok(()) }) }