refactor(ffi): return null ptr instead of aborting in C API (#2478)
Make C API functions that return pointers return null in case of a panic, instead of aborting. Add ffi_fn! macro rules that enable default error values to be returned by writing "?= <value>" after an ffi function's body.
This commit is contained in:
		| @@ -34,7 +34,7 @@ ffi_fn! { | ||||
|     /// If not configured, this body acts as an empty payload. | ||||
|     fn hyper_body_new() -> *mut hyper_body { | ||||
|         Box::into_raw(Box::new(hyper_body(Body::empty()))) | ||||
|     } | ||||
|     } ?= ptr::null_mut() | ||||
| } | ||||
|  | ||||
| ffi_fn! { | ||||
| @@ -66,7 +66,7 @@ ffi_fn! { | ||||
|         Box::into_raw(hyper_task::boxed(async move { | ||||
|             body.0.data().await.map(|res| res.map(hyper_buf)) | ||||
|         })) | ||||
|     } | ||||
|     } ?= ptr::null_mut() | ||||
| } | ||||
|  | ||||
| ffi_fn! { | ||||
| @@ -97,7 +97,7 @@ ffi_fn! { | ||||
|             } | ||||
|             Ok(()) | ||||
|         })) | ||||
|     } | ||||
|     } ?= ptr::null_mut() | ||||
| } | ||||
|  | ||||
| ffi_fn! { | ||||
| @@ -198,7 +198,7 @@ ffi_fn! { | ||||
|             std::slice::from_raw_parts(buf, len) | ||||
|         }; | ||||
|         Box::into_raw(Box::new(hyper_buf(Bytes::copy_from_slice(slice)))) | ||||
|     } | ||||
|     } ?= ptr::null_mut() | ||||
| } | ||||
|  | ||||
| ffi_fn! { | ||||
| @@ -211,7 +211,7 @@ ffi_fn! { | ||||
|     /// consumed/freed. | ||||
|     fn hyper_buf_bytes(buf: *const hyper_buf) -> *const u8 { | ||||
|         unsafe { (*buf).0.as_ptr() } | ||||
|     } | ||||
|     } ?= ptr::null() | ||||
| } | ||||
|  | ||||
| ffi_fn! { | ||||
|   | ||||
| @@ -57,7 +57,7 @@ ffi_fn! { | ||||
|                     hyper_clientconn { tx } | ||||
|                 }) | ||||
|         })) | ||||
|     } | ||||
|     } ?= std::ptr::null_mut() | ||||
| } | ||||
|  | ||||
| ffi_fn! { | ||||
| @@ -85,7 +85,7 @@ ffi_fn! { | ||||
|         }; | ||||
|  | ||||
|         Box::into_raw(hyper_task::boxed(fut)) | ||||
|     } | ||||
|     } ?= std::ptr::null_mut() | ||||
| } | ||||
|  | ||||
| ffi_fn! { | ||||
| @@ -110,7 +110,7 @@ ffi_fn! { | ||||
|             builder: conn::Builder::new(), | ||||
|             exec: WeakExec::new(), | ||||
|         })) | ||||
|     } | ||||
|     } ?= std::ptr::null_mut() | ||||
| } | ||||
|  | ||||
| ffi_fn! { | ||||
|   | ||||
| @@ -37,7 +37,7 @@ ffi_fn! { | ||||
|     /// Construct a new HTTP request. | ||||
|     fn hyper_request_new() -> *mut hyper_request { | ||||
|         Box::into_raw(Box::new(hyper_request(Request::new(Body::empty())))) | ||||
|     } | ||||
|     } ?= std::ptr::null_mut() | ||||
| } | ||||
|  | ||||
| ffi_fn! { | ||||
| @@ -114,7 +114,7 @@ ffi_fn! { | ||||
|     /// `hyper_request` has been consumed. | ||||
|     fn hyper_request_headers(req: *mut hyper_request) -> *mut hyper_headers { | ||||
|         hyper_headers::get_or_default(unsafe { &mut *req }.0.extensions_mut()) | ||||
|     } | ||||
|     } ?= std::ptr::null_mut() | ||||
| } | ||||
|  | ||||
| ffi_fn! { | ||||
| @@ -170,7 +170,7 @@ ffi_fn! { | ||||
|     /// buffer. | ||||
|     fn hyper_response_reason_phrase(resp: *const hyper_response) -> *const u8 { | ||||
|         unsafe { &*resp }.reason_phrase().as_ptr() | ||||
|     } | ||||
|     } ?= std::ptr::null() | ||||
| } | ||||
|  | ||||
| ffi_fn! { | ||||
| @@ -210,7 +210,7 @@ ffi_fn! { | ||||
|     /// `hyper_response` has been freed. | ||||
|     fn hyper_response_headers(resp: *mut hyper_response) -> *mut hyper_headers { | ||||
|         hyper_headers::get_or_default(unsafe { &mut *resp }.0.extensions_mut()) | ||||
|     } | ||||
|     } ?= std::ptr::null_mut() | ||||
| } | ||||
|  | ||||
| ffi_fn! { | ||||
| @@ -220,7 +220,7 @@ ffi_fn! { | ||||
|     fn hyper_response_body(resp: *mut hyper_response) -> *mut hyper_body { | ||||
|         let body = std::mem::take(unsafe { &mut *resp }.0.body_mut()); | ||||
|         Box::into_raw(Box::new(hyper_body(body))) | ||||
|     } | ||||
|     } ?= std::ptr::null_mut() | ||||
| } | ||||
|  | ||||
| impl hyper_response { | ||||
|   | ||||
| @@ -37,7 +37,7 @@ ffi_fn! { | ||||
|             write: write_noop, | ||||
|             userdata: std::ptr::null_mut(), | ||||
|         })) | ||||
|     } | ||||
|     } ?= std::ptr::null_mut() | ||||
| } | ||||
|  | ||||
| ffi_fn! { | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| macro_rules! ffi_fn { | ||||
|     ($(#[$doc:meta])* fn $name:ident($($arg:ident: $arg_ty:ty),*) -> $ret:ty $body:block) => { | ||||
|     ($(#[$doc:meta])* fn $name:ident($($arg:ident: $arg_ty:ty),*) -> $ret:ty $body:block ?= $default:expr) => { | ||||
|         $(#[$doc])* | ||||
|         #[no_mangle] | ||||
|         pub extern fn $name($($arg: $arg_ty),*) -> $ret { | ||||
| @@ -8,13 +8,21 @@ macro_rules! ffi_fn { | ||||
|             match panic::catch_unwind(AssertUnwindSafe(move || $body)) { | ||||
|                 Ok(v) => v, | ||||
|                 Err(_) => { | ||||
|                     // TODO: We shouldn't abort, but rather figure out how to | ||||
|                     // convert into the return type that the function errored. | ||||
|                     $default | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     ($(#[$doc:meta])* fn $name:ident($($arg:ident: $arg_ty:ty),*) -> $ret:ty $body:block) => { | ||||
|         ffi_fn!($(#[$doc])* fn $name($($arg: $arg_ty),*) -> $ret $body ?= { | ||||
|             eprintln!("panic unwind caught, aborting"); | ||||
|                     std::process::abort(); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|             std::process::abort() | ||||
|         }); | ||||
|     }; | ||||
|  | ||||
|     ($(#[$doc:meta])* fn $name:ident($($arg:ident: $arg_ty:ty),*) $body:block ?= $default:expr) => { | ||||
|         ffi_fn!($(#[$doc])* fn $name($($arg: $arg_ty),*) -> () $body ?= $default); | ||||
|     }; | ||||
|  | ||||
|     ($(#[$doc:meta])* fn $name:ident($($arg:ident: $arg_ty:ty),*) $body:block) => { | ||||
|   | ||||
| @@ -92,5 +92,5 @@ ffi_fn! { | ||||
|     /// Returns a static ASCII (null terminated) string of the hyper version. | ||||
|     fn hyper_version() -> *const libc::c_char { | ||||
|         VERSION_CSTR.as_ptr() as _ | ||||
|     } | ||||
|     } ?= std::ptr::null() | ||||
| } | ||||
|   | ||||
| @@ -189,7 +189,7 @@ ffi_fn! { | ||||
|     /// Creates a new task executor. | ||||
|     fn hyper_executor_new() -> *const hyper_executor { | ||||
|         Arc::into_raw(hyper_executor::new()) | ||||
|     } | ||||
|     } ?= ptr::null() | ||||
| } | ||||
|  | ||||
| ffi_fn! { | ||||
| @@ -230,7 +230,7 @@ ffi_fn! { | ||||
|             Some(task) => Box::into_raw(task), | ||||
|             None => ptr::null_mut(), | ||||
|         } | ||||
|     } | ||||
|     } ?= ptr::null_mut() | ||||
| } | ||||
|  | ||||
| // ===== impl hyper_task ===== | ||||
| @@ -303,7 +303,7 @@ ffi_fn! { | ||||
|         } else { | ||||
|             ptr::null_mut() | ||||
|         } | ||||
|     } | ||||
|     } ?= ptr::null_mut() | ||||
| } | ||||
|  | ||||
| ffi_fn! { | ||||
| @@ -341,7 +341,7 @@ ffi_fn! { | ||||
|         } | ||||
|  | ||||
|         unsafe { &*task }.userdata.0 | ||||
|     } | ||||
|     } ?= ptr::null_mut() | ||||
| } | ||||
|  | ||||
| // ===== impl AsTaskType ===== | ||||
| @@ -405,7 +405,7 @@ ffi_fn! { | ||||
|     fn hyper_context_waker(cx: *mut hyper_context<'_>) -> *mut hyper_waker { | ||||
|         let waker = unsafe { &mut *cx }.0.waker().clone(); | ||||
|         Box::into_raw(Box::new(hyper_waker { waker })) | ||||
|     } | ||||
|     } ?= ptr::null_mut() | ||||
| } | ||||
|  | ||||
| // ===== impl hyper_waker ===== | ||||
|   | ||||
		Reference in New Issue
	
	Block a user