Skip to content

fix incorrect accessor reference lifetime#132

Open
nbdd0121 wants to merge 2 commits intomainfrom
dev/accessor-lifetime
Open

fix incorrect accessor reference lifetime#132
nbdd0121 wants to merge 2 commits intomainfrom
dev/accessor-lifetime

Conversation

@nbdd0121
Copy link
Copy Markdown
Member

When a field has been initialized, init!/pin_init! create a reference or pinned reference to the field so it can be accessed later during the initialization of other fields. However, the reference it created is incorrectly &'static rather than just the scope of the initializer.

This means that you can do

init!(Foo {
    a: 1,
    _: {
        let b: &'static u32 = a;
    }
})

which is unsound.

This is caused by &mut (*#slot).#ident, which actually allows arbitrary lifetime, so this is effectively 'static. Somewhat ironically, the safety justification of creating the accessor is.. "SAFETY: TODO".

Fix it by adding Deref/DerefMut implementation to DropGuard and derive the reference from dereferencing DropGuard instead. The lifetime of DropGuard is exactly what we want for these accessors.

The old accessor creation code also has a purpose of preventing unaligned fields. So a let _ = &(*#slot).#ident is kept in place to avoid that unsoundness.

@nbdd0121 nbdd0121 requested a review from BennoLossin April 20, 2026 11:16
@nbdd0121 nbdd0121 force-pushed the dev/accessor-lifetime branch 3 times, most recently from 7d6d897 to 6d3e6c1 Compare April 20, 2026 15:46
Copy link
Copy Markdown
Member

@BennoLossin BennoLossin left a comment

Choose a reason for hiding this comment

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

Oh I like the solution of using the drop guard for the access! I have just one comment, this looks very nice :)

Comment thread internal/src/init.rs
@nbdd0121 nbdd0121 force-pushed the dev/accessor-lifetime branch from 6d3e6c1 to 589b3a1 Compare April 20, 2026 17:12
BennoLossin
BennoLossin previously approved these changes Apr 20, 2026
Instead of having the reference creation serving dual-purpose as both for
let bindings and alignment check, detangle them so that the alignment check
is done explicitly in `make_field_check`. This is more robust again
refactors that may change the way let bindings are created.

Signed-off-by: Gary Guo <gary@garyguo.net>
When a field has been initialized, `init!`/`pin_init!` create a reference
or pinned reference to the field so it can be accessed later during the
initialization of other fields. However, the reference it created is
incorrectly `&'static` rather than just the scope of the initializer.

This means that you can do

    init!(Foo {
        a: 1,
        _: {
            let b: &'static u32 = a;
        }
    })

which is unsound.

This is caused by `&mut (*#slot).#ident`, which actually allows arbitrary
lifetime, so this is effectively `'static`. Somewhat ironically, the safety
justification of creating the accessor is.. "SAFETY: TODO".

Fix it by adding `let_binding` method on `DropGuard` to shorten lifetime.
This results exactly what we want for these accessors.

Fixes: db96c51 ("add references to previously initialized fields")
Signed-off-by: Gary Guo <gary@garyguo.net>
@nbdd0121 nbdd0121 force-pushed the dev/accessor-lifetime branch from 1be9fef to c184964 Compare April 23, 2026 14:27
@nbdd0121 nbdd0121 added the soundness Related to soundness issues label Apr 24, 2026
Comment thread src/__internal.rs
Comment on lines +245 to +246
pub struct DropGuard<'a, T: ?Sized> {
ptr: &'a mut T,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

IIRC this is unsound with the Drop impl that we have & we would need to tag 'a as #[maybe_dangling] or wrap ptr in https://doc.rust-lang.org/std/mem/struct.MaybeDangling.html.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

soundness Related to soundness issues

Development

Successfully merging this pull request may close these issues.

2 participants