-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
Enable TrapUnreachable in LLVM. #45920
Conversation
Enable LLVM's TrapUnreachable flag, which tells it to translate `unreachable` instructions into hardware trap instructions, rather than allowing control flow to "fall through" into whatever code happens to follow it in memory.
src/rustllvm/PassWrapper.cpp
Outdated
// Tell LLVM to translate `unreachable` into an explicit trap instruction. | ||
// This limits the extent of possible undefined behavior in some cases, as it | ||
// prevents control flow from "falling through" into whatever code happens to | ||
// be layed out next in memory. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo: "layed" should be "laid"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
As the person who originally asked for this, thanks for making sure it got done. |
With rustc now emitting "ud2" on unreachable code, a "return nothing" sequence may take the same number of lines as an "unreachable" sequence in assembly code. This test is testing that intrinsics::unreachable() works by testing that it reduces the number of lines in the assembly code. Fix it by adding a return value, which requires an extra instruction in the reachable case, which provides the test what it's looking for.
I'd like to see this option as a part of |
unsafe { | ||
// Pretend this asm is an exit() syscall. | ||
asm!("" :: "r"(n) :: "volatile"); | ||
intrinsics::unreachable() | ||
} | ||
42 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you add a comment that the 42
is there just so there's some code for LLVM to remove, making the test that the assembly output of exit-unreachable.rs is shorter than exit-ret.rs succeed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comment added.
The return value in these tests is just being used to generate extra code so that it can be detected in the test script, which is just counting lines in the assembly output.
@bors r+ |
@Zoxc: 🔑 Insufficient privileges: Not in reviewers |
I guess I don't have bors permissions yet. @alexcrichton When will that happen? =P |
@bors r=Zoxc |
📌 Commit 7b6b764 has been approved by |
⌛ Testing commit 7b6b764 with merge 1f893306a350c62927740ec18e4e75c57c9dc517... |
💔 Test failed - status-travis |
Failed to build rustdoc at stage2 in debug build (
|
Yikes, this looks like one of those unreachable traps actually happened.
|
Looks like it's just 32-bit x86. I've been able to reproduce the crash now; here's a backtrace:
|
cc @alexcrichton (#42816) this PR seems to have conflict with the x86 stack probe. |
I've now filed rust-lang/compiler-builtins#207 which makes |
rust-lang/compiler-builtins#207 is now merged. Can we do a new bors run with an updated compiler-builtins? |
@sunfishcode oh that's actually just a submodule in this repository at |
Ok, I've now updated the submodule. |
@bors r=Zoxc |
📌 Commit ac48348 has been approved by |
Enable TrapUnreachable in LLVM. This patch enables LLVM's TrapUnreachable flag, which tells it to translate `unreachable` instructions into hardware trap instructions, rather than allowing control flow to "fall through" into whatever code happens to follow it in memory. This follows up on #28728 (comment). For example, for @zackw's testcase [here](#42009 (comment)), the output function contains a `ud2` instead of no code, so it won't "fall through" into whatever happens to be next in memory. (I'm also working on the problem of LLVM optimizing away infinite loops, but the patch here is useful independently.) I tested this patch on a few different codebases, and the code size increase ranged from 0.0% to 0.1%.
☀️ Test successful - status-appveyor, status-travis |
The object file in the rlib has been renamed again, and the name now includes now gibberish. The assembly now has an extra instruction due to rust-lang/rust#45920 but despite this the final executable is actually smaller than before. (There doesn't appear to be a way to disable the unreachable() trap.)
The object file in the rlib has been renamed again, and the name now includes now gibberish. The assembly now has an extra instruction due to rust-lang/rust#45920 which increases the executable size with two bytes. (There doesn't appear to be a way to disable the unreachable() trap.)
This patch enables LLVM's TrapUnreachable flag, which tells it to translate
unreachable
instructions into hardware trap instructions, rather than allowing control flow to "fall through" into whatever code happens to follow it in memory.This follows up on #28728 (comment). For example, for @zackw's testcase here, the output function contains a
ud2
instead of no code, so it won't "fall through" into whatever happens to be next in memory.(I'm also working on the problem of LLVM optimizing away infinite loops, but the patch here is useful independently.)
I tested this patch on a few different codebases, and the code size increase ranged from 0.0% to 0.1%.