mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 08:13:41 +00:00
Auto merge of #128985 - GrigorenkoPV:instantly-dangling-pointer, r=Urgau
Lint against getting pointers from immediately dropped temporaries Fixes #123613 ## Changes: 1. New lint: `dangling_pointers_from_temporaries`. Is a generalization of `temporary_cstring_as_ptr` for more types and more ways to get a temporary. 2. `temporary_cstring_as_ptr` is removed and marked as renamed to `dangling_pointers_from_temporaries`. 3. `clippy::temporary_cstring_as_ptr` is marked as renamed to `dangling_pointers_from_temporaries`. 4. Fixed a false positive[^fp] for when the pointer is not actually dangling because of lifetime extension for function/method call arguments. 5. `core::cell::Cell` is now `rustc_diagnostic_item = "Cell"` ## Questions: - [ ] Instead of manually checking for a list of known methods and diagnostic items, maybe add some sort of annotation to those methods in library and check for the presence of that annotation? https://github.com/rust-lang/rust/pull/128985#issuecomment-2318714312 ## Known limitations: ### False negatives[^fn]: See the comments in `compiler/rustc_lint/src/dangling.rs` 1. Method calls that are not checked for: - `temporary_unsafe_cell.get()` - `temporary_sync_unsafe_cell.get()` 2. Ways to get a temporary that are not recognized: - `owning_temporary.field` - `owning_temporary[index]` 3. No checks for ref-to-ptr conversions: - `&raw [mut] temporary` - `&temporary as *(const|mut) _` - `ptr::from_ref(&temporary)` and friends [^fn]: lint **should** be emitted, but **is not** [^fp]: lint **should not** be emitted, but **is**
This commit is contained in:
commit
a9d17627d2
@ -203,14 +203,14 @@ lint_confusable_identifier_pair = found both `{$existing_sym}` and `{$sym}` as i
|
|||||||
.current_use = this identifier can be confused with `{$existing_sym}`
|
.current_use = this identifier can be confused with `{$existing_sym}`
|
||||||
.other_use = other identifier used here
|
.other_use = other identifier used here
|
||||||
|
|
||||||
lint_cstring_ptr = getting the inner pointer of a temporary `CString`
|
|
||||||
.as_ptr_label = this pointer will be invalid
|
|
||||||
.unwrap_label = this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
|
|
||||||
.note = pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
|
|
||||||
.help = for more information, see https://doc.rust-lang.org/reference/destructors.html
|
|
||||||
|
|
||||||
lint_custom_inner_attribute_unstable = custom inner attributes are unstable
|
lint_custom_inner_attribute_unstable = custom inner attributes are unstable
|
||||||
|
|
||||||
|
lint_dangling_pointers_from_temporaries = a dangling pointer will be produced because the temporary `{$ty}` will be dropped
|
||||||
|
.label_ptr = this pointer will immediately be invalid
|
||||||
|
.label_temporary = this `{$ty}` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
|
||||||
|
.note = pointers do not have a lifetime; when calling `{$callee}` the `{$ty}` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
|
||||||
|
.help = for more information, see <https://doc.rust-lang.org/reference/destructors.html>
|
||||||
|
|
||||||
lint_default_hash_types = prefer `{$preferred}` over `{$used}`, it has better performance
|
lint_default_hash_types = prefer `{$preferred}` over `{$used}`, it has better performance
|
||||||
.note = a `use rustc_data_structures::fx::{$preferred}` may be necessary
|
.note = a `use rustc_data_structures::fx::{$preferred}` may be necessary
|
||||||
|
|
||||||
|
223
compiler/rustc_lint/src/dangling.rs
Normal file
223
compiler/rustc_lint/src/dangling.rs
Normal file
@ -0,0 +1,223 @@
|
|||||||
|
use rustc_ast::visit::{visit_opt, walk_list};
|
||||||
|
use rustc_hir::def_id::LocalDefId;
|
||||||
|
use rustc_hir::intravisit::{FnKind, Visitor, walk_expr};
|
||||||
|
use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, LangItem};
|
||||||
|
use rustc_middle::ty::{Ty, TyCtxt};
|
||||||
|
use rustc_session::{declare_lint, impl_lint_pass};
|
||||||
|
use rustc_span::Span;
|
||||||
|
use rustc_span::symbol::sym;
|
||||||
|
|
||||||
|
use crate::lints::DanglingPointersFromTemporaries;
|
||||||
|
use crate::{LateContext, LateLintPass};
|
||||||
|
|
||||||
|
declare_lint! {
|
||||||
|
/// The `dangling_pointers_from_temporaries` lint detects getting a pointer to data
|
||||||
|
/// of a temporary that will immediately get dropped.
|
||||||
|
///
|
||||||
|
/// ### Example
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # #![allow(unused)]
|
||||||
|
/// # unsafe fn use_data(ptr: *const u8) { }
|
||||||
|
/// fn gather_and_use(bytes: impl Iterator<Item = u8>) {
|
||||||
|
/// let x: *const u8 = bytes.collect::<Vec<u8>>().as_ptr();
|
||||||
|
/// unsafe { use_data(x) }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// {{produces}}
|
||||||
|
///
|
||||||
|
/// ### Explanation
|
||||||
|
///
|
||||||
|
/// Getting a pointer from a temporary value will not prolong its lifetime,
|
||||||
|
/// which means that the value can be dropped and the allocation freed
|
||||||
|
/// while the pointer still exists, making the pointer dangling.
|
||||||
|
/// This is not an error (as far as the type system is concerned)
|
||||||
|
/// but probably is not what the user intended either.
|
||||||
|
///
|
||||||
|
/// If you need stronger guarantees, consider using references instead,
|
||||||
|
/// as they are statically verified by the borrow-checker to never dangle.
|
||||||
|
pub DANGLING_POINTERS_FROM_TEMPORARIES,
|
||||||
|
Warn,
|
||||||
|
"detects getting a pointer from a temporary"
|
||||||
|
}
|
||||||
|
|
||||||
|
/// FIXME: false negatives (i.e. the lint is not emitted when it should be)
|
||||||
|
/// 1. Method calls that are not checked for:
|
||||||
|
/// - [`temporary_unsafe_cell.get()`][`core::cell::UnsafeCell::get()`]
|
||||||
|
/// - [`temporary_sync_unsafe_cell.get()`][`core::cell::SyncUnsafeCell::get()`]
|
||||||
|
/// 2. Ways to get a temporary that are not recognized:
|
||||||
|
/// - `owning_temporary.field`
|
||||||
|
/// - `owning_temporary[index]`
|
||||||
|
/// 3. No checks for ref-to-ptr conversions:
|
||||||
|
/// - `&raw [mut] temporary`
|
||||||
|
/// - `&temporary as *(const|mut) _`
|
||||||
|
/// - `ptr::from_ref(&temporary)` and friends
|
||||||
|
#[derive(Clone, Copy, Default)]
|
||||||
|
pub(crate) struct DanglingPointers;
|
||||||
|
|
||||||
|
impl_lint_pass!(DanglingPointers => [DANGLING_POINTERS_FROM_TEMPORARIES]);
|
||||||
|
|
||||||
|
// This skips over const blocks, but they cannot use or return a dangling pointer anyways.
|
||||||
|
impl<'tcx> LateLintPass<'tcx> for DanglingPointers {
|
||||||
|
fn check_fn(
|
||||||
|
&mut self,
|
||||||
|
cx: &LateContext<'tcx>,
|
||||||
|
_: FnKind<'tcx>,
|
||||||
|
_: &'tcx FnDecl<'tcx>,
|
||||||
|
body: &'tcx Body<'tcx>,
|
||||||
|
_: Span,
|
||||||
|
_: LocalDefId,
|
||||||
|
) {
|
||||||
|
DanglingPointerSearcher { cx, inside_call_args: false }.visit_body(body)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This produces a dangling pointer:
|
||||||
|
/// ```ignore (example)
|
||||||
|
/// let ptr = CString::new("hello").unwrap().as_ptr();
|
||||||
|
/// foo(ptr)
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// But this does not:
|
||||||
|
/// ```ignore (example)
|
||||||
|
/// foo(CString::new("hello").unwrap().as_ptr())
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// But this does:
|
||||||
|
/// ```ignore (example)
|
||||||
|
/// foo({ let ptr = CString::new("hello").unwrap().as_ptr(); ptr })
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// So we have to keep track of when we are inside of a function/method call argument.
|
||||||
|
struct DanglingPointerSearcher<'lcx, 'tcx> {
|
||||||
|
cx: &'lcx LateContext<'tcx>,
|
||||||
|
/// Keeps track of whether we are inside of function/method call arguments,
|
||||||
|
/// where this lint should not be emitted.
|
||||||
|
///
|
||||||
|
/// See [the main doc][`Self`] for examples.
|
||||||
|
inside_call_args: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Visitor<'_> for DanglingPointerSearcher<'_, '_> {
|
||||||
|
fn visit_expr(&mut self, expr: &Expr<'_>) -> Self::Result {
|
||||||
|
if !self.inside_call_args {
|
||||||
|
lint_expr(self.cx, expr)
|
||||||
|
}
|
||||||
|
match expr.kind {
|
||||||
|
ExprKind::Call(lhs, args) | ExprKind::MethodCall(_, lhs, args, _) => {
|
||||||
|
self.visit_expr(lhs);
|
||||||
|
self.with_inside_call_args(true, |this| walk_list!(this, visit_expr, args))
|
||||||
|
}
|
||||||
|
ExprKind::Block(&Block { stmts, expr, .. }, _) => {
|
||||||
|
self.with_inside_call_args(false, |this| walk_list!(this, visit_stmt, stmts));
|
||||||
|
visit_opt!(self, visit_expr, expr)
|
||||||
|
}
|
||||||
|
_ => walk_expr(self, expr),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DanglingPointerSearcher<'_, '_> {
|
||||||
|
fn with_inside_call_args<R>(
|
||||||
|
&mut self,
|
||||||
|
inside_call_args: bool,
|
||||||
|
callback: impl FnOnce(&mut Self) -> R,
|
||||||
|
) -> R {
|
||||||
|
let old = core::mem::replace(&mut self.inside_call_args, inside_call_args);
|
||||||
|
let result = callback(self);
|
||||||
|
self.inside_call_args = old;
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lint_expr(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||||
|
if let ExprKind::MethodCall(method, receiver, _args, _span) = expr.kind
|
||||||
|
&& matches!(method.ident.name, sym::as_ptr | sym::as_mut_ptr)
|
||||||
|
&& is_temporary_rvalue(receiver)
|
||||||
|
&& let ty = cx.typeck_results().expr_ty(receiver)
|
||||||
|
&& is_interesting(cx.tcx, ty)
|
||||||
|
{
|
||||||
|
// FIXME: use `emit_node_lint` when `#[primary_span]` is added.
|
||||||
|
cx.tcx.emit_node_span_lint(
|
||||||
|
DANGLING_POINTERS_FROM_TEMPORARIES,
|
||||||
|
expr.hir_id,
|
||||||
|
method.ident.span,
|
||||||
|
DanglingPointersFromTemporaries {
|
||||||
|
callee: method.ident.name,
|
||||||
|
ty,
|
||||||
|
ptr_span: method.ident.span,
|
||||||
|
temporary_span: receiver.span,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_temporary_rvalue(expr: &Expr<'_>) -> bool {
|
||||||
|
match expr.kind {
|
||||||
|
// Const is not temporary.
|
||||||
|
ExprKind::ConstBlock(..) | ExprKind::Repeat(..) | ExprKind::Lit(..) => false,
|
||||||
|
|
||||||
|
// This is literally lvalue.
|
||||||
|
ExprKind::Path(..) => false,
|
||||||
|
|
||||||
|
// Calls return rvalues.
|
||||||
|
ExprKind::Call(..) | ExprKind::MethodCall(..) | ExprKind::Binary(..) => true,
|
||||||
|
|
||||||
|
// Inner blocks are rvalues.
|
||||||
|
ExprKind::If(..) | ExprKind::Loop(..) | ExprKind::Match(..) | ExprKind::Block(..) => true,
|
||||||
|
|
||||||
|
// FIXME: these should probably recurse and typecheck along the way.
|
||||||
|
// Some false negatives are possible for now.
|
||||||
|
ExprKind::Index(..) | ExprKind::Field(..) | ExprKind::Unary(..) => false,
|
||||||
|
|
||||||
|
ExprKind::Struct(..) => true,
|
||||||
|
|
||||||
|
// FIXME: this has false negatives, but I do not want to deal with 'static/const promotion just yet.
|
||||||
|
ExprKind::Array(..) => false,
|
||||||
|
|
||||||
|
// These typecheck to `!`
|
||||||
|
ExprKind::Break(..) | ExprKind::Continue(..) | ExprKind::Ret(..) | ExprKind::Become(..) => {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
// These typecheck to `()`
|
||||||
|
ExprKind::Assign(..) | ExprKind::AssignOp(..) | ExprKind::Yield(..) => false,
|
||||||
|
|
||||||
|
// Compiler-magic macros
|
||||||
|
ExprKind::AddrOf(..) | ExprKind::OffsetOf(..) | ExprKind::InlineAsm(..) => false,
|
||||||
|
|
||||||
|
// We are not interested in these
|
||||||
|
ExprKind::Cast(..)
|
||||||
|
| ExprKind::Closure(..)
|
||||||
|
| ExprKind::Tup(..)
|
||||||
|
| ExprKind::DropTemps(..)
|
||||||
|
| ExprKind::Let(..) => false,
|
||||||
|
|
||||||
|
// Not applicable
|
||||||
|
ExprKind::Type(..) | ExprKind::Err(..) => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Array, Vec, String, CString, MaybeUninit, Cell, Box<[_]>, Box<str>, Box<CStr>,
|
||||||
|
// or any of the above in arbitrary many nested Box'es.
|
||||||
|
fn is_interesting(tcx: TyCtxt<'_>, ty: Ty<'_>) -> bool {
|
||||||
|
if ty.is_array() {
|
||||||
|
true
|
||||||
|
} else if let Some(inner) = ty.boxed_ty() {
|
||||||
|
inner.is_slice()
|
||||||
|
|| inner.is_str()
|
||||||
|
|| inner.ty_adt_def().is_some_and(|def| tcx.is_lang_item(def.did(), LangItem::CStr))
|
||||||
|
|| is_interesting(tcx, inner)
|
||||||
|
} else if let Some(def) = ty.ty_adt_def() {
|
||||||
|
for lang_item in [LangItem::String, LangItem::MaybeUninit] {
|
||||||
|
if tcx.is_lang_item(def.did(), lang_item) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tcx.get_diagnostic_name(def.did())
|
||||||
|
.is_some_and(|name| matches!(name, sym::cstring_type | sym::Vec | sym::Cell))
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
@ -40,6 +40,7 @@ mod async_closures;
|
|||||||
mod async_fn_in_trait;
|
mod async_fn_in_trait;
|
||||||
pub mod builtin;
|
pub mod builtin;
|
||||||
mod context;
|
mod context;
|
||||||
|
mod dangling;
|
||||||
mod deref_into_dyn_supertrait;
|
mod deref_into_dyn_supertrait;
|
||||||
mod drop_forget_useless;
|
mod drop_forget_useless;
|
||||||
mod early;
|
mod early;
|
||||||
@ -59,7 +60,6 @@ mod levels;
|
|||||||
mod lints;
|
mod lints;
|
||||||
mod macro_expr_fragment_specifier_2024_migration;
|
mod macro_expr_fragment_specifier_2024_migration;
|
||||||
mod map_unit_fn;
|
mod map_unit_fn;
|
||||||
mod methods;
|
|
||||||
mod multiple_supertrait_upcastable;
|
mod multiple_supertrait_upcastable;
|
||||||
mod non_ascii_idents;
|
mod non_ascii_idents;
|
||||||
mod non_fmt_panic;
|
mod non_fmt_panic;
|
||||||
@ -85,6 +85,7 @@ mod unused;
|
|||||||
use async_closures::AsyncClosureUsage;
|
use async_closures::AsyncClosureUsage;
|
||||||
use async_fn_in_trait::AsyncFnInTrait;
|
use async_fn_in_trait::AsyncFnInTrait;
|
||||||
use builtin::*;
|
use builtin::*;
|
||||||
|
use dangling::*;
|
||||||
use deref_into_dyn_supertrait::*;
|
use deref_into_dyn_supertrait::*;
|
||||||
use drop_forget_useless::*;
|
use drop_forget_useless::*;
|
||||||
use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums;
|
use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums;
|
||||||
@ -97,7 +98,6 @@ use invalid_from_utf8::*;
|
|||||||
use let_underscore::*;
|
use let_underscore::*;
|
||||||
use macro_expr_fragment_specifier_2024_migration::*;
|
use macro_expr_fragment_specifier_2024_migration::*;
|
||||||
use map_unit_fn::*;
|
use map_unit_fn::*;
|
||||||
use methods::*;
|
|
||||||
use multiple_supertrait_upcastable::*;
|
use multiple_supertrait_upcastable::*;
|
||||||
use non_ascii_idents::*;
|
use non_ascii_idents::*;
|
||||||
use non_fmt_panic::NonPanicFmt;
|
use non_fmt_panic::NonPanicFmt;
|
||||||
@ -225,7 +225,7 @@ late_lint_methods!(
|
|||||||
UngatedAsyncFnTrackCaller: UngatedAsyncFnTrackCaller,
|
UngatedAsyncFnTrackCaller: UngatedAsyncFnTrackCaller,
|
||||||
ShadowedIntoIter: ShadowedIntoIter,
|
ShadowedIntoIter: ShadowedIntoIter,
|
||||||
DropTraitConstraints: DropTraitConstraints,
|
DropTraitConstraints: DropTraitConstraints,
|
||||||
TemporaryCStringAsPtr: TemporaryCStringAsPtr,
|
DanglingPointers: DanglingPointers,
|
||||||
NonPanicFmt: NonPanicFmt,
|
NonPanicFmt: NonPanicFmt,
|
||||||
NoopMethodCall: NoopMethodCall,
|
NoopMethodCall: NoopMethodCall,
|
||||||
EnumIntrinsicsNonEnums: EnumIntrinsicsNonEnums,
|
EnumIntrinsicsNonEnums: EnumIntrinsicsNonEnums,
|
||||||
@ -350,6 +350,7 @@ fn register_builtins(store: &mut LintStore) {
|
|||||||
store.register_renamed("non_fmt_panic", "non_fmt_panics");
|
store.register_renamed("non_fmt_panic", "non_fmt_panics");
|
||||||
store.register_renamed("unused_tuple_struct_fields", "dead_code");
|
store.register_renamed("unused_tuple_struct_fields", "dead_code");
|
||||||
store.register_renamed("static_mut_ref", "static_mut_refs");
|
store.register_renamed("static_mut_ref", "static_mut_refs");
|
||||||
|
store.register_renamed("temporary_cstring_as_ptr", "dangling_pointers_from_temporaries");
|
||||||
|
|
||||||
// These were moved to tool lints, but rustc still sees them when compiling normally, before
|
// These were moved to tool lints, but rustc still sees them when compiling normally, before
|
||||||
// tool lints are registered, so `check_tool_name_for_backwards_compat` doesn't work. Use
|
// tool lints are registered, so `check_tool_name_for_backwards_compat` doesn't work. Use
|
||||||
|
@ -1137,16 +1137,19 @@ pub(crate) struct IgnoredUnlessCrateSpecified<'a> {
|
|||||||
pub name: Symbol,
|
pub name: Symbol,
|
||||||
}
|
}
|
||||||
|
|
||||||
// methods.rs
|
// dangling.rs
|
||||||
#[derive(LintDiagnostic)]
|
#[derive(LintDiagnostic)]
|
||||||
#[diag(lint_cstring_ptr)]
|
#[diag(lint_dangling_pointers_from_temporaries)]
|
||||||
#[note]
|
#[note]
|
||||||
#[help]
|
#[help]
|
||||||
pub(crate) struct CStringPtr {
|
// FIXME: put #[primary_span] on `ptr_span` once it does not cause conflicts
|
||||||
#[label(lint_as_ptr_label)]
|
pub(crate) struct DanglingPointersFromTemporaries<'tcx> {
|
||||||
pub as_ptr: Span,
|
pub callee: Symbol,
|
||||||
#[label(lint_unwrap_label)]
|
pub ty: Ty<'tcx>,
|
||||||
pub unwrap: Span,
|
#[label(lint_label_ptr)]
|
||||||
|
pub ptr_span: Span,
|
||||||
|
#[label(lint_label_temporary)]
|
||||||
|
pub temporary_span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
// multiple_supertrait_upcastable.rs
|
// multiple_supertrait_upcastable.rs
|
||||||
|
@ -1,69 +0,0 @@
|
|||||||
use rustc_hir::{Expr, ExprKind};
|
|
||||||
use rustc_middle::ty;
|
|
||||||
use rustc_session::{declare_lint, declare_lint_pass};
|
|
||||||
use rustc_span::Span;
|
|
||||||
use rustc_span::symbol::sym;
|
|
||||||
|
|
||||||
use crate::lints::CStringPtr;
|
|
||||||
use crate::{LateContext, LateLintPass, LintContext};
|
|
||||||
|
|
||||||
declare_lint! {
|
|
||||||
/// The `temporary_cstring_as_ptr` lint detects getting the inner pointer of
|
|
||||||
/// a temporary `CString`.
|
|
||||||
///
|
|
||||||
/// ### Example
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # #![allow(unused)]
|
|
||||||
/// # use std::ffi::CString;
|
|
||||||
/// let c_str = CString::new("foo").unwrap().as_ptr();
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// {{produces}}
|
|
||||||
///
|
|
||||||
/// ### Explanation
|
|
||||||
///
|
|
||||||
/// The inner pointer of a `CString` lives only as long as the `CString` it
|
|
||||||
/// points to. Getting the inner pointer of a *temporary* `CString` allows the `CString`
|
|
||||||
/// to be dropped at the end of the statement, as it is not being referenced as far as the
|
|
||||||
/// typesystem is concerned. This means outside of the statement the pointer will point to
|
|
||||||
/// freed memory, which causes undefined behavior if the pointer is later dereferenced.
|
|
||||||
pub TEMPORARY_CSTRING_AS_PTR,
|
|
||||||
Warn,
|
|
||||||
"detects getting the inner pointer of a temporary `CString`"
|
|
||||||
}
|
|
||||||
|
|
||||||
declare_lint_pass!(TemporaryCStringAsPtr => [TEMPORARY_CSTRING_AS_PTR]);
|
|
||||||
|
|
||||||
impl<'tcx> LateLintPass<'tcx> for TemporaryCStringAsPtr {
|
|
||||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
|
||||||
if let ExprKind::MethodCall(as_ptr_path, as_ptr_receiver, ..) = expr.kind
|
|
||||||
&& as_ptr_path.ident.name == sym::as_ptr
|
|
||||||
&& let ExprKind::MethodCall(unwrap_path, unwrap_receiver, ..) = as_ptr_receiver.kind
|
|
||||||
&& (unwrap_path.ident.name == sym::unwrap || unwrap_path.ident.name == sym::expect)
|
|
||||||
{
|
|
||||||
lint_cstring_as_ptr(cx, as_ptr_path.ident.span, unwrap_receiver, as_ptr_receiver);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn lint_cstring_as_ptr(
|
|
||||||
cx: &LateContext<'_>,
|
|
||||||
as_ptr_span: Span,
|
|
||||||
source: &rustc_hir::Expr<'_>,
|
|
||||||
unwrap: &rustc_hir::Expr<'_>,
|
|
||||||
) {
|
|
||||||
let source_type = cx.typeck_results().expr_ty(source);
|
|
||||||
if let ty::Adt(def, args) = source_type.kind() {
|
|
||||||
if cx.tcx.is_diagnostic_item(sym::Result, def.did()) {
|
|
||||||
if let ty::Adt(adt, _) = args.type_at(0).kind() {
|
|
||||||
if cx.tcx.is_diagnostic_item(sym::cstring_type, adt.did()) {
|
|
||||||
cx.emit_span_lint(TEMPORARY_CSTRING_AS_PTR, as_ptr_span, CStringPtr {
|
|
||||||
as_ptr: as_ptr_span,
|
|
||||||
unwrap: unwrap.span,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -171,6 +171,7 @@ symbols! {
|
|||||||
CallOnceFuture,
|
CallOnceFuture,
|
||||||
CallRefFuture,
|
CallRefFuture,
|
||||||
Capture,
|
Capture,
|
||||||
|
Cell,
|
||||||
Center,
|
Center,
|
||||||
Cleanup,
|
Cleanup,
|
||||||
Clone,
|
Clone,
|
||||||
@ -409,6 +410,7 @@ symbols! {
|
|||||||
arm,
|
arm,
|
||||||
arm_target_feature,
|
arm_target_feature,
|
||||||
array,
|
array,
|
||||||
|
as_mut_ptr,
|
||||||
as_ptr,
|
as_ptr,
|
||||||
as_ref,
|
as_ref,
|
||||||
as_str,
|
as_str,
|
||||||
|
@ -4,6 +4,7 @@ use core::mem::MaybeUninit;
|
|||||||
use core::ptr::NonNull;
|
use core::ptr::NonNull;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg_attr(not(bootstrap), expect(dangling_pointers_from_temporaries))]
|
||||||
fn uninitialized_zero_size_box() {
|
fn uninitialized_zero_size_box() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
&*Box::<()>::new_uninit() as *const _,
|
&*Box::<()>::new_uninit() as *const _,
|
||||||
|
@ -304,6 +304,7 @@ pub use once::OnceCell;
|
|||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// See the [module-level documentation](self) for more.
|
/// See the [module-level documentation](self) for more.
|
||||||
|
#[cfg_attr(not(test), rustc_diagnostic_item = "Cell")]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
#[rustc_pub_transparent]
|
#[rustc_pub_transparent]
|
||||||
|
@ -464,7 +464,9 @@ impl CStr {
|
|||||||
/// behavior when `ptr` is used inside the `unsafe` block:
|
/// behavior when `ptr` is used inside the `unsafe` block:
|
||||||
///
|
///
|
||||||
/// ```no_run
|
/// ```no_run
|
||||||
/// # #![allow(unused_must_use)] #![allow(temporary_cstring_as_ptr)]
|
/// # #![allow(unused_must_use)]
|
||||||
|
/// # #![cfg_attr(bootstrap, expect(temporary_cstring_as_ptr))]
|
||||||
|
/// # #![cfg_attr(not(bootstrap), expect(dangling_pointers_from_temporaries))]
|
||||||
/// use std::ffi::CString;
|
/// use std::ffi::CString;
|
||||||
///
|
///
|
||||||
/// // Do not do this:
|
/// // Do not do this:
|
||||||
|
@ -166,7 +166,7 @@ declare_with_version! { RENAMED(RENAMED_VERSION): &[(&str, &str)] = &[
|
|||||||
#[clippy::version = ""]
|
#[clippy::version = ""]
|
||||||
("clippy::positional_named_format_parameters", "named_arguments_used_positionally"),
|
("clippy::positional_named_format_parameters", "named_arguments_used_positionally"),
|
||||||
#[clippy::version = ""]
|
#[clippy::version = ""]
|
||||||
("clippy::temporary_cstring_as_ptr", "temporary_cstring_as_ptr"),
|
("clippy::temporary_cstring_as_ptr", "dangling_pointers_from_temporaries"),
|
||||||
#[clippy::version = ""]
|
#[clippy::version = ""]
|
||||||
("clippy::undropped_manually_drops", "undropped_manually_drops"),
|
("clippy::undropped_manually_drops", "undropped_manually_drops"),
|
||||||
#[clippy::version = ""]
|
#[clippy::version = ""]
|
||||||
|
@ -54,7 +54,7 @@
|
|||||||
#![allow(enum_intrinsics_non_enums)]
|
#![allow(enum_intrinsics_non_enums)]
|
||||||
#![allow(non_fmt_panics)]
|
#![allow(non_fmt_panics)]
|
||||||
#![allow(named_arguments_used_positionally)]
|
#![allow(named_arguments_used_positionally)]
|
||||||
#![allow(temporary_cstring_as_ptr)]
|
#![allow(dangling_pointers_from_temporaries)]
|
||||||
#![allow(undropped_manually_drops)]
|
#![allow(undropped_manually_drops)]
|
||||||
#![allow(unknown_lints)]
|
#![allow(unknown_lints)]
|
||||||
#![allow(unused_labels)]
|
#![allow(unused_labels)]
|
||||||
@ -120,7 +120,7 @@
|
|||||||
#![warn(unexpected_cfgs)] //~ ERROR: lint `clippy::mismatched_target_os`
|
#![warn(unexpected_cfgs)] //~ ERROR: lint `clippy::mismatched_target_os`
|
||||||
#![warn(non_fmt_panics)] //~ ERROR: lint `clippy::panic_params`
|
#![warn(non_fmt_panics)] //~ ERROR: lint `clippy::panic_params`
|
||||||
#![warn(named_arguments_used_positionally)] //~ ERROR: lint `clippy::positional_named_format_parameters`
|
#![warn(named_arguments_used_positionally)] //~ ERROR: lint `clippy::positional_named_format_parameters`
|
||||||
#![warn(temporary_cstring_as_ptr)] //~ ERROR: lint `clippy::temporary_cstring_as_ptr`
|
#![warn(dangling_pointers_from_temporaries)] //~ ERROR: lint `clippy::temporary_cstring_as_ptr`
|
||||||
#![warn(undropped_manually_drops)] //~ ERROR: lint `clippy::undropped_manually_drops`
|
#![warn(undropped_manually_drops)] //~ ERROR: lint `clippy::undropped_manually_drops`
|
||||||
#![warn(unknown_lints)] //~ ERROR: lint `clippy::unknown_clippy_lints`
|
#![warn(unknown_lints)] //~ ERROR: lint `clippy::unknown_clippy_lints`
|
||||||
#![warn(unused_labels)] //~ ERROR: lint `clippy::unused_label`
|
#![warn(unused_labels)] //~ ERROR: lint `clippy::unused_label`
|
||||||
|
@ -1,11 +1,17 @@
|
|||||||
|
error: lint `temporary_cstring_as_ptr` has been renamed to `dangling_pointers_from_temporaries`
|
||||||
|
--> tests/ui/rename.rs:57:10
|
||||||
|
|
|
||||||
|
LL | #![allow(temporary_cstring_as_ptr)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `dangling_pointers_from_temporaries`
|
||||||
|
|
|
||||||
|
= note: `-D renamed-and-removed-lints` implied by `-D warnings`
|
||||||
|
= help: to override `-D warnings` add `#[allow(renamed_and_removed_lints)]`
|
||||||
|
|
||||||
error: lint `clippy::almost_complete_letter_range` has been renamed to `clippy::almost_complete_range`
|
error: lint `clippy::almost_complete_letter_range` has been renamed to `clippy::almost_complete_range`
|
||||||
--> tests/ui/rename.rs:63:9
|
--> tests/ui/rename.rs:63:9
|
||||||
|
|
|
|
||||||
LL | #![warn(clippy::almost_complete_letter_range)]
|
LL | #![warn(clippy::almost_complete_letter_range)]
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range`
|
||||||
|
|
|
||||||
= note: `-D renamed-and-removed-lints` implied by `-D warnings`
|
|
||||||
= help: to override `-D warnings` add `#[allow(renamed_and_removed_lints)]`
|
|
||||||
|
|
||||||
error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names`
|
error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names`
|
||||||
--> tests/ui/rename.rs:64:9
|
--> tests/ui/rename.rs:64:9
|
||||||
@ -361,11 +367,11 @@ error: lint `clippy::positional_named_format_parameters` has been renamed to `na
|
|||||||
LL | #![warn(clippy::positional_named_format_parameters)]
|
LL | #![warn(clippy::positional_named_format_parameters)]
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally`
|
||||||
|
|
||||||
error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr`
|
error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `dangling_pointers_from_temporaries`
|
||||||
--> tests/ui/rename.rs:123:9
|
--> tests/ui/rename.rs:123:9
|
||||||
|
|
|
|
||||||
LL | #![warn(clippy::temporary_cstring_as_ptr)]
|
LL | #![warn(clippy::temporary_cstring_as_ptr)]
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `dangling_pointers_from_temporaries`
|
||||||
|
|
||||||
error: lint `clippy::undropped_manually_drops` has been renamed to `undropped_manually_drops`
|
error: lint `clippy::undropped_manually_drops` has been renamed to `undropped_manually_drops`
|
||||||
--> tests/ui/rename.rs:124:9
|
--> tests/ui/rename.rs:124:9
|
||||||
@ -397,5 +403,5 @@ error: lint `clippy::reverse_range_loop` has been renamed to `clippy::reversed_e
|
|||||||
LL | #![warn(clippy::reverse_range_loop)]
|
LL | #![warn(clippy::reverse_range_loop)]
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::reversed_empty_ranges`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::reversed_empty_ranges`
|
||||||
|
|
||||||
error: aborting due to 66 previous errors
|
error: aborting due to 67 previous errors
|
||||||
|
|
||||||
|
@ -17,8 +17,11 @@ fn main() {
|
|||||||
|
|
||||||
// The exact addresses returned by these library functions are not necessarily stable guarantees
|
// The exact addresses returned by these library functions are not necessarily stable guarantees
|
||||||
// but for now we assert that we're still matching.
|
// but for now we assert that we're still matching.
|
||||||
assert_eq!(<Vec<i32>>::new().as_ptr(), <&[i32]>::default().as_ptr());
|
#[allow(dangling_pointers_from_temporaries)]
|
||||||
assert_eq!(<Box<[i32]>>::default().as_ptr(), (&[]).as_ptr());
|
{
|
||||||
|
assert_eq!(<Vec<i32>>::new().as_ptr(), <&[i32]>::default().as_ptr());
|
||||||
|
assert_eq!(<Box<[i32]>>::default().as_ptr(), (&[]).as_ptr());
|
||||||
|
};
|
||||||
|
|
||||||
// statics must have a unique address (see https://github.com/rust-lang/rust/issues/18297, not
|
// statics must have a unique address (see https://github.com/rust-lang/rust/issues/18297, not
|
||||||
// clear whether this is a stable guarantee)
|
// clear whether this is a stable guarantee)
|
||||||
|
23
tests/ui/lint/dangling-pointers-from-temporaries/allow.rs
Normal file
23
tests/ui/lint/dangling-pointers-from-temporaries/allow.rs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#![allow(dangling_pointers_from_temporaries)]
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
dbg!(String::new().as_ptr());
|
||||||
|
// ^ no error
|
||||||
|
|
||||||
|
#[deny(dangling_pointers_from_temporaries)]
|
||||||
|
{
|
||||||
|
dbg!(String::new().as_ptr());
|
||||||
|
//~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped
|
||||||
|
}
|
||||||
|
S.foo()
|
||||||
|
}
|
||||||
|
|
||||||
|
struct S;
|
||||||
|
|
||||||
|
impl S {
|
||||||
|
#[warn(dangling_pointers_from_temporaries)]
|
||||||
|
fn foo(self) {
|
||||||
|
dbg!(String::new().as_ptr());
|
||||||
|
//~^ WARNING a dangling pointer will be produced because the temporary `String` will be dropped
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
error: a dangling pointer will be produced because the temporary `String` will be dropped
|
||||||
|
--> $DIR/allow.rs:9:28
|
||||||
|
|
|
||||||
|
LL | dbg!(String::new().as_ptr());
|
||||||
|
| ------------- ^^^^^^ this pointer will immediately be invalid
|
||||||
|
| |
|
||||||
|
| this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
|
||||||
|
|
|
||||||
|
= note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
|
||||||
|
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
|
||||||
|
note: the lint level is defined here
|
||||||
|
--> $DIR/allow.rs:7:12
|
||||||
|
|
|
||||||
|
LL | #[deny(dangling_pointers_from_temporaries)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
warning: a dangling pointer will be produced because the temporary `String` will be dropped
|
||||||
|
--> $DIR/allow.rs:20:28
|
||||||
|
|
|
||||||
|
LL | dbg!(String::new().as_ptr());
|
||||||
|
| ------------- ^^^^^^ this pointer will immediately be invalid
|
||||||
|
| |
|
||||||
|
| this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
|
||||||
|
|
|
||||||
|
= note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
|
||||||
|
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
|
||||||
|
note: the lint level is defined here
|
||||||
|
--> $DIR/allow.rs:18:12
|
||||||
|
|
|
||||||
|
LL | #[warn(dangling_pointers_from_temporaries)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error; 1 warning emitted
|
||||||
|
|
52
tests/ui/lint/dangling-pointers-from-temporaries/calls.rs
Normal file
52
tests/ui/lint/dangling-pointers-from-temporaries/calls.rs
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
#![deny(dangling_pointers_from_temporaries)]
|
||||||
|
|
||||||
|
use std::ffi::{c_char, CString};
|
||||||
|
|
||||||
|
fn cstring() -> CString {
|
||||||
|
CString::new("hello").unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn consume(ptr: *const c_char) {
|
||||||
|
let c = unsafe { ptr.read() };
|
||||||
|
dbg!(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
// None of these should trigger the lint.
|
||||||
|
fn ok() {
|
||||||
|
consume(cstring().as_ptr());
|
||||||
|
consume({ cstring() }.as_ptr());
|
||||||
|
consume({ cstring().as_ptr() });
|
||||||
|
consume(cstring().as_ptr().cast());
|
||||||
|
consume({ cstring() }.as_ptr().cast());
|
||||||
|
consume({ cstring().as_ptr() }.cast());
|
||||||
|
}
|
||||||
|
|
||||||
|
// All of these should trigger the lint.
|
||||||
|
fn not_ok() {
|
||||||
|
{
|
||||||
|
let ptr = cstring().as_ptr();
|
||||||
|
//~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped
|
||||||
|
consume(ptr);
|
||||||
|
}
|
||||||
|
consume({
|
||||||
|
let ptr = cstring().as_ptr();
|
||||||
|
//~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped
|
||||||
|
ptr
|
||||||
|
});
|
||||||
|
consume({
|
||||||
|
let s = cstring();
|
||||||
|
s.as_ptr()
|
||||||
|
//^ FIXME: should error
|
||||||
|
});
|
||||||
|
let _ptr: *const u8 = cstring().as_ptr().cast();
|
||||||
|
//~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped
|
||||||
|
let _ptr: *const u8 = { cstring() }.as_ptr().cast();
|
||||||
|
//~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped
|
||||||
|
let _ptr: *const u8 = { cstring().as_ptr() }.cast();
|
||||||
|
//~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
ok();
|
||||||
|
not_ok();
|
||||||
|
}
|
@ -0,0 +1,62 @@
|
|||||||
|
error: a dangling pointer will be produced because the temporary `CString` will be dropped
|
||||||
|
--> $DIR/calls.rs:27:29
|
||||||
|
|
|
||||||
|
LL | let ptr = cstring().as_ptr();
|
||||||
|
| --------- ^^^^^^ this pointer will immediately be invalid
|
||||||
|
| |
|
||||||
|
| this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
|
||||||
|
|
|
||||||
|
= note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
|
||||||
|
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
|
||||||
|
note: the lint level is defined here
|
||||||
|
--> $DIR/calls.rs:1:9
|
||||||
|
|
|
||||||
|
LL | #![deny(dangling_pointers_from_temporaries)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: a dangling pointer will be produced because the temporary `CString` will be dropped
|
||||||
|
--> $DIR/calls.rs:32:29
|
||||||
|
|
|
||||||
|
LL | let ptr = cstring().as_ptr();
|
||||||
|
| --------- ^^^^^^ this pointer will immediately be invalid
|
||||||
|
| |
|
||||||
|
| this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
|
||||||
|
|
|
||||||
|
= note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
|
||||||
|
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
|
||||||
|
|
||||||
|
error: a dangling pointer will be produced because the temporary `CString` will be dropped
|
||||||
|
--> $DIR/calls.rs:41:37
|
||||||
|
|
|
||||||
|
LL | let _ptr: *const u8 = cstring().as_ptr().cast();
|
||||||
|
| --------- ^^^^^^ this pointer will immediately be invalid
|
||||||
|
| |
|
||||||
|
| this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
|
||||||
|
|
|
||||||
|
= note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
|
||||||
|
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
|
||||||
|
|
||||||
|
error: a dangling pointer will be produced because the temporary `CString` will be dropped
|
||||||
|
--> $DIR/calls.rs:43:41
|
||||||
|
|
|
||||||
|
LL | let _ptr: *const u8 = { cstring() }.as_ptr().cast();
|
||||||
|
| ------------- ^^^^^^ this pointer will immediately be invalid
|
||||||
|
| |
|
||||||
|
| this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
|
||||||
|
|
|
||||||
|
= note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
|
||||||
|
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
|
||||||
|
|
||||||
|
error: a dangling pointer will be produced because the temporary `CString` will be dropped
|
||||||
|
--> $DIR/calls.rs:45:39
|
||||||
|
|
|
||||||
|
LL | let _ptr: *const u8 = { cstring().as_ptr() }.cast();
|
||||||
|
| --------- ^^^^^^ this pointer will immediately be invalid
|
||||||
|
| |
|
||||||
|
| this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
|
||||||
|
|
|
||||||
|
= note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
|
||||||
|
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
|
||||||
|
|
||||||
|
error: aborting due to 5 previous errors
|
||||||
|
|
@ -1,4 +1,7 @@
|
|||||||
|
//@ check-pass
|
||||||
|
|
||||||
#![deny(temporary_cstring_as_ptr)]
|
#![deny(temporary_cstring_as_ptr)]
|
||||||
|
//~^ WARNING lint `temporary_cstring_as_ptr` has been renamed to `dangling_pointers_from_temporaries`
|
||||||
|
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
use std::os::raw::c_char;
|
use std::os::raw::c_char;
|
||||||
@ -7,5 +10,4 @@ fn some_function(data: *const c_char) {}
|
|||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
some_function(CString::new("").unwrap().as_ptr());
|
some_function(CString::new("").unwrap().as_ptr());
|
||||||
//~^ ERROR getting the inner pointer of a temporary `CString`
|
|
||||||
}
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
warning: lint `temporary_cstring_as_ptr` has been renamed to `dangling_pointers_from_temporaries`
|
||||||
|
--> $DIR/cstring-as-param.rs:3:9
|
||||||
|
|
|
||||||
|
LL | #![deny(temporary_cstring_as_ptr)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `dangling_pointers_from_temporaries`
|
||||||
|
|
|
||||||
|
= note: `#[warn(renamed_and_removed_lints)]` on by default
|
||||||
|
|
||||||
|
warning: 1 warning emitted
|
||||||
|
|
@ -1,17 +1,18 @@
|
|||||||
// this program is not technically incorrect, but is an obscure enough style to be worth linting
|
// this program is not technically incorrect, but is an obscure enough style to be worth linting
|
||||||
#![deny(temporary_cstring_as_ptr)]
|
#![deny(temporary_cstring_as_ptr)]
|
||||||
|
//~^ WARNING lint `temporary_cstring_as_ptr` has been renamed to `dangling_pointers_from_temporaries`
|
||||||
|
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
|
|
||||||
macro_rules! mymacro {
|
macro_rules! mymacro {
|
||||||
() => {
|
() => {
|
||||||
let s = CString::new("some text").unwrap().as_ptr();
|
let s = CString::new("some text").unwrap().as_ptr();
|
||||||
//~^ ERROR getting the inner pointer of a temporary `CString`
|
//~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let s = CString::new("some text").unwrap().as_ptr();
|
let s = CString::new("some text").unwrap().as_ptr();
|
||||||
//~^ ERROR getting the inner pointer of a temporary `CString`
|
//~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped
|
||||||
mymacro!();
|
mymacro!();
|
||||||
}
|
}
|
@ -1,24 +1,32 @@
|
|||||||
error: getting the inner pointer of a temporary `CString`
|
warning: lint `temporary_cstring_as_ptr` has been renamed to `dangling_pointers_from_temporaries`
|
||||||
--> $DIR/lint-temporary-cstring-as-ptr.rs:14:48
|
--> $DIR/cstring-as-ptr.rs:2:9
|
||||||
|
|
|
||||||
|
LL | #![deny(temporary_cstring_as_ptr)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `dangling_pointers_from_temporaries`
|
||||||
|
|
|
||||||
|
= note: `#[warn(renamed_and_removed_lints)]` on by default
|
||||||
|
|
||||||
|
error: a dangling pointer will be produced because the temporary `CString` will be dropped
|
||||||
|
--> $DIR/cstring-as-ptr.rs:15:48
|
||||||
|
|
|
|
||||||
LL | let s = CString::new("some text").unwrap().as_ptr();
|
LL | let s = CString::new("some text").unwrap().as_ptr();
|
||||||
| ---------------------------------- ^^^^^^ this pointer will be invalid
|
| ---------------------------------- ^^^^^^ this pointer will immediately be invalid
|
||||||
| |
|
| |
|
||||||
| this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
|
| this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
|
||||||
|
|
|
|
||||||
= note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
|
= note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
|
||||||
= help: for more information, see https://doc.rust-lang.org/reference/destructors.html
|
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
|
||||||
note: the lint level is defined here
|
note: the lint level is defined here
|
||||||
--> $DIR/lint-temporary-cstring-as-ptr.rs:2:9
|
--> $DIR/cstring-as-ptr.rs:2:9
|
||||||
|
|
|
|
||||||
LL | #![deny(temporary_cstring_as_ptr)]
|
LL | #![deny(temporary_cstring_as_ptr)]
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: getting the inner pointer of a temporary `CString`
|
error: a dangling pointer will be produced because the temporary `CString` will be dropped
|
||||||
--> $DIR/lint-temporary-cstring-as-ptr.rs:8:52
|
--> $DIR/cstring-as-ptr.rs:9:52
|
||||||
|
|
|
|
||||||
LL | let s = CString::new("some text").unwrap().as_ptr();
|
LL | let s = CString::new("some text").unwrap().as_ptr();
|
||||||
| ---------------------------------- ^^^^^^ this pointer will be invalid
|
| ---------------------------------- ^^^^^^ this pointer will immediately be invalid
|
||||||
| |
|
| |
|
||||||
| this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
|
| this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
|
||||||
...
|
...
|
||||||
@ -26,8 +34,8 @@ LL | mymacro!();
|
|||||||
| ---------- in this macro invocation
|
| ---------- in this macro invocation
|
||||||
|
|
|
|
||||||
= note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
|
= note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
|
||||||
= help: for more information, see https://doc.rust-lang.org/reference/destructors.html
|
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
|
||||||
= note: this error originates in the macro `mymacro` (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in the macro `mymacro` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 2 previous errors; 1 warning emitted
|
||||||
|
|
19
tests/ui/lint/dangling-pointers-from-temporaries/emacs.rs
Normal file
19
tests/ui/lint/dangling-pointers-from-temporaries/emacs.rs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
//@ check-pass
|
||||||
|
|
||||||
|
#![deny(dangling_pointers_from_temporaries)]
|
||||||
|
|
||||||
|
// The original code example comes from bindgen-produced code for emacs.
|
||||||
|
// Hence the name of the test.
|
||||||
|
// https://github.com/rust-lang/rust/pull/128985#issuecomment-2338951363
|
||||||
|
|
||||||
|
use std::ffi::{c_char, CString};
|
||||||
|
|
||||||
|
fn read(ptr: *const c_char) -> c_char {
|
||||||
|
unsafe { ptr.read() }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let fnptr: Option<fn(ptr: *const c_char) -> c_char> = Some(read);
|
||||||
|
let x = fnptr.unwrap()(CString::new("foo").unwrap().as_ptr());
|
||||||
|
assert_eq!(x as u8, b'f');
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
#![deny(dangling_pointers_from_temporaries)]
|
||||||
|
|
||||||
|
const MAX_PATH: usize = 260;
|
||||||
|
fn main() {
|
||||||
|
let str1 = String::with_capacity(MAX_PATH).as_mut_ptr();
|
||||||
|
//~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped
|
||||||
|
let str2 = String::from("TotototototototototototototototototoT").as_ptr();
|
||||||
|
//~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped
|
||||||
|
unsafe {
|
||||||
|
std::ptr::copy_nonoverlapping(str2, str1, 30);
|
||||||
|
println!("{:?}", String::from_raw_parts(str1, 30, 30));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
error: a dangling pointer will be produced because the temporary `String` will be dropped
|
||||||
|
--> $DIR/example-from-issue123613.rs:5:48
|
||||||
|
|
|
||||||
|
LL | let str1 = String::with_capacity(MAX_PATH).as_mut_ptr();
|
||||||
|
| ------------------------------- ^^^^^^^^^^ this pointer will immediately be invalid
|
||||||
|
| |
|
||||||
|
| this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
|
||||||
|
|
|
||||||
|
= note: pointers do not have a lifetime; when calling `as_mut_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
|
||||||
|
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
|
||||||
|
note: the lint level is defined here
|
||||||
|
--> $DIR/example-from-issue123613.rs:1:9
|
||||||
|
|
|
||||||
|
LL | #![deny(dangling_pointers_from_temporaries)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: a dangling pointer will be produced because the temporary `String` will be dropped
|
||||||
|
--> $DIR/example-from-issue123613.rs:7:70
|
||||||
|
|
|
||||||
|
LL | let str2 = String::from("TotototototototototototototototototoT").as_ptr();
|
||||||
|
| ----------------------------------------------------- ^^^^^^ this pointer will immediately be invalid
|
||||||
|
| |
|
||||||
|
| this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
|
||||||
|
|
|
||||||
|
= note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
|
||||||
|
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
32
tests/ui/lint/dangling-pointers-from-temporaries/ext.rs
Normal file
32
tests/ui/lint/dangling-pointers-from-temporaries/ext.rs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#![deny(dangling_pointers_from_temporaries)]
|
||||||
|
|
||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
trait Ext1 {
|
||||||
|
fn dbg(self) -> Self
|
||||||
|
where
|
||||||
|
Self: Sized + Debug,
|
||||||
|
{
|
||||||
|
dbg!(&self);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Ext1 for *const T {}
|
||||||
|
|
||||||
|
trait Ext2 {
|
||||||
|
fn foo(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ext2 for *const u32 {
|
||||||
|
fn foo(self) {
|
||||||
|
dbg!(unsafe { self.read() });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let _ptr1 = Vec::<u32>::new().as_ptr().dbg();
|
||||||
|
//~^ ERROR a dangling pointer will be produced because the temporary `Vec<u32>` will be dropped
|
||||||
|
let _ptr2 = vec![0].as_ptr().foo();
|
||||||
|
//~^ ERROR a dangling pointer will be produced because the temporary `Vec<u32>` will be dropped
|
||||||
|
}
|
29
tests/ui/lint/dangling-pointers-from-temporaries/ext.stderr
Normal file
29
tests/ui/lint/dangling-pointers-from-temporaries/ext.stderr
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
error: a dangling pointer will be produced because the temporary `Vec<u32>` will be dropped
|
||||||
|
--> $DIR/ext.rs:28:35
|
||||||
|
|
|
||||||
|
LL | let _ptr1 = Vec::<u32>::new().as_ptr().dbg();
|
||||||
|
| ----------------- ^^^^^^ this pointer will immediately be invalid
|
||||||
|
| |
|
||||||
|
| this `Vec<u32>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
|
||||||
|
|
|
||||||
|
= note: pointers do not have a lifetime; when calling `as_ptr` the `Vec<u32>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
|
||||||
|
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
|
||||||
|
note: the lint level is defined here
|
||||||
|
--> $DIR/ext.rs:1:9
|
||||||
|
|
|
||||||
|
LL | #![deny(dangling_pointers_from_temporaries)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: a dangling pointer will be produced because the temporary `Vec<u32>` will be dropped
|
||||||
|
--> $DIR/ext.rs:30:25
|
||||||
|
|
|
||||||
|
LL | let _ptr2 = vec![0].as_ptr().foo();
|
||||||
|
| ------- ^^^^^^ this pointer will immediately be invalid
|
||||||
|
| |
|
||||||
|
| this `Vec<u32>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
|
||||||
|
|
|
||||||
|
= note: pointers do not have a lifetime; when calling `as_ptr` the `Vec<u32>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
|
||||||
|
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
@ -0,0 +1,8 @@
|
|||||||
|
#![deny(dangling_pointers_from_temporaries)]
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
vec![0u8].as_ptr();
|
||||||
|
//~^ ERROR a dangling pointer will be produced because the temporary `Vec<u8>` will be dropped
|
||||||
|
vec![0u8].as_mut_ptr();
|
||||||
|
//~^ ERROR a dangling pointer will be produced because the temporary `Vec<u8>` will be dropped
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
error: a dangling pointer will be produced because the temporary `Vec<u8>` will be dropped
|
||||||
|
--> $DIR/methods.rs:4:15
|
||||||
|
|
|
||||||
|
LL | vec![0u8].as_ptr();
|
||||||
|
| --------- ^^^^^^ this pointer will immediately be invalid
|
||||||
|
| |
|
||||||
|
| this `Vec<u8>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
|
||||||
|
|
|
||||||
|
= note: pointers do not have a lifetime; when calling `as_ptr` the `Vec<u8>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
|
||||||
|
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
|
||||||
|
note: the lint level is defined here
|
||||||
|
--> $DIR/methods.rs:1:9
|
||||||
|
|
|
||||||
|
LL | #![deny(dangling_pointers_from_temporaries)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: a dangling pointer will be produced because the temporary `Vec<u8>` will be dropped
|
||||||
|
--> $DIR/methods.rs:6:15
|
||||||
|
|
|
||||||
|
LL | vec![0u8].as_mut_ptr();
|
||||||
|
| --------- ^^^^^^^^^^ this pointer will immediately be invalid
|
||||||
|
| |
|
||||||
|
| this `Vec<u8>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
|
||||||
|
|
|
||||||
|
= note: pointers do not have a lifetime; when calling `as_mut_ptr` the `Vec<u8>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
|
||||||
|
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
136
tests/ui/lint/dangling-pointers-from-temporaries/temporaries.rs
Normal file
136
tests/ui/lint/dangling-pointers-from-temporaries/temporaries.rs
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
#![allow(unused)]
|
||||||
|
#![deny(dangling_pointers_from_temporaries)]
|
||||||
|
|
||||||
|
fn string() -> String {
|
||||||
|
"hello".into()
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Wrapper(String);
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// ConstBlock
|
||||||
|
const { String::new() }.as_ptr();
|
||||||
|
|
||||||
|
// Array
|
||||||
|
{
|
||||||
|
[string()].as_ptr(); // False negative
|
||||||
|
[true].as_ptr();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call
|
||||||
|
string().as_ptr();
|
||||||
|
//~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped
|
||||||
|
|
||||||
|
// MethodCall
|
||||||
|
"hello".to_string().as_ptr();
|
||||||
|
//~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped
|
||||||
|
|
||||||
|
// Tup
|
||||||
|
// impossible
|
||||||
|
|
||||||
|
// Binary
|
||||||
|
(string() + "hello").as_ptr();
|
||||||
|
//~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped
|
||||||
|
|
||||||
|
// Path
|
||||||
|
{
|
||||||
|
let x = string();
|
||||||
|
x.as_ptr();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unary
|
||||||
|
{
|
||||||
|
let x = string();
|
||||||
|
let x: &String = &x;
|
||||||
|
(*x).as_ptr();
|
||||||
|
(&[0u8]).as_ptr();
|
||||||
|
(&string()).as_ptr(); // False negative
|
||||||
|
(*&string()).as_ptr(); // False negative
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lit
|
||||||
|
"hello".as_ptr();
|
||||||
|
|
||||||
|
// Cast
|
||||||
|
// impossible
|
||||||
|
|
||||||
|
// Type
|
||||||
|
// impossible
|
||||||
|
|
||||||
|
// DropTemps
|
||||||
|
// impossible
|
||||||
|
|
||||||
|
// Let
|
||||||
|
// impossible
|
||||||
|
|
||||||
|
// If
|
||||||
|
{
|
||||||
|
(if true { String::new() } else { "hello".into() }).as_ptr();
|
||||||
|
//~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop
|
||||||
|
{
|
||||||
|
(loop {
|
||||||
|
break String::new();
|
||||||
|
})
|
||||||
|
.as_ptr();
|
||||||
|
//~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped
|
||||||
|
}
|
||||||
|
|
||||||
|
// Match
|
||||||
|
{
|
||||||
|
match string() {
|
||||||
|
s => s,
|
||||||
|
}
|
||||||
|
.as_ptr();
|
||||||
|
//~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped
|
||||||
|
}
|
||||||
|
|
||||||
|
// Closure
|
||||||
|
// impossible
|
||||||
|
|
||||||
|
// Block
|
||||||
|
{ string() }.as_ptr();
|
||||||
|
//~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped
|
||||||
|
|
||||||
|
// Assign, AssignOp
|
||||||
|
// impossible
|
||||||
|
|
||||||
|
// Field
|
||||||
|
{
|
||||||
|
Wrapper(string()).0.as_ptr(); // False negative
|
||||||
|
let x = Wrapper(string());
|
||||||
|
x.0.as_ptr();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Index
|
||||||
|
{
|
||||||
|
vec![string()][0].as_ptr(); // False negative
|
||||||
|
let x = vec![string()];
|
||||||
|
x[0].as_ptr();
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddrOf, InlineAsm, OffsetOf
|
||||||
|
// impossible
|
||||||
|
|
||||||
|
// Break, Continue, Ret
|
||||||
|
// are !
|
||||||
|
|
||||||
|
// Become, Yield
|
||||||
|
// unstable, are !
|
||||||
|
|
||||||
|
// Repeat
|
||||||
|
[0u8; 100].as_ptr();
|
||||||
|
[const { String::new() }; 100].as_ptr();
|
||||||
|
|
||||||
|
// Struct
|
||||||
|
// Cannot test this without access to private fields of the linted types.
|
||||||
|
|
||||||
|
// Err
|
||||||
|
// impossible
|
||||||
|
|
||||||
|
// Macro
|
||||||
|
vec![0u8].as_ptr();
|
||||||
|
//~^ ERROR a dangling pointer will be produced because the temporary `Vec<u8>` will be dropped
|
||||||
|
}
|
@ -0,0 +1,99 @@
|
|||||||
|
error: a dangling pointer will be produced because the temporary `String` will be dropped
|
||||||
|
--> $DIR/temporaries.rs:21:14
|
||||||
|
|
|
||||||
|
LL | string().as_ptr();
|
||||||
|
| -------- ^^^^^^ this pointer will immediately be invalid
|
||||||
|
| |
|
||||||
|
| this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
|
||||||
|
|
|
||||||
|
= note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
|
||||||
|
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
|
||||||
|
note: the lint level is defined here
|
||||||
|
--> $DIR/temporaries.rs:2:9
|
||||||
|
|
|
||||||
|
LL | #![deny(dangling_pointers_from_temporaries)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: a dangling pointer will be produced because the temporary `String` will be dropped
|
||||||
|
--> $DIR/temporaries.rs:25:25
|
||||||
|
|
|
||||||
|
LL | "hello".to_string().as_ptr();
|
||||||
|
| ------------------- ^^^^^^ this pointer will immediately be invalid
|
||||||
|
| |
|
||||||
|
| this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
|
||||||
|
|
|
||||||
|
= note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
|
||||||
|
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
|
||||||
|
|
||||||
|
error: a dangling pointer will be produced because the temporary `String` will be dropped
|
||||||
|
--> $DIR/temporaries.rs:32:26
|
||||||
|
|
|
||||||
|
LL | (string() + "hello").as_ptr();
|
||||||
|
| -------------------- ^^^^^^ this pointer will immediately be invalid
|
||||||
|
| |
|
||||||
|
| this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
|
||||||
|
|
|
||||||
|
= note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
|
||||||
|
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
|
||||||
|
|
||||||
|
error: a dangling pointer will be produced because the temporary `String` will be dropped
|
||||||
|
--> $DIR/temporaries.rs:68:61
|
||||||
|
|
|
||||||
|
LL | (if true { String::new() } else { "hello".into() }).as_ptr();
|
||||||
|
| --------------------------------------------------- ^^^^^^ this pointer will immediately be invalid
|
||||||
|
| |
|
||||||
|
| this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
|
||||||
|
|
|
||||||
|
= note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
|
||||||
|
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
|
||||||
|
|
||||||
|
error: a dangling pointer will be produced because the temporary `String` will be dropped
|
||||||
|
--> $DIR/temporaries.rs:77:10
|
||||||
|
|
|
||||||
|
LL | / (loop {
|
||||||
|
LL | | break String::new();
|
||||||
|
LL | | })
|
||||||
|
| |__________- this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
|
||||||
|
LL | .as_ptr();
|
||||||
|
| ^^^^^^ this pointer will immediately be invalid
|
||||||
|
|
|
||||||
|
= note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
|
||||||
|
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
|
||||||
|
|
||||||
|
error: a dangling pointer will be produced because the temporary `String` will be dropped
|
||||||
|
--> $DIR/temporaries.rs:86:10
|
||||||
|
|
|
||||||
|
LL | / match string() {
|
||||||
|
LL | | s => s,
|
||||||
|
LL | | }
|
||||||
|
| |_________- this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
|
||||||
|
LL | .as_ptr();
|
||||||
|
| ^^^^^^ this pointer will immediately be invalid
|
||||||
|
|
|
||||||
|
= note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
|
||||||
|
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
|
||||||
|
|
||||||
|
error: a dangling pointer will be produced because the temporary `String` will be dropped
|
||||||
|
--> $DIR/temporaries.rs:94:18
|
||||||
|
|
|
||||||
|
LL | { string() }.as_ptr();
|
||||||
|
| ------------ ^^^^^^ this pointer will immediately be invalid
|
||||||
|
| |
|
||||||
|
| this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
|
||||||
|
|
|
||||||
|
= note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
|
||||||
|
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
|
||||||
|
|
||||||
|
error: a dangling pointer will be produced because the temporary `Vec<u8>` will be dropped
|
||||||
|
--> $DIR/temporaries.rs:134:15
|
||||||
|
|
|
||||||
|
LL | vec![0u8].as_ptr();
|
||||||
|
| --------- ^^^^^^ this pointer will immediately be invalid
|
||||||
|
| |
|
||||||
|
| this `Vec<u8>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
|
||||||
|
|
|
||||||
|
= note: pointers do not have a lifetime; when calling `as_ptr` the `Vec<u8>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
|
||||||
|
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
|
||||||
|
|
||||||
|
error: aborting due to 8 previous errors
|
||||||
|
|
52
tests/ui/lint/dangling-pointers-from-temporaries/types.rs
Normal file
52
tests/ui/lint/dangling-pointers-from-temporaries/types.rs
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
#![deny(dangling_pointers_from_temporaries)]
|
||||||
|
|
||||||
|
use std::cell::Cell;
|
||||||
|
use std::ffi::{CStr, CString};
|
||||||
|
use std::mem::MaybeUninit;
|
||||||
|
|
||||||
|
struct AsPtrFake;
|
||||||
|
|
||||||
|
impl AsPtrFake {
|
||||||
|
fn as_ptr(&self) -> *const () {
|
||||||
|
std::ptr::null()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn declval<T>() -> T {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
declval::<CString>().as_ptr();
|
||||||
|
//~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped
|
||||||
|
declval::<String>().as_ptr();
|
||||||
|
//~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped
|
||||||
|
declval::<Vec<u8>>().as_ptr();
|
||||||
|
//~^ ERROR a dangling pointer will be produced because the temporary `Vec<u8>` will be dropped
|
||||||
|
declval::<Box<CString>>().as_ptr();
|
||||||
|
//~^ ERROR a dangling pointer will be produced because the temporary `Box<CString>` will be dropped
|
||||||
|
declval::<Box<[u8]>>().as_ptr();
|
||||||
|
//~^ ERROR a dangling pointer will be produced because the temporary `Box<[u8]>` will be dropped
|
||||||
|
declval::<Box<str>>().as_ptr();
|
||||||
|
//~^ ERROR a dangling pointer will be produced because the temporary `Box<str>` will be dropped
|
||||||
|
declval::<Box<CStr>>().as_ptr();
|
||||||
|
//~^ ERROR a dangling pointer will be produced because the temporary `Box<CStr>` will be dropped
|
||||||
|
declval::<[u8; 10]>().as_ptr();
|
||||||
|
//~^ ERROR a dangling pointer will be produced because the temporary `[u8; 10]` will be dropped
|
||||||
|
declval::<Box<[u8; 10]>>().as_ptr();
|
||||||
|
//~^ ERROR a dangling pointer will be produced because the temporary `Box<[u8; 10]>` will be dropped
|
||||||
|
declval::<Box<Vec<u8>>>().as_ptr();
|
||||||
|
//~^ ERROR a dangling pointer will be produced because the temporary `Box<Vec<u8>>` will be dropped
|
||||||
|
declval::<Box<String>>().as_ptr();
|
||||||
|
//~^ ERROR a dangling pointer will be produced because the temporary `Box<String>` will be dropped
|
||||||
|
declval::<Box<Box<Box<Box<[u8]>>>>>().as_ptr();
|
||||||
|
//~^ ERROR a dangling pointer will be produced because the temporary `Box<Box<Box<Box<[u8]>>>>` will be dropped
|
||||||
|
declval::<Cell<u8>>().as_ptr();
|
||||||
|
//~^ ERROR a dangling pointer will be produced because the temporary `Cell<u8>` will be dropped
|
||||||
|
declval::<MaybeUninit<u8>>().as_ptr();
|
||||||
|
//~^ ERROR a dangling pointer will be produced because the temporary `MaybeUninit<u8>` will be dropped
|
||||||
|
declval::<Vec<AsPtrFake>>().as_ptr();
|
||||||
|
//~^ ERROR a dangling pointer will be produced because the temporary `Vec<AsPtrFake>` will be dropped
|
||||||
|
declval::<Box<AsPtrFake>>().as_ptr();
|
||||||
|
declval::<AsPtrFake>().as_ptr();
|
||||||
|
}
|
172
tests/ui/lint/dangling-pointers-from-temporaries/types.stderr
Normal file
172
tests/ui/lint/dangling-pointers-from-temporaries/types.stderr
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
error: a dangling pointer will be produced because the temporary `CString` will be dropped
|
||||||
|
--> $DIR/types.rs:20:26
|
||||||
|
|
|
||||||
|
LL | declval::<CString>().as_ptr();
|
||||||
|
| -------------------- ^^^^^^ this pointer will immediately be invalid
|
||||||
|
| |
|
||||||
|
| this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
|
||||||
|
|
|
||||||
|
= note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
|
||||||
|
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
|
||||||
|
note: the lint level is defined here
|
||||||
|
--> $DIR/types.rs:1:9
|
||||||
|
|
|
||||||
|
LL | #![deny(dangling_pointers_from_temporaries)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: a dangling pointer will be produced because the temporary `String` will be dropped
|
||||||
|
--> $DIR/types.rs:22:25
|
||||||
|
|
|
||||||
|
LL | declval::<String>().as_ptr();
|
||||||
|
| ------------------- ^^^^^^ this pointer will immediately be invalid
|
||||||
|
| |
|
||||||
|
| this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
|
||||||
|
|
|
||||||
|
= note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
|
||||||
|
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
|
||||||
|
|
||||||
|
error: a dangling pointer will be produced because the temporary `Vec<u8>` will be dropped
|
||||||
|
--> $DIR/types.rs:24:26
|
||||||
|
|
|
||||||
|
LL | declval::<Vec<u8>>().as_ptr();
|
||||||
|
| -------------------- ^^^^^^ this pointer will immediately be invalid
|
||||||
|
| |
|
||||||
|
| this `Vec<u8>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
|
||||||
|
|
|
||||||
|
= note: pointers do not have a lifetime; when calling `as_ptr` the `Vec<u8>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
|
||||||
|
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
|
||||||
|
|
||||||
|
error: a dangling pointer will be produced because the temporary `Box<CString>` will be dropped
|
||||||
|
--> $DIR/types.rs:26:31
|
||||||
|
|
|
||||||
|
LL | declval::<Box<CString>>().as_ptr();
|
||||||
|
| ------------------------- ^^^^^^ this pointer will immediately be invalid
|
||||||
|
| |
|
||||||
|
| this `Box<CString>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
|
||||||
|
|
|
||||||
|
= note: pointers do not have a lifetime; when calling `as_ptr` the `Box<CString>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
|
||||||
|
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
|
||||||
|
|
||||||
|
error: a dangling pointer will be produced because the temporary `Box<[u8]>` will be dropped
|
||||||
|
--> $DIR/types.rs:28:28
|
||||||
|
|
|
||||||
|
LL | declval::<Box<[u8]>>().as_ptr();
|
||||||
|
| ---------------------- ^^^^^^ this pointer will immediately be invalid
|
||||||
|
| |
|
||||||
|
| this `Box<[u8]>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
|
||||||
|
|
|
||||||
|
= note: pointers do not have a lifetime; when calling `as_ptr` the `Box<[u8]>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
|
||||||
|
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
|
||||||
|
|
||||||
|
error: a dangling pointer will be produced because the temporary `Box<str>` will be dropped
|
||||||
|
--> $DIR/types.rs:30:27
|
||||||
|
|
|
||||||
|
LL | declval::<Box<str>>().as_ptr();
|
||||||
|
| --------------------- ^^^^^^ this pointer will immediately be invalid
|
||||||
|
| |
|
||||||
|
| this `Box<str>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
|
||||||
|
|
|
||||||
|
= note: pointers do not have a lifetime; when calling `as_ptr` the `Box<str>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
|
||||||
|
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
|
||||||
|
|
||||||
|
error: a dangling pointer will be produced because the temporary `Box<CStr>` will be dropped
|
||||||
|
--> $DIR/types.rs:32:28
|
||||||
|
|
|
||||||
|
LL | declval::<Box<CStr>>().as_ptr();
|
||||||
|
| ---------------------- ^^^^^^ this pointer will immediately be invalid
|
||||||
|
| |
|
||||||
|
| this `Box<CStr>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
|
||||||
|
|
|
||||||
|
= note: pointers do not have a lifetime; when calling `as_ptr` the `Box<CStr>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
|
||||||
|
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
|
||||||
|
|
||||||
|
error: a dangling pointer will be produced because the temporary `[u8; 10]` will be dropped
|
||||||
|
--> $DIR/types.rs:34:27
|
||||||
|
|
|
||||||
|
LL | declval::<[u8; 10]>().as_ptr();
|
||||||
|
| --------------------- ^^^^^^ this pointer will immediately be invalid
|
||||||
|
| |
|
||||||
|
| this `[u8; 10]` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
|
||||||
|
|
|
||||||
|
= note: pointers do not have a lifetime; when calling `as_ptr` the `[u8; 10]` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
|
||||||
|
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
|
||||||
|
|
||||||
|
error: a dangling pointer will be produced because the temporary `Box<[u8; 10]>` will be dropped
|
||||||
|
--> $DIR/types.rs:36:32
|
||||||
|
|
|
||||||
|
LL | declval::<Box<[u8; 10]>>().as_ptr();
|
||||||
|
| -------------------------- ^^^^^^ this pointer will immediately be invalid
|
||||||
|
| |
|
||||||
|
| this `Box<[u8; 10]>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
|
||||||
|
|
|
||||||
|
= note: pointers do not have a lifetime; when calling `as_ptr` the `Box<[u8; 10]>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
|
||||||
|
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
|
||||||
|
|
||||||
|
error: a dangling pointer will be produced because the temporary `Box<Vec<u8>>` will be dropped
|
||||||
|
--> $DIR/types.rs:38:31
|
||||||
|
|
|
||||||
|
LL | declval::<Box<Vec<u8>>>().as_ptr();
|
||||||
|
| ------------------------- ^^^^^^ this pointer will immediately be invalid
|
||||||
|
| |
|
||||||
|
| this `Box<Vec<u8>>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
|
||||||
|
|
|
||||||
|
= note: pointers do not have a lifetime; when calling `as_ptr` the `Box<Vec<u8>>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
|
||||||
|
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
|
||||||
|
|
||||||
|
error: a dangling pointer will be produced because the temporary `Box<String>` will be dropped
|
||||||
|
--> $DIR/types.rs:40:30
|
||||||
|
|
|
||||||
|
LL | declval::<Box<String>>().as_ptr();
|
||||||
|
| ------------------------ ^^^^^^ this pointer will immediately be invalid
|
||||||
|
| |
|
||||||
|
| this `Box<String>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
|
||||||
|
|
|
||||||
|
= note: pointers do not have a lifetime; when calling `as_ptr` the `Box<String>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
|
||||||
|
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
|
||||||
|
|
||||||
|
error: a dangling pointer will be produced because the temporary `Box<Box<Box<Box<[u8]>>>>` will be dropped
|
||||||
|
--> $DIR/types.rs:42:43
|
||||||
|
|
|
||||||
|
LL | declval::<Box<Box<Box<Box<[u8]>>>>>().as_ptr();
|
||||||
|
| ------------------------------------- ^^^^^^ this pointer will immediately be invalid
|
||||||
|
| |
|
||||||
|
| this `Box<Box<Box<Box<[u8]>>>>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
|
||||||
|
|
|
||||||
|
= note: pointers do not have a lifetime; when calling `as_ptr` the `Box<Box<Box<Box<[u8]>>>>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
|
||||||
|
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
|
||||||
|
|
||||||
|
error: a dangling pointer will be produced because the temporary `Cell<u8>` will be dropped
|
||||||
|
--> $DIR/types.rs:44:27
|
||||||
|
|
|
||||||
|
LL | declval::<Cell<u8>>().as_ptr();
|
||||||
|
| --------------------- ^^^^^^ this pointer will immediately be invalid
|
||||||
|
| |
|
||||||
|
| this `Cell<u8>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
|
||||||
|
|
|
||||||
|
= note: pointers do not have a lifetime; when calling `as_ptr` the `Cell<u8>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
|
||||||
|
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
|
||||||
|
|
||||||
|
error: a dangling pointer will be produced because the temporary `MaybeUninit<u8>` will be dropped
|
||||||
|
--> $DIR/types.rs:46:34
|
||||||
|
|
|
||||||
|
LL | declval::<MaybeUninit<u8>>().as_ptr();
|
||||||
|
| ---------------------------- ^^^^^^ this pointer will immediately be invalid
|
||||||
|
| |
|
||||||
|
| this `MaybeUninit<u8>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
|
||||||
|
|
|
||||||
|
= note: pointers do not have a lifetime; when calling `as_ptr` the `MaybeUninit<u8>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
|
||||||
|
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
|
||||||
|
|
||||||
|
error: a dangling pointer will be produced because the temporary `Vec<AsPtrFake>` will be dropped
|
||||||
|
--> $DIR/types.rs:48:33
|
||||||
|
|
|
||||||
|
LL | declval::<Vec<AsPtrFake>>().as_ptr();
|
||||||
|
| --------------------------- ^^^^^^ this pointer will immediately be invalid
|
||||||
|
| |
|
||||||
|
| this `Vec<AsPtrFake>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
|
||||||
|
|
|
||||||
|
= note: pointers do not have a lifetime; when calling `as_ptr` the `Vec<AsPtrFake>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
|
||||||
|
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
|
||||||
|
|
||||||
|
error: aborting due to 15 previous errors
|
||||||
|
|
@ -1,18 +0,0 @@
|
|||||||
error: getting the inner pointer of a temporary `CString`
|
|
||||||
--> $DIR/lint-temporary-cstring-as-param.rs:9:45
|
|
||||||
|
|
|
||||||
LL | some_function(CString::new("").unwrap().as_ptr());
|
|
||||||
| ------------------------- ^^^^^^ this pointer will be invalid
|
|
||||||
| |
|
|
||||||
| this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
|
|
||||||
|
|
|
||||||
= note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
|
|
||||||
= help: for more information, see https://doc.rust-lang.org/reference/destructors.html
|
|
||||||
note: the lint level is defined here
|
|
||||||
--> $DIR/lint-temporary-cstring-as-param.rs:1:9
|
|
||||||
|
|
|
||||||
LL | #![deny(temporary_cstring_as_ptr)]
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user