-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
184 additions
and
117 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
use clippy_utils::{consts::is_promotable, diagnostics::span_lint_and_note, is_from_proc_macro}; | ||
use rustc_hir::{BorrowKind, Expr, ExprKind, ItemKind, OwnerNode}; | ||
use rustc_lint::{LateContext, LateLintPass, LintContext}; | ||
use rustc_middle::lint::in_external_macro; | ||
use rustc_session::{declare_lint_pass, declare_tool_lint}; | ||
|
||
declare_clippy_lint! { | ||
/// ### What it does | ||
/// Checks for raw pointers pointing to temporary values that will **not** be promoted to a | ||
/// constant through | ||
/// [constant promotion](https://doc.rust-lang.org/stable/reference/destructors.html#constant-promotion). | ||
/// | ||
/// ### Why is this bad? | ||
/// Usage of such a pointer can result in Undefined Behavior, as the pointer will stop pointing | ||
/// to valid stack memory once the temporary is dropped. | ||
/// | ||
/// ### Example | ||
/// ```rust,ignore | ||
/// fn x() -> *const i32 { | ||
/// let x = 0; | ||
/// &x as *const i32 | ||
/// } | ||
/// | ||
/// let x = x(); | ||
/// unsafe { *x }; // ⚠️ | ||
/// ``` | ||
#[clippy::version = "1.72.0"] | ||
pub PTR_TO_TEMPORARY, | ||
correctness, | ||
"disallows returning a raw pointer to a temporary value" | ||
} | ||
declare_lint_pass!(PtrToTemporary => [PTR_TO_TEMPORARY]); | ||
|
||
impl<'tcx> LateLintPass<'tcx> for PtrToTemporary { | ||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { | ||
if in_external_macro(cx.sess(), expr.span) { | ||
return; | ||
} | ||
|
||
// Get the final return statement if this is a return statement, or don't lint | ||
let expr = if let ExprKind::Ret(Some(expr)) = expr.kind { | ||
expr | ||
} else if let OwnerNode::Item(parent) = cx.tcx.hir().owner(cx.tcx.hir().get_parent_item(expr.hir_id)) | ||
&& let ItemKind::Fn(_, _, body) = parent.kind | ||
&& let block = cx.tcx.hir().body(body).value | ||
&& let ExprKind::Block(block, _) = block.kind | ||
&& let Some(final_block_expr) = block.expr | ||
&& final_block_expr.hir_id == expr.hir_id | ||
{ | ||
expr | ||
} else { | ||
return; | ||
}; | ||
|
||
if let ExprKind::Cast(cast_expr, _) = expr.kind | ||
&& let ExprKind::AddrOf(BorrowKind::Ref, _, e) = cast_expr.kind | ||
&& !is_promotable(cx, e) | ||
&& !is_from_proc_macro(cx, expr) | ||
{ | ||
span_lint_and_note( | ||
cx, | ||
PTR_TO_TEMPORARY, | ||
expr.span, | ||
"returning a raw pointer to a temporary value that cannot be promoted to a constant", | ||
None, | ||
"usage of this pointer by callers will cause Undefined Behavior", | ||
); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,34 +1,65 @@ | ||
#![allow(clippy::explicit_auto_deref, clippy::unnecessary_cast, clippy::useless_vec)] | ||
//@aux-build:proc_macros.rs | ||
#![allow(clippy::borrow_deref_ref, clippy::deref_addrof, clippy::identity_op, unused)] | ||
#![warn(clippy::ptr_to_temporary)] | ||
#![no_main] | ||
|
||
use std::ptr::addr_of; | ||
#[macro_use] | ||
extern crate proc_macros; | ||
|
||
fn a() -> i32 { | ||
0 | ||
fn bad_1() -> *const i32 { | ||
&(100 + *&0) as *const i32 | ||
} | ||
|
||
struct Vec3 { | ||
x: f32, | ||
y: f32, | ||
z: f32, | ||
fn bad_2() -> *const i32 { | ||
let a = 0i32; | ||
&(*&a) as *const i32 | ||
} | ||
|
||
fn main() { | ||
let _p = &0 as *const i32; | ||
let _p = &a() as *const i32; | ||
let vec = vec![1]; | ||
let _p = &vec.len() as *const usize; | ||
let x = &(1 + 2) as *const i32; | ||
let x = &(x as *const i32) as *const *const i32; | ||
fn bad_3() -> *const i32 { | ||
let a = 0i32; | ||
&a as *const i32 | ||
} | ||
|
||
fn bad_4() -> *const i32 { | ||
let mut a = 0i32; | ||
&a as *const i32 | ||
} | ||
|
||
fn bad_5() -> *const i32 { | ||
const A: &i32 = &1i32; | ||
let mut a = 0i32; | ||
|
||
// Do not lint... | ||
let ptr = &Vec3 { x: 1.0, y: 2.0, z: 3.0 }; | ||
let some_variable = 1i32; | ||
let x = &(*ptr).x as *const f32; | ||
let x = &(some_variable) as *const i32; | ||
if true { | ||
return &(*A) as *const i32; | ||
} | ||
&a as *const i32 | ||
} | ||
|
||
fn fine_1() -> *const i32 { | ||
&100 as *const i32 | ||
} | ||
|
||
fn fine_2() -> *const i32 { | ||
const A: &i32 = &0i32; | ||
A as *const i32 | ||
} | ||
|
||
fn fine_3() -> *const i32 { | ||
const A: &i32 = &0i32; | ||
&(*A) as *const i32 | ||
} | ||
|
||
external! { | ||
fn fine_external() -> *const i32 { | ||
let a = 0i32; | ||
&a as *const i32 | ||
} | ||
} | ||
|
||
// ...As `addr_of!` does not report anything out of the ordinary | ||
let ptr = &Vec3 { x: 1.0, y: 2.0, z: 3.0 }; | ||
let some_variable = 1i32; | ||
let x = addr_of!((*ptr).x) as *const f32; | ||
let x = addr_of!(some_variable); | ||
with_span! { | ||
span | ||
fn fine_proc_macro() -> *const i32 { | ||
let a = 0i32; | ||
&a as *const i32 | ||
} | ||
} |
Oops, something went wrong.