-
Notifications
You must be signed in to change notification settings - Fork 12.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CFI: Abstract Closures and Coroutines #123106
Conversation
How does this handle Fn subtraits? More specifically:
And how does this handle Fn subtraits of multiple Fn supertraits, like the example you gave at #123082 (comment) (i.e., |
Supertraits are entirely handled by #123012 - if the callsite tries to call a method on
At the callsite for each, #123012 would translate the |
As I we discussed on Zulip, I had two observations about this approach:
And as you noted: It would improve:
And as I noted:
We've come a far and long way away from the original CfiShim proposal, which is great. If you understand the possible costs of these added levels of indirections for KCFI for cache coherence/locality and performance, possible introduction of gadgets or bypasses, and is willing to move forward with these on the Linux kernel (cc @ojeda), Android, and other embedded devices, I'm okay with moving forward with these changes. If this becomes an issue later, we can always revisit #123082, which works for both CFI and KCFI and doesn't require reifying types. |
☔ The latest upstream changes (presumably #123128) made this pull request unmergeable. Please resolve the merge conflicts. |
compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
Outdated
Show resolved
Hide resolved
.expect("No call-family function on closure-like Fn trait?") | ||
.def_id; | ||
|
||
instance.def = ty::InstanceDef::Virtual(call, 0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I said this earlier but I don't think I got a response, so I'll say it again: Why are you using InstanceDef::Virtual
over just using InstanceDef::Item
? You have an associated item def id, so just use it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I answered this on the previous change, but I also left a comment above it in the first half of this if
statement when I set Virtual
the first time explaining. The short version of that comment is that this is an adjusted type for the case where the callsite will have a Virtual
. I wanted to make the callsite and the declaration match as closely as possible to make it harder to make a mistake.
This also means that fn_abi
will use its special logic for unwrapping receivers in the case that the receiver is not already directly a pointer to a dyn Trait
- it'll unwrap the ZST repeatedly until it gets to one. This is load-bearing in the top half of the if
condition, because alternate receivers happen.
Finally, in the future we could choose to support the fact that Virtual
&dyn Trait
in receiver position is different from any other instance's &dyn Trait
in receiver position, in that it's a single pointer instead of double-wide, and encode that differently (we don't do this today).
All that said, since none of the Fn
-trait receivers use receivers that need unwrapping, I can replace this with Item
if you really want me to.
compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
Outdated
Show resolved
Hide resolved
compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
Outdated
Show resolved
Hide resolved
compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
Outdated
Show resolved
Hide resolved
I addressed some of the comments, but I don't think we need to generalize async closures because the I wanted to add a test that we don't barf on The HRTB test I added is pretty simple, but I expect that if we can handle any HRTB, it's likely we can handle all of it. If you think it needs to be more broad, I can look around the test suite for HRTB edge cases to add. @rustbot ready |
compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
Outdated
Show resolved
Hide resolved
compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
Outdated
Show resolved
Hide resolved
compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
Outdated
Show resolved
Hide resolved
befd136
to
6bce455
Compare
I've made all the requested adjustments other than @rustbot ready |
☔ The latest upstream changes (presumably #123147) made this pull request unmergeable. Please resolve the merge conflicts. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be fine to approve this after rebase. Anything I mentioned can be done as a follow-up.
let mut s = String::new(); | ||
let name = encode_ty_name(tcx, *def_id); | ||
let _ = write!(s, "u{}{}", name.len(), &name); | ||
let parent_args = tcx.mk_args(args.as_coroutine_closure().parent_args()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should do this for closures too; shouldn't change anything, but it means encoding fewer args for closures.
s.push_str(&encode_args(tcx, parent_args, dict, options)); | ||
compress(dict, DictKey::Ty(ty, TyQ::None), &mut s); | ||
typeid.push_str(&s); | ||
} | ||
|
||
ty::Coroutine(def_id, args, ..) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For coroutines, we should actually also encode args.as_closure().kind_ty()
in addition to the parent args. But if you don't want to do this, I could craft a test where this matters.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't object to doing it, but would prefer it in a follow up to keep things moving.
The other thing to note here is that lacking the kind_ty
won't break anything, it will just make our alias sets not-as-good-as-they-could-be, since coroutines of different kinds will be swappable by an attacker.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, making them distinguishable would be useful though. Follow-up.
☔ The latest upstream changes (presumably #123012) made this pull request unmergeable. Please resolve the merge conflicts. |
KCFI: Require -C panic=abort While the KCFI scheme is not incompatible with unwinding, LLVM's `invoke` instruction does not currently support KCFI bundles. While it likely will in the near future, we won't be able to assume that in Rust for a while. We encountered this problem while [turning on closure support](rust-lang#123106 (comment)). r? `@workingjubilee`
KCFI: Require -C panic=abort While the KCFI scheme is not incompatible with unwinding, LLVM's `invoke` instruction does not currently support KCFI bundles. While it likely will in the near future, we won't be able to assume that in Rust for a while. We encountered this problem while [turning on closure support](rust-lang#123106 (comment)). r? ``@workingjubilee``
Rollup merge of rust-lang#123200 - maurer:kcfi-abort, r=compiler-errors KCFI: Require -C panic=abort While the KCFI scheme is not incompatible with unwinding, LLVM's `invoke` instruction does not currently support KCFI bundles. While it likely will in the near future, we won't be able to assume that in Rust for a while. We encountered this problem while [turning on closure support](rust-lang#123106 (comment)). r? ``@workingjubilee``
☔ The latest upstream changes (presumably #123230) made this pull request unmergeable. Please resolve the merge conflicts. |
Similar to methods on a trait object, the most common way to indirectly call a closure or coroutine is through the vtable on the appropriate trait. This uses the same approach as we use for trait methods, after backing out the trait arguments from the type.
yeet @bors r+ |
☀️ Test successful - checks-actions |
Finished benchmarking commit (70714e3): comparison URL. Overall result: no relevant changes - no action needed@rustbot label: -perf-regression Instruction countThis benchmark run did not return any relevant results for this metric. Max RSS (memory usage)ResultsThis is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.
CyclesThis benchmark run did not return any relevant results for this metric. Binary sizeResultsThis is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.
Bootstrap: 667.603s -> 667.994s (0.06%) |
The compiler crashes with the following code with this PR:
I can take a look at it later if you don't have time to. |
I was unaware that there is more than one variety of
Since that value doesn't implement See #123368 for an explicit solution to this issue, but it doesn't yet support generator coroutines or async generator coroutines, I'll find time to get those working soon. |
… r=compiler-errors CFI: Support non-general coroutines Previously, we assumed all `ty::Coroutine` were general coroutines and attempted to generalize them through the `Coroutine` trait. Select appropriate traits for each kind of coroutine. I have this marked as a draft because it currently only fixes async coroutines, and I think it make sense to try to fix gen/async gen coroutines before this is merged. If the issue [mentioned](rust-lang#123106 (comment)) in the original PR is actually affecting someone, we can land this as is to remedy it.
… r=compiler-errors CFI: Support non-general coroutines Previously, we assumed all `ty::Coroutine` were general coroutines and attempted to generalize them through the `Coroutine` trait. Select appropriate traits for each kind of coroutine. I have this marked as a draft because it currently only fixes async coroutines, and I think it make sense to try to fix gen/async gen coroutines before this is merged. If the issue [mentioned](rust-lang#123106 (comment)) in the original PR is actually affecting someone, we can land this as is to remedy it.
Rollup merge of rust-lang#123368 - maurer:cfi-non-general-coroutines, r=compiler-errors CFI: Support non-general coroutines Previously, we assumed all `ty::Coroutine` were general coroutines and attempted to generalize them through the `Coroutine` trait. Select appropriate traits for each kind of coroutine. I have this marked as a draft because it currently only fixes async coroutines, and I think it make sense to try to fix gen/async gen coroutines before this is merged. If the issue [mentioned](rust-lang#123106 (comment)) in the original PR is actually affecting someone, we can land this as is to remedy it.
This will abstract coroutines in a moment, it's just abstracting closures for now to show @rcvalle
This uses the same principal as the methods on traits - figure out the
dyn
type representing the fn trait, instantiate it, and attach that alias set. We're essentially just computing how we would be called in a dynamic context, and attaching that.