Skip to content

fn() -> Out is a valid type for unsized types Out, and it implements FnOnce<(), Output = Out> #82633

Closed
@steffahn

Description

@steffahn
Member

fn() -> Out is a valid type, even for unsized types Out, and it implements FnOnce<(), Output = Out>, even though FnOnce::Output is not ?Sized. So far, I haven’t found a way to turn this into unsoundness without using unboxed_closures.

#![feature(unboxed_closures)]

trait A { fn a() where Self: Sized; }

fn foo<F: FnOnce<()>>() where F::Output: A { F::Output::a() }

fn main() { foo::<fn() -> dyn A>() }

(Playground)

code after rustfmt
#![feature(unboxed_closures)]

trait A {
    fn a()
    where
        Self: Sized;
}

fn foo<F: FnOnce<()>>()
where
    F::Output: A,
{
    F::Output::a()
}

fn main() {
    foo::<fn() -> dyn A>()
}

Errors:

   Compiling playground v0.0.1 (/playground)
error: linking with `cc` failed: exit code: 1
  |
  = note: "cc" "-Wl,--as-needed" "-Wl,-z,noexecstack" "-m64" "-Wl,--eh-frame-hdr" "-L" "/playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib" "/playground/target/debug/deps/playground-51f3bbb2c25d281d.playground.4dy3dxin-cgu.0.rcgu.o" "-o" "/playground/target/debug/deps/playground-51f3bbb2c25d281d" "/playground/target/debug/deps/playground-51f3bbb2c25d281d.1r48kp97232mukin.rcgu.o" "-Wl,--gc-sections" "-pie" "-Wl,-zrelro" "-Wl,-znow" "-nodefaultlibs" "-L" "/playground/target/debug/deps" "-L" "/playground/target/debug/build/libsqlite3-sys-f766054917a587df/out" "-L" "/playground/target/debug/build/ring-f55e8d4980a6255d/out" "-L" "/playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib" "-Wl,--start-group" "-Wl,-Bstatic" "/playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd-e3026a7ea720d3a3.rlib" "/playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libpanic_unwind-dea899c54966188d.rlib" "/playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libminiz_oxide-dda4c0b69607e93b.rlib" "/playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libadler-4b7dae8949ac132c.rlib" "/playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libobject-978e97832b309706.rlib" "/playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libaddr2line-073b1b693304b876.rlib" "/playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libgimli-c07f996a53ee6558.rlib" "/playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/librustc_demangle-0ae8ed6a282247d0.rlib" "/playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libhashbrown-72f6aee6e444f535.rlib" "/playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/librustc_std_workspace_alloc-14b94bdd9a47d665.rlib" "/playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libunwind-97d562419076c156.rlib" "/playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcfg_if-022f1a0e7cd794ec.rlib" "/playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/liblibc-6c8051b8141a3b3d.rlib" "/playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/liballoc-3aeb407930ebd519.rlib" "/playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/librustc_std_workspace_core-6ab1ee6dbc17ad08.rlib" "/playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcore-166dae07beec0398.rlib" "-Wl,--end-group" "/playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcompiler_builtins-761b290f47712921.rlib" "-Wl,-Bdynamic" "-lgcc_s" "-lutil" "-lrt" "-lpthread" "-lm" "-ldl" "-lc"
  = note: /usr/bin/ld: /playground/target/debug/deps/playground-51f3bbb2c25d281d.playground.4dy3dxin-cgu.0.rcgu.o: in function `playground::foo':
          /playground/src/main.rs:5: undefined reference to `playground::A::a'
          /usr/bin/ld: /playground/target/debug/deps/playground-51f3bbb2c25d281d: hidden symbol `_ZN10playground1A1a17h9a4c65829fc0d7d1E' isn't defined
          /usr/bin/ld: final link failed: bad value
          collect2: error: ld returned 1 exit status
          

error: aborting due to previous error

error: could not compile `playground`

To learn more, run the command again with --verbose.

Activity

changed the title [-]`fn() -> Out` is a valid type unsized types `Out`, and it implements `FnOnce<(), Output = Out>`[/-] [+]`fn() -> Out` is a valid type for unsized types `Out`, and it implements `FnOnce<(), Output = Out>`[/+] on Feb 28, 2021
steffahn

steffahn commented on Feb 28, 2021

@steffahn
MemberAuthor

The labeling is a bit tricky on this one. This is most definitely I-unsound 💥-worthy when using unboxed_closures. (And you can, of course, also generate ICE’s in a multitude of ways.)

On the other hand, the fact that there is a type implementing FnOnce with unsized Output type is definitely observable on stable, so this issue is not really only about the #![feature(unboxed_closures)] case. I mean, not even trait objects allow you to skip a Sized bound like that even though trait object types don’t seem to care too much about behaving soundly in other cases (#57893, #80800).

steffahn

steffahn commented on Feb 28, 2021

@steffahn
MemberAuthor

@rustbot modify labels: A-associated-items, A-typesystem, T-compiler

added
A-associated-itemsArea: Associated items (types, constants & functions)
T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
on Feb 28, 2021
added
I-unsoundIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/Soundness
on Mar 2, 2021
added
I-prioritizeIssue: Indicates that prioritization has been requested for this issue.
on Mar 2, 2021
jyn514

jyn514 commented on Mar 2, 2021

@jyn514
Member

I had trouble seeing the unsoundness, so here's another example:

#![feature(trivial_bounds)]
#![feature(unboxed_closures)]

trait A { fn a() where Self: Sized; }
impl A for str {
    fn a() where Self: Sized {
        unsafe { std::hint::unreachable_unchecked() }
    }
}

fn foo<F: FnOnce<()>>() where F::Output: A { F::Output::a() }

fn main() { foo::<fn() -> str>() }

str: Sized is false, so str::a() should never be executed:

error[E0277]: the size for values of type `str` cannot be known at compilation time
  --> src/main.rs:15:5
   |
4  | trait A { fn a() where Self: Sized; }
   |           ------------------------- required by `A::a`
...
15 |     str::a();
   |     ^^^^^^ doesn't have a size known at compile-time

yet it is anyway:

/playground/tools/entrypoint.sh: line 11:     7 Illegal instruction     timeout --signal=KILL ${timeout} "$@"
camelid

camelid commented on Mar 2, 2021

@camelid
Member

And note that you can observe the unsoundness on stable (@steffahn's code, I just wanted to highlight it):

fn weird_situation<F: FnOnce() -> str>() {
    println!("if this is reachable, there’s a function type with unsized Output type `str`");
}

fn main() {
    weird_situation::<fn() -> str>()
}

This code compiles, but it shouldn't.

removed
I-prioritizeIssue: Indicates that prioritization has been requested for this issue.
on Mar 2, 2021

56 remaining items

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

Metadata

Metadata

Assignees

Labels

A-associated-itemsArea: Associated items (types, constants & functions)A-closuresArea: Closures (`|…| { … }`)A-trait-systemArea: Trait systemA-type-systemArea: Type systemC-bugCategory: This is a bug.E-easyCall for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue.E-needs-testCall for participation: An issue has been fixed and does not reproduce, but no test has been added.F-unboxed_closures`#![feature(unboxed_closures)]`I-unsoundIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/SoundnessP-highHigh priorityT-langRelevant to the language teamT-typesRelevant to the types team, which will review and decide on the PR/issue.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

    Participants

    @joshtriplett@pnkfelix@oli-obk@estebank@jonas-schievink

    Issue actions

      `fn() -> Out` is a valid type for unsized types `Out`, and it implements `FnOnce<(), Output = Out>` · Issue #82633 · rust-lang/rust