rust-lang / rust

Empowering everyone to build reliable and efficient software.
https://www.rust-lang.org
Other
97.39k stars 12.59k forks source link

Segfault when returning deep function compositions #93237

Open fredlahde opened 2 years ago

fredlahde commented 2 years ago

This issue is tightly bound to this PR (93082), which aims to add the ability to return impl Fn() -> impl Trait from a function.

I played around with it, and got the idea to test out if there is a limit to how deep we can nest those functions (since the PR also enables impl Fn() -> impl Fn() -> impl Trait). It quickly noticed a segfault from rustc and was able to determine the exact depth that causes the crash.

Code

For generating test files quickly, I wrote a small code generator:

const FILE_NAME: &str = "test.rs";

use std::io::Write;
use std::env;

fn main() {
    let args: Vec<String> = env::args().collect();
    let n_depth: usize = args[1].parse().unwrap();
    let mut fd = std::fs::OpenOptions::new()
        .create(true)
        .truncate(true)
        .write(true)
        .open(FILE_NAME)
        .unwrap();
    fd.write(b"use std::fmt::Debug;\n").unwrap();
    fd.write(b"fn foo()").unwrap();
    (0..n_depth).for_each(|_| {
        let _w = fd.write(b"-> impl Fn() ").unwrap();
    });
    fd.write(b"-> impl Debug {\n").unwrap();
    (0..n_depth).for_each(|_| {
        let _w = fd.write(b"|| ").unwrap();
    });
    fd.write(br#""hi""#).unwrap();
    fd.write(b"}\n").unwrap();

    fd.write(br#"
        fn main() {
            let x = foo()"#).unwrap();
    (0..n_depth).for_each(|_| {
        let _w = fd.write(b"()").unwrap();
    });
    fd.write(br#";
        println!("{:?}", x);
        }"#).unwrap();
}

Once compiled, one can call it like this: ./gen <depth>. The depth argument controls the count of -> impl Fn() that is emitted. The following listing is an example with depth set to 5:

use std::fmt::Debug;
fn foo()-> impl Fn() -> impl Fn() -> impl Fn() -> impl Fn() -> impl Fn() -> impl Debug {
|| || || || || "hi"}

        fn main() {
            let x = foo()()()()()();
        println!("{:?}", x);
        }

If one then tries to compile this with the rustc from the PR at commit 3ed486b37477dde94c87539, the test program compiles successfully.

However, when I set depth to 560, I get a segfault.

Meta

rustc --version --verbose:

rustc 1.60.0-dev
binary: rustc
commit-hash: unknown
commit-date: unknown
host: x86_64-unknown-linux-gnu
release: 1.60.0-dev
LLVM version: 13.0.0

Error output

I got a backtrace from gdb:

#0  0x00007ffff5a28670 in core::iter::adapters::process_results::<core::iter::adapters::map::Map<core::iter::adapters::enumerate::Enumerate<core::iter::adapters::zip::Zip<core::iter::adapters::copied::Copied<core::slice::iter::Iter<rustc_middle::ty::subst::GenericArg>>, core::iter::adapters::copied::Copied<core::slice::iter::Iter<rustc_middle::ty::subst::GenericArg>>>>, rustc_middle::ty::relate::relate_substs<rustc_infer::infer::nll_relate::TypeRelating<rustc_borrowck::type_check::relate_tys::NllTypeRelatingDelegate>>::{closure#0}>, rustc_middle::ty::subst::GenericArg, rustc_middle::ty::error::TypeError, <core::result::Result<smallvec::SmallVec<[rustc_middle::ty::subst::GenericArg; 8]>, rustc_middle::ty::error::TypeError> as core::iter::traits::collect::FromIterator<core::result::Result<rustc_middle::ty::subst::GenericArg, rustc_middle::ty::error::TypeError>>>::from_iter<core::iter::adapters::map::Map<core::iter::adapters::enumerate::Enumerate<core::iter::adapters::zip::Zip<core::iter::adapters::copied::Copied<core::slice::iter::Iter<rustc_middle::ty::subst::GenericArg>>, core::iter::adapters::copied::Copied<core::slice::iter::Iter<rustc_middle::ty::subst::GenericArg>>>>, rustc_middle::ty::relate::relate_substs<rustc_infer::infer::nll_relate::TypeRelating<rustc_borrowck::type_check::relate_tys::NllTypeRelatingDelegate>>::{closure#0}>>::{closure#0}, smallvec::SmallVec<[rustc_middle::ty::subst::GenericArg; 8]>> ()
   from /mnt/work/home/fredlahde/research/rust-impl-fn-depth-test/rust-fork/build/x86_64-unknown-linux-gnu/stage1/bin/../lib/librustc_driver-135a9886b846246a.so
#1  0x00007ffff5ab8cb0 in <core::result::Result<rustc_middle::ty::subst::GenericArg, rustc_middle::ty::error::TypeError> as rustc_middle::ty::context::InternIteratorElement<rustc_middle::ty::subst::GenericArg, &rustc_middle::ty::list::List<rustc_middle::ty::subst::GenericArg>>>::intern_with::<core::iter::adapters::map::Map<core::iter::adapters::enumerate::Enumerate<core::iter::adapters::zip::Zip<core::iter::adapters::copied::Copied<core::slice::iter::Iter<rustc_middle::ty::subst::GenericArg>>, core::iter::adapters::copied::Copied<core::slice::iter::Iter<rustc_middle::ty::subst::GenericArg>>>>, rustc_middle::ty::relate::relate_substs<rustc_infer::infer::nll_relate::TypeRelating<rustc_borrowck::type_check::relate_tys::NllTypeRelatingDelegate>>::{closure#0}>, <rustc_middle::ty::context::TyCtxt>::mk_substs<core::iter::adapters::map::Map<core::iter::adapters::enumerate::Enumerate<core::iter::adapters::zip::Zip<core::iter::adapters::copied::Copied<core::slice::iter::Iter<rustc_middle::ty::subst::GenericArg>>, core::iter::adapters::copied::Copied<core::slice::iter::Iter<rustc_middle::ty::subst::GenericArg>>>>, rustc_middle::ty::relate::relate_substs<rustc_infer::infer::nll_relate::TypeRelating<rustc_borrowck::type_check::relate_tys::NllTypeRelatingDelegate>>::{closure#0}>>::{closure#0}> ()
   from /mnt/work/home/fredlahde/research/rust-impl-fn-depth-test/rust-fork/build/x86_64-unknown-linux-gnu/stage1/bin/../lib/librustc_driver-135a9886b846246a.so
#2  0x00007ffff598b20d in <rustc_middle::ty::context::TyCtxt>::mk_substs::<core::iter::adapters::map::Map<core::iter::adapters::enumerate::Enumerate<core::iter::adapters::zip::Zip<core::iter::adapters::copied::Copied<core::slice::iter::Iter<rustc_middle::ty::subst::GenericArg>>, core::iter::adapters::copied::Copied<core::slice::iter::Iter<rustc_middle::ty::subst::GenericArg>>>>, rustc_middle::ty::relate::relate_substs<rustc_infer::infer::nll_relate::TypeRelating<rustc_borrowck::type_check::relate_tys::NllTypeRelatingDelegate>>::{closure#0}>> ()
   from /mnt/work/home/fredlahde/research/rust-impl-fn-depth-test/rust-fork/build/x86_64-unknown-linux-gnu/stage1/bin/../lib/librustc_driver-135a9886b846246a.so
#3  0x00007ffff5af7b0a in rustc_middle::ty::relate::relate_substs::<rustc_infer::infer::nll_relate::TypeRelating<rustc_borrowck::type_check::relate_tys::NllTypeRelatingDelegate>> ()
   from /mnt/work/home/fredlahde/research/rust-impl-fn-depth-test/rust-fork/build/x86_64-unknown-linux-gnu/stage1/bin/../lib/librustc_driver-135a9886b846246a.so
#4  0x00007ffff5ae1780 in <&rustc_middle::ty::list::List<rustc_middle::ty::subst::GenericArg> as rustc_middle::ty::relate::Relate>::relate::<rustc_infer::infer::nll_relate::TypeRelating<rustc_borrowck::type_check::relate_tys::NllTypeRelatingDelegate>> ()
   from /mnt/work/home/fredlahde/research/rust-impl-fn-depth-test/rust-fork/build/x86_64-unknown-linux-gnu/stage1/bin/../lib/librustc_driver-135a9886b846246a.so
#5  0x00007ffff5af8f11 in rustc_middle::ty::relate::super_relate_tys::<rustc_infer::infer::nll_relate::TypeRelating<rustc_borrowck::type_check::relate_tys::NllTypeRelatingDelegate>> ()
   from /mnt/work/home/fredlahde/research/rust-impl-fn-depth-test/rust-fork/build/x86_64-unknown-linux-gnu/stage1/bin/../lib/librustc_driver-135a9886b846246a.so
#6  0x00007ffff59cb2e6 in <rustc_infer::infer::InferCtxt>::super_combine_tys::<rustc_infer::infer::nll_relate::TypeRelating<rustc_borrowck::type_check::relate_tys::NllTypeRelatingDelegate>> ()
   from /mnt/work/home/fredlahde/research/rust-impl-fn-depth-test/rust-fork/build/x86_64-unknown-linux-gnu/stage1/bin/../lib/librustc_driver-135a9886b846246a.so
#7  0x00007ffff5a99bd7 in <rustc_infer::infer::nll_relate::TypeRelating<rustc_borrowck::type_check::relate_tys::NllTypeRelatingDelegate> as rustc_middle::ty::relate::TypeRelation>::relate::<&rustc_middle::ty::TyS> ()
   from /mnt/work/home/fredlahde/research/rust-impl-fn-depth-test/rust-fork/build/x86_64-unknown-linux-gnu/stage1/bin/../lib/librustc_driver-135a9886b846246a.so
#8  0x00007ffff5b011c3 in <&mut <rustc_middle::ty::sty::FnSig as rustc_middle::ty::relate::Relate>::relate<rustc_infer::infer::nll_relate::TypeRelating<rustc_borrowck::type_check::relate_tys::NllTypeRelatingDelegate>>::{closure#1} as core::ops::function::FnOnce<(((&rustc_middle::ty::TyS, &rustc_middle::ty::TyS), bool),)>>::call_once ()
   from /mnt/work/home/fredlahde/research/rust-impl-fn-depth-test/rust-fork/build/x86_64-unknown-linux-gnu/stage1/bin/../lib/librustc_driver-135a9886b846246a.so
#9  0x00007ffff5abe042 in <core::iter::adapters::map::Map<core::iter::adapters::enumerate::Enumerate<core::iter::adapters::map::Map<core::iter::adapters::chain::Chain<core::iter::adapters::map::Map<core::iter::adapters::zip::Zip<core::slice::iter::Iter<&rustc_middle::ty::TyS>, core::slice::iter::Iter<&rustc_middle::ty::TyS>>, <rustc_middle::ty::sty::FnSig as rustc_middle::ty::relate::Relate>::relate<rustc_infer::infer::nll_relate::TypeRelating<rustc_borrowck::type_check::relate_tys::NllTypeRelatingDelegate>>::{closure#0}>, core::iter::sources::once::Once<((&rustc_middle::ty::TyS, &rustc_middle::ty::TyS), bool)>>, <rustc_middle::ty::sty::FnSig as rustc_middle::ty::relate::Relate>::relate<rustc_infer::infer::nll_relate::TypeRelating<rustc_borrowck::type_check::relate_tys::NllTypeRelatingDelegate>>::{closure#1}>>, <rustc_middle::ty::sty::FnSig as rustc_middle::ty::relate::Relate>::relate<rustc_infer::infer::nll_relate::TypeRelating<rustc_borrowck::type_check::relate_tys::NllTypeRelatingDelegate>>::{closure#2}> as core::iter::traits::iterator::Iterator>::next ()
   from /mnt/work/home/fredlahde/research/rust-impl-fn-depth-test/rust-fork/build/x86_64-unknown-linux-gnu/stage1/bin/../lib/librustc_driver-135a9886b846246a.so

I am not entirely sure, if this is important enough for having it's own issue, since it's so tightly bound to the PR. Feel free to close / move accordingly.

WaffleLapkin commented 2 years ago

Note that this issue is not actually related to #93082, since you can reach the same segfault on stable. Here is a MRE:

use std::io::Write;

fn main() {
    let n = 1380;
    let open = "impl Trait<Assoc = ".repeat(n);
    let close = ">".repeat(n);

    let code = format!("
trait Trait {{ type Assoc; }}
impl Trait for () {{ type Assoc = (); }}

fn _f() -> {open}(){close} {{}}

fn main() {{}}
");

    std::fs::File::options()
        .truncate(true)
        .write(true)
        .create(true)
        .open("./nested_rpit.rs")
        .unwrap()
        .write(code.as_bytes())
        .unwrap();   
}

(this generates a file nested_rpit.rs that segfaults the compiler)

fredlahde commented 2 years ago

Interestingly, the MRE from @WaffleLapkin only segfaults on stable (1.58.1) but not on nightly (rustc 1.60.0-nightly (bfe156467 2022-01-22)) https://dpaste.com/4AQ2Q3GE6

WaffleLapkin commented 2 years ago

For nightly you just need a higher n, like n = 1500

fredlahde commented 2 years ago

@rustbot label: -I-ICE +I-crash

steffahn commented 2 years ago

@WaffleLapkin We don’t need to write code generators, we have macros…

trait Trait {
    type Assoc;
}
impl Trait for () {
    type Assoc = ();
}

macro_rules! m {
    ([#$($t:tt)*] [$($open:tt)*] [$($close:tt)*]) => {
        m!{[$($t)*][$($open)*$($open)*][$($close)*$($close)*]}
    };
    ([] [$($open:tt)*] [$($close:tt)*]) => {
        fn _f() -> $($open)*()$($close)* {}
    };
}

m! {[###########][impl Trait<Assoc =][>]}

(playground)