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
The scripts match "[PATCH .*]" which breaks if a single patch is involved,
which is "[PATCH]".

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 `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` still needs to be present, but this
no longer has to care about pinning, so it is moved to just before the
guard generation.

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 6d3e6c1 to 589b3a1 Compare April 20, 2026 17:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants