Skip to content

Commit 96c9004

Browse files
committed
new lint ptr_to_temporary
Update mod.rs Update mod.rs
1 parent cda13a8 commit 96c9004

16 files changed

+157
-13
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -5088,6 +5088,7 @@ Released 2018-09-13
50885088
[`ptr_cast_constness`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_cast_constness
50895089
[`ptr_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_eq
50905090
[`ptr_offset_with_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_offset_with_cast
5091+
[`ptr_to_temporary`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_to_temporary
50915092
[`pub_enum_variant_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#pub_enum_variant_names
50925093
[`pub_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#pub_use
50935094
[`question_mark`]: https://rust-lang.github.io/rust-clippy/master/index.html#question_mark

clippy_lints/src/casts/mod.rs

+30
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ mod fn_to_numeric_cast_any;
1818
mod fn_to_numeric_cast_with_truncation;
1919
mod ptr_as_ptr;
2020
mod ptr_cast_constness;
21+
mod ptr_to_temporary;
2122
mod unnecessary_cast;
2223
mod utils;
2324

@@ -657,6 +658,33 @@ declare_clippy_lint! {
657658
"casting a known floating-point NaN into an integer"
658659
}
659660

661+
declare_clippy_lint! {
662+
/// ### What it does
663+
/// Checks for raw pointers that point to temporary values.
664+
///
665+
/// ### Why is this bad?
666+
/// Usage of such a pointer can result in Undefined Behavior, as the pointer will stop pointing
667+
/// to valid stack memory once the temporary is dropped.
668+
///
669+
/// ### Example
670+
/// ```rust,ignore
671+
/// const PS: [usize; 3] = [2usize, 3usize, 11usize];
672+
/// let mut ps = vec![];
673+
///
674+
/// for p in PS {
675+
/// ps.push(&p as *const usize);
676+
/// }
677+
///
678+
/// for p in ps {
679+
/// unsafe { p.read() }; // ⚠️
680+
/// }
681+
/// ```
682+
#[clippy::version = "1.72.0"]
683+
pub PTR_TO_TEMPORARY,
684+
correctness,
685+
"disallows obtaining a raw pointer to a temporary value"
686+
}
687+
660688
pub struct Casts {
661689
msrv: Msrv,
662690
}
@@ -691,6 +719,7 @@ impl_lint_pass!(Casts => [
691719
CAST_SLICE_FROM_RAW_PARTS,
692720
AS_PTR_CAST_MUT,
693721
CAST_NAN_TO_INT,
722+
PTR_TO_TEMPORARY,
694723
]);
695724

696725
impl<'tcx> LateLintPass<'tcx> for Casts {
@@ -736,6 +765,7 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
736765
}
737766

738767
as_underscore::check(cx, expr, cast_to_hir);
768+
ptr_to_temporary::check(cx, expr, cast_expr, cast_to_hir);
739769

740770
if self.msrv.meets(msrvs::BORROW_AS_PTR) {
741771
borrow_as_ptr::check(cx, expr, cast_expr, cast_to_hir);
+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
use clippy_utils::diagnostics::span_lint_and_help;
2+
use rustc_hir::{BorrowKind, Expr, ExprKind, Ty, TyKind};
3+
use rustc_lint::LateContext;
4+
use rustc_middle::ty::adjustment::Adjust;
5+
6+
use super::PTR_TO_TEMPORARY;
7+
8+
pub(super) fn check<'tcx>(
9+
cx: &LateContext<'tcx>,
10+
expr: &'tcx Expr<'_>,
11+
cast_expr: &'tcx Expr<'_>,
12+
cast_to: &'tcx Ty<'_>,
13+
) {
14+
if matches!(cast_to.kind, TyKind::Ptr(_))
15+
&& let ExprKind::AddrOf(BorrowKind::Ref, _, e) = cast_expr.kind
16+
{
17+
// rustc's criteria of a "temporary value", so this should be 100% accurate
18+
if !e.is_place_expr(|base| {
19+
cx.typeck_results()
20+
.adjustments()
21+
.get(base.hir_id)
22+
.is_some_and(|x| x.iter().any(|adj| matches!(adj.kind, Adjust::Deref(_))))
23+
}) {
24+
span_lint_and_help(
25+
cx,
26+
PTR_TO_TEMPORARY,
27+
expr.span,
28+
"raw pointer to a temporary value",
29+
None,
30+
"usage of this pointer will cause Undefined Behavior; create a local binding to make it longer lived",
31+
);
32+
}
33+
}
34+
}

clippy_lints/src/declared_lints.rs

+1
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
9494
crate::casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION_INFO,
9595
crate::casts::PTR_AS_PTR_INFO,
9696
crate::casts::PTR_CAST_CONSTNESS_INFO,
97+
crate::casts::PTR_TO_TEMPORARY_INFO,
9798
crate::casts::UNNECESSARY_CAST_INFO,
9899
crate::checked_conversions::CHECKED_CONVERSIONS_INFO,
99100
crate::cognitive_complexity::COGNITIVE_COMPLEXITY_INFO,

tests/ui/borrow_deref_ref.fixed

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//@run-rustfix
22
//@aux-build: proc_macros.rs
33

4-
#![allow(dead_code, unused_variables)]
4+
#![allow(clippy::ptr_to_temporary, dead_code, unused_variables)]
55

66
extern crate proc_macros;
77
use proc_macros::with_span;

tests/ui/borrow_deref_ref.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//@run-rustfix
22
//@aux-build: proc_macros.rs
33

4-
#![allow(dead_code, unused_variables)]
4+
#![allow(clippy::ptr_to_temporary, dead_code, unused_variables)]
55

66
extern crate proc_macros;
77
use proc_macros::with_span;

tests/ui/cast_alignment.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ extern crate libc;
99
clippy::no_effect,
1010
clippy::unnecessary_operation,
1111
clippy::cast_lossless,
12-
clippy::borrow_as_ptr
12+
clippy::borrow_as_ptr,
13+
clippy::ptr_to_temporary
1314
)]
1415

1516
fn main() {

tests/ui/cast_alignment.stderr

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,25 @@
11
error: casting from `*const u8` to a more-strictly-aligned pointer (`*const u16`) (1 < 2 bytes)
2-
--> $DIR/cast_alignment.rs:19:5
2+
--> $DIR/cast_alignment.rs:20:5
33
|
44
LL | (&1u8 as *const u8) as *const u16;
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
66
|
77
= note: `-D clippy::cast-ptr-alignment` implied by `-D warnings`
88

99
error: casting from `*mut u8` to a more-strictly-aligned pointer (`*mut u16`) (1 < 2 bytes)
10-
--> $DIR/cast_alignment.rs:20:5
10+
--> $DIR/cast_alignment.rs:21:5
1111
|
1212
LL | (&mut 1u8 as *mut u8) as *mut u16;
1313
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1414

1515
error: casting from `*const u8` to a more-strictly-aligned pointer (`*const u16`) (1 < 2 bytes)
16-
--> $DIR/cast_alignment.rs:23:5
16+
--> $DIR/cast_alignment.rs:24:5
1717
|
1818
LL | (&1u8 as *const u8).cast::<u16>();
1919
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2020

2121
error: casting from `*mut u8` to a more-strictly-aligned pointer (`*mut u16`) (1 < 2 bytes)
22-
--> $DIR/cast_alignment.rs:24:5
22+
--> $DIR/cast_alignment.rs:25:5
2323
|
2424
LL | (&mut 1u8 as *mut u8).cast::<u16>();
2525
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/ui/ptr_to_temporary.rs

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#![allow(clippy::explicit_auto_deref, clippy::unnecessary_cast, clippy::useless_vec)]
2+
3+
use std::ptr::addr_of;
4+
5+
fn a() -> i32 {
6+
0
7+
}
8+
9+
struct Vec3 {
10+
x: f32,
11+
y: f32,
12+
z: f32,
13+
}
14+
15+
fn main() {
16+
let _p = &0 as *const i32;
17+
let _p = &a() as *const i32;
18+
let vec = vec![1];
19+
let _p = &vec.len() as *const usize;
20+
let x = &(1 + 2) as *const i32;
21+
let x = &(x as *const i32) as *const *const i32;
22+
23+
// Do not lint...
24+
let ptr = &Vec3 { x: 1.0, y: 2.0, z: 3.0 };
25+
let some_variable = 1i32;
26+
let x = &(*ptr).x as *const f32;
27+
let x = &(some_variable) as *const i32;
28+
29+
// ...As `addr_of!` does not report anything out of the ordinary
30+
let ptr = &Vec3 { x: 1.0, y: 2.0, z: 3.0 };
31+
let some_variable = 1i32;
32+
let x = addr_of!((*ptr).x) as *const f32;
33+
let x = addr_of!(some_variable);
34+
}

tests/ui/ptr_to_temporary.stderr

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
error: raw pointer to a temporary value
2+
--> $DIR/ptr_to_temporary.rs:16:14
3+
|
4+
LL | let _p = &0 as *const i32;
5+
| ^^^^^^^^^^^^^^^^
6+
|
7+
= help: usage of this pointer will cause Undefined Behavior; create a local binding to make it longer lived
8+
= note: `#[deny(clippy::ptr_to_temporary)]` on by default
9+
10+
error: raw pointer to a temporary value
11+
--> $DIR/ptr_to_temporary.rs:17:14
12+
|
13+
LL | let _p = &a() as *const i32;
14+
| ^^^^^^^^^^^^^^^^^^
15+
|
16+
= help: usage of this pointer will cause Undefined Behavior; create a local binding to make it longer lived
17+
18+
error: raw pointer to a temporary value
19+
--> $DIR/ptr_to_temporary.rs:19:14
20+
|
21+
LL | let _p = &vec.len() as *const usize;
22+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
23+
|
24+
= help: usage of this pointer will cause Undefined Behavior; create a local binding to make it longer lived
25+
26+
error: raw pointer to a temporary value
27+
--> $DIR/ptr_to_temporary.rs:20:13
28+
|
29+
LL | let x = &(1 + 2) as *const i32;
30+
| ^^^^^^^^^^^^^^^^^^^^^^
31+
|
32+
= help: usage of this pointer will cause Undefined Behavior; create a local binding to make it longer lived
33+
34+
error: raw pointer to a temporary value
35+
--> $DIR/ptr_to_temporary.rs:21:13
36+
|
37+
LL | let x = &(x as *const i32) as *const *const i32;
38+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
39+
|
40+
= help: usage of this pointer will cause Undefined Behavior; create a local binding to make it longer lived
41+
42+
error: aborting due to 5 previous errors
43+

tests/ui/transmute_ptr_to_ptr.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#![warn(clippy::transmute_ptr_to_ptr)]
2-
#![allow(clippy::borrow_as_ptr)]
2+
#![allow(clippy::borrow_as_ptr, clippy::ptr_to_temporary)]
33

44
// Make sure we can modify lifetimes, which is one of the recommended uses
55
// of transmute

tests/ui/transmutes_expressible_as_ptr_casts.fixed

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
// would otherwise be responsible for
55
#![warn(clippy::useless_transmute)]
66
#![warn(clippy::transmute_ptr_to_ptr)]
7-
#![allow(unused, clippy::borrow_as_ptr)]
7+
#![allow(unused, clippy::borrow_as_ptr, clippy::ptr_to_temporary)]
88

99
use std::mem::{size_of, transmute};
1010

tests/ui/transmutes_expressible_as_ptr_casts.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
// would otherwise be responsible for
55
#![warn(clippy::useless_transmute)]
66
#![warn(clippy::transmute_ptr_to_ptr)]
7-
#![allow(unused, clippy::borrow_as_ptr)]
7+
#![allow(unused, clippy::borrow_as_ptr, clippy::ptr_to_temporary)]
88

99
use std::mem::{size_of, transmute};
1010

tests/ui/unnecessary_struct_initialization.fixed

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//@run-rustfix
22

3-
#![allow(unused)]
3+
#![allow(clippy::ptr_to_temporary, unused)]
44
#![warn(clippy::unnecessary_struct_initialization)]
55

66
struct S {

tests/ui/unnecessary_struct_initialization.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//@run-rustfix
22

3-
#![allow(unused)]
3+
#![allow(clippy::ptr_to_temporary, unused)]
44
#![warn(clippy::unnecessary_struct_initialization)]
55

66
struct S {

tests/ui/zero_offset.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#[allow(clippy::borrow_as_ptr)]
1+
#[allow(clippy::borrow_as_ptr, clippy::ptr_to_temporary)]
22
fn main() {
33
unsafe {
44
let m = &mut () as *mut ();

0 commit comments

Comments
 (0)