Skip to content

Warn about Box::from_raw::<c_void> #9679

@andreubotella

Description

@andreubotella

What it does

Often in FFI, some APIs will take *c_void or *mut c_void to indicate arbitrary objects from the caller side. When interacting with such APIs in Rust it is common to allocate something with {Box,Rc,Arc}::into_raw and then casting the raw pointer. For deallocating you often get the c_void pointer back from the FFI API and you would turn it into the corresponding owned/shared pointer with {Box,Rc,Arc}::from_raw, after which you can drop it.

However, it is easy to run into the pitfall of calling from_raw with the c_void pointer. Note that the definition of, say, Box::from_raw is:

pub unsafe fn from_raw(raw: *mut T) -> Box<T>

meaning that if you pass a *mut c_void you will get a Box<c_void>. Per the safety requirements in the documentation, for this to be safe, c_void would need to have the same memory layout as the original type, which is often not the case. And even if it was the case, if the original type or one of its fields (or one of its fields, recursively) had a Drop implementation, that implementation would not run when this newly recreated box is dropped. (And similarly for Rc and Arc.)

While it is possible to purposefully create a Box<c_void>, it's hard to see any case where it would be useful. Therefore, uses of Box::from_raw::<c_void> can be safely assumed to be a mistake, and clippy should have a lint for it.

Lint Name

from-raw-cvoid

Category

No response

Advantage

  • Remove an easy pitfall of FFI, particularly with some C or C++ APIs.

Drawbacks

  • Might conflict with genuine usages of Box<c_void>, but those are incredibly rare, and not good practice.

Example

use std::ffi::c_void;

let ptr = Box::into_raw(Box::new(42usize)) as *mut c_void;
// pass `ptr` through C FFI or something.
let _ = unsafe { Box::from_raw(ptr) };

Could be written as:

use std::ffi::c_void;

let ptr = Box::into_raw(Box::new(42usize)) as *mut c_void;
// pass `ptr` through C FFI or something.
let _ = unsafe { Box::from_raw(ptr as *mut usize) };

Metadata

Metadata

Assignees

Labels

A-lintArea: New lints

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions