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

Remove implicit total orderings #107982

Closed

Conversation

dingxiangfei2009
Copy link
Contributor

This PR will attempt to remove implicit orderings on sty data that are not naturally bestowed with either total or partial ordering.

It has come to attention specifically that a subtle mis-compilation was introduced in #104786 causing segfaults. By transposing the order of the variants in Mutability, in rare cases ADT constructors are miscompiled with incorrect memory layout. More details will come as the investigation into making a MVCE is underway.

@rustbot
Copy link
Collaborator

rustbot commented Feb 13, 2023

r? @wesleywiser

(rustbot has picked a reviewer for you, use r? to override)

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Feb 13, 2023
@compiler-errors
Copy link
Member

compiler-errors commented Feb 13, 2023

I'm happy with this implementation, but I'm curious why...

By transposing the order of the variants in Mutability, in rare cases ADT constructors are miscompiled with incorrect memory layout.

^ this was happening. My understanding of #104786 (seeing that I reviewed it) is that we're allowed to rely on the total ordering of enums in Rust. In what cases were segfaults occurring? Are there any issue # filed against rust-lang/rust associated with it?

@bors
Copy link
Contributor

bors commented Feb 13, 2023

☔ The latest upstream changes (presumably #107924) made this pull request unmergeable. Please resolve the merge conflicts.

@dingxiangfei2009
Copy link
Contributor Author

@compiler-errors I am curious, too. It is unfortunate that the code is proprietary, but I will post as much detail as possible here.

The segfault happens when a Option<&String> is read from without checking if it is None. I have inspected the disassembly of the mis-compiled binary.
The original Rust program. Sketch

let options = if cond {
    Some(format!(...))
} else {
    None
};
// ...
let obj = Struct {
    val: options.as_ref(),
};

This is compiled into this AArch64 disassembly. Sketch

LAB_COND_TRUE:
    # some calls to alloc::fmt::format::format_inner
    ldr q0, [x25] # move the String...
    str q0, [sp, 0xb0] # ... into the destination place
    b LAB_BOMB
LAB_COND_FALSE:
    str xzr, [sp, 0xb8]
    b LAB_BOMB
    # ...
LAB_BOMB:
    add x12, sp, 0xb0 # unconditionally take pointer to Option<String>
    str x12, [sp, 0x1b0] # and put it into the "Struct"

Further in another call, it would test if this pointer to Option<String> is not null and access the content accordingly. However, since $sp+0xb0 is never properly initialized, it is reading garbage in that call because the pointer here is never null.

This appears to happen on AMD64 as well.

By inserting println! randomly, it sometimes compiles correctly. Here is the difference in the disassembly.

LAB_COND_TRUE:
    # some calls to alloc::fmt::format::format_inner
    ldr q0, [x25] # move the String...
    str q0, [sp, 0xb0] # ... into the destination place
    # ...
    ldr x8, [sp, 0xb8]
    add x9, sp, 0xb0
    cmp x8, 0x0
    csel x11, xzr, x9, eq # I believe it is checking if String is empty
    b LAB_GOOD
LAB_COND_FALSE:
    mov x11, 0x0
    str xzr, [sp, 0xb8]
    b LAB_GOOD
    # ...
LAB_GOOD:
    str x11, [sp, 0x1b0] # Put it into the "Struct"

Strangely, it is really hard to make a MVCE out of it. It seems that even by adding RUSTFLAGS=--emit=llvm-ir or --emit=mir would make the segfault go away. I would happily accept advice on how to dump the IRs without "disturbing" the internals to much.

@dingxiangfei2009 dingxiangfei2009 marked this pull request as ready for review February 15, 2023 17:55
}
_ => None,
}
})?;
})
.min_by_key(|(discr, vid, ..)| (*discr, *vid))?;
Copy link
Contributor

Choose a reason for hiding this comment

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

Why doesn't find_map work any more?

#[derive(HashStable_Generic, Encodable, Decodable)]
pub enum Mutability {
// N.B. Order is deliberate, so that Not < Mut
Copy link
Contributor

Choose a reason for hiding this comment

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

Mutability is perhaps the one case where keeping the order is useful and sensible.

input_constraints.sort_by_key(|c| match c {
Constraint::VarSubVar(..) => 0u8,
Constraint::RegSubVar(..) => 1,
Constraint::VarSubReg(..) | Constraint::RegSubReg(..) => 2,
Copy link
Contributor

Choose a reason for hiding this comment

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

This definitely needs a comment.

@@ -0,0 +1,27 @@
use super::ConstraintCategory;

impl<'tcx> ConstraintCategory<'tcx> {
Copy link
Contributor

Choose a reason for hiding this comment

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

This does not need to be in a separate file.

candidates.sort();
candidates.dedup();
let len = candidates.len();
let report = |candidates: Vec<TraitRef<'tcx>>, err: &mut Diagnostic| {
Copy link
Contributor

Choose a reason for hiding this comment

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

Directly make candidates a FxIndexSet.

@bors
Copy link
Contributor

bors commented Feb 16, 2023

☔ The latest upstream changes (presumably #108116) made this pull request unmergeable. Please resolve the merge conflicts.

@cjgillot cjgillot removed the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Mar 6, 2023
@cjgillot cjgillot self-assigned this Mar 6, 2023
@cjgillot cjgillot added the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Mar 6, 2023
@Dylan-DPC
Copy link
Member

@dingxiangfei2009 any updates on this?

@dingxiangfei2009
Copy link
Contributor Author

@Dylan-DPC I forgot about this! The original issue was fixed in LLVM. However, I think it might still be a good idea to work with the types without ordering. If there is no objection to this idea, I will come back to it, rebase it and post fresh commits.

@compiler-errors
Copy link
Member

If this was due to an LLVM bug, and not a Rust bug, then I don't see why it's beneficial to remove these total orderings personally.

@JohnCSimon
Copy link
Member

@dingxiangfei2009
Ping from triage: I'm closing this due to inactivity, Please reopen when you are ready to continue with this.
Note: if you are going to continue please open the PR BEFORE you push to it, else you won't be able to reopen - this is a quirk of github.
Thanks for your contribution.

@rustbot label: +S-inactive

@JohnCSimon JohnCSimon closed this Aug 27, 2023
@rustbot rustbot added the S-inactive Status: Inactive and waiting on the author. This is often applied to closed PRs. label Aug 27, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-inactive Status: Inactive and waiting on the author. This is often applied to closed PRs. S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. 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.

9 participants