Skip to content

Commit de87e83

Browse files
committed
Auto merge of #9700 - andreubotella:from-raw-with-void-non-box, r=flip1995
Update `from_raw_with_void_ptr` to support types other than `Box` This PR updates the `from_raw_with_void_ptr` lint, which covered `Box::from_raw`, to also cover the `from_raw` static method of the `Rc`, `Arc`, `alloc::rc::Weak` and `alloc::sync::Weak` types. It also improves the description and error messages of this lint. --- changelog: [`from_raw_with_void_ptr`]: Now works with the `Rc`, `Arc`, `alloc::rc::Weak` and `alloc::sync::Weak` types.
2 parents 6f16596 + e49cde7 commit de87e83

File tree

3 files changed

+105
-19
lines changed

3 files changed

+105
-19
lines changed
Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,22 @@
11
use clippy_utils::diagnostics::span_lint_and_help;
2-
use clippy_utils::path_def_id;
32
use clippy_utils::ty::is_c_void;
3+
use clippy_utils::{match_def_path, path_def_id, paths};
4+
use rustc_hir::def_id::DefId;
45
use rustc_hir::{Expr, ExprKind, QPath};
56
use rustc_lint::{LateContext, LateLintPass};
67
use rustc_middle::ty::RawPtr;
78
use rustc_middle::ty::TypeAndMut;
89
use rustc_session::{declare_lint_pass, declare_tool_lint};
10+
use rustc_span::sym;
911

1012
declare_clippy_lint! {
1113
/// ### What it does
12-
/// Checks if we're passing a `c_void` raw pointer to `Box::from_raw(_)`
14+
/// Checks if we're passing a `c_void` raw pointer to `{Box,Rc,Arc,Weak}::from_raw(_)`
1315
///
1416
/// ### 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.
17+
/// When dealing with `c_void` raw pointers in FFI, it is easy to run into the pitfall of calling `from_raw` with the `c_void` pointer.
18+
/// The type signature of `Box::from_raw` is `fn from_raw(raw: *mut T) -> Box<T>`, so if you pass a `*mut c_void` you will get a `Box<c_void>` (and similarly for `Rc`, `Arc` and `Weak`).
19+
/// 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.
2320
///
2421
/// ### Example
2522
/// ```rust
@@ -37,7 +34,7 @@ declare_clippy_lint! {
3734
#[clippy::version = "1.66.0"]
3835
pub FROM_RAW_WITH_VOID_PTR,
3936
suspicious,
40-
"creating a `Box` from a raw void pointer"
37+
"creating a `Box` from a void raw pointer"
4138
}
4239
declare_lint_pass!(FromRawWithVoidPtr => [FROM_RAW_WITH_VOID_PTR]);
4340

@@ -46,12 +43,35 @@ impl LateLintPass<'_> for FromRawWithVoidPtr {
4643
if let ExprKind::Call(box_from_raw, [arg]) = expr.kind
4744
&& let ExprKind::Path(QPath::TypeRelative(ty, seg)) = box_from_raw.kind
4845
&& 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())
46+
&& let Some(type_str) = path_def_id(cx, ty).and_then(|id| def_id_matches_type(cx, id))
5147
&& let arg_kind = cx.typeck_results().expr_ty(arg).kind()
5248
&& let RawPtr(TypeAndMut { ty, .. }) = arg_kind
5349
&& 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");
50+
let msg = format!("creating a `{type_str}` from a void raw pointer");
51+
span_lint_and_help(cx, FROM_RAW_WITH_VOID_PTR, expr.span, &msg, Some(arg.span), "cast this to a pointer of the appropriate type");
52+
}
53+
}
54+
}
55+
56+
/// Checks whether a `DefId` matches `Box`, `Rc`, `Arc`, or one of the `Weak` types.
57+
/// Returns a static string slice with the name of the type, if one was found.
58+
fn def_id_matches_type(cx: &LateContext<'_>, def_id: DefId) -> Option<&'static str> {
59+
// Box
60+
if Some(def_id) == cx.tcx.lang_items().owned_box() {
61+
return Some("Box");
62+
}
63+
64+
if let Some(symbol) = cx.tcx.get_diagnostic_name(def_id) {
65+
if symbol == sym::Arc {
66+
return Some("Arc");
67+
} else if symbol == sym::Rc {
68+
return Some("Rc");
5569
}
5670
}
71+
72+
if match_def_path(cx, def_id, &paths::WEAK_RC) || match_def_path(cx, def_id, &paths::WEAK_ARC) {
73+
Some("Weak")
74+
} else {
75+
None
76+
}
5777
}

tests/ui/from_raw_with_void_ptr.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#![warn(clippy::from_raw_with_void_ptr)]
22

33
use std::ffi::c_void;
4+
use std::rc::Rc;
5+
use std::sync::Arc;
46

57
fn main() {
68
// must lint
@@ -13,4 +15,20 @@ fn main() {
1315
// shouldn't be linted
1416
let should_not_lint_ptr = Box::into_raw(Box::new(12u8)) as *mut u8;
1517
let _ = unsafe { Box::from_raw(should_not_lint_ptr as *mut u8) };
18+
19+
// must lint
20+
let ptr = Rc::into_raw(Rc::new(42usize)) as *mut c_void;
21+
let _ = unsafe { Rc::from_raw(ptr) };
22+
23+
// must lint
24+
let ptr = Arc::into_raw(Arc::new(42usize)) as *mut c_void;
25+
let _ = unsafe { Arc::from_raw(ptr) };
26+
27+
// must lint
28+
let ptr = std::rc::Weak::into_raw(Rc::downgrade(&Rc::new(42usize))) as *mut c_void;
29+
let _ = unsafe { std::rc::Weak::from_raw(ptr) };
30+
31+
// must lint
32+
let ptr = std::sync::Weak::into_raw(Arc::downgrade(&Arc::new(42usize))) as *mut c_void;
33+
let _ = unsafe { std::sync::Weak::from_raw(ptr) };
1634
}
Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,63 @@
1-
error: creating a `Box` from a raw void pointer
2-
--> $DIR/from_raw_with_void_ptr.rs:8:22
1+
error: creating a `Box` from a void raw pointer
2+
--> $DIR/from_raw_with_void_ptr.rs:10:22
33
|
44
LL | let _ = unsafe { Box::from_raw(ptr) };
55
| ^^^^^^^^^^^^^^^^^^
66
|
7-
help: cast this to a pointer of the actual type
8-
--> $DIR/from_raw_with_void_ptr.rs:8:36
7+
help: cast this to a pointer of the appropriate type
8+
--> $DIR/from_raw_with_void_ptr.rs:10:36
99
|
1010
LL | let _ = unsafe { Box::from_raw(ptr) };
1111
| ^^^
1212
= note: `-D clippy::from-raw-with-void-ptr` implied by `-D warnings`
1313

14-
error: aborting due to previous error
14+
error: creating a `Rc` from a void raw pointer
15+
--> $DIR/from_raw_with_void_ptr.rs:21:22
16+
|
17+
LL | let _ = unsafe { Rc::from_raw(ptr) };
18+
| ^^^^^^^^^^^^^^^^^
19+
|
20+
help: cast this to a pointer of the appropriate type
21+
--> $DIR/from_raw_with_void_ptr.rs:21:35
22+
|
23+
LL | let _ = unsafe { Rc::from_raw(ptr) };
24+
| ^^^
25+
26+
error: creating a `Arc` from a void raw pointer
27+
--> $DIR/from_raw_with_void_ptr.rs:25:22
28+
|
29+
LL | let _ = unsafe { Arc::from_raw(ptr) };
30+
| ^^^^^^^^^^^^^^^^^^
31+
|
32+
help: cast this to a pointer of the appropriate type
33+
--> $DIR/from_raw_with_void_ptr.rs:25:36
34+
|
35+
LL | let _ = unsafe { Arc::from_raw(ptr) };
36+
| ^^^
37+
38+
error: creating a `Weak` from a void raw pointer
39+
--> $DIR/from_raw_with_void_ptr.rs:29:22
40+
|
41+
LL | let _ = unsafe { std::rc::Weak::from_raw(ptr) };
42+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
43+
|
44+
help: cast this to a pointer of the appropriate type
45+
--> $DIR/from_raw_with_void_ptr.rs:29:46
46+
|
47+
LL | let _ = unsafe { std::rc::Weak::from_raw(ptr) };
48+
| ^^^
49+
50+
error: creating a `Weak` from a void raw pointer
51+
--> $DIR/from_raw_with_void_ptr.rs:33:22
52+
|
53+
LL | let _ = unsafe { std::sync::Weak::from_raw(ptr) };
54+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
55+
|
56+
help: cast this to a pointer of the appropriate type
57+
--> $DIR/from_raw_with_void_ptr.rs:33:48
58+
|
59+
LL | let _ = unsafe { std::sync::Weak::from_raw(ptr) };
60+
| ^^^
61+
62+
error: aborting due to 5 previous errors
1563

0 commit comments

Comments
 (0)