Skip to content
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

a fn pointer doesn't implement Fn/FnMut/FnOnce if its return type isn't sized #100096

Merged
merged 1 commit into from
Sep 21, 2022

Conversation

compiler-errors
Copy link
Member

@compiler-errors compiler-errors commented Aug 3, 2022

I stumbled upon #83915 which hasn't received much attention recently, and I wanted to revive it since this is one existing soundness hole that seems pretty easy to fix.

I'm not actually sure that the alternative approach described here is sufficient, given the src/test/ui/function-pointer/unsized-ret.rs example I provided below. Rebasing the branch mentioned in that comment and testing that UI test, it seems that we actually end up only observing that str: !Sized during monomorphization, whereupon we ICE. Even if we were to fix that ICE, ideally we'd be raising an error that a fn pointer is being used badly during typecheck instead of monomorphization, hence adapting the original approach in #83915.

I am happy to close this if people would prefer we rebase the original PR and land that -- I am partly opening to be annoying and get people thinking about this unsoundness again ❤️ 😸

cc: @estebank and @nikomatsakis
r? types

Here's a link to the thread: https://rust-lang.zulipchat.com/#narrow/stream/144729-t-types/topic/PR.20.2383915/near/235421351 for more context.

@rustbot rustbot added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Aug 3, 2022
@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Aug 3, 2022
LL | foo::<fn() -> str, _>(None, ());
| ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: within `fn() -> str`, the trait `Sized` is not implemented for `str`
Copy link
Contributor

Choose a reason for hiding this comment

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

Random thought: I wonder if we could get the span for the str and use it for a span_help here, opportunistically (because for things like type aliases in a foreign crate, we might not be able to recover them).

Comment on lines +9 to +15
note: required by a bound in `foo`
--> $DIR/unsized-ret.rs:4:11
|
LL | fn foo<F: Fn<T>, T>(f: Option<F>, t: T) {
| ^^^^^ required by this bound in `foo`
Copy link
Contributor

Choose a reason for hiding this comment

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

The implicit Sized requirements should have their own obligation cause so that we could mention why it was required (as the code doesn't mention it, this would be mystifying the first time you encounter it).

@estebank
Copy link
Contributor

estebank commented Aug 3, 2022

@estebank
Copy link
Contributor

estebank commented Aug 3, 2022

I'm ok with landing this instead of my PR. I'll let the types team decide whether this is the right approach (although it looks reasonable to me).

@compiler-errors
Copy link
Member Author

i guess this really should be r? @nikomatsakis since he reviewed the last one

@rust-highfive rust-highfive assigned nikomatsakis and unassigned lcnr Aug 10, 2022
@pnkfelix
Copy link
Member

pnkfelix commented Sep 8, 2022

Discussed in T-compiler triage meeting. Nominating for T-types to handle forward movement.

@rustbot label: I-types-nominated

@rustbot rustbot added the I-types-nominated Nominated for discussion during a types team meeting. label Sep 8, 2022
@compiler-errors
Copy link
Member Author

r? @jackh726

Copy link
Member

@jackh726 jackh726 left a comment

Choose a reason for hiding this comment

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

r=me with testing for fn ptrs with bound vars

Comment on lines +591 to +643
// The binder on the Fn obligation is "less" important than the one on
// the signature, as evidenced by how we treat it during projection.
// The safe thing to do here is to liberate it, though, which should
// have no worse effect than skipping the binder here.
let liberated_fn_ty = self.infcx.replace_bound_vars_with_placeholders(obligation.self_ty());
let output_ty = self
.infcx
.replace_bound_vars_with_placeholders(liberated_fn_ty.fn_sig(self.tcx()).output());
let output_ty = normalize_with_depth_to(
self,
obligation.param_env,
cause.clone(),
obligation.recursion_depth,
output_ty,
&mut nested,
);
let tr = ty::Binder::dummy(ty::TraitRef::new(
self.tcx().require_lang_item(LangItem::Sized, None),
self.tcx().mk_substs_trait(output_ty, &[]),
));
Copy link
Member

Choose a reason for hiding this comment

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

Just for completeness, can you update the test to include some fn ptrs with bound vars?

@jackh726 jackh726 added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Sep 12, 2022
@compiler-errors
Copy link
Member Author

Added some check-pass tests with higher-ranked lifetimes, and a failure to the unsized-return test with a higher-ranked lifetime

| |
| required by a bound introduced by this call
|
= help: within `for<'a> fn(&'a ()) -> (dyn std::fmt::Display + 'a)`, the trait `for<'a> Sized` is not implemented for `(dyn std::fmt::Display + 'a)`
Copy link
Member Author

Choose a reason for hiding this comment

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

Interestingly this mentions for<'a> Sized, but I think that's because we print placeholder regions as if they were in binders.

@compiler-errors compiler-errors added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Sep 12, 2022
@jackh726
Copy link
Member

@bors r+

IIUC, this doesn't change stable behavior, only fixes unstable behavior.

@bors
Copy link
Contributor

bors commented Sep 20, 2022

📌 Commit 3b573c9 has been approved by jackh726

It is now in the queue for this repository.

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Sep 20, 2022
@jackh726 jackh726 removed the I-types-nominated Nominated for discussion during a types team meeting. label Sep 20, 2022
@bors
Copy link
Contributor

bors commented Sep 21, 2022

⌛ Testing commit 3b573c9 with merge 1de00d1...

@bors
Copy link
Contributor

bors commented Sep 21, 2022

☀️ Test successful - checks-actions
Approved by: jackh726
Pushing 1de00d1 to master...

@bors bors added the merged-by-bors This PR was explicitly merged by bors. label Sep 21, 2022
@bors bors merged commit 1de00d1 into rust-lang:master Sep 21, 2022
@rustbot rustbot added this to the 1.66.0 milestone Sep 21, 2022
@rust-timer
Copy link
Collaborator

Finished benchmarking commit (1de00d1): comparison URL.

Overall result: ❌ regressions - ACTION NEEDED

Next Steps: If you can justify the regressions found in this perf run, please indicate this with @rustbot label: +perf-regression-triaged along with sufficient written justification. If you cannot justify the regressions please open an issue or create a new PR that fixes the regressions, add a comment linking to the newly created issue or PR, and then add the perf-regression-triaged label to this PR.

@rustbot label: +perf-regression
cc @rust-lang/wg-compiler-performance

Instruction count

This is a highly reliable metric that was used to determine the overall result at the top of this comment.

mean1 range count2
Regressions ❌
(primary)
- - 0
Regressions ❌
(secondary)
23.0% [21.3%, 25.2%] 6
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) - - 0

Max RSS (memory usage)

Results

This 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.

mean1 range count2
Regressions ❌
(primary)
- - 0
Regressions ❌
(secondary)
9.1% [7.4%, 10.6%] 6
Improvements ✅
(primary)
-0.8% [-0.8%, -0.8%] 1
Improvements ✅
(secondary)
-1.4% [-1.4%, -1.4%] 1
All ❌✅ (primary) -0.8% [-0.8%, -0.8%] 1

Cycles

Results

This 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.

mean1 range count2
Regressions ❌
(primary)
2.7% [2.7%, 2.7%] 1
Regressions ❌
(secondary)
21.0% [2.6%, 26.6%] 7
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) 2.7% [2.7%, 2.7%] 1

Footnotes

  1. the arithmetic mean of the percent change 2 3

  2. number of relevant changes 2 3

@rustbot rustbot added the perf-regression Performance regression. label Sep 21, 2022
@compiler-errors
Copy link
Member Author

Oh my goodness, I will look into those perf regressions ASAP.

@Mark-Simulacrum
Copy link
Member

FWIW, the regressions are on a single secondary benchmark, and while they're real this is a soundness fix so if we can't mitigate them it makes sense to move forward I think. (That said the change here seems like it could definitely affect other code, wg-grammar probably just has more fn ptrs or something).

We do see a similar-ish regression in some of the bootstrap benchmarks, though to a lesser extent, so it's not entirely limited I guess.

@compiler-errors
Copy link
Member Author

So I haven't had time to fix this, nor do I think this is an easily mitigated regression. I'm not sure if @rust-lang/wg-prioritization deems this a bad enough perf regression that we should roll it back.

This is technically an issue that is only triggered with #![feature(fn_traits, unboxed_closures)], so it doesn't represent a risk on stable Rust, for example. Not sure if @rust-lang/types has an opinion on whether we should roll back/table this and revisit it before (theoretically) we were to stabilize the raw Fn traits.

@lcnr
Copy link
Contributor

lcnr commented Oct 4, 2022

I don't think we should revert this PR, the regression is limited to only one secondary benchmark and while it may make sense to look into how we can reduce that regression there, it doesn't feel bad enough to warrant a complete revert of this soundness fix

bors added a commit to rust-lang-ci/rust that referenced this pull request Feb 19, 2023
…safety, r=lcnr

Check that built-in callable types validate their output type is `Sized` (in new solver)

Working on parity with old solver. Putting this up for consideration, it's not *really* needed or anything just yet. Maybe it's better to approach this from another direction (like always checking the item bounds when calling `consider_assumption`? we may need that for coinduction to be sound though?)

This basically implements rust-lang#100096 for the new solver.
@compiler-errors compiler-errors deleted the fn-return-must-be-sized branch August 11, 2023 20:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
merged-by-bors This PR was explicitly merged by bors. perf-regression Performance regression. S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.