Skip to content

Commit

Permalink
fn dav1d_default_picture_{alloc,release}: Mark unsafe due to raw …
Browse files Browse the repository at this point in the history
…ptr args, but make private and ensure they must be used safely.
  • Loading branch information
kkysen committed Apr 28, 2024
1 parent ac1bd5a commit b045646
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 15 deletions.
11 changes: 2 additions & 9 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,6 @@ use crate::src::mem::rav1d_freep_aligned;
use crate::src::obu::rav1d_parse_obus;
use crate::src::obu::rav1d_parse_sequence_header;
use crate::src::pal::rav1d_pal_dsp_init;
use crate::src::picture::dav1d_default_picture_alloc;
use crate::src::picture::dav1d_default_picture_release;
use crate::src::picture::rav1d_picture_alloc_copy;
use crate::src::picture::PictureFlags;
use crate::src::picture::Rav1dThreadPicture;
Expand Down Expand Up @@ -211,17 +209,12 @@ pub(crate) unsafe fn rav1d_open(c_out: &mut *mut Rav1dContext, s: &Rav1dSettings
(*c).decode_frame_type = s.decode_frame_type;
(*c).cached_error_props = Default::default();
addr_of_mut!((*c).picture_pool).write(Default::default());
if (*c).allocator.alloc_picture_callback == dav1d_default_picture_alloc
&& (*c).allocator.release_picture_callback == dav1d_default_picture_release
{

if (*c).allocator.is_default() {
if !(*c).allocator.cookie.is_null() {
return error(c, c_out);
}
(*c).allocator.cookie = ptr::from_mut(&mut (*c).picture_pool).cast::<c_void>();
} else if (*c).allocator.alloc_picture_callback == dav1d_default_picture_alloc
|| (*c).allocator.release_picture_callback == dav1d_default_picture_release
{
return error(c, c_out);
}
if (::core::mem::size_of::<usize>() as c_ulong) < 8 as c_ulong
&& (s.frame_size_limit).wrapping_sub(1 as c_int as c_uint) >= (8192 * 8192) as c_uint
Expand Down
35 changes: 29 additions & 6 deletions src/picture.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,15 @@ struct MemPoolBuf<T> {
buf: Vec<T>,
}

pub extern "C" fn dav1d_default_picture_alloc(
/// # Safety
///
/// * `p_c` must be from a `&mut Dav1dPicture`.
/// * `cookie` must be from a `&Arc<MemPool<u8>>`.
unsafe extern "C" fn dav1d_default_picture_alloc(
p_c: *mut Dav1dPicture,
cookie: *mut c_void,
) -> Dav1dResult {
// SAFETY: `Rav1dPicAllocator::alloc_picture_callback`'s safety guarantees that `p_c` was a `&mut`.
// SAFETY: Guaranteed by safety preconditions.
let p = unsafe { p_c.read() }.to::<Rav1dPicture>();
let hbd = (p.p.bpc > 8) as c_int;
let aligned_w = p.p.w + 127 & !127;
Expand All @@ -106,7 +110,7 @@ pub extern "C" fn dav1d_default_picture_alloc(
let uv_sz = (uv_stride * (aligned_h >> ss_ver) as isize) as usize;
let pic_size = y_sz + 2 * uv_sz;

// SAFETY: When `Rav1dPicAllocator::alloc_picture_callback == dav1d_default_picture_alloc`, we set `Rav1dPicAllocator::cookie` to an `&Arc<MemPool<u8>>`.
// SAFETY: Guaranteed by safety preconditions.
let pool = unsafe { &*cookie.cast::<Arc<MemPool<u8>>>() };
let pool = pool.clone();
let pic_cap = pic_size + RAV1D_PICTURE_ALIGNMENT;
Expand Down Expand Up @@ -137,7 +141,7 @@ pub extern "C" fn dav1d_default_picture_alloc(
// but this way is simpler and more uniform, especially when we move to slices.
let data = [data0, data1, data2].map(|data| data.as_mut_ptr().cast());

// SAFETY: `Rav1dPicAllocator::alloc_picture_callback`'s safety guarantees that `p_c` was a `&mut`.
// SAFETY: Guaranteed by safety preconditions.
let p_c = unsafe { &mut *p_c };
p_c.stride = stride;
p_c.data = data.map(NonNull::new);
Expand All @@ -149,8 +153,11 @@ pub extern "C" fn dav1d_default_picture_alloc(
Rav1dResult::Ok(()).into()
}

pub extern "C" fn dav1d_default_picture_release(p: *mut Dav1dPicture, _cookie: *mut c_void) {
// SAFETY: `Rav1dPicAllocator::release_picture_callback`'s safety guarantees that `p_c` was a `&mut`.
/// # Safety
///
/// * `p` is from a `&mut Dav1dPicture` initialized by [`dav1d_default_picture_alloc`].
unsafe extern "C" fn dav1d_default_picture_release(p: *mut Dav1dPicture, _cookie: *mut c_void) {
// SAFETY: Guaranteed by safety preconditions.
let p = unsafe { &mut *p };
let buf = p.allocator_data.unwrap().as_ptr();
// SAFETY: `dav1d_default_picture_alloc` stores `Box::into_raw` of a `MemPoolBuf<u8>` in `Dav1dPicture::allocator_data`,
Expand All @@ -164,12 +171,28 @@ impl Default for Rav1dPicAllocator {
fn default() -> Self {
Self {
cookie: ptr::null_mut(),
// SAFETY: `dav1d_default_picture_alloc` requires `p_c` be from a `&mut Dav1dPicture`,
// `Self::alloc_picture_callback` safety preconditions guarantee that.
// `dav1d_default_picture_alloc` also requires that `cookie` be from a `&Arc<MemPool<u8>>`,
// which is set if `Self::is_default()` in `rav1d_open`.
alloc_picture_callback: dav1d_default_picture_alloc,
// SAFETY: `dav1d_default_picture_release` requires `p` be from a `&mut Dav1dPicture`
// initialized by `dav1d_default_picture_alloc`.
// Since these `fn`s are private and we only use them here, that is guaranteed.
release_picture_callback: dav1d_default_picture_release,
}
}
}

impl Rav1dPicAllocator {
pub fn is_default(&self) -> bool {
let alloc = self.alloc_picture_callback == dav1d_default_picture_alloc;
let release = self.release_picture_callback == dav1d_default_picture_release;
assert!(alloc == release); // This should be impossible since these `fn`s are private.
alloc && release
}
}

impl Rav1dPicAllocator {
pub fn alloc_picture_data(
&self,
Expand Down

0 comments on commit b045646

Please sign in to comment.