Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit a9d1762

Browse files
committedOct 29, 2024·
Auto merge of rust-lang#128985 - GrigorenkoPV:instantly-dangling-pointer, r=Urgau
Lint against getting pointers from immediately dropped temporaries Fixes rust-lang#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? rust-lang#128985 (comment) ## 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**
2 parents 3f1be1e + c69894e commit a9d1762

33 files changed

+1093
-128
lines changed
 

‎compiler/rustc_lint/messages.ftl

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -203,14 +203,14 @@ lint_confusable_identifier_pair = found both `{$existing_sym}` and `{$sym}` as i
203203
.current_use = this identifier can be confused with `{$existing_sym}`
204204
.other_use = other identifier used here
205205
206-
lint_cstring_ptr = getting the inner pointer of a temporary `CString`
207-
.as_ptr_label = this pointer will be invalid
208-
.unwrap_label = this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
209-
.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
210-
.help = for more information, see https://doc.rust-lang.org/reference/destructors.html
211-
212206
lint_custom_inner_attribute_unstable = custom inner attributes are unstable
213207
208+
lint_dangling_pointers_from_temporaries = a dangling pointer will be produced because the temporary `{$ty}` will be dropped
209+
.label_ptr = this pointer will immediately be invalid
210+
.label_temporary = this `{$ty}` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
211+
.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
212+
.help = for more information, see <https://doc.rust-lang.org/reference/destructors.html>
213+
214214
lint_default_hash_types = prefer `{$preferred}` over `{$used}`, it has better performance
215215
.note = a `use rustc_data_structures::fx::{$preferred}` may be necessary
216216

‎compiler/rustc_lint/src/dangling.rs

Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
use rustc_ast::visit::{visit_opt, walk_list};
2+
use rustc_hir::def_id::LocalDefId;
3+
use rustc_hir::intravisit::{FnKind, Visitor, walk_expr};
4+
use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, LangItem};
5+
use rustc_middle::ty::{Ty, TyCtxt};
6+
use rustc_session::{declare_lint, impl_lint_pass};
7+
use rustc_span::Span;
8+
use rustc_span::symbol::sym;
9+
10+
use crate::lints::DanglingPointersFromTemporaries;
11+
use crate::{LateContext, LateLintPass};
12+
13+
declare_lint! {
14+
/// The `dangling_pointers_from_temporaries` lint detects getting a pointer to data
15+
/// of a temporary that will immediately get dropped.
16+
///
17+
/// ### Example
18+
///
19+
/// ```rust
20+
/// # #![allow(unused)]
21+
/// # unsafe fn use_data(ptr: *const u8) { }
22+
/// fn gather_and_use(bytes: impl Iterator<Item = u8>) {
23+
/// let x: *const u8 = bytes.collect::<Vec<u8>>().as_ptr();
24+
/// unsafe { use_data(x) }
25+
/// }
26+
/// ```
27+
///
28+
/// {{produces}}
29+
///
30+
/// ### Explanation
31+
///
32+
/// Getting a pointer from a temporary value will not prolong its lifetime,
33+
/// which means that the value can be dropped and the allocation freed
34+
/// while the pointer still exists, making the pointer dangling.
35+
/// This is not an error (as far as the type system is concerned)
36+
/// but probably is not what the user intended either.
37+
///
38+
/// If you need stronger guarantees, consider using references instead,
39+
/// as they are statically verified by the borrow-checker to never dangle.
40+
pub DANGLING_POINTERS_FROM_TEMPORARIES,
41+
Warn,
42+
"detects getting a pointer from a temporary"
43+
}
44+
45+
/// FIXME: false negatives (i.e. the lint is not emitted when it should be)
46+
/// 1. Method calls that are not checked for:
47+
/// - [`temporary_unsafe_cell.get()`][`core::cell::UnsafeCell::get()`]
48+
/// - [`temporary_sync_unsafe_cell.get()`][`core::cell::SyncUnsafeCell::get()`]
49+
/// 2. Ways to get a temporary that are not recognized:
50+
/// - `owning_temporary.field`
51+
/// - `owning_temporary[index]`
52+
/// 3. No checks for ref-to-ptr conversions:
53+
/// - `&raw [mut] temporary`
54+
/// - `&temporary as *(const|mut) _`
55+
/// - `ptr::from_ref(&temporary)` and friends
56+
#[derive(Clone, Copy, Default)]
57+
pub(crate) struct DanglingPointers;
58+
59+
impl_lint_pass!(DanglingPointers => [DANGLING_POINTERS_FROM_TEMPORARIES]);
60+
61+
// This skips over const blocks, but they cannot use or return a dangling pointer anyways.
62+
impl<'tcx> LateLintPass<'tcx> for DanglingPointers {
63+
fn check_fn(
64+
&mut self,
65+
cx: &LateContext<'tcx>,
66+
_: FnKind<'tcx>,
67+
_: &'tcx FnDecl<'tcx>,
68+
body: &'tcx Body<'tcx>,
69+
_: Span,
70+
_: LocalDefId,
71+
) {
72+
DanglingPointerSearcher { cx, inside_call_args: false }.visit_body(body)
73+
}
74+
}
75+
76+
/// This produces a dangling pointer:
77+
/// ```ignore (example)
78+
/// let ptr = CString::new("hello").unwrap().as_ptr();
79+
/// foo(ptr)
80+
/// ```
81+
///
82+
/// But this does not:
83+
/// ```ignore (example)
84+
/// foo(CString::new("hello").unwrap().as_ptr())
85+
/// ```
86+
///
87+
/// But this does:
88+
/// ```ignore (example)
89+
/// foo({ let ptr = CString::new("hello").unwrap().as_ptr(); ptr })
90+
/// ```
91+
///
92+
/// So we have to keep track of when we are inside of a function/method call argument.
93+
struct DanglingPointerSearcher<'lcx, 'tcx> {
94+
cx: &'lcx LateContext<'tcx>,
95+
/// Keeps track of whether we are inside of function/method call arguments,
96+
/// where this lint should not be emitted.
97+
///
98+
/// See [the main doc][`Self`] for examples.
99+
inside_call_args: bool,
100+
}
101+
102+
impl Visitor<'_> for DanglingPointerSearcher<'_, '_> {
103+
fn visit_expr(&mut self, expr: &Expr<'_>) -> Self::Result {
104+
if !self.inside_call_args {
105+
lint_expr(self.cx, expr)
106+
}
107+
match expr.kind {
108+
ExprKind::Call(lhs, args) | ExprKind::MethodCall(_, lhs, args, _) => {
109+
self.visit_expr(lhs);
110+
self.with_inside_call_args(true, |this| walk_list!(this, visit_expr, args))
111+
}
112+
ExprKind::Block(&Block { stmts, expr, .. }, _) => {
113+
self.with_inside_call_args(false, |this| walk_list!(this, visit_stmt, stmts));
114+
visit_opt!(self, visit_expr, expr)
115+
}
116+
_ => walk_expr(self, expr),
117+
}
118+
}
119+
}
120+
121+
impl DanglingPointerSearcher<'_, '_> {
122+
fn with_inside_call_args<R>(
123+
&mut self,
124+
inside_call_args: bool,
125+
callback: impl FnOnce(&mut Self) -> R,
126+
) -> R {
127+
let old = core::mem::replace(&mut self.inside_call_args, inside_call_args);
128+
let result = callback(self);
129+
self.inside_call_args = old;
130+
result
131+
}
132+
}
133+
134+
fn lint_expr(cx: &LateContext<'_>, expr: &Expr<'_>) {
135+
if let ExprKind::MethodCall(method, receiver, _args, _span) = expr.kind
136+
&& matches!(method.ident.name, sym::as_ptr | sym::as_mut_ptr)
137+
&& is_temporary_rvalue(receiver)
138+
&& let ty = cx.typeck_results().expr_ty(receiver)
139+
&& is_interesting(cx.tcx, ty)
140+
{
141+
// FIXME: use `emit_node_lint` when `#[primary_span]` is added.
142+
cx.tcx.emit_node_span_lint(
143+
DANGLING_POINTERS_FROM_TEMPORARIES,
144+
expr.hir_id,
145+
method.ident.span,
146+
DanglingPointersFromTemporaries {
147+
callee: method.ident.name,
148+
ty,
149+
ptr_span: method.ident.span,
150+
temporary_span: receiver.span,
151+
},
152+
)
153+
}
154+
}
155+
156+
fn is_temporary_rvalue(expr: &Expr<'_>) -> bool {
157+
match expr.kind {
158+
// Const is not temporary.
159+
ExprKind::ConstBlock(..) | ExprKind::Repeat(..) | ExprKind::Lit(..) => false,
160+
161+
// This is literally lvalue.
162+
ExprKind::Path(..) => false,
163+
164+
// Calls return rvalues.
165+
ExprKind::Call(..) | ExprKind::MethodCall(..) | ExprKind::Binary(..) => true,
166+
167+
// Inner blocks are rvalues.
168+
ExprKind::If(..) | ExprKind::Loop(..) | ExprKind::Match(..) | ExprKind::Block(..) => true,
169+
170+
// FIXME: these should probably recurse and typecheck along the way.
171+
// Some false negatives are possible for now.
172+
ExprKind::Index(..) | ExprKind::Field(..) | ExprKind::Unary(..) => false,
173+
174+
ExprKind::Struct(..) => true,
175+
176+
// FIXME: this has false negatives, but I do not want to deal with 'static/const promotion just yet.
177+
ExprKind::Array(..) => false,
178+
179+
// These typecheck to `!`
180+
ExprKind::Break(..) | ExprKind::Continue(..) | ExprKind::Ret(..) | ExprKind::Become(..) => {
181+
false
182+
}
183+
184+
// These typecheck to `()`
185+
ExprKind::Assign(..) | ExprKind::AssignOp(..) | ExprKind::Yield(..) => false,
186+
187+
// Compiler-magic macros
188+
ExprKind::AddrOf(..) | ExprKind::OffsetOf(..) | ExprKind::InlineAsm(..) => false,
189+
190+
// We are not interested in these
191+
ExprKind::Cast(..)
192+
| ExprKind::Closure(..)
193+
| ExprKind::Tup(..)
194+
| ExprKind::DropTemps(..)
195+
| ExprKind::Let(..) => false,
196+
197+
// Not applicable
198+
ExprKind::Type(..) | ExprKind::Err(..) => false,
199+
}
200+
}
201+
202+
// Array, Vec, String, CString, MaybeUninit, Cell, Box<[_]>, Box<str>, Box<CStr>,
203+
// or any of the above in arbitrary many nested Box'es.
204+
fn is_interesting(tcx: TyCtxt<'_>, ty: Ty<'_>) -> bool {
205+
if ty.is_array() {
206+
true
207+
} else if let Some(inner) = ty.boxed_ty() {
208+
inner.is_slice()
209+
|| inner.is_str()
210+
|| inner.ty_adt_def().is_some_and(|def| tcx.is_lang_item(def.did(), LangItem::CStr))
211+
|| is_interesting(tcx, inner)
212+
} else if let Some(def) = ty.ty_adt_def() {
213+
for lang_item in [LangItem::String, LangItem::MaybeUninit] {
214+
if tcx.is_lang_item(def.did(), lang_item) {
215+
return true;
216+
}
217+
}
218+
tcx.get_diagnostic_name(def.did())
219+
.is_some_and(|name| matches!(name, sym::cstring_type | sym::Vec | sym::Cell))
220+
} else {
221+
false
222+
}
223+
}

‎compiler/rustc_lint/src/lib.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ mod async_closures;
4040
mod async_fn_in_trait;
4141
pub mod builtin;
4242
mod context;
43+
mod dangling;
4344
mod deref_into_dyn_supertrait;
4445
mod drop_forget_useless;
4546
mod early;
@@ -59,7 +60,6 @@ mod levels;
5960
mod lints;
6061
mod macro_expr_fragment_specifier_2024_migration;
6162
mod map_unit_fn;
62-
mod methods;
6363
mod multiple_supertrait_upcastable;
6464
mod non_ascii_idents;
6565
mod non_fmt_panic;
@@ -85,6 +85,7 @@ mod unused;
8585
use async_closures::AsyncClosureUsage;
8686
use async_fn_in_trait::AsyncFnInTrait;
8787
use builtin::*;
88+
use dangling::*;
8889
use deref_into_dyn_supertrait::*;
8990
use drop_forget_useless::*;
9091
use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums;
@@ -97,7 +98,6 @@ use invalid_from_utf8::*;
9798
use let_underscore::*;
9899
use macro_expr_fragment_specifier_2024_migration::*;
99100
use map_unit_fn::*;
100-
use methods::*;
101101
use multiple_supertrait_upcastable::*;
102102
use non_ascii_idents::*;
103103
use non_fmt_panic::NonPanicFmt;
@@ -225,7 +225,7 @@ late_lint_methods!(
225225
UngatedAsyncFnTrackCaller: UngatedAsyncFnTrackCaller,
226226
ShadowedIntoIter: ShadowedIntoIter,
227227
DropTraitConstraints: DropTraitConstraints,
228-
TemporaryCStringAsPtr: TemporaryCStringAsPtr,
228+
DanglingPointers: DanglingPointers,
229229
NonPanicFmt: NonPanicFmt,
230230
NoopMethodCall: NoopMethodCall,
231231
EnumIntrinsicsNonEnums: EnumIntrinsicsNonEnums,
@@ -350,6 +350,7 @@ fn register_builtins(store: &mut LintStore) {
350350
store.register_renamed("non_fmt_panic", "non_fmt_panics");
351351
store.register_renamed("unused_tuple_struct_fields", "dead_code");
352352
store.register_renamed("static_mut_ref", "static_mut_refs");
353+
store.register_renamed("temporary_cstring_as_ptr", "dangling_pointers_from_temporaries");
353354

354355
// These were moved to tool lints, but rustc still sees them when compiling normally, before
355356
// tool lints are registered, so `check_tool_name_for_backwards_compat` doesn't work. Use

‎compiler/rustc_lint/src/lints.rs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1137,16 +1137,19 @@ pub(crate) struct IgnoredUnlessCrateSpecified<'a> {
11371137
pub name: Symbol,
11381138
}
11391139

1140-
// methods.rs
1140+
// dangling.rs
11411141
#[derive(LintDiagnostic)]
1142-
#[diag(lint_cstring_ptr)]
1142+
#[diag(lint_dangling_pointers_from_temporaries)]
11431143
#[note]
11441144
#[help]
1145-
pub(crate) struct CStringPtr {
1146-
#[label(lint_as_ptr_label)]
1147-
pub as_ptr: Span,
1148-
#[label(lint_unwrap_label)]
1149-
pub unwrap: Span,
1145+
// FIXME: put #[primary_span] on `ptr_span` once it does not cause conflicts
1146+
pub(crate) struct DanglingPointersFromTemporaries<'tcx> {
1147+
pub callee: Symbol,
1148+
pub ty: Ty<'tcx>,
1149+
#[label(lint_label_ptr)]
1150+
pub ptr_span: Span,
1151+
#[label(lint_label_temporary)]
1152+
pub temporary_span: Span,
11501153
}
11511154

11521155
// multiple_supertrait_upcastable.rs

‎compiler/rustc_lint/src/methods.rs

Lines changed: 0 additions & 69 deletions
This file was deleted.

‎compiler/rustc_span/src/symbol.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ symbols! {
171171
CallOnceFuture,
172172
CallRefFuture,
173173
Capture,
174+
Cell,
174175
Center,
175176
Cleanup,
176177
Clone,
@@ -409,6 +410,7 @@ symbols! {
409410
arm,
410411
arm_target_feature,
411412
array,
413+
as_mut_ptr,
412414
as_ptr,
413415
as_ref,
414416
as_str,

‎library/alloc/tests/boxed.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use core::mem::MaybeUninit;
44
use core::ptr::NonNull;
55

66
#[test]
7+
#[cfg_attr(not(bootstrap), expect(dangling_pointers_from_temporaries))]
78
fn uninitialized_zero_size_box() {
89
assert_eq!(
910
&*Box::<()>::new_uninit() as *const _,

‎library/core/src/cell.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,7 @@ pub use once::OnceCell;
304304
/// ```
305305
///
306306
/// See the [module-level documentation](self) for more.
307+
#[cfg_attr(not(test), rustc_diagnostic_item = "Cell")]
307308
#[stable(feature = "rust1", since = "1.0.0")]
308309
#[repr(transparent)]
309310
#[rustc_pub_transparent]

‎library/core/src/ffi/c_str.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -464,7 +464,9 @@ impl CStr {
464464
/// behavior when `ptr` is used inside the `unsafe` block:
465465
///
466466
/// ```no_run
467-
/// # #![allow(unused_must_use)] #![allow(temporary_cstring_as_ptr)]
467+
/// # #![allow(unused_must_use)]
468+
/// # #![cfg_attr(bootstrap, expect(temporary_cstring_as_ptr))]
469+
/// # #![cfg_attr(not(bootstrap), expect(dangling_pointers_from_temporaries))]
468470
/// use std::ffi::CString;
469471
///
470472
/// // Do not do this:

‎src/tools/clippy/clippy_lints/src/deprecated_lints.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ declare_with_version! { RENAMED(RENAMED_VERSION): &[(&str, &str)] = &[
166166
#[clippy::version = ""]
167167
("clippy::positional_named_format_parameters", "named_arguments_used_positionally"),
168168
#[clippy::version = ""]
169-
("clippy::temporary_cstring_as_ptr", "temporary_cstring_as_ptr"),
169+
("clippy::temporary_cstring_as_ptr", "dangling_pointers_from_temporaries"),
170170
#[clippy::version = ""]
171171
("clippy::undropped_manually_drops", "undropped_manually_drops"),
172172
#[clippy::version = ""]

‎src/tools/clippy/tests/ui/rename.fixed

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@
5454
#![allow(enum_intrinsics_non_enums)]
5555
#![allow(non_fmt_panics)]
5656
#![allow(named_arguments_used_positionally)]
57-
#![allow(temporary_cstring_as_ptr)]
57+
#![allow(dangling_pointers_from_temporaries)]
5858
#![allow(undropped_manually_drops)]
5959
#![allow(unknown_lints)]
6060
#![allow(unused_labels)]
@@ -120,7 +120,7 @@
120120
#![warn(unexpected_cfgs)] //~ ERROR: lint `clippy::mismatched_target_os`
121121
#![warn(non_fmt_panics)] //~ ERROR: lint `clippy::panic_params`
122122
#![warn(named_arguments_used_positionally)] //~ ERROR: lint `clippy::positional_named_format_parameters`
123-
#![warn(temporary_cstring_as_ptr)] //~ ERROR: lint `clippy::temporary_cstring_as_ptr`
123+
#![warn(dangling_pointers_from_temporaries)] //~ ERROR: lint `clippy::temporary_cstring_as_ptr`
124124
#![warn(undropped_manually_drops)] //~ ERROR: lint `clippy::undropped_manually_drops`
125125
#![warn(unknown_lints)] //~ ERROR: lint `clippy::unknown_clippy_lints`
126126
#![warn(unused_labels)] //~ ERROR: lint `clippy::unused_label`

‎src/tools/clippy/tests/ui/rename.stderr

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
1+
error: lint `temporary_cstring_as_ptr` has been renamed to `dangling_pointers_from_temporaries`
2+
--> tests/ui/rename.rs:57:10
3+
|
4+
LL | #![allow(temporary_cstring_as_ptr)]
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `dangling_pointers_from_temporaries`
6+
|
7+
= note: `-D renamed-and-removed-lints` implied by `-D warnings`
8+
= help: to override `-D warnings` add `#[allow(renamed_and_removed_lints)]`
9+
110
error: lint `clippy::almost_complete_letter_range` has been renamed to `clippy::almost_complete_range`
211
--> tests/ui/rename.rs:63:9
312
|
413
LL | #![warn(clippy::almost_complete_letter_range)]
514
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range`
6-
|
7-
= note: `-D renamed-and-removed-lints` implied by `-D warnings`
8-
= help: to override `-D warnings` add `#[allow(renamed_and_removed_lints)]`
915

1016
error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names`
1117
--> tests/ui/rename.rs:64:9
@@ -361,11 +367,11 @@ error: lint `clippy::positional_named_format_parameters` has been renamed to `na
361367
LL | #![warn(clippy::positional_named_format_parameters)]
362368
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally`
363369

364-
error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr`
370+
error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `dangling_pointers_from_temporaries`
365371
--> tests/ui/rename.rs:123:9
366372
|
367373
LL | #![warn(clippy::temporary_cstring_as_ptr)]
368-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr`
374+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `dangling_pointers_from_temporaries`
369375

370376
error: lint `clippy::undropped_manually_drops` has been renamed to `undropped_manually_drops`
371377
--> tests/ui/rename.rs:124:9
@@ -397,5 +403,5 @@ error: lint `clippy::reverse_range_loop` has been renamed to `clippy::reversed_e
397403
LL | #![warn(clippy::reverse_range_loop)]
398404
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::reversed_empty_ranges`
399405

400-
error: aborting due to 66 previous errors
406+
error: aborting due to 67 previous errors
401407

‎tests/ui/consts/zst_no_llvm_alloc.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,11 @@ fn main() {
1717

1818
// The exact addresses returned by these library functions are not necessarily stable guarantees
1919
// but for now we assert that we're still matching.
20-
assert_eq!(<Vec<i32>>::new().as_ptr(), <&[i32]>::default().as_ptr());
21-
assert_eq!(<Box<[i32]>>::default().as_ptr(), (&[]).as_ptr());
20+
#[allow(dangling_pointers_from_temporaries)]
21+
{
22+
assert_eq!(<Vec<i32>>::new().as_ptr(), <&[i32]>::default().as_ptr());
23+
assert_eq!(<Box<[i32]>>::default().as_ptr(), (&[]).as_ptr());
24+
};
2225

2326
// statics must have a unique address (see https://github.com/rust-lang/rust/issues/18297, not
2427
// clear whether this is a stable guarantee)
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#![allow(dangling_pointers_from_temporaries)]
2+
3+
fn main() {
4+
dbg!(String::new().as_ptr());
5+
// ^ no error
6+
7+
#[deny(dangling_pointers_from_temporaries)]
8+
{
9+
dbg!(String::new().as_ptr());
10+
//~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped
11+
}
12+
S.foo()
13+
}
14+
15+
struct S;
16+
17+
impl S {
18+
#[warn(dangling_pointers_from_temporaries)]
19+
fn foo(self) {
20+
dbg!(String::new().as_ptr());
21+
//~^ WARNING a dangling pointer will be produced because the temporary `String` will be dropped
22+
}
23+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
error: a dangling pointer will be produced because the temporary `String` will be dropped
2+
--> $DIR/allow.rs:9:28
3+
|
4+
LL | dbg!(String::new().as_ptr());
5+
| ------------- ^^^^^^ this pointer will immediately be invalid
6+
| |
7+
| this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
8+
|
9+
= 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
10+
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
11+
note: the lint level is defined here
12+
--> $DIR/allow.rs:7:12
13+
|
14+
LL | #[deny(dangling_pointers_from_temporaries)]
15+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
16+
17+
warning: a dangling pointer will be produced because the temporary `String` will be dropped
18+
--> $DIR/allow.rs:20:28
19+
|
20+
LL | dbg!(String::new().as_ptr());
21+
| ------------- ^^^^^^ this pointer will immediately be invalid
22+
| |
23+
| this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
24+
|
25+
= 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
26+
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
27+
note: the lint level is defined here
28+
--> $DIR/allow.rs:18:12
29+
|
30+
LL | #[warn(dangling_pointers_from_temporaries)]
31+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
32+
33+
error: aborting due to 1 previous error; 1 warning emitted
34+
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
#![deny(dangling_pointers_from_temporaries)]
2+
3+
use std::ffi::{c_char, CString};
4+
5+
fn cstring() -> CString {
6+
CString::new("hello").unwrap()
7+
}
8+
9+
fn consume(ptr: *const c_char) {
10+
let c = unsafe { ptr.read() };
11+
dbg!(c);
12+
}
13+
14+
// None of these should trigger the lint.
15+
fn ok() {
16+
consume(cstring().as_ptr());
17+
consume({ cstring() }.as_ptr());
18+
consume({ cstring().as_ptr() });
19+
consume(cstring().as_ptr().cast());
20+
consume({ cstring() }.as_ptr().cast());
21+
consume({ cstring().as_ptr() }.cast());
22+
}
23+
24+
// All of these should trigger the lint.
25+
fn not_ok() {
26+
{
27+
let ptr = cstring().as_ptr();
28+
//~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped
29+
consume(ptr);
30+
}
31+
consume({
32+
let ptr = cstring().as_ptr();
33+
//~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped
34+
ptr
35+
});
36+
consume({
37+
let s = cstring();
38+
s.as_ptr()
39+
//^ FIXME: should error
40+
});
41+
let _ptr: *const u8 = cstring().as_ptr().cast();
42+
//~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped
43+
let _ptr: *const u8 = { cstring() }.as_ptr().cast();
44+
//~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped
45+
let _ptr: *const u8 = { cstring().as_ptr() }.cast();
46+
//~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped
47+
}
48+
49+
fn main() {
50+
ok();
51+
not_ok();
52+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
error: a dangling pointer will be produced because the temporary `CString` will be dropped
2+
--> $DIR/calls.rs:27:29
3+
|
4+
LL | let ptr = cstring().as_ptr();
5+
| --------- ^^^^^^ this pointer will immediately be invalid
6+
| |
7+
| this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
8+
|
9+
= 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
10+
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
11+
note: the lint level is defined here
12+
--> $DIR/calls.rs:1:9
13+
|
14+
LL | #![deny(dangling_pointers_from_temporaries)]
15+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
16+
17+
error: a dangling pointer will be produced because the temporary `CString` will be dropped
18+
--> $DIR/calls.rs:32:29
19+
|
20+
LL | let ptr = cstring().as_ptr();
21+
| --------- ^^^^^^ this pointer will immediately be invalid
22+
| |
23+
| this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
24+
|
25+
= 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
26+
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
27+
28+
error: a dangling pointer will be produced because the temporary `CString` will be dropped
29+
--> $DIR/calls.rs:41:37
30+
|
31+
LL | let _ptr: *const u8 = cstring().as_ptr().cast();
32+
| --------- ^^^^^^ this pointer will immediately be invalid
33+
| |
34+
| this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
35+
|
36+
= 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
37+
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
38+
39+
error: a dangling pointer will be produced because the temporary `CString` will be dropped
40+
--> $DIR/calls.rs:43:41
41+
|
42+
LL | let _ptr: *const u8 = { cstring() }.as_ptr().cast();
43+
| ------------- ^^^^^^ this pointer will immediately be invalid
44+
| |
45+
| this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
46+
|
47+
= 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
48+
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
49+
50+
error: a dangling pointer will be produced because the temporary `CString` will be dropped
51+
--> $DIR/calls.rs:45:39
52+
|
53+
LL | let _ptr: *const u8 = { cstring().as_ptr() }.cast();
54+
| --------- ^^^^^^ this pointer will immediately be invalid
55+
| |
56+
| this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
57+
|
58+
= 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
59+
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
60+
61+
error: aborting due to 5 previous errors
62+
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
//@ check-pass
2+
13
#![deny(temporary_cstring_as_ptr)]
4+
//~^ WARNING lint `temporary_cstring_as_ptr` has been renamed to `dangling_pointers_from_temporaries`
25

36
use std::ffi::CString;
47
use std::os::raw::c_char;
@@ -7,5 +10,4 @@ fn some_function(data: *const c_char) {}
710

811
fn main() {
912
some_function(CString::new("").unwrap().as_ptr());
10-
//~^ ERROR getting the inner pointer of a temporary `CString`
1113
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
warning: lint `temporary_cstring_as_ptr` has been renamed to `dangling_pointers_from_temporaries`
2+
--> $DIR/cstring-as-param.rs:3:9
3+
|
4+
LL | #![deny(temporary_cstring_as_ptr)]
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `dangling_pointers_from_temporaries`
6+
|
7+
= note: `#[warn(renamed_and_removed_lints)]` on by default
8+
9+
warning: 1 warning emitted
10+
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
// this program is not technically incorrect, but is an obscure enough style to be worth linting
22
#![deny(temporary_cstring_as_ptr)]
3+
//~^ WARNING lint `temporary_cstring_as_ptr` has been renamed to `dangling_pointers_from_temporaries`
34

45
use std::ffi::CString;
56

67
macro_rules! mymacro {
78
() => {
89
let s = CString::new("some text").unwrap().as_ptr();
9-
//~^ ERROR getting the inner pointer of a temporary `CString`
10+
//~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped
1011
}
1112
}
1213

1314
fn main() {
1415
let s = CString::new("some text").unwrap().as_ptr();
15-
//~^ ERROR getting the inner pointer of a temporary `CString`
16+
//~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped
1617
mymacro!();
1718
}
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,41 @@
1-
error: getting the inner pointer of a temporary `CString`
2-
--> $DIR/lint-temporary-cstring-as-ptr.rs:14:48
1+
warning: lint `temporary_cstring_as_ptr` has been renamed to `dangling_pointers_from_temporaries`
2+
--> $DIR/cstring-as-ptr.rs:2:9
3+
|
4+
LL | #![deny(temporary_cstring_as_ptr)]
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `dangling_pointers_from_temporaries`
6+
|
7+
= note: `#[warn(renamed_and_removed_lints)]` on by default
8+
9+
error: a dangling pointer will be produced because the temporary `CString` will be dropped
10+
--> $DIR/cstring-as-ptr.rs:15:48
311
|
412
LL | let s = CString::new("some text").unwrap().as_ptr();
5-
| ---------------------------------- ^^^^^^ this pointer will be invalid
13+
| ---------------------------------- ^^^^^^ this pointer will immediately be invalid
614
| |
715
| this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
816
|
917
= 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
10-
= help: for more information, see https://doc.rust-lang.org/reference/destructors.html
18+
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
1119
note: the lint level is defined here
12-
--> $DIR/lint-temporary-cstring-as-ptr.rs:2:9
20+
--> $DIR/cstring-as-ptr.rs:2:9
1321
|
1422
LL | #![deny(temporary_cstring_as_ptr)]
1523
| ^^^^^^^^^^^^^^^^^^^^^^^^
1624

17-
error: getting the inner pointer of a temporary `CString`
18-
--> $DIR/lint-temporary-cstring-as-ptr.rs:8:52
25+
error: a dangling pointer will be produced because the temporary `CString` will be dropped
26+
--> $DIR/cstring-as-ptr.rs:9:52
1927
|
2028
LL | let s = CString::new("some text").unwrap().as_ptr();
21-
| ---------------------------------- ^^^^^^ this pointer will be invalid
29+
| ---------------------------------- ^^^^^^ this pointer will immediately be invalid
2230
| |
2331
| this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
2432
...
2533
LL | mymacro!();
2634
| ---------- in this macro invocation
2735
|
2836
= 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
29-
= help: for more information, see https://doc.rust-lang.org/reference/destructors.html
37+
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
3038
= note: this error originates in the macro `mymacro` (in Nightly builds, run with -Z macro-backtrace for more info)
3139

32-
error: aborting due to 2 previous errors
40+
error: aborting due to 2 previous errors; 1 warning emitted
3341

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//@ check-pass
2+
3+
#![deny(dangling_pointers_from_temporaries)]
4+
5+
// The original code example comes from bindgen-produced code for emacs.
6+
// Hence the name of the test.
7+
// https://github.com/rust-lang/rust/pull/128985#issuecomment-2338951363
8+
9+
use std::ffi::{c_char, CString};
10+
11+
fn read(ptr: *const c_char) -> c_char {
12+
unsafe { ptr.read() }
13+
}
14+
15+
fn main() {
16+
let fnptr: Option<fn(ptr: *const c_char) -> c_char> = Some(read);
17+
let x = fnptr.unwrap()(CString::new("foo").unwrap().as_ptr());
18+
assert_eq!(x as u8, b'f');
19+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#![deny(dangling_pointers_from_temporaries)]
2+
3+
const MAX_PATH: usize = 260;
4+
fn main() {
5+
let str1 = String::with_capacity(MAX_PATH).as_mut_ptr();
6+
//~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped
7+
let str2 = String::from("TotototototototototototototototototoT").as_ptr();
8+
//~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped
9+
unsafe {
10+
std::ptr::copy_nonoverlapping(str2, str1, 30);
11+
println!("{:?}", String::from_raw_parts(str1, 30, 30));
12+
}
13+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
error: a dangling pointer will be produced because the temporary `String` will be dropped
2+
--> $DIR/example-from-issue123613.rs:5:48
3+
|
4+
LL | let str1 = String::with_capacity(MAX_PATH).as_mut_ptr();
5+
| ------------------------------- ^^^^^^^^^^ this pointer will immediately be invalid
6+
| |
7+
| this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
8+
|
9+
= 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
10+
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
11+
note: the lint level is defined here
12+
--> $DIR/example-from-issue123613.rs:1:9
13+
|
14+
LL | #![deny(dangling_pointers_from_temporaries)]
15+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
16+
17+
error: a dangling pointer will be produced because the temporary `String` will be dropped
18+
--> $DIR/example-from-issue123613.rs:7:70
19+
|
20+
LL | let str2 = String::from("TotototototototototototototototototoT").as_ptr();
21+
| ----------------------------------------------------- ^^^^^^ this pointer will immediately be invalid
22+
| |
23+
| this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
24+
|
25+
= 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
26+
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
27+
28+
error: aborting due to 2 previous errors
29+
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#![deny(dangling_pointers_from_temporaries)]
2+
3+
use std::fmt::Debug;
4+
5+
trait Ext1 {
6+
fn dbg(self) -> Self
7+
where
8+
Self: Sized + Debug,
9+
{
10+
dbg!(&self);
11+
self
12+
}
13+
}
14+
15+
impl<T> Ext1 for *const T {}
16+
17+
trait Ext2 {
18+
fn foo(self);
19+
}
20+
21+
impl Ext2 for *const u32 {
22+
fn foo(self) {
23+
dbg!(unsafe { self.read() });
24+
}
25+
}
26+
27+
fn main() {
28+
let _ptr1 = Vec::<u32>::new().as_ptr().dbg();
29+
//~^ ERROR a dangling pointer will be produced because the temporary `Vec<u32>` will be dropped
30+
let _ptr2 = vec![0].as_ptr().foo();
31+
//~^ ERROR a dangling pointer will be produced because the temporary `Vec<u32>` will be dropped
32+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
error: a dangling pointer will be produced because the temporary `Vec<u32>` will be dropped
2+
--> $DIR/ext.rs:28:35
3+
|
4+
LL | let _ptr1 = Vec::<u32>::new().as_ptr().dbg();
5+
| ----------------- ^^^^^^ this pointer will immediately be invalid
6+
| |
7+
| this `Vec<u32>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
8+
|
9+
= 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
10+
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
11+
note: the lint level is defined here
12+
--> $DIR/ext.rs:1:9
13+
|
14+
LL | #![deny(dangling_pointers_from_temporaries)]
15+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
16+
17+
error: a dangling pointer will be produced because the temporary `Vec<u32>` will be dropped
18+
--> $DIR/ext.rs:30:25
19+
|
20+
LL | let _ptr2 = vec![0].as_ptr().foo();
21+
| ------- ^^^^^^ this pointer will immediately be invalid
22+
| |
23+
| this `Vec<u32>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
24+
|
25+
= 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
26+
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
27+
28+
error: aborting due to 2 previous errors
29+
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#![deny(dangling_pointers_from_temporaries)]
2+
3+
fn main() {
4+
vec![0u8].as_ptr();
5+
//~^ ERROR a dangling pointer will be produced because the temporary `Vec<u8>` will be dropped
6+
vec![0u8].as_mut_ptr();
7+
//~^ ERROR a dangling pointer will be produced because the temporary `Vec<u8>` will be dropped
8+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
error: a dangling pointer will be produced because the temporary `Vec<u8>` will be dropped
2+
--> $DIR/methods.rs:4:15
3+
|
4+
LL | vec![0u8].as_ptr();
5+
| --------- ^^^^^^ this pointer will immediately be invalid
6+
| |
7+
| this `Vec<u8>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
8+
|
9+
= 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
10+
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
11+
note: the lint level is defined here
12+
--> $DIR/methods.rs:1:9
13+
|
14+
LL | #![deny(dangling_pointers_from_temporaries)]
15+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
16+
17+
error: a dangling pointer will be produced because the temporary `Vec<u8>` will be dropped
18+
--> $DIR/methods.rs:6:15
19+
|
20+
LL | vec![0u8].as_mut_ptr();
21+
| --------- ^^^^^^^^^^ this pointer will immediately be invalid
22+
| |
23+
| this `Vec<u8>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
24+
|
25+
= 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
26+
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
27+
28+
error: aborting due to 2 previous errors
29+
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
#![allow(unused)]
2+
#![deny(dangling_pointers_from_temporaries)]
3+
4+
fn string() -> String {
5+
"hello".into()
6+
}
7+
8+
struct Wrapper(String);
9+
10+
fn main() {
11+
// ConstBlock
12+
const { String::new() }.as_ptr();
13+
14+
// Array
15+
{
16+
[string()].as_ptr(); // False negative
17+
[true].as_ptr();
18+
}
19+
20+
// Call
21+
string().as_ptr();
22+
//~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped
23+
24+
// MethodCall
25+
"hello".to_string().as_ptr();
26+
//~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped
27+
28+
// Tup
29+
// impossible
30+
31+
// Binary
32+
(string() + "hello").as_ptr();
33+
//~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped
34+
35+
// Path
36+
{
37+
let x = string();
38+
x.as_ptr();
39+
}
40+
41+
// Unary
42+
{
43+
let x = string();
44+
let x: &String = &x;
45+
(*x).as_ptr();
46+
(&[0u8]).as_ptr();
47+
(&string()).as_ptr(); // False negative
48+
(*&string()).as_ptr(); // False negative
49+
}
50+
51+
// Lit
52+
"hello".as_ptr();
53+
54+
// Cast
55+
// impossible
56+
57+
// Type
58+
// impossible
59+
60+
// DropTemps
61+
// impossible
62+
63+
// Let
64+
// impossible
65+
66+
// If
67+
{
68+
(if true { String::new() } else { "hello".into() }).as_ptr();
69+
//~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped
70+
}
71+
72+
// Loop
73+
{
74+
(loop {
75+
break String::new();
76+
})
77+
.as_ptr();
78+
//~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped
79+
}
80+
81+
// Match
82+
{
83+
match string() {
84+
s => s,
85+
}
86+
.as_ptr();
87+
//~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped
88+
}
89+
90+
// Closure
91+
// impossible
92+
93+
// Block
94+
{ string() }.as_ptr();
95+
//~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped
96+
97+
// Assign, AssignOp
98+
// impossible
99+
100+
// Field
101+
{
102+
Wrapper(string()).0.as_ptr(); // False negative
103+
let x = Wrapper(string());
104+
x.0.as_ptr();
105+
}
106+
107+
// Index
108+
{
109+
vec![string()][0].as_ptr(); // False negative
110+
let x = vec![string()];
111+
x[0].as_ptr();
112+
}
113+
114+
// AddrOf, InlineAsm, OffsetOf
115+
// impossible
116+
117+
// Break, Continue, Ret
118+
// are !
119+
120+
// Become, Yield
121+
// unstable, are !
122+
123+
// Repeat
124+
[0u8; 100].as_ptr();
125+
[const { String::new() }; 100].as_ptr();
126+
127+
// Struct
128+
// Cannot test this without access to private fields of the linted types.
129+
130+
// Err
131+
// impossible
132+
133+
// Macro
134+
vec![0u8].as_ptr();
135+
//~^ ERROR a dangling pointer will be produced because the temporary `Vec<u8>` will be dropped
136+
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
error: a dangling pointer will be produced because the temporary `String` will be dropped
2+
--> $DIR/temporaries.rs:21:14
3+
|
4+
LL | string().as_ptr();
5+
| -------- ^^^^^^ this pointer will immediately be invalid
6+
| |
7+
| this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
8+
|
9+
= 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
10+
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
11+
note: the lint level is defined here
12+
--> $DIR/temporaries.rs:2:9
13+
|
14+
LL | #![deny(dangling_pointers_from_temporaries)]
15+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
16+
17+
error: a dangling pointer will be produced because the temporary `String` will be dropped
18+
--> $DIR/temporaries.rs:25:25
19+
|
20+
LL | "hello".to_string().as_ptr();
21+
| ------------------- ^^^^^^ this pointer will immediately be invalid
22+
| |
23+
| this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
24+
|
25+
= 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
26+
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
27+
28+
error: a dangling pointer will be produced because the temporary `String` will be dropped
29+
--> $DIR/temporaries.rs:32:26
30+
|
31+
LL | (string() + "hello").as_ptr();
32+
| -------------------- ^^^^^^ this pointer will immediately be invalid
33+
| |
34+
| this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
35+
|
36+
= 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
37+
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
38+
39+
error: a dangling pointer will be produced because the temporary `String` will be dropped
40+
--> $DIR/temporaries.rs:68:61
41+
|
42+
LL | (if true { String::new() } else { "hello".into() }).as_ptr();
43+
| --------------------------------------------------- ^^^^^^ this pointer will immediately be invalid
44+
| |
45+
| this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
46+
|
47+
= 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
48+
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
49+
50+
error: a dangling pointer will be produced because the temporary `String` will be dropped
51+
--> $DIR/temporaries.rs:77:10
52+
|
53+
LL | / (loop {
54+
LL | | break String::new();
55+
LL | | })
56+
| |__________- this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
57+
LL | .as_ptr();
58+
| ^^^^^^ this pointer will immediately be invalid
59+
|
60+
= 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
61+
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
62+
63+
error: a dangling pointer will be produced because the temporary `String` will be dropped
64+
--> $DIR/temporaries.rs:86:10
65+
|
66+
LL | / match string() {
67+
LL | | s => s,
68+
LL | | }
69+
| |_________- this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
70+
LL | .as_ptr();
71+
| ^^^^^^ this pointer will immediately be invalid
72+
|
73+
= 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
74+
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
75+
76+
error: a dangling pointer will be produced because the temporary `String` will be dropped
77+
--> $DIR/temporaries.rs:94:18
78+
|
79+
LL | { string() }.as_ptr();
80+
| ------------ ^^^^^^ this pointer will immediately be invalid
81+
| |
82+
| this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
83+
|
84+
= 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
85+
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
86+
87+
error: a dangling pointer will be produced because the temporary `Vec<u8>` will be dropped
88+
--> $DIR/temporaries.rs:134:15
89+
|
90+
LL | vec![0u8].as_ptr();
91+
| --------- ^^^^^^ this pointer will immediately be invalid
92+
| |
93+
| this `Vec<u8>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
94+
|
95+
= 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
96+
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
97+
98+
error: aborting due to 8 previous errors
99+
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
#![deny(dangling_pointers_from_temporaries)]
2+
3+
use std::cell::Cell;
4+
use std::ffi::{CStr, CString};
5+
use std::mem::MaybeUninit;
6+
7+
struct AsPtrFake;
8+
9+
impl AsPtrFake {
10+
fn as_ptr(&self) -> *const () {
11+
std::ptr::null()
12+
}
13+
}
14+
15+
fn declval<T>() -> T {
16+
loop {}
17+
}
18+
19+
fn main() {
20+
declval::<CString>().as_ptr();
21+
//~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped
22+
declval::<String>().as_ptr();
23+
//~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped
24+
declval::<Vec<u8>>().as_ptr();
25+
//~^ ERROR a dangling pointer will be produced because the temporary `Vec<u8>` will be dropped
26+
declval::<Box<CString>>().as_ptr();
27+
//~^ ERROR a dangling pointer will be produced because the temporary `Box<CString>` will be dropped
28+
declval::<Box<[u8]>>().as_ptr();
29+
//~^ ERROR a dangling pointer will be produced because the temporary `Box<[u8]>` will be dropped
30+
declval::<Box<str>>().as_ptr();
31+
//~^ ERROR a dangling pointer will be produced because the temporary `Box<str>` will be dropped
32+
declval::<Box<CStr>>().as_ptr();
33+
//~^ ERROR a dangling pointer will be produced because the temporary `Box<CStr>` will be dropped
34+
declval::<[u8; 10]>().as_ptr();
35+
//~^ ERROR a dangling pointer will be produced because the temporary `[u8; 10]` will be dropped
36+
declval::<Box<[u8; 10]>>().as_ptr();
37+
//~^ ERROR a dangling pointer will be produced because the temporary `Box<[u8; 10]>` will be dropped
38+
declval::<Box<Vec<u8>>>().as_ptr();
39+
//~^ ERROR a dangling pointer will be produced because the temporary `Box<Vec<u8>>` will be dropped
40+
declval::<Box<String>>().as_ptr();
41+
//~^ ERROR a dangling pointer will be produced because the temporary `Box<String>` will be dropped
42+
declval::<Box<Box<Box<Box<[u8]>>>>>().as_ptr();
43+
//~^ ERROR a dangling pointer will be produced because the temporary `Box<Box<Box<Box<[u8]>>>>` will be dropped
44+
declval::<Cell<u8>>().as_ptr();
45+
//~^ ERROR a dangling pointer will be produced because the temporary `Cell<u8>` will be dropped
46+
declval::<MaybeUninit<u8>>().as_ptr();
47+
//~^ ERROR a dangling pointer will be produced because the temporary `MaybeUninit<u8>` will be dropped
48+
declval::<Vec<AsPtrFake>>().as_ptr();
49+
//~^ ERROR a dangling pointer will be produced because the temporary `Vec<AsPtrFake>` will be dropped
50+
declval::<Box<AsPtrFake>>().as_ptr();
51+
declval::<AsPtrFake>().as_ptr();
52+
}
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
error: a dangling pointer will be produced because the temporary `CString` will be dropped
2+
--> $DIR/types.rs:20:26
3+
|
4+
LL | declval::<CString>().as_ptr();
5+
| -------------------- ^^^^^^ this pointer will immediately be invalid
6+
| |
7+
| this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
8+
|
9+
= 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
10+
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
11+
note: the lint level is defined here
12+
--> $DIR/types.rs:1:9
13+
|
14+
LL | #![deny(dangling_pointers_from_temporaries)]
15+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
16+
17+
error: a dangling pointer will be produced because the temporary `String` will be dropped
18+
--> $DIR/types.rs:22:25
19+
|
20+
LL | declval::<String>().as_ptr();
21+
| ------------------- ^^^^^^ this pointer will immediately be invalid
22+
| |
23+
| this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
24+
|
25+
= 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
26+
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
27+
28+
error: a dangling pointer will be produced because the temporary `Vec<u8>` will be dropped
29+
--> $DIR/types.rs:24:26
30+
|
31+
LL | declval::<Vec<u8>>().as_ptr();
32+
| -------------------- ^^^^^^ this pointer will immediately be invalid
33+
| |
34+
| this `Vec<u8>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
35+
|
36+
= 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
37+
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
38+
39+
error: a dangling pointer will be produced because the temporary `Box<CString>` will be dropped
40+
--> $DIR/types.rs:26:31
41+
|
42+
LL | declval::<Box<CString>>().as_ptr();
43+
| ------------------------- ^^^^^^ this pointer will immediately be invalid
44+
| |
45+
| this `Box<CString>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
46+
|
47+
= 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
48+
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
49+
50+
error: a dangling pointer will be produced because the temporary `Box<[u8]>` will be dropped
51+
--> $DIR/types.rs:28:28
52+
|
53+
LL | declval::<Box<[u8]>>().as_ptr();
54+
| ---------------------- ^^^^^^ this pointer will immediately be invalid
55+
| |
56+
| this `Box<[u8]>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
57+
|
58+
= 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
59+
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
60+
61+
error: a dangling pointer will be produced because the temporary `Box<str>` will be dropped
62+
--> $DIR/types.rs:30:27
63+
|
64+
LL | declval::<Box<str>>().as_ptr();
65+
| --------------------- ^^^^^^ this pointer will immediately be invalid
66+
| |
67+
| this `Box<str>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
68+
|
69+
= 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
70+
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
71+
72+
error: a dangling pointer will be produced because the temporary `Box<CStr>` will be dropped
73+
--> $DIR/types.rs:32:28
74+
|
75+
LL | declval::<Box<CStr>>().as_ptr();
76+
| ---------------------- ^^^^^^ this pointer will immediately be invalid
77+
| |
78+
| this `Box<CStr>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
79+
|
80+
= 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
81+
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
82+
83+
error: a dangling pointer will be produced because the temporary `[u8; 10]` will be dropped
84+
--> $DIR/types.rs:34:27
85+
|
86+
LL | declval::<[u8; 10]>().as_ptr();
87+
| --------------------- ^^^^^^ this pointer will immediately be invalid
88+
| |
89+
| this `[u8; 10]` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
90+
|
91+
= 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
92+
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
93+
94+
error: a dangling pointer will be produced because the temporary `Box<[u8; 10]>` will be dropped
95+
--> $DIR/types.rs:36:32
96+
|
97+
LL | declval::<Box<[u8; 10]>>().as_ptr();
98+
| -------------------------- ^^^^^^ this pointer will immediately be invalid
99+
| |
100+
| this `Box<[u8; 10]>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
101+
|
102+
= 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
103+
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
104+
105+
error: a dangling pointer will be produced because the temporary `Box<Vec<u8>>` will be dropped
106+
--> $DIR/types.rs:38:31
107+
|
108+
LL | declval::<Box<Vec<u8>>>().as_ptr();
109+
| ------------------------- ^^^^^^ this pointer will immediately be invalid
110+
| |
111+
| this `Box<Vec<u8>>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
112+
|
113+
= 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
114+
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
115+
116+
error: a dangling pointer will be produced because the temporary `Box<String>` will be dropped
117+
--> $DIR/types.rs:40:30
118+
|
119+
LL | declval::<Box<String>>().as_ptr();
120+
| ------------------------ ^^^^^^ this pointer will immediately be invalid
121+
| |
122+
| this `Box<String>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
123+
|
124+
= 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
125+
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
126+
127+
error: a dangling pointer will be produced because the temporary `Box<Box<Box<Box<[u8]>>>>` will be dropped
128+
--> $DIR/types.rs:42:43
129+
|
130+
LL | declval::<Box<Box<Box<Box<[u8]>>>>>().as_ptr();
131+
| ------------------------------------- ^^^^^^ this pointer will immediately be invalid
132+
| |
133+
| this `Box<Box<Box<Box<[u8]>>>>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
134+
|
135+
= 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
136+
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
137+
138+
error: a dangling pointer will be produced because the temporary `Cell<u8>` will be dropped
139+
--> $DIR/types.rs:44:27
140+
|
141+
LL | declval::<Cell<u8>>().as_ptr();
142+
| --------------------- ^^^^^^ this pointer will immediately be invalid
143+
| |
144+
| this `Cell<u8>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
145+
|
146+
= 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
147+
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
148+
149+
error: a dangling pointer will be produced because the temporary `MaybeUninit<u8>` will be dropped
150+
--> $DIR/types.rs:46:34
151+
|
152+
LL | declval::<MaybeUninit<u8>>().as_ptr();
153+
| ---------------------------- ^^^^^^ this pointer will immediately be invalid
154+
| |
155+
| this `MaybeUninit<u8>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
156+
|
157+
= 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
158+
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
159+
160+
error: a dangling pointer will be produced because the temporary `Vec<AsPtrFake>` will be dropped
161+
--> $DIR/types.rs:48:33
162+
|
163+
LL | declval::<Vec<AsPtrFake>>().as_ptr();
164+
| --------------------------- ^^^^^^ this pointer will immediately be invalid
165+
| |
166+
| this `Vec<AsPtrFake>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
167+
|
168+
= 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
169+
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
170+
171+
error: aborting due to 15 previous errors
172+

‎tests/ui/lint/lint-temporary-cstring-as-param.stderr

Lines changed: 0 additions & 18 deletions
This file was deleted.

0 commit comments

Comments
 (0)
This repository has been archived.