diff --git a/include/dav1d/picture.rs b/include/dav1d/picture.rs index 8003d6ec5..a2c1c63b5 100644 --- a/include/dav1d/picture.rs +++ b/include/dav1d/picture.rs @@ -185,9 +185,15 @@ impl Rav1dPictureDataComponentInner { /// # Safety /// - /// As opposed to [`Self::new`], this is safe because `buf` is a `&mut` and thus unique, - /// so it is sound to further subdivide it into disjoint `&mut`s. - pub fn wrap_buf(buf: &mut [BD::Pixel], stride: usize) -> Self { + /// `buf` must outlive the returned [`Self`]. + /// + /// As opposed to [`Self::new`], `buf` is a `&mut`, so it must be unique, + /// so it is sound to further subdivide it into disjoint `&mut`s as long as its lifetime lasts. + /// However, adding proper lifetimes is difficult + /// (see [#1317](https://github.com/memorysafety/rav1d/pull/1317)), + /// so instead we make this an `unsafe` precondition, + /// that `buf` must outlive the returned [`Self`]. + pub unsafe fn wrap_buf(buf: &mut [BD::Pixel], stride: usize) -> Self { let buf = AsBytes::as_bytes_mut(buf); let ptr = NonNull::new(buf.as_mut_ptr()).unwrap(); assert!(ptr.cast::().is_aligned()); @@ -245,9 +251,15 @@ impl Strided for Rav1dPictureDataComponent { } impl Rav1dPictureDataComponent { - pub fn wrap_buf(buf: &mut [BD::Pixel], stride: usize) -> Self { + /// # Safety + /// + /// `buf` must outlive the returned [`Self`]. + /// + /// See [`Rav1dPictureDataComponentInner::wrap_buf`] for more details. + pub unsafe fn wrap_buf(buf: &mut [BD::Pixel], stride: usize) -> Self { Self(DisjointMut::new( - Rav1dPictureDataComponentInner::wrap_buf::(buf, stride), + // SAFETY: Delegated. + unsafe { Rav1dPictureDataComponentInner::wrap_buf::(buf, stride) }, )) } diff --git a/src/recon.rs b/src/recon.rs index 2ef0df76e..5e2ff5854 100644 --- a/src/recon.rs +++ b/src/recon.rs @@ -1779,7 +1779,8 @@ fn mc( ); let stride = 192; Rav1dPictureDataComponentOffset { - data: &Rav1dPictureDataComponent::wrap_buf::(emu_edge_buf, stride), + // SAFETY: Lifetime extension forces `buf` to outlive it. + data: &unsafe { Rav1dPictureDataComponent::wrap_buf::(emu_edge_buf, stride) }, offset: stride * (my != 0) as usize * 3 + (mx != 0) as usize * 3, } } else { @@ -1852,7 +1853,8 @@ fn mc( } let stride = 320; Rav1dPictureDataComponentOffset { - data: &Rav1dPictureDataComponent::wrap_buf::(emu_edge_buf, stride), + // SAFETY: Lifetime extension forces `buf` to outlive it. + data: &unsafe { Rav1dPictureDataComponent::wrap_buf::(emu_edge_buf, stride) }, offset: stride * 3 + 3, } } else { @@ -1920,10 +1922,13 @@ fn obmc( t.b, MaybeTempPixels::NonTemp { dst: Rav1dPictureDataComponentOffset { - data: &Rav1dPictureDataComponent::wrap_buf::( - lap, - ow4 as usize * h_mul as usize, - ), + // SAFETY: Lifetime extension forces `buf` to outlive it. + data: &unsafe { + Rav1dPictureDataComponent::wrap_buf::( + lap, + ow4 as usize * h_mul as usize, + ) + }, offset: 0, }, }, @@ -1968,10 +1973,13 @@ fn obmc( t.b, MaybeTempPixels::NonTemp { dst: Rav1dPictureDataComponentOffset { - data: &Rav1dPictureDataComponent::wrap_buf::( - lap, - ow4 as usize * h_mul as usize, - ), + // SAFETY: Lifetime extension forces `buf` to outlive it. + data: &unsafe { + Rav1dPictureDataComponent::wrap_buf::( + lap, + ow4 as usize * h_mul as usize, + ) + }, offset: 0, }, }, @@ -2056,7 +2064,10 @@ fn warp_affine( ); let stride = 32; Rav1dPictureDataComponentOffset { - data: &Rav1dPictureDataComponent::wrap_buf::(emu_edge_buf, stride), + // SAFETY: Lifetime extension forces `buf` to outlive it. + data: &unsafe { + Rav1dPictureDataComponent::wrap_buf::(emu_edge_buf, stride) + }, offset: stride * 3 + 3, } } else { @@ -3123,7 +3134,10 @@ pub(crate) fn rav1d_recon_b_inter( let tmp = interintra_edge_pal.interintra.buf_mut::(); f.dsp.ipred.intra_pred[m as usize].call( Rav1dPictureDataComponentOffset { - data: &Rav1dPictureDataComponent::wrap_buf::(tmp, 4 * bw4 as usize), + // SAFETY: Lifetime extension forces `buf` to outlive it. + data: &unsafe { + Rav1dPictureDataComponent::wrap_buf::(tmp, 4 * bw4 as usize) + }, offset: 0, }, tl_edge_array, @@ -3407,10 +3421,13 @@ pub(crate) fn rav1d_recon_b_inter( let tmp = interintra_edge_pal.interintra.buf_mut::(); f.dsp.ipred.intra_pred[m as usize].call( Rav1dPictureDataComponentOffset { - data: &Rav1dPictureDataComponent::wrap_buf::( - tmp, - 4 * cbw4 as usize, - ), + // SAFETY: Lifetime extension forces `buf` to outlive it. + data: &unsafe { + Rav1dPictureDataComponent::wrap_buf::( + tmp, + 4 * cbw4 as usize, + ) + }, offset: 0, }, tl_edge_array,