TL;DR: Adding an automatic marker type (one that can’t be externally implemented with current features) would remove unsafety from a significant source of unsafe{} blocks today.
Hello, I’ve only been playing with Rust for a few weeks, but I’ve noticed a certain unsafe pattern that can easily be made safe with just a tiny bit of compiler grease.
In low level/embedded/OS code, it is not uncommon to define #repr(C)
structures that are used to interpret external data, e.g. I/O-mapped memory areas, or even files when you can depend on endianness being native to the machine. Unsafe blocks are simply used to cast references.
Obviously, this includes a number of pitfalls. Some rust types cannot contain arbitrary bit patterns (bool, enum, references, etc.), and while most Rust programmers should know that, it’s inevitable some people coming from C will unknowingly invoke undefined behavior with this. Additionally, casting pointers around comes with alignment issues, which even less people would consider when writing unsafe code.
I wrote a tiny crate to alleviate said issues: https://github.com/randomites/plain
The gist of it is that when you know certain set of assumptions holds for type T
(#repr(C)
, all bit patterns being valid, not being a Drop
type, perhaps also that all contents are public – note that these requirements are strictly stronger than those of Copy
), then you can perform conversions between &T
and &[u8]
without ever using unsafe
blocks yourself. The wrapper functions just check size and alignment, and restrictions on T
make sure safe code can’t do anything unsafe with those references.
In the current crate, plain::Plain
is an unsafe trait that you have to unsafely apply to types you work with. However, in theory, it should be quite easy to add trait core::marker::Plain
(name subject to discussion), and let compiler automatically derive it for admissible types, similar to how Send
and Sync
are currently handled.
Doing this would remove a notable source of unsafety in low-level code.
In case this proposal needs an RFC, I’m absolutely willing to write it up, but I’d need guidance from someone more experienced.
EDIT: Added non-Drop
to the list of requirements.