refactor(ffi): check pointer arguments for NULL (#2624)

This changes all the extern C functions in `hyper::ffi` to check passed
pointer arguments for being `NULL` before trying to use them. Before, we
would just assume the programmer had passed a good pointer, which could
result in segmentation faults. Now:

- In debug builds, it will assert they aren't null, and so if they are,
  a message identifying the argument name will be printed and then the
  process will crash.
- In release builds, it will still check for null, but if found, it will
  return early, with a return value indicating failure if the return type
  allows (such as returning NULL, or `HYPERE_INVALID_ARG`).

Closes #2620
This commit is contained in:
Sean McArthur
2021-08-18 14:15:14 -07:00
committed by GitHub
parent c35153998e
commit 3b26572876
8 changed files with 85 additions and 93 deletions

View File

@@ -195,7 +195,7 @@ ffi_fn! {
ffi_fn! {
/// Frees an executor and any incomplete tasks still part of it.
fn hyper_executor_free(exec: *const hyper_executor) {
drop(unsafe { Arc::from_raw(exec) });
drop(non_null!(Arc::from_raw(exec) ?= ()));
}
}
@@ -205,11 +205,8 @@ ffi_fn! {
/// The executor takes ownership of the task, it should not be accessed
/// again unless returned back to the user with `hyper_executor_poll`.
fn hyper_executor_push(exec: *const hyper_executor, task: *mut hyper_task) -> hyper_code {
if exec.is_null() || task.is_null() {
return hyper_code::HYPERE_INVALID_ARG;
}
let exec = unsafe { &*exec };
let task = unsafe { Box::from_raw(task) };
let exec = non_null!(&*exec ?= hyper_code::HYPERE_INVALID_ARG);
let task = non_null!(Box::from_raw(task) ?= hyper_code::HYPERE_INVALID_ARG);
exec.spawn(task);
hyper_code::HYPERE_OK
}
@@ -223,9 +220,7 @@ ffi_fn! {
///
/// If there are no ready tasks, this returns `NULL`.
fn hyper_executor_poll(exec: *const hyper_executor) -> *mut hyper_task {
// We only want an `&Arc` in here, so wrap in a `ManuallyDrop` so we
// don't accidentally trigger a ref_dec of the Arc.
let exec = unsafe { &*exec };
let exec = non_null!(&*exec ?= ptr::null_mut());
match exec.poll_next() {
Some(task) => Box::into_raw(task),
None => ptr::null_mut(),
@@ -274,7 +269,7 @@ impl Future for TaskFuture {
ffi_fn! {
/// Free a task.
fn hyper_task_free(task: *mut hyper_task) {
drop(unsafe { Box::from_raw(task) });
drop(non_null!(Box::from_raw(task) ?= ()));
}
}
@@ -286,11 +281,7 @@ ffi_fn! {
///
/// Use `hyper_task_type` to determine the type of the `void *` return value.
fn hyper_task_value(task: *mut hyper_task) -> *mut c_void {
if task.is_null() {
return ptr::null_mut();
}
let task = unsafe { &mut *task };
let task = non_null!(&mut *task ?= ptr::null_mut());
if let Some(val) = task.output.take() {
let p = Box::into_raw(val) as *mut c_void;
@@ -309,13 +300,9 @@ ffi_fn! {
ffi_fn! {
/// Query the return type of this task.
fn hyper_task_type(task: *mut hyper_task) -> hyper_task_return_type {
if task.is_null() {
// instead of blowing up spectacularly, just say this null task
// doesn't have a value to retrieve.
return hyper_task_return_type::HYPER_TASK_EMPTY;
}
unsafe { &*task }.output_type()
// instead of blowing up spectacularly, just say this null task
// doesn't have a value to retrieve.
non_null!(&*task ?= hyper_task_return_type::HYPER_TASK_EMPTY).output_type()
}
}
@@ -336,11 +323,7 @@ ffi_fn! {
ffi_fn! {
/// Retrieve the userdata that has been set via `hyper_task_set_userdata`.
fn hyper_task_userdata(task: *mut hyper_task) -> *mut c_void {
if task.is_null() {
return ptr::null_mut();
}
unsafe { &*task }.userdata.0
non_null!(&*task ?= ptr::null_mut()).userdata.0
} ?= ptr::null_mut()
}
@@ -403,7 +386,7 @@ impl hyper_context<'_> {
ffi_fn! {
/// Copies a waker out of the task context.
fn hyper_context_waker(cx: *mut hyper_context<'_>) -> *mut hyper_waker {
let waker = unsafe { &mut *cx }.0.waker().clone();
let waker = non_null!(&mut *cx ?= ptr::null_mut()).0.waker().clone();
Box::into_raw(Box::new(hyper_waker { waker }))
} ?= ptr::null_mut()
}
@@ -413,7 +396,7 @@ ffi_fn! {
ffi_fn! {
/// Free a waker that hasn't been woken.
fn hyper_waker_free(waker: *mut hyper_waker) {
drop(unsafe { Box::from_raw(waker) });
drop(non_null!(Box::from_raw(waker) ?= ()));
}
}
@@ -422,7 +405,7 @@ ffi_fn! {
///
/// NOTE: This consumes the waker. You should not use or free the waker afterwards.
fn hyper_waker_wake(waker: *mut hyper_waker) {
let waker = unsafe { Box::from_raw(waker) };
let waker = non_null!(Box::from_raw(waker) ?= ());
waker.waker.wake();
}
}