-
Notifications
You must be signed in to change notification settings - Fork 22
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fn unaligned_lvl_slice
: Safely encapsulate "unaligned" slices of lvl: &[[u8; 4]]
, as previous accesses were UB
#731
Conversation
…as it removes the padding.
…vl: &[[u8; 4]]`, as previous accesses were UB.
8e3ae3e
to
dc02d18
Compare
fn unaligned_lvl
: Safely encapsulate "unaligned" reads of lvl: &[[u8; 4]]
, as previous accesses were UBfn unaligned_lvl_slice
: Safely encapsulate "unaligned" slices of lvl: &[[u8; 4]]
, as previous accesses were UB
The doc for
Is the sanitizer behaviour something we need to worry about? |
@@ -377,7 +394,7 @@ unsafe fn filter_plane_cols_y<BD: BitDepth>( | |||
dst.offset((x * 4) as isize).cast(), | |||
ls, | |||
hmask.as_mut_ptr(), | |||
lvl[x as usize][0..].as_ptr() as *const [u8; 4], | |||
&lvl[x as usize], |
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.
If enforcing a minimum slice size, this would be something like lvl[x as usize..][..((endy4 - starty4 - 1) as isize * b4_stride + 1) as usize].as_ptr()
. However, index -1
of such as slice can also be read, so more work on slice definitions will be needed. But that's probably outside the scope of this 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.
I was hoping to structure things as, at this point in the code, we don't care about checking the length, as it is up to the inner fn
to correctly bounds check when reading elements. That's of course not true for the asm fn
s, though it will be eventually true (once we make them safe) for the C/Rust fallbacks. If we do check the length eagerly here, the only real safety that gives us in documentation, that is, if we check that the asm fn
claims it will access X elements and here we check for X elements, we check that the actual length matches the docs, but it doesn't enforce anything on the asm. Not sure if that made sense.
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.
Yes, that makes sense. If, down the road, we want the C/Rust fallbacks to check bounds, then we'll probably have to change fn
interfaces to avoid casting to raw pointers and recreating slices in the fallback fn
s? One potential wrinkle here, is that an asm fn
may access memory locations that are different from the corresponding fallback fn
(because asm may read a 128-bit word where the fallback reads a couple 16-bit words; I can't immediately think of a case where that would also apply a write). I don't know whether we need to consider that.
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 can't change the existing fn
ptr args without modifying the asm, which we don't want to do. But what we can do is is pass extra args that asm ignores (which we already do for passing bitdepth_max: c_int
for 8bpc fn
s). So we can split a slice into the ptr and len, pass the len as an extra arg, and then recreate the slice in the fallback C/Rust fn
. Where it will be technically unsafe
, but quite safe in practice.
As for asm fn
s accessing more memory locations than the fallbacks, we could eagerly checks the bounds, but it's still ultimately up to the asm not to access any more than that. It's always going to be inherently very unsafe
.
Hmm, that's a bit worrying. I didn't realize that would ever be done. Let me think about it, and maybe one of those newer nightly methods can help. |
…gn_to` impl with the unstable `.flatten` and `.as_chunks` ported from `std`.
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.
LGTM
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.
yes changes look good!
should the discussion/conclusion around checking the slice length be documented somewhere?
I'm not too hopeful on a quick stabilization of these methods but the benefit of stabilization is mostly aesthetics at this point.
Hmm, perhaps in an issue? It's a concern for all of the |
See:
mod lf_apply
: clean up code and use slices instead of raw pointers #728 (comment)mod lf_apply
: clean up code and use slices instead of raw pointers #728 (comment)The current "unaligned" access of
lvl
, added in #726, and a proposed change in #728, are UB according tomiri
, as they cast&[u8; 3]
and&u8
to&[u8; 4]
, which is an out of bounds read of a borrow. Thisfn unaligned_lvl_slice
helperfn
fixes it and passesmiri
by transmuting (through.align_to
) to a&[u8]
, doing the slice, and then doing a checked cast back to[u8; 4]
. It also does correct bounds checking, as the previous ways were off by one in their bounds checking, as they didn't consider the read of the unaligned part into the next[u8; 4]
. Doing it this way also optimizes just as well as the previous methods.We could also use a dependency like
zerocopy
to encapsulate theunsafe
.align_to
, but as long as these kinds of "unaligned" array reads are a one-off, doing it inline here seems better.Update: Switched to using unstable
fn
s fromstd
that make things fully safe and correct, copied into our codebase for stability.I already figured out how to fix the UB in reviewing #728, so I just went ahead and made the fix independently.