-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Fix or allow all hard clippy errors. #11409
base: master
Are you sure you want to change the base?
Conversation
It looks like @afck signed our Contributor License Agreement. 👍 Many thanks, Parity Technologies CLA Bot |
We could also |
ethash/src/cache.rs
Outdated
@@ -185,6 +185,7 @@ fn make_memmapped_cache(path: &Path, num_nodes: usize, ident: &H256) -> io::Resu | |||
|
|||
let mut memmap = unsafe { MmapMut::map_mut(&file)? }; | |||
|
|||
#[allow(clippy::cast_ptr_alignment)] // TODO: Why is this okay? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should use ptr::read_unaligned instead but it will still be a clippy error see rust-lang/rust-clippy#2881
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm still a bit confused about what's going on here. But it really looks wrong to me:
initialize_memory
internally creates aslice::from_raw_parts_mut
of type&mut [Node]
.MmapMut
does not guarantee alignment, otherwise it wouldn't have analign_to_mut
method.from_raw_parts_mut
explicitly requires the data to be aligned.
read_unaligned
would copy the data: My impression is that most of this code was written as an optimization to avoid copying. If we are fine with copying, we could probably do away with most of the unsafe code here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought mmap is page-aligned http://man7.org/linux/man-pages/man2/mmap.2.html, but maybe @Vurich could provide more input.
MmapMut does not guarantee alignment, otherwise it wouldn't have an align_to_mut method.
This is a method on a slice though (I guess it shows up in the docs, because MapMut
implements Deref
to a slice), which can be arbitrary aligned.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And I agree we should remove unsafe code as much as possible, we have some benchmarks, see e.g. #10861. But let's do it in a separate PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I see! Sorry! 🤦♂️
Then I guess I should just add a comment pointing to the mmap man page? (But what about platforms other than Linux?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought mmap is page-aligned http://man7.org/linux/man-pages/man2/mmap.2.html, but maybe @Vurich could provide more input.
MmapMut does not guarantee alignment, otherwise it wouldn't have an align_to_mut method.
This is a method on a slice though (I guess it shows up in the docs, because
MapMut
implementsDeref
to a slice), which can be arbitrary aligned.
I have been summoned! The link you want is https://pubs.opengroup.org/onlinepubs/9699919799/functions/mmap.html - while on Linux it is defined to be page-aligned, mmap is a POSIX syscall and so on non-Linux POSIX environments it might fail. I'd add an alignment check (with error on fail) here, LLVM has alignment knowledge for libc functions for all architectures it supports so we can rely on it to remove the alignment check where appropriate. I'd be shocked if there are any real-world environments that will return unaligned pointers from mmap but better do the right thing now instead of dealing with a truly nasty bug further down the road.
I made the same mistake while writing this code, of using the Linux docs instead of the POSIX docs.
@@ -83,6 +83,7 @@ impl NodeEndpoint { | |||
let address = match addr_bytes.len() { | |||
4 => Ok(SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(addr_bytes[0], addr_bytes[1], addr_bytes[2], addr_bytes[3]), tcp_port))), | |||
16 => unsafe { | |||
#[allow(clippy::cast_ptr_alignment)] // TODO: Why is this okay? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
well, I'm not super intimate with this piece of code why it is unsafe in the first place but I think it is because we don't want to copy the bytes to perform the conversion [u8; 16] -> [u16; 8]
We could do this in safe rust:
let mut addr = [0_u8; 16];
addr.copy_from_slice(&addr_bytes[0..16]);
Ok(SocketAddr::V6(SocketAddrV6::new(Ipv6Addr::from(addr), tcp_port, 0, 0)))
The unsafe scope could be reduced because only slice::from_raw_parts
is unsafe.
I'm up making it safe, but let's here what the others have to say //cc @ordian @dvdplm
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AFAICT it is not used on any hot paths (on_ping
, on_pong
and on_neighbours
). It is called often, sure, but not so often as to be a performance bottleneck I'd say. On the other hand the code today is, I'd say, safe.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with @niklasad1, we should just replace it with the safe code unless it introduces a perf bottleneck.
ethash/src/cache.rs
Outdated
@@ -265,6 +266,7 @@ fn read_from_path(path: &Path) -> io::Result<Vec<Node>> { | |||
} | |||
|
|||
let out: Vec<Node> = unsafe { | |||
#[allow(clippy::cast_ptr_alignment)] // TODO: Why is this okay? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm, this is a good question, I'm not sure myself about the alignment cc @Vurich
Sorry for the delay! I added alignment checks and removed some unsafe code. |
unsafe { initialize_memory(memmap.as_mut_ptr() as *mut Node, num_nodes, ident) }; | ||
unsafe { | ||
let bytes = memmap.as_mut_ptr(); | ||
assert_eq!(bytes as usize % mem::align_of::<Node>(), 0, "Mmap memory not aligned."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what's the rationale of panicking instead of returning an Error as in the code below?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is there any way to check this at compile-time?
mem::align_of is const fn
please merge with master, that should help with CI |
I rebased on
and:
|
This makes clippy succeed, albeit with lots of warnings.
Co-Authored-By: Niklas Adolfsson <[email protected]>
This would make
cargo clippy
succeed, albeit with lots of warnings.I think the
write
calls are an actual potential bug, since the returned number of written bytes is not handled. (I.e. it would just continue, even if the strings were only partially written.)I'm very unsure about the alignment issues.