Add lint against dangling pointers form local variables
This commit is contained in:
@@ -207,6 +207,12 @@ lint_confusable_identifier_pair = found both `{$existing_sym}` and `{$sym}` as i
|
|||||||
|
|
||||||
lint_custom_inner_attribute_unstable = custom inner attributes are unstable
|
lint_custom_inner_attribute_unstable = custom inner attributes are unstable
|
||||||
|
|
||||||
|
lint_dangling_pointers_from_locals = a dangling pointer will be produced because the local variable `{$local_var_name}` will be dropped
|
||||||
|
.ret_ty = return type of the {$fn_kind} is `{$ret_ty}`
|
||||||
|
.local_var = `{$local_var_name}` is part the {$fn_kind} and will be dropped at the end of the {$fn_kind}
|
||||||
|
.created_at = dangling pointer created here
|
||||||
|
.note = pointers do not have a lifetime; after returning, the `{$local_var_ty}` will be deallocated at the end of the {$fn_kind} because nothing is referencing it as far as the type system is concerned
|
||||||
|
|
||||||
lint_dangling_pointers_from_temporaries = a dangling pointer will be produced because the temporary `{$ty}` will be dropped
|
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_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
|
.label_temporary = this `{$ty}` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
use rustc_ast::visit::{visit_opt, walk_list};
|
use rustc_ast::visit::{visit_opt, walk_list};
|
||||||
use rustc_hir::attrs::AttributeKind;
|
use rustc_hir::attrs::AttributeKind;
|
||||||
|
use rustc_hir::def::Res;
|
||||||
use rustc_hir::def_id::LocalDefId;
|
use rustc_hir::def_id::LocalDefId;
|
||||||
use rustc_hir::intravisit::{FnKind, Visitor, walk_expr};
|
use rustc_hir::intravisit::{FnKind, Visitor, walk_expr};
|
||||||
use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, LangItem, find_attr};
|
use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, FnRetTy, LangItem, TyKind, find_attr};
|
||||||
use rustc_middle::ty::{Ty, TyCtxt};
|
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||||
use rustc_session::{declare_lint, impl_lint_pass};
|
use rustc_session::{declare_lint, impl_lint_pass};
|
||||||
use rustc_span::{Span, sym};
|
use rustc_span::{Span, sym};
|
||||||
|
|
||||||
use crate::lints::DanglingPointersFromTemporaries;
|
use crate::lints::{DanglingPointersFromLocals, DanglingPointersFromTemporaries};
|
||||||
use crate::{LateContext, LateLintPass};
|
use crate::{LateContext, LateLintPass};
|
||||||
|
|
||||||
declare_lint! {
|
declare_lint! {
|
||||||
@@ -42,6 +43,36 @@ declare_lint! {
|
|||||||
"detects getting a pointer from a temporary"
|
"detects getting a pointer from a temporary"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare_lint! {
|
||||||
|
/// The `dangling_pointers_from_locals` lint detects getting a pointer to data
|
||||||
|
/// of a local that will be dropped at the end of the function.
|
||||||
|
///
|
||||||
|
/// ### Example
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// fn f() -> *const u8 {
|
||||||
|
/// let x = 0;
|
||||||
|
/// &x // returns a dangling ptr to `x`
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// {{produces}}
|
||||||
|
///
|
||||||
|
/// ### Explanation
|
||||||
|
///
|
||||||
|
/// Returning a pointer from a local 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_LOCALS,
|
||||||
|
Warn,
|
||||||
|
"detects returning a pointer from a local variable"
|
||||||
|
}
|
||||||
|
|
||||||
/// FIXME: false negatives (i.e. the lint is not emitted when it should be)
|
/// FIXME: false negatives (i.e. the lint is not emitted when it should be)
|
||||||
/// 1. Ways to get a temporary that are not recognized:
|
/// 1. Ways to get a temporary that are not recognized:
|
||||||
/// - `owning_temporary.field`
|
/// - `owning_temporary.field`
|
||||||
@@ -53,20 +84,123 @@ declare_lint! {
|
|||||||
#[derive(Clone, Copy, Default)]
|
#[derive(Clone, Copy, Default)]
|
||||||
pub(crate) struct DanglingPointers;
|
pub(crate) struct DanglingPointers;
|
||||||
|
|
||||||
impl_lint_pass!(DanglingPointers => [DANGLING_POINTERS_FROM_TEMPORARIES]);
|
impl_lint_pass!(DanglingPointers => [DANGLING_POINTERS_FROM_TEMPORARIES, DANGLING_POINTERS_FROM_LOCALS]);
|
||||||
|
|
||||||
// This skips over const blocks, but they cannot use or return a dangling pointer anyways.
|
// This skips over const blocks, but they cannot use or return a dangling pointer anyways.
|
||||||
impl<'tcx> LateLintPass<'tcx> for DanglingPointers {
|
impl<'tcx> LateLintPass<'tcx> for DanglingPointers {
|
||||||
fn check_fn(
|
fn check_fn(
|
||||||
&mut self,
|
&mut self,
|
||||||
cx: &LateContext<'tcx>,
|
cx: &LateContext<'tcx>,
|
||||||
_: FnKind<'tcx>,
|
fn_kind: FnKind<'tcx>,
|
||||||
_: &'tcx FnDecl<'tcx>,
|
fn_decl: &'tcx FnDecl<'tcx>,
|
||||||
body: &'tcx Body<'tcx>,
|
body: &'tcx Body<'tcx>,
|
||||||
_: Span,
|
_: Span,
|
||||||
_: LocalDefId,
|
def_id: LocalDefId,
|
||||||
) {
|
) {
|
||||||
DanglingPointerSearcher { cx, inside_call_args: false }.visit_body(body)
|
DanglingPointerSearcher { cx, inside_call_args: false }.visit_body(body);
|
||||||
|
|
||||||
|
if let FnRetTy::Return(ret_ty) = &fn_decl.output
|
||||||
|
&& let TyKind::Ptr(_) = ret_ty.kind
|
||||||
|
{
|
||||||
|
// get the return type of the function or closure
|
||||||
|
let ty = match cx.tcx.type_of(def_id).instantiate_identity().kind() {
|
||||||
|
ty::FnDef(..) => cx.tcx.fn_sig(def_id).instantiate_identity(),
|
||||||
|
ty::Closure(_, args) => args.as_closure().sig(),
|
||||||
|
_ => return,
|
||||||
|
};
|
||||||
|
let ty = ty.output();
|
||||||
|
|
||||||
|
// this type is only used for layout computation and pretty-printing, neither of them rely on regions
|
||||||
|
let ty = cx.tcx.instantiate_bound_regions_with_erased(ty);
|
||||||
|
|
||||||
|
// verify that we have a pointer type
|
||||||
|
let inner_ty = match ty.kind() {
|
||||||
|
ty::RawPtr(inner_ty, _) => *inner_ty,
|
||||||
|
_ => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
if cx
|
||||||
|
.tcx
|
||||||
|
.layout_of(cx.typing_env().as_query_input(inner_ty))
|
||||||
|
.is_ok_and(|layout| !layout.is_1zst())
|
||||||
|
{
|
||||||
|
let dcx = &DanglingPointerLocalContext {
|
||||||
|
body: def_id,
|
||||||
|
fn_ret: ty,
|
||||||
|
fn_ret_span: ret_ty.span,
|
||||||
|
fn_ret_inner: inner_ty,
|
||||||
|
fn_kind: match fn_kind {
|
||||||
|
FnKind::ItemFn(..) => "function",
|
||||||
|
FnKind::Method(..) => "method",
|
||||||
|
FnKind::Closure => "closure",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// look for `return`s
|
||||||
|
DanglingPointerReturnSearcher { cx, dcx }.visit_body(body);
|
||||||
|
|
||||||
|
// analyze implicit return expression
|
||||||
|
if let ExprKind::Block(block, None) = &body.value.kind
|
||||||
|
&& let innermost_block = block.innermost_block()
|
||||||
|
&& let Some(expr) = innermost_block.expr
|
||||||
|
{
|
||||||
|
lint_addr_of_local(cx, dcx, expr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DanglingPointerLocalContext<'tcx> {
|
||||||
|
body: LocalDefId,
|
||||||
|
fn_ret: Ty<'tcx>,
|
||||||
|
fn_ret_span: Span,
|
||||||
|
fn_ret_inner: Ty<'tcx>,
|
||||||
|
fn_kind: &'static str,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DanglingPointerReturnSearcher<'lcx, 'tcx> {
|
||||||
|
cx: &'lcx LateContext<'tcx>,
|
||||||
|
dcx: &'lcx DanglingPointerLocalContext<'tcx>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> Visitor<'tcx> for DanglingPointerReturnSearcher<'_, 'tcx> {
|
||||||
|
fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) -> Self::Result {
|
||||||
|
if let ExprKind::Ret(Some(expr)) = expr.kind {
|
||||||
|
lint_addr_of_local(self.cx, self.dcx, expr);
|
||||||
|
}
|
||||||
|
walk_expr(self, expr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Look for `&<path_to_local_in_same_body>` pattern and emit lint for it
|
||||||
|
fn lint_addr_of_local<'a>(
|
||||||
|
cx: &LateContext<'a>,
|
||||||
|
dcx: &DanglingPointerLocalContext<'a>,
|
||||||
|
expr: &'a Expr<'a>,
|
||||||
|
) {
|
||||||
|
// peel casts as they do not interest us here, we want the inner expression.
|
||||||
|
let (inner, _) = super::utils::peel_casts(cx, expr);
|
||||||
|
|
||||||
|
if let ExprKind::AddrOf(_, _, inner_of) = inner.kind
|
||||||
|
&& let ExprKind::Path(ref qpath) = inner_of.peel_blocks().kind
|
||||||
|
&& let Res::Local(from) = cx.qpath_res(qpath, inner_of.hir_id)
|
||||||
|
&& cx.tcx.hir_enclosing_body_owner(from) == dcx.body
|
||||||
|
{
|
||||||
|
cx.tcx.emit_node_span_lint(
|
||||||
|
DANGLING_POINTERS_FROM_LOCALS,
|
||||||
|
expr.hir_id,
|
||||||
|
expr.span,
|
||||||
|
DanglingPointersFromLocals {
|
||||||
|
ret_ty: dcx.fn_ret,
|
||||||
|
ret_ty_span: dcx.fn_ret_span,
|
||||||
|
fn_kind: dcx.fn_kind,
|
||||||
|
local_var: cx.tcx.hir_span(from),
|
||||||
|
local_var_name: cx.tcx.hir_ident(from),
|
||||||
|
local_var_ty: dcx.fn_ret_inner,
|
||||||
|
created_at: (expr.hir_id != inner.hir_id).then_some(inner.span),
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1188,6 +1188,22 @@ pub(crate) struct DanglingPointersFromTemporaries<'tcx> {
|
|||||||
pub temporary_span: Span,
|
pub temporary_span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(LintDiagnostic)]
|
||||||
|
#[diag(lint_dangling_pointers_from_locals)]
|
||||||
|
#[note]
|
||||||
|
pub(crate) struct DanglingPointersFromLocals<'tcx> {
|
||||||
|
pub ret_ty: Ty<'tcx>,
|
||||||
|
#[label(lint_ret_ty)]
|
||||||
|
pub ret_ty_span: Span,
|
||||||
|
pub fn_kind: &'static str,
|
||||||
|
#[label(lint_local_var)]
|
||||||
|
pub local_var: Span,
|
||||||
|
pub local_var_name: Ident,
|
||||||
|
pub local_var_ty: Ty<'tcx>,
|
||||||
|
#[label(lint_created_at)]
|
||||||
|
pub created_at: Option<Span>,
|
||||||
|
}
|
||||||
|
|
||||||
// multiple_supertrait_upcastable.rs
|
// multiple_supertrait_upcastable.rs
|
||||||
#[derive(LintDiagnostic)]
|
#[derive(LintDiagnostic)]
|
||||||
#[diag(lint_multiple_supertrait_upcastable)]
|
#[diag(lint_multiple_supertrait_upcastable)]
|
||||||
|
|||||||
188
tests/ui/lint/dangling-pointers-from-locals.rs
Normal file
188
tests/ui/lint/dangling-pointers-from-locals.rs
Normal file
@@ -0,0 +1,188 @@
|
|||||||
|
//@ check-pass
|
||||||
|
|
||||||
|
struct Zst((), ());
|
||||||
|
struct Adt(u8);
|
||||||
|
|
||||||
|
const X: u8 = 5;
|
||||||
|
|
||||||
|
fn simple() -> *const u8 {
|
||||||
|
let x = 0;
|
||||||
|
&x
|
||||||
|
//~^ WARN a dangling pointer will be produced
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bindings() -> *const u8 {
|
||||||
|
let x = 0;
|
||||||
|
let x = &x;
|
||||||
|
x
|
||||||
|
//~^ WARN a dangling pointer will be produced
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bindings_with_return() -> *const u8 {
|
||||||
|
let x = 42;
|
||||||
|
let y = &x;
|
||||||
|
return y;
|
||||||
|
//~^ WARN a dangling pointer will be produced
|
||||||
|
}
|
||||||
|
|
||||||
|
fn with_simple_cast() -> *const u8 {
|
||||||
|
let x = 0u8;
|
||||||
|
&x as *const u8
|
||||||
|
//~^ WARN a dangling pointer will be produced
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bindings_and_casts() -> *const u8 {
|
||||||
|
let x = 0u8;
|
||||||
|
let x = &x as *const u8;
|
||||||
|
x as *const u8
|
||||||
|
//~^ WARN a dangling pointer will be produced
|
||||||
|
}
|
||||||
|
|
||||||
|
fn return_with_complex_cast() -> *mut u8 {
|
||||||
|
let mut x = 0u8;
|
||||||
|
return &mut x as *mut u8 as *const u8 as *mut u8;
|
||||||
|
//~^ WARN a dangling pointer will be produced
|
||||||
|
}
|
||||||
|
|
||||||
|
fn with_block() -> *const u8 {
|
||||||
|
let x = 0;
|
||||||
|
&{ x }
|
||||||
|
//~^ WARN a dangling pointer will be produced
|
||||||
|
}
|
||||||
|
|
||||||
|
fn with_many_blocks() -> *const u8 {
|
||||||
|
let x = 0;
|
||||||
|
{
|
||||||
|
{
|
||||||
|
&{
|
||||||
|
//~^ WARN a dangling pointer will be produced
|
||||||
|
{ x }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn simple_return() -> *const u8 {
|
||||||
|
let x = 0;
|
||||||
|
return &x;
|
||||||
|
//~^ WARN a dangling pointer will be produced
|
||||||
|
}
|
||||||
|
|
||||||
|
fn return_mut() -> *mut u8 {
|
||||||
|
let mut x = 0;
|
||||||
|
return &mut x;
|
||||||
|
//~^ WARN a dangling pointer will be produced
|
||||||
|
}
|
||||||
|
|
||||||
|
fn const_and_flow() -> *const u8 {
|
||||||
|
if false {
|
||||||
|
let x = 8;
|
||||||
|
return &x;
|
||||||
|
//~^ WARN a dangling pointer will be produced
|
||||||
|
}
|
||||||
|
&X // not dangling
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vector<T: Default>() -> *const Vec<T> {
|
||||||
|
let x = vec![T::default()];
|
||||||
|
&x
|
||||||
|
//~^ WARN a dangling pointer will be produced
|
||||||
|
}
|
||||||
|
|
||||||
|
fn local_adt() -> *const Adt {
|
||||||
|
let x = Adt(5);
|
||||||
|
return &x;
|
||||||
|
//~^ WARN a dangling pointer will be produced
|
||||||
|
}
|
||||||
|
|
||||||
|
fn closure() -> *const u8 {
|
||||||
|
let _x = || -> *const u8 {
|
||||||
|
let x = 8;
|
||||||
|
return &x;
|
||||||
|
//~^ WARN a dangling pointer will be produced
|
||||||
|
};
|
||||||
|
&X // not dangling
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fn_ptr() -> *const fn() -> u8 {
|
||||||
|
fn ret_u8() -> u8 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
let x = ret_u8 as fn() -> u8;
|
||||||
|
&x
|
||||||
|
//~^ WARN a dangling pointer will be produced
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_arg(a: Adt) -> *const Adt {
|
||||||
|
&a
|
||||||
|
//~^ WARN a dangling pointer will be produced
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fn_ptr_as_arg(a: fn() -> u8) -> *const fn() -> u8 {
|
||||||
|
&a
|
||||||
|
//~^ WARN a dangling pointer will be produced
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ptr_as_arg(a: *const Adt) -> *const *const Adt {
|
||||||
|
&a
|
||||||
|
//~^ WARN a dangling pointer will be produced
|
||||||
|
}
|
||||||
|
|
||||||
|
fn adt_as_arg(a: &Adt) -> *const &Adt {
|
||||||
|
&a
|
||||||
|
//~^ WARN a dangling pointer will be produced
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unit() -> *const () {
|
||||||
|
let x = ();
|
||||||
|
&x // not dangling
|
||||||
|
}
|
||||||
|
|
||||||
|
fn zst() -> *const Zst {
|
||||||
|
let x = Zst((), ());
|
||||||
|
&x // not dangling
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ref_implicit(a: &Adt) -> *const Adt {
|
||||||
|
a // not dangling
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ref_explicit(a: &Adt) -> *const Adt {
|
||||||
|
&*a // not dangling
|
||||||
|
}
|
||||||
|
|
||||||
|
fn identity(a: *const Adt) -> *const Adt {
|
||||||
|
a // not dangling
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_ref(a: &Adt) -> *const Adt {
|
||||||
|
std::ptr::from_ref(a) // not dangling
|
||||||
|
}
|
||||||
|
|
||||||
|
fn inner_static() -> *const u8 {
|
||||||
|
static U: u8 = 5;
|
||||||
|
if false {
|
||||||
|
return &U as *const u8; // not dangling
|
||||||
|
}
|
||||||
|
&U // not dangling
|
||||||
|
}
|
||||||
|
|
||||||
|
fn return_in_closure() {
|
||||||
|
let x = 0;
|
||||||
|
let c = || -> *const u8 {
|
||||||
|
&x // not dangling by it-self
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn option<T: Default>() -> *const Option<T> {
|
||||||
|
let x = Some(T::default());
|
||||||
|
&x // can't compute layout of `Option<T>`, so cnat' be sure it won't be a ZST
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generic<T: Default>() -> *const T {
|
||||||
|
let x = T::default();
|
||||||
|
&x // can't compute layout of `T`, so can't be sure it won't be a ZST
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
247
tests/ui/lint/dangling-pointers-from-locals.stderr
Normal file
247
tests/ui/lint/dangling-pointers-from-locals.stderr
Normal file
@@ -0,0 +1,247 @@
|
|||||||
|
warning: a dangling pointer will be produced because the local variable `x` will be dropped
|
||||||
|
--> $DIR/dangling-pointers-from-locals.rs:10:5
|
||||||
|
|
|
||||||
|
LL | fn simple() -> *const u8 {
|
||||||
|
| --------- return type of the function is `*const u8`
|
||||||
|
LL | let x = 0;
|
||||||
|
| - `x` is part the function and will be dropped at the end of the function
|
||||||
|
LL | &x
|
||||||
|
| ^^
|
||||||
|
|
|
||||||
|
= note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned
|
||||||
|
= note: `#[warn(dangling_pointers_from_locals)]` on by default
|
||||||
|
|
||||||
|
warning: a dangling pointer will be produced because the local variable `x` will be dropped
|
||||||
|
--> $DIR/dangling-pointers-from-locals.rs:17:5
|
||||||
|
|
|
||||||
|
LL | fn bindings() -> *const u8 {
|
||||||
|
| --------- return type of the function is `*const u8`
|
||||||
|
LL | let x = 0;
|
||||||
|
| - `x` is part the function and will be dropped at the end of the function
|
||||||
|
LL | let x = &x;
|
||||||
|
| -- dangling pointer created here
|
||||||
|
LL | x
|
||||||
|
| ^
|
||||||
|
|
|
||||||
|
= note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned
|
||||||
|
|
||||||
|
warning: a dangling pointer will be produced because the local variable `x` will be dropped
|
||||||
|
--> $DIR/dangling-pointers-from-locals.rs:24:12
|
||||||
|
|
|
||||||
|
LL | fn bindings_with_return() -> *const u8 {
|
||||||
|
| --------- return type of the function is `*const u8`
|
||||||
|
LL | let x = 42;
|
||||||
|
| - `x` is part the function and will be dropped at the end of the function
|
||||||
|
LL | let y = &x;
|
||||||
|
| -- dangling pointer created here
|
||||||
|
LL | return y;
|
||||||
|
| ^
|
||||||
|
|
|
||||||
|
= note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned
|
||||||
|
|
||||||
|
warning: a dangling pointer will be produced because the local variable `x` will be dropped
|
||||||
|
--> $DIR/dangling-pointers-from-locals.rs:30:5
|
||||||
|
|
|
||||||
|
LL | fn with_simple_cast() -> *const u8 {
|
||||||
|
| --------- return type of the function is `*const u8`
|
||||||
|
LL | let x = 0u8;
|
||||||
|
| - `x` is part the function and will be dropped at the end of the function
|
||||||
|
LL | &x as *const u8
|
||||||
|
| --^^^^^^^^^^^^^
|
||||||
|
| |
|
||||||
|
| dangling pointer created here
|
||||||
|
|
|
||||||
|
= note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned
|
||||||
|
|
||||||
|
warning: a dangling pointer will be produced because the local variable `x` will be dropped
|
||||||
|
--> $DIR/dangling-pointers-from-locals.rs:37:5
|
||||||
|
|
|
||||||
|
LL | fn bindings_and_casts() -> *const u8 {
|
||||||
|
| --------- return type of the function is `*const u8`
|
||||||
|
LL | let x = 0u8;
|
||||||
|
| - `x` is part the function and will be dropped at the end of the function
|
||||||
|
LL | let x = &x as *const u8;
|
||||||
|
| -- dangling pointer created here
|
||||||
|
LL | x as *const u8
|
||||||
|
| ^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned
|
||||||
|
|
||||||
|
warning: a dangling pointer will be produced because the local variable `x` will be dropped
|
||||||
|
--> $DIR/dangling-pointers-from-locals.rs:43:12
|
||||||
|
|
|
||||||
|
LL | fn return_with_complex_cast() -> *mut u8 {
|
||||||
|
| ------- return type of the function is `*mut u8`
|
||||||
|
LL | let mut x = 0u8;
|
||||||
|
| ----- `x` is part the function and will be dropped at the end of the function
|
||||||
|
LL | return &mut x as *mut u8 as *const u8 as *mut u8;
|
||||||
|
| ------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
| |
|
||||||
|
| dangling pointer created here
|
||||||
|
|
|
||||||
|
= note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned
|
||||||
|
|
||||||
|
warning: a dangling pointer will be produced because the local variable `x` will be dropped
|
||||||
|
--> $DIR/dangling-pointers-from-locals.rs:49:5
|
||||||
|
|
|
||||||
|
LL | fn with_block() -> *const u8 {
|
||||||
|
| --------- return type of the function is `*const u8`
|
||||||
|
LL | let x = 0;
|
||||||
|
| - `x` is part the function and will be dropped at the end of the function
|
||||||
|
LL | &{ x }
|
||||||
|
| ^^^^^^
|
||||||
|
|
|
||||||
|
= note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned
|
||||||
|
|
||||||
|
warning: a dangling pointer will be produced because the local variable `x` will be dropped
|
||||||
|
--> $DIR/dangling-pointers-from-locals.rs:57:13
|
||||||
|
|
|
||||||
|
LL | fn with_many_blocks() -> *const u8 {
|
||||||
|
| --------- return type of the function is `*const u8`
|
||||||
|
LL | let x = 0;
|
||||||
|
| - `x` is part the function and will be dropped at the end of the function
|
||||||
|
...
|
||||||
|
LL | / &{
|
||||||
|
LL | |
|
||||||
|
LL | | { x }
|
||||||
|
LL | | }
|
||||||
|
| |_____________^
|
||||||
|
|
|
||||||
|
= note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned
|
||||||
|
|
||||||
|
warning: a dangling pointer will be produced because the local variable `x` will be dropped
|
||||||
|
--> $DIR/dangling-pointers-from-locals.rs:67:12
|
||||||
|
|
|
||||||
|
LL | fn simple_return() -> *const u8 {
|
||||||
|
| --------- return type of the function is `*const u8`
|
||||||
|
LL | let x = 0;
|
||||||
|
| - `x` is part the function and will be dropped at the end of the function
|
||||||
|
LL | return &x;
|
||||||
|
| ^^
|
||||||
|
|
|
||||||
|
= note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned
|
||||||
|
|
||||||
|
warning: a dangling pointer will be produced because the local variable `x` will be dropped
|
||||||
|
--> $DIR/dangling-pointers-from-locals.rs:73:12
|
||||||
|
|
|
||||||
|
LL | fn return_mut() -> *mut u8 {
|
||||||
|
| ------- return type of the function is `*mut u8`
|
||||||
|
LL | let mut x = 0;
|
||||||
|
| ----- `x` is part the function and will be dropped at the end of the function
|
||||||
|
LL | return &mut x;
|
||||||
|
| ^^^^^^
|
||||||
|
|
|
||||||
|
= note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned
|
||||||
|
|
||||||
|
warning: a dangling pointer will be produced because the local variable `x` will be dropped
|
||||||
|
--> $DIR/dangling-pointers-from-locals.rs:80:16
|
||||||
|
|
|
||||||
|
LL | fn const_and_flow() -> *const u8 {
|
||||||
|
| --------- return type of the function is `*const u8`
|
||||||
|
LL | if false {
|
||||||
|
LL | let x = 8;
|
||||||
|
| - `x` is part the function and will be dropped at the end of the function
|
||||||
|
LL | return &x;
|
||||||
|
| ^^
|
||||||
|
|
|
||||||
|
= note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned
|
||||||
|
|
||||||
|
warning: a dangling pointer will be produced because the local variable `x` will be dropped
|
||||||
|
--> $DIR/dangling-pointers-from-locals.rs:88:5
|
||||||
|
|
|
||||||
|
LL | fn vector<T: Default>() -> *const Vec<T> {
|
||||||
|
| ------------- return type of the function is `*const Vec<T>`
|
||||||
|
LL | let x = vec![T::default()];
|
||||||
|
| - `x` is part the function and will be dropped at the end of the function
|
||||||
|
LL | &x
|
||||||
|
| ^^
|
||||||
|
|
|
||||||
|
= note: pointers do not have a lifetime; after returning, the `Vec<T>` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned
|
||||||
|
|
||||||
|
warning: a dangling pointer will be produced because the local variable `x` will be dropped
|
||||||
|
--> $DIR/dangling-pointers-from-locals.rs:94:12
|
||||||
|
|
|
||||||
|
LL | fn local_adt() -> *const Adt {
|
||||||
|
| ---------- return type of the function is `*const Adt`
|
||||||
|
LL | let x = Adt(5);
|
||||||
|
| - `x` is part the function and will be dropped at the end of the function
|
||||||
|
LL | return &x;
|
||||||
|
| ^^
|
||||||
|
|
|
||||||
|
= note: pointers do not have a lifetime; after returning, the `Adt` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned
|
||||||
|
|
||||||
|
warning: a dangling pointer will be produced because the local variable `x` will be dropped
|
||||||
|
--> $DIR/dangling-pointers-from-locals.rs:101:16
|
||||||
|
|
|
||||||
|
LL | let _x = || -> *const u8 {
|
||||||
|
| --------- return type of the closure is `*const u8`
|
||||||
|
LL | let x = 8;
|
||||||
|
| - `x` is part the closure and will be dropped at the end of the closure
|
||||||
|
LL | return &x;
|
||||||
|
| ^^
|
||||||
|
|
|
||||||
|
= note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the closure because nothing is referencing it as far as the type system is concerned
|
||||||
|
|
||||||
|
warning: a dangling pointer will be produced because the local variable `x` will be dropped
|
||||||
|
--> $DIR/dangling-pointers-from-locals.rs:113:5
|
||||||
|
|
|
||||||
|
LL | fn fn_ptr() -> *const fn() -> u8 {
|
||||||
|
| ----------------- return type of the function is `*const fn() -> u8`
|
||||||
|
...
|
||||||
|
LL | let x = ret_u8 as fn() -> u8;
|
||||||
|
| - `x` is part the function and will be dropped at the end of the function
|
||||||
|
LL | &x
|
||||||
|
| ^^
|
||||||
|
|
|
||||||
|
= note: pointers do not have a lifetime; after returning, the `fn() -> u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned
|
||||||
|
|
||||||
|
warning: a dangling pointer will be produced because the local variable `a` will be dropped
|
||||||
|
--> $DIR/dangling-pointers-from-locals.rs:118:5
|
||||||
|
|
|
||||||
|
LL | fn as_arg(a: Adt) -> *const Adt {
|
||||||
|
| - ---------- return type of the function is `*const Adt`
|
||||||
|
| |
|
||||||
|
| `a` is part the function and will be dropped at the end of the function
|
||||||
|
LL | &a
|
||||||
|
| ^^
|
||||||
|
|
|
||||||
|
= note: pointers do not have a lifetime; after returning, the `Adt` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned
|
||||||
|
|
||||||
|
warning: a dangling pointer will be produced because the local variable `a` will be dropped
|
||||||
|
--> $DIR/dangling-pointers-from-locals.rs:123:5
|
||||||
|
|
|
||||||
|
LL | fn fn_ptr_as_arg(a: fn() -> u8) -> *const fn() -> u8 {
|
||||||
|
| - ----------------- return type of the function is `*const fn() -> u8`
|
||||||
|
| |
|
||||||
|
| `a` is part the function and will be dropped at the end of the function
|
||||||
|
LL | &a
|
||||||
|
| ^^
|
||||||
|
|
|
||||||
|
= note: pointers do not have a lifetime; after returning, the `fn() -> u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned
|
||||||
|
|
||||||
|
warning: a dangling pointer will be produced because the local variable `a` will be dropped
|
||||||
|
--> $DIR/dangling-pointers-from-locals.rs:128:5
|
||||||
|
|
|
||||||
|
LL | fn ptr_as_arg(a: *const Adt) -> *const *const Adt {
|
||||||
|
| - ----------------- return type of the function is `*const *const Adt`
|
||||||
|
| |
|
||||||
|
| `a` is part the function and will be dropped at the end of the function
|
||||||
|
LL | &a
|
||||||
|
| ^^
|
||||||
|
|
|
||||||
|
= note: pointers do not have a lifetime; after returning, the `*const Adt` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned
|
||||||
|
|
||||||
|
warning: a dangling pointer will be produced because the local variable `a` will be dropped
|
||||||
|
--> $DIR/dangling-pointers-from-locals.rs:133:5
|
||||||
|
|
|
||||||
|
LL | fn adt_as_arg(a: &Adt) -> *const &Adt {
|
||||||
|
| - ----------- return type of the function is `*const &Adt`
|
||||||
|
| |
|
||||||
|
| `a` is part the function and will be dropped at the end of the function
|
||||||
|
LL | &a
|
||||||
|
| ^^
|
||||||
|
|
|
||||||
|
= note: pointers do not have a lifetime; after returning, the `&Adt` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned
|
||||||
|
|
||||||
|
warning: 19 warnings emitted
|
||||||
|
|
||||||
Reference in New Issue
Block a user