-
-
Notifications
You must be signed in to change notification settings - Fork 14.8k
derive(CoercePointee) is unsound with user-defined attribute macros. #148899
Copy link
Copy link
Open
Labels
A-macrosArea: All kinds of macros (custom derive, macro_rules!, proc macros, ..)Area: All kinds of macros (custom derive, macro_rules!, proc macros, ..)A-pinArea: PinArea: PinA-proc-macrosArea: Procedural macrosArea: Procedural macrosC-bugCategory: This is a bug.Category: This is a bug.F-derive_coerce_pointeeFeature: RFC 3621's oft-renamed implementationFeature: RFC 3621's oft-renamed implementationI-lang-radarItems that are on lang's radar and will need eventual work or consideration.Items that are on lang's radar and will need eventual work or consideration.I-unsoundIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/SoundnessIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/SoundnessT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.Relevant to the compiler team, which will review and decide on the PR/issue.T-langRelevant to the language teamRelevant to the language teamT-libsRelevant to the library team, which will review and decide on the PR/issue.Relevant to the library team, which will review and decide on the PR/issue.requires-nightlyThis issue requires a nightly compiler in some way. When possible, use a F-* label instead.This issue requires a nightly compiler in some way. When possible, use a F-* label instead.
Metadata
Metadata
Assignees
Labels
A-macrosArea: All kinds of macros (custom derive, macro_rules!, proc macros, ..)Area: All kinds of macros (custom derive, macro_rules!, proc macros, ..)A-pinArea: PinArea: PinA-proc-macrosArea: Procedural macrosArea: Procedural macrosC-bugCategory: This is a bug.Category: This is a bug.F-derive_coerce_pointeeFeature: RFC 3621's oft-renamed implementationFeature: RFC 3621's oft-renamed implementationI-lang-radarItems that are on lang's radar and will need eventual work or consideration.Items that are on lang's radar and will need eventual work or consideration.I-unsoundIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/SoundnessIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/SoundnessT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.Relevant to the compiler team, which will review and decide on the PR/issue.T-langRelevant to the language teamRelevant to the language teamT-libsRelevant to the library team, which will review and decide on the PR/issue.Relevant to the library team, which will review and decide on the PR/issue.requires-nightlyThis issue requires a nightly compiler in some way. When possible, use a F-* label instead.This issue requires a nightly compiler in some way. When possible, use a F-* label instead.
Type
Fields
Give feedbackNo fields configured for issues without a type.
This issue has the same cause as #148423, but applied to a different derive macro.
This issue uses a similar mechanism to #134407 to cause unsoundness, but this issue uses unsize-coercion instead of higher ranked function pointer subtyping.
The following code causes a use-after-free, crashing in my testing. (The explanation is below the code.)
(Here's the equivalent code on the playground, using the
macro_attrfeature to define an attribute macro without needing to use a separate crate.)dep/src/lib.rs:
src/main.rs:
The
derive(CoercePointee)macro tries to implement theUnsizetrait on a struct namedThing. Due to the#[discard]macro, theUnsizetrait instead gets implemented on the type aliastype Thing<T> = Pin<Wrap<T>>;(which doesn't violate orphan rules, sincePinis a fundamental type). As a result,Pin<Wrap<T>>can unsize-coerce theTtype, as thoughWrap<T>implemented thePinCoerceUnsizedtrait.I implement
DerefonWrap<impl Sized>andWrap<dyn IsType<T>>so that no pin guarantee exists on those types (since they deref tou8, which isUnpin). However, I implementWrap<dyn SubIsType<T>>so that there is actually a pin guarantee.In the
wrong_pinfunction, I create aWrap<impl Sized>(without any pin guarantees). I unsize-coerce it toWrap<dyn SubIsType<T>>(which does have a pin guarantee), and then trait-upcast it toWrap<dyn IsType<T>>(without any pin guarantees). I then extract theTout and return it. During the time where the pin guarantee exists, I call a callback which makes use of the pin guarantee. This pin guarantee is, of course, violated when theTvalue is extracted.The
mainfunction then uses this violation ofPinguarantees to cause UB.Meta
rustc --version --verbose: