Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions compiler/rustc_lint/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -197,15 +197,16 @@ lint_dangling_pointers_from_locals = {$fn_kind} returns a dangling pointer to dr
.ret_ty = return type is `{$ret_ty}`
.local_var = local variable `{$local_var_name}` is dropped at the end of the {$fn_kind}
.created_at = dangling pointer created here
.help_visit = for more information, see <https://doc.rust-lang.org/reference/destructors.html>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's not used right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, I forgot to wire that up. Will fix.

.note = a dangling pointer is safe, but dereferencing one is undefined behavior
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_bind = you must make sure that the variable you bind the `{$ty}` to lives at least as long as the pointer returned by the call to `{$callee}`
.help_returned = in particular, if this pointer is returned from the current function, binding the `{$ty}` inside the function will not suffice
lint_dangling_pointers_from_temporaries = expression creates a dangling pointer to dropped temporary `{$ty}`
Copy link
Member

@Urgau Urgau Nov 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure that's the a good description of the issue, I feel like it's a bit misleading, the temporary is not yet dropped (otherwise this would insta UB), it's dropped only after creating the pointer, and it's the dropping of the temporary which makes the pointer dangling.

The previously wording was clearer IMO on this point. Not sure how to best improve that.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I thought that detail did not matter. Do you have a reference for your claim that that would be insta UB?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have a reference for your claim that that would be insta UB?

For String::new().DROPPED.as_ptr() it's apparently a grey area rust-lang/unsafe-code-guidelines#188 where use-after-dropped and use-after-free are different regarding opsem. I was told that it should probably be UB and is heavily discouraged.

But for allocation like "".to_string().DROPPED.as_ptr() Miri flags it as UB1 on the as_ptr() call, so 🤷

Footnotes

  1. https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=1c4f3446888f2b92d486a5f478722640

.label_ptr = dangling pointer created here
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This also is misleading IMO, it's not yet dangling but it will be.

.label_temporary = this `{$ty}` is dropped at the end of the statement
.help_bind = bind the `{$ty}` to a variable such that it outlives the pointer returned by `{$callee}`
.help_returned = returning a pointer to a local variable will always result in a dangling pointer
.help_visit = for more information, see <https://doc.rust-lang.org/reference/destructors.html>
.note = a dangling pointer is safe, but dereferencing one is undefined behavior
lint_default_hash_types = prefer `{$preferred}` over `{$used}`, it has better performance
.note = a `use rustc_data_structures::fx::{$preferred}` may be necessary
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_lint/src/lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1106,10 +1106,10 @@ pub(crate) struct IgnoredUnlessCrateSpecified<'a> {
// dangling.rs
#[derive(LintDiagnostic)]
#[diag(lint_dangling_pointers_from_temporaries)]
#[note]
#[help(lint_help_bind)]
#[help(lint_help_returned)]
#[help(lint_help_visit)]
#[note]
// FIXME: put #[primary_span] on `ptr_span` once it does not cause conflicts
pub(crate) struct DanglingPointersFromTemporaries<'tcx> {
pub callee: Ident,
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/lint/dangling-pointers-from-temporaries/allow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ fn main() {
#[deny(dangling_pointers_from_temporaries)]
{
dbg!(String::new().as_ptr());
//~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped
//~^ ERROR dangling pointer
}
S.foo()
}
Expand All @@ -18,6 +18,6 @@ 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
//~^ WARNING dangling pointer
}
}
24 changes: 12 additions & 12 deletions tests/ui/lint/dangling-pointers-from-temporaries/allow.stderr
Original file line number Diff line number Diff line change
@@ -1,33 +1,33 @@
error: a dangling pointer will be produced because the temporary `String` will be dropped
error: expression creates a dangling pointer to dropped temporary `String`
--> $DIR/allow.rs:9:28
|
LL | dbg!(String::new().as_ptr());
| ------------- ^^^^^^ this pointer will immediately be invalid
| ------------- ^^^^^^ dangling pointer created here
| |
| this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
| this `String` is dropped at the end of the statement
|
= 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: you must make sure that the variable you bind the `String` to lives at least as long as the pointer returned by the call to `as_ptr`
= help: in particular, if this pointer is returned from the current function, binding the `String` inside the function will not suffice
= help: bind the `String` to a variable such that it outlives the pointer returned by `as_ptr`
= help: returning a pointer to a local variable will always result in a dangling pointer
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
= note: a dangling pointer is safe, but dereferencing one is undefined behavior
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
warning: expression creates a dangling pointer to dropped temporary `String`
--> $DIR/allow.rs:20:28
|
LL | dbg!(String::new().as_ptr());
| ------------- ^^^^^^ this pointer will immediately be invalid
| ------------- ^^^^^^ dangling pointer created here
| |
| this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
| this `String` is dropped at the end of the statement
|
= 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: you must make sure that the variable you bind the `String` to lives at least as long as the pointer returned by the call to `as_ptr`
= help: in particular, if this pointer is returned from the current function, binding the `String` inside the function will not suffice
= help: bind the `String` to a variable such that it outlives the pointer returned by `as_ptr`
= help: returning a pointer to a local variable will always result in a dangling pointer
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
= note: a dangling pointer is safe, but dereferencing one is undefined behavior
note: the lint level is defined here
--> $DIR/allow.rs:18:12
|
Expand Down
10 changes: 5 additions & 5 deletions tests/ui/lint/dangling-pointers-from-temporaries/calls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@ fn ok() {
fn not_ok() {
{
let ptr = cstring().as_ptr();
//~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped
//~^ ERROR dangling pointer
consume(ptr);
}
consume({
let ptr = cstring().as_ptr();
//~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped
//~^ ERROR dangling pointer
ptr
});
consume({
Expand All @@ -39,11 +39,11 @@ fn not_ok() {
//^ 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
//~^ ERROR dangling pointer
let _ptr: *const u8 = { cstring() }.as_ptr().cast();
//~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped
//~^ ERROR dangling pointer
let _ptr: *const u8 = { cstring().as_ptr() }.cast();
//~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped
//~^ ERROR dangling pointer
}

fn main() {
Expand Down
60 changes: 30 additions & 30 deletions tests/ui/lint/dangling-pointers-from-temporaries/calls.stderr
Original file line number Diff line number Diff line change
@@ -1,72 +1,72 @@
error: a dangling pointer will be produced because the temporary `CString` will be dropped
error: expression creates a dangling pointer to dropped temporary `CString`
--> $DIR/calls.rs:27:29
|
LL | let ptr = cstring().as_ptr();
| --------- ^^^^^^ this pointer will immediately be invalid
| --------- ^^^^^^ dangling pointer created here
| |
| this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
| this `CString` is dropped at the end of the statement
|
= 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: you must make sure that the variable you bind the `CString` to lives at least as long as the pointer returned by the call to `as_ptr`
= help: in particular, if this pointer is returned from the current function, binding the `CString` inside the function will not suffice
= help: bind the `CString` to a variable such that it outlives the pointer returned by `as_ptr`
= help: returning a pointer to a local variable will always result in a dangling pointer
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
= note: a dangling pointer is safe, but dereferencing one is undefined behavior
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
error: expression creates a dangling pointer to dropped temporary `CString`
--> $DIR/calls.rs:32:29
|
LL | let ptr = cstring().as_ptr();
| --------- ^^^^^^ this pointer will immediately be invalid
| --------- ^^^^^^ dangling pointer created here
| |
| this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
| this `CString` is dropped at the end of the statement
|
= 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: you must make sure that the variable you bind the `CString` to lives at least as long as the pointer returned by the call to `as_ptr`
= help: in particular, if this pointer is returned from the current function, binding the `CString` inside the function will not suffice
= help: bind the `CString` to a variable such that it outlives the pointer returned by `as_ptr`
= help: returning a pointer to a local variable will always result in a dangling pointer
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
= note: a dangling pointer is safe, but dereferencing one is undefined behavior

error: a dangling pointer will be produced because the temporary `CString` will be dropped
error: expression creates a dangling pointer to dropped temporary `CString`
--> $DIR/calls.rs:41:37
|
LL | let _ptr: *const u8 = cstring().as_ptr().cast();
| --------- ^^^^^^ this pointer will immediately be invalid
| --------- ^^^^^^ dangling pointer created here
| |
| this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
| this `CString` is dropped at the end of the statement
|
= 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: you must make sure that the variable you bind the `CString` to lives at least as long as the pointer returned by the call to `as_ptr`
= help: in particular, if this pointer is returned from the current function, binding the `CString` inside the function will not suffice
= help: bind the `CString` to a variable such that it outlives the pointer returned by `as_ptr`
= help: returning a pointer to a local variable will always result in a dangling pointer
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
= note: a dangling pointer is safe, but dereferencing one is undefined behavior

error: a dangling pointer will be produced because the temporary `CString` will be dropped
error: expression creates a dangling pointer to dropped temporary `CString`
--> $DIR/calls.rs:43:41
|
LL | let _ptr: *const u8 = { cstring() }.as_ptr().cast();
| ------------- ^^^^^^ this pointer will immediately be invalid
| ------------- ^^^^^^ dangling pointer created here
| |
| this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
| this `CString` is dropped at the end of the statement
|
= 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: you must make sure that the variable you bind the `CString` to lives at least as long as the pointer returned by the call to `as_ptr`
= help: in particular, if this pointer is returned from the current function, binding the `CString` inside the function will not suffice
= help: bind the `CString` to a variable such that it outlives the pointer returned by `as_ptr`
= help: returning a pointer to a local variable will always result in a dangling pointer
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
= note: a dangling pointer is safe, but dereferencing one is undefined behavior

error: a dangling pointer will be produced because the temporary `CString` will be dropped
error: expression creates a dangling pointer to dropped temporary `CString`
--> $DIR/calls.rs:45:39
|
LL | let _ptr: *const u8 = { cstring().as_ptr() }.cast();
| --------- ^^^^^^ this pointer will immediately be invalid
| --------- ^^^^^^ dangling pointer created here
| |
| this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
| this `CString` is dropped at the end of the statement
|
= 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: you must make sure that the variable you bind the `CString` to lives at least as long as the pointer returned by the call to `as_ptr`
= help: in particular, if this pointer is returned from the current function, binding the `CString` inside the function will not suffice
= help: bind the `CString` to a variable such that it outlives the pointer returned by `as_ptr`
= help: returning a pointer to a local variable will always result in a dangling pointer
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
= note: a dangling pointer is safe, but dereferencing one is undefined behavior

error: aborting due to 5 previous errors

Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ use std::ffi::CString;
macro_rules! mymacro {
() => {
let s = CString::new("some text").unwrap().as_ptr();
//~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped
//~^ ERROR dangling pointer
}
}

fn main() {
let s = CString::new("some text").unwrap().as_ptr();
//~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped
//~^ ERROR dangling pointer
mymacro!();
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,39 +6,39 @@ LL | #![deny(temporary_cstring_as_ptr)]
|
= note: `#[warn(renamed_and_removed_lints)]` on by default

error: a dangling pointer will be produced because the temporary `CString` will be dropped
error: expression creates a dangling pointer to dropped temporary `CString`
--> $DIR/cstring-as-ptr.rs:15:48
|
LL | let s = CString::new("some text").unwrap().as_ptr();
| ---------------------------------- ^^^^^^ this pointer will immediately be invalid
| ---------------------------------- ^^^^^^ dangling pointer created here
| |
| this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
| this `CString` is dropped at the end of the statement
|
= 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: you must make sure that the variable you bind the `CString` to lives at least as long as the pointer returned by the call to `as_ptr`
= help: in particular, if this pointer is returned from the current function, binding the `CString` inside the function will not suffice
= help: bind the `CString` to a variable such that it outlives the pointer returned by `as_ptr`
= help: returning a pointer to a local variable will always result in a dangling pointer
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
= note: a dangling pointer is safe, but dereferencing one is undefined behavior
note: the lint level is defined here
--> $DIR/cstring-as-ptr.rs:2:9
|
LL | #![deny(temporary_cstring_as_ptr)]
| ^^^^^^^^^^^^^^^^^^^^^^^^

error: a dangling pointer will be produced because the temporary `CString` will be dropped
error: expression creates a dangling pointer to dropped temporary `CString`
--> $DIR/cstring-as-ptr.rs:9:52
|
LL | let s = CString::new("some text").unwrap().as_ptr();
| ---------------------------------- ^^^^^^ this pointer will immediately be invalid
| ---------------------------------- ^^^^^^ dangling pointer created here
| |
| this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
| this `CString` is dropped at the end of the statement
...
LL | mymacro!();
| ---------- 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
= help: you must make sure that the variable you bind the `CString` to lives at least as long as the pointer returned by the call to `as_ptr`
= help: in particular, if this pointer is returned from the current function, binding the `CString` inside the function will not suffice
= help: bind the `CString` to a variable such that it outlives the pointer returned by `as_ptr`
= help: returning a pointer to a local variable will always result in a dangling pointer
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
= note: a dangling pointer is safe, but dereferencing one is undefined behavior
= 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; 1 warning emitted
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
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
//~^ ERROR dangling pointer
let str2 = String::from("TotototototototototototototototototoT").as_ptr();
//~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped
//~^ ERROR dangling pointer
unsafe {
std::ptr::copy_nonoverlapping(str2, str1, 30);
println!("{:?}", String::from_raw_parts(str1, 30, 30));
Expand Down
Loading
Loading