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:
bors 2024-10-29 00:24:07 +00:00
commit a9d17627d2
33 changed files with 1093 additions and 128 deletions

View File

@ -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

View 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
}
}

View File

@ -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

View File

@ -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

View File

@ -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,
});
}
}
}
}
}

View File

@ -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,

View File

@ -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 _,

View File

@ -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]

View File

@ -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:

View File

@ -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 = ""]

View File

@ -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`

View File

@ -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

View File

@ -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)

View 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
}
}

View File

@ -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

View 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();
}

View File

@ -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

View File

@ -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`
} }

View File

@ -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

View File

@ -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!();
} }

View File

@ -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

View 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');
}

View File

@ -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));
}
}

View File

@ -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

View 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
}

View 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

View File

@ -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
}

View File

@ -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

View 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
}

View File

@ -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

View 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();
}

View 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

View File

@ -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