Skip to content
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

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

Merged
merged 1 commit into from Aug 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 4 additions & 2 deletions capi/examples/upload.c
Expand Up @@ -153,8 +153,10 @@ static void print_informational(void *userdata, const hyper_response *resp) {

printf("\nInformational (1xx): %d\n", http_status);

const hyper_buf* headers = hyper_response_headers_raw(resp);
write(1, hyper_buf_bytes(headers), hyper_buf_len(headers));
const hyper_buf *headers = hyper_response_headers_raw(resp);
if (headers) {
write(1, hyper_buf_bytes(headers), hyper_buf_len(headers));
}
}

typedef enum {
Expand Down
18 changes: 5 additions & 13 deletions src/ffi/body.rs
Expand Up @@ -40,11 +40,7 @@ ffi_fn! {
ffi_fn! {
/// Free a `hyper_body *`.
fn hyper_body_free(body: *mut hyper_body) {
if body.is_null() {
return;
}

drop(unsafe { Box::from_raw(body) });
drop(non_null!(Box::from_raw(body) ?= ()));
}
}

Expand All @@ -61,7 +57,7 @@ ffi_fn! {
/// However, it MUST NOT be used or freed until the related task completes.
fn hyper_body_data(body: *mut hyper_body) -> *mut hyper_task {
// This doesn't take ownership of the Body, so don't allow destructor
let mut body = ManuallyDrop::new(unsafe { Box::from_raw(body) });
let mut body = ManuallyDrop::new(non_null!(Box::from_raw(body) ?= ptr::null_mut()));

Box::into_raw(hyper_task::boxed(async move {
body.0.data().await.map(|res| res.map(hyper_buf))
Expand All @@ -81,11 +77,7 @@ ffi_fn! {
///
/// This will consume the `hyper_body *`, you shouldn't use it anymore or free it.
fn hyper_body_foreach(body: *mut hyper_body, func: hyper_body_foreach_callback, userdata: *mut c_void) -> *mut hyper_task {
if body.is_null() {
return ptr::null_mut();
}

let mut body = unsafe { Box::from_raw(body) };
let mut body = non_null!(Box::from_raw(body) ?= ptr::null_mut());
let userdata = UserDataPointer(userdata);

Box::into_raw(hyper_task::boxed(async move {
Expand All @@ -103,7 +95,7 @@ ffi_fn! {
ffi_fn! {
/// Set userdata on this body, which will be passed to callback functions.
fn hyper_body_set_userdata(body: *mut hyper_body, userdata: *mut c_void) {
let b = unsafe { &mut *body };
let b = non_null!(&mut *body ?= ());
b.0.as_ffi_mut().userdata = userdata;
}
}
Expand All @@ -129,7 +121,7 @@ ffi_fn! {
/// If some error has occurred, you can return `HYPER_POLL_ERROR` to abort
/// the body.
fn hyper_body_set_data_func(body: *mut hyper_body, func: hyper_body_data_callback) {
let b = unsafe { &mut *body };
let b = non_null!{ &mut *body ?= () };
b.0.as_ffi_mut().data_func = func;
}
}
Expand Down
35 changes: 11 additions & 24 deletions src/ffi/client.rs
@@ -1,3 +1,4 @@
use std::ptr;
use std::sync::Arc;

use libc::c_int;
Expand Down Expand Up @@ -37,15 +38,8 @@ ffi_fn! {
/// The returned `hyper_task *` must be polled with an executor until the
/// handshake completes, at which point the value can be taken.
fn hyper_clientconn_handshake(io: *mut hyper_io, options: *mut hyper_clientconn_options) -> *mut hyper_task {
if io.is_null() {
return std::ptr::null_mut();
}
if options.is_null() {
return std::ptr::null_mut();
}

let options = unsafe { Box::from_raw(options) };
let io = unsafe { Box::from_raw(io) };
let options = non_null! { Box::from_raw(options) ?= ptr::null_mut() };
let io = non_null! { Box::from_raw(io) ?= ptr::null_mut() };

Box::into_raw(hyper_task::boxed(async move {
options.builder.handshake::<_, crate::Body>(io)
Expand All @@ -66,19 +60,12 @@ ffi_fn! {
/// Returns a task that needs to be polled until it is ready. When ready, the
/// task yields a `hyper_response *`.
fn hyper_clientconn_send(conn: *mut hyper_clientconn, req: *mut hyper_request) -> *mut hyper_task {
if conn.is_null() {
return std::ptr::null_mut();
}
if req.is_null() {
return std::ptr::null_mut();
}

let mut req = unsafe { Box::from_raw(req) };
let mut req = non_null! { Box::from_raw(req) ?= ptr::null_mut() };

// Update request with original-case map of headers
req.finalize_request();

let fut = unsafe { &mut *conn }.tx.send_request(req.0);
let fut = non_null! { &mut *conn ?= ptr::null_mut() }.tx.send_request(req.0);

let fut = async move {
fut.await.map(hyper_response::wrap)
Expand All @@ -91,7 +78,7 @@ ffi_fn! {
ffi_fn! {
/// Free a `hyper_clientconn *`.
fn hyper_clientconn_free(conn: *mut hyper_clientconn) {
drop(unsafe { Box::from_raw(conn) });
drop(non_null! { Box::from_raw(conn) ?= () });
}
}

Expand Down Expand Up @@ -119,7 +106,7 @@ ffi_fn! {
ffi_fn! {
/// Free a `hyper_clientconn_options *`.
fn hyper_clientconn_options_free(opts: *mut hyper_clientconn_options) {
drop(unsafe { Box::from_raw(opts) });
drop(non_null! { Box::from_raw(opts) ?= () });
}
}

Expand All @@ -128,9 +115,9 @@ ffi_fn! {
///
/// This does not consume the `options` or the `exec`.
fn hyper_clientconn_options_exec(opts: *mut hyper_clientconn_options, exec: *const hyper_executor) {
let opts = unsafe { &mut *opts };
let opts = non_null! { &mut *opts ?= () };

let exec = unsafe { Arc::from_raw(exec) };
let exec = non_null! { Arc::from_raw(exec) ?= () };
let weak_exec = hyper_executor::downgrade(&exec);
std::mem::forget(exec);

Expand All @@ -146,7 +133,7 @@ ffi_fn! {
fn hyper_clientconn_options_http2(opts: *mut hyper_clientconn_options, enabled: c_int) -> hyper_code {
#[cfg(feature = "http2")]
{
let opts = unsafe { &mut *opts };
let opts = non_null! { &mut *opts ?= hyper_code::HYPERE_INVALID_ARG };
opts.builder.http2_only(enabled != 0);
hyper_code::HYPERE_OK
}
Expand All @@ -168,7 +155,7 @@ ffi_fn! {
///
/// If enabled, see `hyper_response_headers_raw()` for usage.
fn hyper_clientconn_options_headers_raw(opts: *mut hyper_clientconn_options, enabled: c_int) -> hyper_code {
let opts = unsafe { &mut *opts };
let opts = non_null! { &mut *opts ?= hyper_code::HYPERE_INVALID_ARG };
opts.builder.http1_headers_raw(enabled != 0);
hyper_code::HYPERE_OK
}
Expand Down
6 changes: 3 additions & 3 deletions src/ffi/error.rs
Expand Up @@ -58,14 +58,14 @@ impl hyper_error {
ffi_fn! {
/// Frees a `hyper_error`.
fn hyper_error_free(err: *mut hyper_error) {
drop(unsafe { Box::from_raw(err) });
drop(non_null!(Box::from_raw(err) ?= ()));
}
}

ffi_fn! {
/// Get an equivalent `hyper_code` from this error.
fn hyper_error_code(err: *const hyper_error) -> hyper_code {
unsafe { &*err }.code()
non_null!(&*err ?= hyper_code::HYPERE_INVALID_ARG).code()
}
}

Expand All @@ -80,6 +80,6 @@ ffi_fn! {
let dst = unsafe {
std::slice::from_raw_parts_mut(dst, dst_len)
};
unsafe { &*err }.print_to(dst)
non_null!(&*err ?= 0).print_to(dst)
}
}
40 changes: 23 additions & 17 deletions src/ffi/http_types.rs
Expand Up @@ -48,7 +48,7 @@ ffi_fn! {
ffi_fn! {
/// Free an HTTP request if not going to send it on a client.
fn hyper_request_free(req: *mut hyper_request) {
drop(unsafe { Box::from_raw(req) });
drop(non_null!(Box::from_raw(req) ?= ()));
}
}

Expand All @@ -58,9 +58,10 @@ ffi_fn! {
let bytes = unsafe {
std::slice::from_raw_parts(method, method_len as usize)
};
let req = non_null!(&mut *req ?= hyper_code::HYPERE_INVALID_ARG);
match Method::from_bytes(bytes) {
Ok(m) => {
*unsafe { &mut *req }.0.method_mut() = m;
*req.0.method_mut() = m;
hyper_code::HYPERE_OK
},
Err(_) => {
Expand All @@ -76,9 +77,10 @@ ffi_fn! {
let bytes = unsafe {
std::slice::from_raw_parts(uri, uri_len as usize)
};
let req = non_null!(&mut *req ?= hyper_code::HYPERE_INVALID_ARG);
match Uri::from_maybe_shared(bytes) {
Ok(u) => {
*unsafe { &mut *req }.0.uri_mut() = u;
*req.0.uri_mut() = u;
hyper_code::HYPERE_OK
},
Err(_) => {
Expand All @@ -98,7 +100,8 @@ ffi_fn! {
fn hyper_request_set_version(req: *mut hyper_request, version: c_int) -> hyper_code {
use http::Version;

*unsafe { &mut *req }.0.version_mut() = match version {
let req = non_null!(&mut *req ?= hyper_code::HYPERE_INVALID_ARG);
*req.0.version_mut() = match version {
super::HYPER_HTTP_VERSION_NONE => Version::HTTP_11,
super::HYPER_HTTP_VERSION_1_0 => Version::HTTP_10,
super::HYPER_HTTP_VERSION_1_1 => Version::HTTP_11,
Expand Down Expand Up @@ -130,8 +133,9 @@ ffi_fn! {
/// This takes ownership of the `hyper_body *`, you must not use it or
/// free it after setting it on the request.
fn hyper_request_set_body(req: *mut hyper_request, body: *mut hyper_body) -> hyper_code {
let body = unsafe { Box::from_raw(body) };
*unsafe { &mut *req }.0.body_mut() = body.0;
let body = non_null!(Box::from_raw(body) ?= hyper_code::HYPERE_INVALID_ARG);
let req = non_null!(&mut *req ?= hyper_code::HYPERE_INVALID_ARG);
*req.0.body_mut() = body.0;
hyper_code::HYPERE_OK
}
}
Expand All @@ -157,7 +161,8 @@ ffi_fn! {
func: callback,
data: UserDataPointer(data),
};
unsafe { &mut *req }.0.extensions_mut().insert(ext);
let req = non_null!(&mut *req ?= hyper_code::HYPERE_INVALID_ARG);
req.0.extensions_mut().insert(ext);
hyper_code::HYPERE_OK
}
}
Expand All @@ -176,7 +181,7 @@ impl hyper_request {
ffi_fn! {
/// Free an HTTP response after using it.
fn hyper_response_free(resp: *mut hyper_response) {
drop(unsafe { Box::from_raw(resp) });
drop(non_null!(Box::from_raw(resp) ?= ()));
}
}

Expand All @@ -185,7 +190,7 @@ ffi_fn! {
///
/// It will always be within the range of 100-599.
fn hyper_response_status(resp: *const hyper_response) -> u16 {
unsafe { &*resp }.0.status().as_u16()
non_null!(&*resp ?= 0).0.status().as_u16()
}
}

Expand All @@ -200,7 +205,7 @@ ffi_fn! {
/// Use `hyper_response_reason_phrase_len()` to get the length of this
/// buffer.
fn hyper_response_reason_phrase(resp: *const hyper_response) -> *const u8 {
unsafe { &*resp }.reason_phrase().as_ptr()
non_null!(&*resp ?= std::ptr::null()).reason_phrase().as_ptr()
} ?= std::ptr::null()
}

Expand All @@ -209,7 +214,7 @@ ffi_fn! {
///
/// Use `hyper_response_reason_phrase()` to get the buffer pointer.
fn hyper_response_reason_phrase_len(resp: *const hyper_response) -> size_t {
unsafe { &*resp }.reason_phrase().len()
non_null!(&*resp ?= 0).reason_phrase().len()
}
}

Expand All @@ -226,7 +231,8 @@ ffi_fn! {
/// The buffer is not null-terminated, see the `hyper_buf` functions for
/// getting the bytes and length.
fn hyper_response_headers_raw(resp: *const hyper_response) -> *const hyper_buf {
match unsafe { &*resp }.0.extensions().get::<RawHeaders>() {
let resp = non_null!(&*resp ?= std::ptr::null());
match resp.0.extensions().get::<RawHeaders>() {
Some(raw) => &raw.0,
None => std::ptr::null(),
}
Expand All @@ -245,7 +251,7 @@ ffi_fn! {
fn hyper_response_version(resp: *const hyper_response) -> c_int {
use http::Version;

match unsafe { &*resp }.0.version() {
match non_null!(&*resp ?= 0).0.version() {
Version::HTTP_10 => super::HYPER_HTTP_VERSION_1_0,
Version::HTTP_11 => super::HYPER_HTTP_VERSION_1_1,
Version::HTTP_2 => super::HYPER_HTTP_VERSION_2,
Expand All @@ -269,7 +275,7 @@ ffi_fn! {
///
/// It is safe to free the response even after taking ownership of its body.
fn hyper_response_body(resp: *mut hyper_response) -> *mut hyper_body {
let body = std::mem::take(unsafe { &mut *resp }.0.body_mut());
let body = std::mem::take(non_null!(&mut *resp ?= std::ptr::null_mut()).0.body_mut());
Box::into_raw(Box::new(hyper_body(body)))
} ?= std::ptr::null_mut()
}
Expand Down Expand Up @@ -331,7 +337,7 @@ ffi_fn! {
/// The callback should return `HYPER_ITER_CONTINUE` to keep iterating, or
/// `HYPER_ITER_BREAK` to stop.
fn hyper_headers_foreach(headers: *const hyper_headers, func: hyper_headers_foreach_callback, userdata: *mut c_void) {
let headers = unsafe { &*headers };
let headers = non_null!(&*headers ?= ());
// For each header name/value pair, there may be a value in the casemap
// that corresponds to the HeaderValue. So, we iterator all the keys,
// and for each one, try to pair the originally cased name with the value.
Expand Down Expand Up @@ -366,7 +372,7 @@ ffi_fn! {
///
/// This overwrites any previous value set for the header.
fn hyper_headers_set(headers: *mut hyper_headers, name: *const u8, name_len: size_t, value: *const u8, value_len: size_t) -> hyper_code {
let headers = unsafe { &mut *headers };
let headers = non_null!(&mut *headers ?= hyper_code::HYPERE_INVALID_ARG);
match unsafe { raw_name_value(name, name_len, value, value_len) } {
Ok((name, value, orig_name)) => {
headers.headers.insert(&name, value);
Expand All @@ -384,7 +390,7 @@ ffi_fn! {
/// If there were already existing values for the name, this will append the
/// new value to the internal list.
fn hyper_headers_add(headers: *mut hyper_headers, name: *const u8, name_len: size_t, value: *const u8, value_len: size_t) -> hyper_code {
let headers = unsafe { &mut *headers };
let headers = non_null!(&mut *headers ?= hyper_code::HYPERE_INVALID_ARG);

match unsafe { raw_name_value(name, name_len, value, value_len) } {
Ok((name, value, orig_name)) => {
Expand Down
8 changes: 4 additions & 4 deletions src/ffi/io.rs
Expand Up @@ -46,7 +46,7 @@ ffi_fn! {
/// This is typically only useful if you aren't going to pass ownership
/// of the IO handle to hyper, such as with `hyper_clientconn_handshake()`.
fn hyper_io_free(io: *mut hyper_io) {
drop(unsafe { Box::from_raw(io) });
drop(non_null!(Box::from_raw(io) ?= ()));
}
}

Expand All @@ -55,7 +55,7 @@ ffi_fn! {
///
/// This value is passed as an argument to the read and write callbacks.
fn hyper_io_set_userdata(io: *mut hyper_io, data: *mut c_void) {
unsafe { &mut *io }.userdata = data;
non_null!(&mut *io ?= ()).userdata = data;
}
}

Expand All @@ -77,7 +77,7 @@ ffi_fn! {
/// If there is an irrecoverable error reading data, then `HYPER_IO_ERROR`
/// should be the return value.
fn hyper_io_set_read(io: *mut hyper_io, func: hyper_io_read_callback) {
unsafe { &mut *io }.read = func;
non_null!(&mut *io ?= ()).read = func;
}
}

Expand All @@ -96,7 +96,7 @@ ffi_fn! {
/// If there is an irrecoverable error reading data, then `HYPER_IO_ERROR`
/// should be the return value.
fn hyper_io_set_write(io: *mut hyper_io, func: hyper_io_write_callback) {
unsafe { &mut *io }.write = func;
non_null!(&mut *io ?= ()).write = func;
}
}

Expand Down