Log trait missing unsafe
Description
The Log trait in the log crate is used to mark a type as loggable. It requires the implementer to provide the implementation of (at least) write_with_args, which takes a buffer of MaybeUninit<u8> and parameters relevant for logging. It then returns the amount of bytes that it had written to.
/// Trait to specify the log behavior for a type.
pub trait Log {
#[inline(always)]
fn debug(&self, buffer: &mut [MaybeUninit<u8>]) -> usize {
self.debug_with_args(buffer, &[])
}
#[inline(always)]
fn debug_with_args(&self, buffer: &mut [MaybeUninit<u8>], args: &[Argument]) -> usize {
self.write_with_args(buffer, args)
}
#[inline(always)]
fn write(&self, buffer: &mut [MaybeUninit<u8>]) -> usize {
self.write_with_args(buffer, &[])
}
! fn write_with_args(&self, buffer: &mut [MaybeUninit<u8>], parameters: &[Argument]) -> usize;
}This buffer, passed from the Logger struct, is ultimately then read from to log the message.
The implementation of write_with_args has memory safety implications. If a usize is returned that does not accurately reflect the number of bytes consecutively written to the buffer, this can result in undefined behavior by reading from an uninitialized MaybeUninit<u8>. In Rust, if the implementation of a trait can result in undefined behavior, it must be marked with unsafe to communicate in the type signature that the implication of this trait has memory safety implications.
Impact
Undefined behavior can result from an incorrect implementation of Log, despite the trait not being an unsafe trait. This could result in reading uninitialized memory in otherwise safe Rust.
Recommendations
Either mark Log as unsafe, or change the signature to use &[u8].