@@ -152,3 +152,54 @@ macro_rules! from_kernel_result {
152
152
} ) ( ) )
153
153
} } ;
154
154
}
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