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:
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user