Skip to content

Commit 191c983

Browse files
committed
Auto merge of #9690 - royrustdev:boxed_void, r=flip1995
add `from_raw_with_void_ptr` lint This PR `fixes #9679` - \[x] Followed [lint naming conventions][lint_naming] - \[x] Added passing UI tests (including committed `.stderr` file) - \[x] `cargo test` passes locally - \[x] Executed `cargo dev update_lints` - \[x] Added lint documentation - \[x] Run `cargo dev fmt` --- changelog: [`from_raw_with_void_ptr`]: added new lint
2 parents 628a79d + b083a39 commit 191c983

10 files changed

+117
-0
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -3903,6 +3903,7 @@ Released 2018-09-13
39033903
[`format_push_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#format_push_string
39043904
[`from_iter_instead_of_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_iter_instead_of_collect
39053905
[`from_over_into`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_over_into
3906+
[`from_raw_with_void_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_raw_with_void_ptr
39063907
[`from_str_radix_10`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_str_radix_10
39073908
[`future_not_send`]: https://rust-lang.github.io/rust-clippy/master/index.html#future_not_send
39083909
[`get_first`]: https://rust-lang.github.io/rust-clippy/master/index.html#get_first
+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
use clippy_utils::diagnostics::span_lint_and_help;
2+
use clippy_utils::path_def_id;
3+
use clippy_utils::ty::is_c_void;
4+
use rustc_hir::{Expr, ExprKind, QPath};
5+
use rustc_lint::{LateContext, LateLintPass};
6+
use rustc_middle::ty::RawPtr;
7+
use rustc_middle::ty::TypeAndMut;
8+
use rustc_session::{declare_lint_pass, declare_tool_lint};
9+
10+
declare_clippy_lint! {
11+
/// ### What it does
12+
/// Checks if we're passing a `c_void` raw pointer to `Box::from_raw(_)`
13+
///
14+
/// ### Why is this bad?
15+
/// However, it is easy to run into the pitfall of calling from_raw with the c_void pointer.
16+
/// Note that the definition of, say, Box::from_raw is:
17+
///
18+
/// `pub unsafe fn from_raw(raw: *mut T) -> Box<T>`
19+
///
20+
/// meaning that if you pass a *mut c_void you will get a Box<c_void>.
21+
/// Per the safety requirements in the documentation, for this to be safe,
22+
/// c_void would need to have the same memory layout as the original type, which is often not the case.
23+
///
24+
/// ### Example
25+
/// ```rust
26+
/// # use std::ffi::c_void;
27+
/// let ptr = Box::into_raw(Box::new(42usize)) as *mut c_void;
28+
/// let _ = unsafe { Box::from_raw(ptr) };
29+
/// ```
30+
/// Use instead:
31+
/// ```rust
32+
/// # use std::ffi::c_void;
33+
/// # let ptr = Box::into_raw(Box::new(42usize)) as *mut c_void;
34+
/// let _ = unsafe { Box::from_raw(ptr as *mut usize) };
35+
/// ```
36+
///
37+
#[clippy::version = "1.66.0"]
38+
pub FROM_RAW_WITH_VOID_PTR,
39+
suspicious,
40+
"creating a `Box` from a raw void pointer"
41+
}
42+
declare_lint_pass!(FromRawWithVoidPtr => [FROM_RAW_WITH_VOID_PTR]);
43+
44+
impl LateLintPass<'_> for FromRawWithVoidPtr {
45+
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
46+
if let ExprKind::Call(box_from_raw, [arg]) = expr.kind
47+
&& let ExprKind::Path(QPath::TypeRelative(ty, seg)) = box_from_raw.kind
48+
&& seg.ident.name == sym!(from_raw)
49+
// FIXME: This lint is also applicable to other types, like `Rc`, `Arc` and `Weak`.
50+
&& path_def_id(cx, ty).map_or(false, |id| Some(id) == cx.tcx.lang_items().owned_box())
51+
&& let arg_kind = cx.typeck_results().expr_ty(arg).kind()
52+
&& let RawPtr(TypeAndMut { ty, .. }) = arg_kind
53+
&& is_c_void(cx, *ty) {
54+
span_lint_and_help(cx, FROM_RAW_WITH_VOID_PTR, expr.span, "creating a `Box` from a raw void pointer", Some(arg.span), "cast this to a pointer of the actual type");
55+
}
56+
}
57+
}

clippy_lints/src/lib.register_all.rs

+1
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
8181
LintId::of(formatting::SUSPICIOUS_ELSE_FORMATTING),
8282
LintId::of(formatting::SUSPICIOUS_UNARY_OP_FORMATTING),
8383
LintId::of(from_over_into::FROM_OVER_INTO),
84+
LintId::of(from_raw_with_void_ptr::FROM_RAW_WITH_VOID_PTR),
8485
LintId::of(from_str_radix_10::FROM_STR_RADIX_10),
8586
LintId::of(functions::DOUBLE_MUST_USE),
8687
LintId::of(functions::MUST_USE_UNIT),

clippy_lints/src/lib.register_lints.rs

+1
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ store.register_lints(&[
173173
formatting::SUSPICIOUS_ELSE_FORMATTING,
174174
formatting::SUSPICIOUS_UNARY_OP_FORMATTING,
175175
from_over_into::FROM_OVER_INTO,
176+
from_raw_with_void_ptr::FROM_RAW_WITH_VOID_PTR,
176177
from_str_radix_10::FROM_STR_RADIX_10,
177178
functions::DOUBLE_MUST_USE,
178179
functions::MUST_USE_CANDIDATE,

clippy_lints/src/lib.register_suspicious.rs

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec!
2121
LintId::of(formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING),
2222
LintId::of(formatting::SUSPICIOUS_ELSE_FORMATTING),
2323
LintId::of(formatting::SUSPICIOUS_UNARY_OP_FORMATTING),
24+
LintId::of(from_raw_with_void_ptr::FROM_RAW_WITH_VOID_PTR),
2425
LintId::of(loops::EMPTY_LOOP),
2526
LintId::of(loops::MUT_RANGE_BOUND),
2627
LintId::of(methods::NO_EFFECT_REPLACE),

clippy_lints/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@ mod format_impl;
230230
mod format_push_string;
231231
mod formatting;
232232
mod from_over_into;
233+
mod from_raw_with_void_ptr;
233234
mod from_str_radix_10;
234235
mod functions;
235236
mod future_not_send;
@@ -918,6 +919,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
918919
store.register_late_pass(|_| Box::new(implicit_saturating_add::ImplicitSaturatingAdd));
919920
store.register_early_pass(|| Box::new(partial_pub_fields::PartialPubFields));
920921
store.register_late_pass(|_| Box::new(missing_trait_methods::MissingTraitMethods));
922+
store.register_late_pass(|_| Box::new(from_raw_with_void_ptr::FromRawWithVoidPtr));
921923
// add lints here, do not remove this comment, it's used in `new_lint`
922924
}
923925

src/docs.rs

+1
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ docs! {
179179
"format_push_string",
180180
"from_iter_instead_of_collect",
181181
"from_over_into",
182+
"from_raw_with_void_ptr",
182183
"from_str_radix_10",
183184
"future_not_send",
184185
"get_first",

src/docs/from_raw_with_void_ptr.txt

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
### What it does
2+
Checks if we're passing a `c_void` raw pointer to `Box::from_raw(_)`
3+
4+
### Why is this bad?
5+
However, it is easy to run into the pitfall of calling from_raw with the c_void pointer.
6+
Note that the definition of, say, Box::from_raw is:
7+
8+
`pub unsafe fn from_raw(raw: *mut T) -> Box<T>`
9+
10+
meaning that if you pass a *mut c_void you will get a Box<c_void>.
11+
Per the safety requirements in the documentation, for this to be safe,
12+
c_void would need to have the same memory layout as the original type, which is often not the case.
13+
14+
### Example
15+
```
16+
let ptr = Box::into_raw(Box::new(42usize)) as *mut c_void;
17+
let _ = unsafe { Box::from_raw(ptr) };
18+
```
19+
Use instead:
20+
```
21+
let _ = unsafe { Box::from_raw(ptr as *mut usize) };
22+
```

tests/ui/from_raw_with_void_ptr.rs

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#![warn(clippy::from_raw_with_void_ptr)]
2+
3+
use std::ffi::c_void;
4+
5+
fn main() {
6+
// must lint
7+
let ptr = Box::into_raw(Box::new(42usize)) as *mut c_void;
8+
let _ = unsafe { Box::from_raw(ptr) };
9+
10+
// shouldn't be linted
11+
let _ = unsafe { Box::from_raw(ptr as *mut usize) };
12+
13+
// shouldn't be linted
14+
let should_not_lint_ptr = Box::into_raw(Box::new(12u8)) as *mut u8;
15+
let _ = unsafe { Box::from_raw(should_not_lint_ptr as *mut u8) };
16+
}
+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error: creating a `Box` from a raw void pointer
2+
--> $DIR/from_raw_with_void_ptr.rs:8:22
3+
|
4+
LL | let _ = unsafe { Box::from_raw(ptr) };
5+
| ^^^^^^^^^^^^^^^^^^
6+
|
7+
help: cast this to a pointer of the actual type
8+
--> $DIR/from_raw_with_void_ptr.rs:8:36
9+
|
10+
LL | let _ = unsafe { Box::from_raw(ptr) };
11+
| ^^^
12+
= note: `-D clippy::from-raw-with-void-ptr` implied by `-D warnings`
13+
14+
error: aborting due to previous error
15+

0 commit comments

Comments
 (0)