@@ -152,3 +152,54 @@ macro_rules! from_kernel_result {
152152 } ) ( ) )
153153 } } ;
154154}
155+
156+ /// Transform a kernel "error pointer" to a normal pointer.
157+ ///
158+ /// Some kernel C API functions return an "error pointer" which optionally
159+ /// embeds an `errno`. Callers are supposed to check the returned pointer
160+ /// for errors. This function performs the check and converts the "error pointer"
161+ /// to a normal pointer in an idiomatic fashion.
162+ ///
163+ /// # Examples
164+ ///
165+ /// ```rust,no_run
166+ /// fn devm_platform_ioremap_resource(
167+ /// pdev: &mut PlatformDevice,
168+ /// index: u32,
169+ /// ) -> Result<*mut c_types::c_void> {
170+ /// // SAFETY: FFI call.
171+ /// unsafe {
172+ /// from_kernel_err_ptr(bindings::devm_platform_ioremap_resource(
173+ /// pdev.to_ptr(),
174+ /// index,
175+ /// ))
176+ /// }
177+ /// }
178+ /// ```
179+ // TODO: remove `dead_code` marker once an in-kernel client is available.
180+ #[ allow( dead_code) ]
181+ pub ( crate ) fn from_kernel_err_ptr < T > ( ptr : * mut T ) -> Result < * mut T > {
182+ extern "C" {
183+ #[ allow( improper_ctypes) ]
184+ fn rust_helper_is_err ( ptr : * const c_types:: c_void ) -> bool ;
185+
186+ #[ allow( improper_ctypes) ]
187+ fn rust_helper_ptr_err ( ptr : * const c_types:: c_void ) -> c_types:: c_long ;
188+ }
189+
190+ // CAST: casting a pointer to `*const c_types::c_void` is always valid.
191+ let const_ptr: * const c_types:: c_void = ptr. cast ( ) ;
192+ // SAFETY: the FFI function does not deref the pointer.
193+ if unsafe { rust_helper_is_err ( const_ptr) } {
194+ // SAFETY: the FFI function does not deref the pointer.
195+ let err = unsafe { rust_helper_ptr_err ( const_ptr) } ;
196+ // CAST: if `rust_helper_is_err()` returns `true`,
197+ // then `rust_helper_ptr_err()` is guaranteed to return a
198+ // negative value greater-or-equal to `-bindings::MAX_ERRNO`,
199+ // which always fits in an `i16`, as per the invariant above.
200+ // And an `i16` always fits in an `i32`. So casting `err` to
201+ // an `i32` can never overflow, and is always valid.
202+ return Err ( Error :: from_kernel_errno ( err as i32 ) ) ;
203+ }
204+ Ok ( ptr)
205+ }
0 commit comments