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

Segfault in an unconditional drop call after a match #30530

Closed
sfackler opened this issue Dec 22, 2015 · 9 comments · Fixed by #30823
Closed

Segfault in an unconditional drop call after a match #30530

sfackler opened this issue Dec 22, 2015 · 9 comments · Fixed by #30823
Assignees
Labels
I-crash Issue: The compiler crashes (SIGSEGV, SIGABRT, etc). Use I-ICE instead when the compiler panics. P-high High priority T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@sfackler
Copy link
Member

This code will segfault running drop glue for Box<Box<Fn()>>, even though a value of that type is not actually created.

enum Handler {
    Default,
    Custom(*mut Box<Fn()>),
}

fn main() {
    take();
}

fn take() -> Box<Fn()> {
    unsafe {
        match Handler::Default {
            Handler::Default => Box::new(main),
            Handler::Custom(ptr) => *Box::from_raw(ptr),
        }
    }
}

Interestingly, it exits successfully if the second match body is wrapped in a block.

@sfackler sfackler added I-crash Issue: The compiler crashes (SIGSEGV, SIGABRT, etc). Use I-ICE instead when the compiler panics. I-nominated T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Dec 22, 2015
@eddyb
Copy link
Member

eddyb commented Dec 22, 2015

It looks like Box<Trait> noop coercions result in non-trivial codegen. Not sure if it's related to the actual cause, but maybe we shouldn't generate 20 instructions for nothing.

@nikomatsakis
Copy link
Contributor

Seems like a case where we failed to initialize the temporary storage slot to 0, even though it is only conditionally initialized.

cc @pnkfelix

@dotdash
Copy link
Contributor

dotdash commented Dec 22, 2015

Looks like it might be the same problem as #29092

@pnkfelix pnkfelix self-assigned this Jan 7, 2016
@pnkfelix
Copy link
Member

pnkfelix commented Jan 7, 2016

triage: P-high

@rust-highfive rust-highfive added P-high High priority and removed I-nominated labels Jan 7, 2016
@pnkfelix
Copy link
Member

pnkfelix commented Jan 8, 2016

Seems like a case where we failed to initialize the temporary storage slot to 0, even though it is only conditionally initialized.

Yes, this looks right.

In particular, the code in trans is structured in a somewhat misleading way: there's this populate callback on lvalue_scratch_datum, where populate is supposed to initialize the scratch data that has been created via an alloca().

The problem, I think, is that there is no guarantee that the populate call will dominates the cleanup code generated at the end of the scope. The bcx (Block context) and the scope are separate inputs to lvalue_scratch_datum, and I think in examples like the one from this bug, the bcx corresponds to the match arm, while the scope is the parent of the match itself. :(

I'm not completely sure the best way to fix this quickly. My current plan is to try to inject initialization code (for types that need the drop flag) that will run right after the alloca() does, and hopefully LLVM will be smart enough to eliminate that initialization when it is effectively dead-code due to the code generated by populate.


Update: (not sure if the above hypothesis is 100% right; I'm reviewing the logic from lvalue_scratch_datum and below, and the populate-generated code seems like it must be generated immediately after the alloca; in the same bcx, etc)

@pnkfelix
Copy link
Member

pnkfelix commented Jan 8, 2016

oh:

mod build { ... fn Alloca(cx, ty, name) -> ValueRef { AllocaFcx(cx.fcx, ty, name) } ... }

@nikomatsakis
Copy link
Contributor

@pnkfelix and I had some discussion on IRC about this -- there used to be a flag (zero) that was used to indicate when the initialization might not dominate the drop, but it was removed in commit f580412

@eddyb
Copy link
Member

eddyb commented Jan 8, 2016

@pnkfelix Yeah, we put all the allocas at the top of the entry BB. Doing otherwise results in dynamic stack manipulation which isn't the best in LLVM (IIRC you can stack overflow by having an alloca in a loop - presumably missing a llvm.lifetime.end call).

@pnkfelix
Copy link
Member

pnkfelix commented Jan 8, 2016

@eddyb right, its actually perfectly sensible; I just worry (or worried) that some people may have the wrong impression based on the function signature(s).

pnkfelix added a commit to pnkfelix/rust that referenced this issue Jan 13, 2016
…st-lang#30530, rust-lang#30822.

Note that the test for rust-lang#30822 is folded into the test for rust-lang#30530 (but
the file name mentions only 30530).
Manishearth added a commit to Manishearth/rust that referenced this issue Jan 14, 2016
…r-issue-30530, r=dotdash

Put back alloca zeroing for issues rust-lang#29092, rust-lang#30018, rust-lang#30530; inject zeroing for rust-lang#30822.

----

Background context: `fn alloca_zeroed` was removed in PR rust-lang#22969, so we haven't been "zero'ing" (\*) the alloca's since at least that point, but the logic behind that PR seems sound, so its not entirely obvious how *long* the underlying bug has actually been present.  In other words, I have not yet done a survey to see when the new `alloc_ty` and `lvalue_scratch_datum` calls were introduced that should have had "zero'ing" the alloca's.

----

I first fixed rust-lang#30018, then decided to do a survey of `alloc_ty` calls to see if they needed similar treatment, which quickly led to a rediscovery of rust-lang#30530.

While making the regression test for the latter, I discovered rust-lang#30822, which is a slightly different bug (in terms of where the "zero'ing" needs to go), but still relevant.

I haven't finished the aforementioned survey of `fn alloc_ty` calls, but I decided I wanted to get this up for review in its current state (namely to see if my attempt to force developers to include a justification for passing `Uninit` can possibly fly, or if I should abandon that path of action).

----

(*): I am putting quotation marks around "zero'ing" because we no longer use zero as our "dropped" marker value.

Fix rust-lang#29092
Fix rust-lang#30018
Fix rust-lang#30530
Fix rust-lang#30822
frewsxcv added a commit to frewsxcv/rust that referenced this issue Nov 24, 2016
sanxiyn added a commit to sanxiyn/rust that referenced this issue Nov 26, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
I-crash Issue: The compiler crashes (SIGSEGV, SIGABRT, etc). Use I-ICE instead when the compiler panics. P-high High priority T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants