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

"Handle" calls to upstream monomorphizations in compiler_builtins #122580

Merged
merged 3 commits into from
Mar 22, 2024

Conversation

saethlin
Copy link
Member

@saethlin saethlin commented Mar 16, 2024

This is pretty cooked, but I think it works.

compiler-builtins has a long-standing problem that at link time, its rlib cannot contain any calls to core. And yet, in codegen we love inserting calls to symbols in core, generally from various panic entrypoints.

I intend this PR to attack that problem as completely as possible. When we generate a function call, we now check if we are generating a function call from compiler_builtins and whether the callee is a function which was not lowered in the current crate, meaning we will have to link to it.

If those conditions are met, actually generating the call is asking for a linker error. So we don't. If the callee diverges, we lower to an abort with the same behavior as core::intrinsics::abort. If the callee does not diverge, we produce an error. This means that compiler-builtins can contain panics, but they'll SIGILL instead of panicking. I made non-diverging calls a compile error because I'm guessing that they'd mostly get into compiler-builtins by someone making a mistake while working on the crate, and compile errors are better than linker errors. We could turn such calls into aborts as well if that's preferred.

@rustbot
Copy link
Collaborator

rustbot commented Mar 16, 2024

r? @pnkfelix

rustbot has assigned @pnkfelix.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

@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 Mar 16, 2024
@rustbot
Copy link
Collaborator

rustbot commented Mar 16, 2024

These commits modify the Cargo.lock file. Unintentional changes to Cargo.lock can be introduced when switching branches and rebasing PRs.

If this was unintentional then you should revert the changes before this PR is merged.
Otherwise, you can ignore this comment.

@rust-log-analyzer

This comment has been minimized.

@saethlin saethlin force-pushed the compiler-builtins-can-panic branch from 67470be to 34feef3 Compare March 16, 2024 04:55
return MergingSucc::False;
}
}
}
Copy link
Member

Choose a reason for hiding this comment

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

cg_clif will need this change too.

Copy link
Member Author

Choose a reason for hiding this comment

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

If I apply this change to cranelift, how would I verify that it works?

Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Member

Choose a reason for hiding this comment

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

@saethlin saethlin force-pushed the compiler-builtins-can-panic branch from 34feef3 to f3131d7 Compare March 16, 2024 19:13
@rustbot
Copy link
Collaborator

rustbot commented Mar 16, 2024

Some changes occurred in compiler/rustc_codegen_cranelift

cc @bjorn3

@saethlin saethlin force-pushed the compiler-builtins-can-panic branch from f3131d7 to 5f4f252 Compare March 16, 2024 19:22
@Amanieu
Copy link
Member

Amanieu commented Mar 17, 2024

I like this approach since it removes the need for existing hacks like disabling debug assertions and disabling overflow checks.

@saethlin
Copy link
Member Author

saethlin commented Mar 17, 2024

That's also why I like it! For the record, @dpaoliello deserves some credit for saying this:

If we can't rely on libcore, would it be possible to implement a "mini panic" in compiler-builtins instead?

Which taken literally is not possible, but it's a very good line of thinking that led me to this.

@pnkfelix
Copy link
Member

Hmm.

Is there any way to test the behavior being introduced here as part of our CI test suite?

It seems like testing it would require either:

  1. substituting in a custom "buggy" version of compiler_builtins solely for testing purposes. Which does not sound feasible, or at least not a good use of effort if its solely to support testing this PR. Or,

  2. maybe there is a way to make a custom variant of libcore and link to that, and have that custom libcore provide items that would normally return true for should_codegen_locally but now they return false for this hypothetical custom libcore..., or

  3. add a new item to compiler_builtins that is itself designed to exercise the behavior being added here, but otherwise serves no purpose.

... so after some reflection, I am guessing that Options 1 and 2 are impossible or non-desirable; option 3 might be doable but isn't really attractive from an overall development trajectory standpoint.

And instead, we just say "we do not intend to regression test this PR as part of our test suite. One can test it in a local fashion by making local changes to compiler-builtins that expose the behavior in question."

Does that all sound right?

@pnkfelix
Copy link
Member

This looks fine to me as it stands, assuming that I'm correct about it not being reasonable to try to test it in CI.

But I also am inferring that it should not land without the corresponding changes to cg_clif

@rustbot author

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Mar 18, 2024
@bjorn3
Copy link
Member

bjorn3 commented Mar 18, 2024

But I also am inferring that it should not land without the corresponding changes to cg_clif

This has been added to the PR since I made that comment.

@pnkfelix
Copy link
Member

This has been added to the PR since I made that comment.

Oh, whoops! Thanks!

@pnkfelix
Copy link
Member

@bors r+

@bors
Copy link
Contributor

bors commented Mar 18, 2024

📌 Commit 5f4f252 has been approved by pnkfelix

It is now in the queue for this repository.

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Mar 18, 2024
@saethlin
Copy link
Member Author

I agree that we should have some tests for this. I'll open an issue with some ideas.

@saethlin
Copy link
Member Author

@bors rollup=never

@rust-timer
Copy link
Collaborator

Finished benchmarking commit (b3df0d7): comparison URL.

Overall result: no relevant changes - no action needed

@rustbot label: -perf-regression

Instruction count

This benchmark run did not return any relevant results for this metric.

Max RSS (memory usage)

This benchmark run did not return any relevant results for this metric.

Cycles

Results

This is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.

mean range count
Regressions ❌
(primary)
- - 0
Regressions ❌
(secondary)
6.5% [5.7%, 7.6%] 3
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) - - 0

Binary size

This benchmark run did not return any relevant results for this metric.

Bootstrap: 669.525s -> 669.004s (-0.08%)
Artifact size: 314.91 MiB -> 314.95 MiB (0.02%)

@saethlin saethlin deleted the compiler-builtins-can-panic branch March 22, 2024 20:39
These symbols may be undefined in a debug build of compiler_builtins:\n\
{:?}",
undefined_relocations
);
Copy link
Member

Choose a reason for hiding this comment

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

Why is this extra check needed, given the check during codegen? How can it even fail?

Copy link
Member Author

Choose a reason for hiding this comment

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

There are compiler changes in the commit that I only discovered are necessary by adding this test. Normally we always build compielr_builtins with optimizations enabled. So those changes would probably have been build failures in the -nopt jobs, but that's such a late failure. Here's that commit: 2f6fb23 And those changes are:

Not only is -Copt-level=0 not optimized, it enables -Zshare-generics by default. So compiler_builtins needs to opt out of this, because sharing the generics of core also makes it inherit panics.

The check in codegen is awfully fiddly to get right. I forgot to apply the "abort on panic" logic inside terminate_block; compiler_builtins uses some rustc_nounwind functions, and that attribute makes us insert UnwindTerminate blocks just in case there is an unwind. Those blocks tend to be optimized out, but if optimizations are off, they become calls into core.

Copy link
Member

Choose a reason for hiding this comment

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

Okay so this kind of sanity-checks the codegen-time checks? Makes sense, thanks. (That may be worth a comment in the code though so it's also clear to a future reader.)

@Amanieu
Copy link
Member

Amanieu commented Mar 23, 2024

While trying to solve the CI issues in compiler_builtins, I noticed that -C embed-bitcode=yes causes references to panicking functions in core to be emitted.

That's not what's causing the currently issues in CI (x86_64-apple-darwin seems to still be generating references to panic), but it might be worth fixing.

@saethlin
Copy link
Member Author

While trying to solve the CI issues in compiler_builtins, I noticed that -C embed-bitcode=yes causes references to panicking functions in core to be emitted.

I just noticed this as well. I'm starting to look into it.

@saethlin
Copy link
Member Author

saethlin commented Mar 23, 2024

Ah no what I was looking at is another case of #118770, at least this time it's just me causing trouble for me. You probably don't care to support -Zcross-crate-inline-threshold=yes.

I'll extract a reproducer of the embed-bitcode issue from the compiler-builtins CI.

bjorn3 pushed a commit to bjorn3/rust that referenced this pull request Mar 28, 2024
…, r=pnkfelix

"Handle" calls to upstream monomorphizations in compiler_builtins

This is pretty cooked, but I think it works.

compiler-builtins has a long-standing problem that at link time, its rlib cannot contain any calls to `core`. And yet, in codegen we _love_ inserting calls to symbols in `core`, generally from various panic entrypoints.

I intend this PR to attack that problem as completely as possible. When we generate a function call, we now check if we are generating a function call from `compiler_builtins` and whether the callee is a function which was not lowered in the current crate, meaning we will have to link to it.

If those conditions are met, actually generating the call is asking for a linker error. So we don't. If the callee diverges, we lower to an abort with the same behavior as `core::intrinsics::abort`. If the callee does not diverge, we produce an error. This means that compiler-builtins can contain panics, but they'll SIGILL instead of panicking. I made non-diverging calls a compile error because I'm guessing that they'd mostly get into compiler-builtins by someone making a mistake while working on the crate, and compile errors are better than linker errors. We could turn such calls into aborts as well if that's preferred.
@petrochenkov
Copy link
Contributor

@saethlin
The added run-make test fails with this message for me:

   Compiling core v0.0.0 (E:\msys64\home\we\rust\build\x86_64-pc-windows-gnu\stage1\lib\rustlib\src\rust\library\core)
   Compiling compiler_builtins v0.1.109
error: couldn't create a temp dir: Access is denied. (os error 5) at path "C:\\Windows\\rustcKMWsUo"

error: could not compile `compiler_builtins` (build script) due to 1 previous error
warning: build failed, waiting for other jobs to finish...
error: couldn't create a temp dir: Access is denied. (os error 5) at path "C:\\Windows\\rustclRyY6G"

error: could not compile `core` (lib) due to 1 previous error
thread 'main' panicked at E:\msys64\home\we\rust\tests\run-make\compiler-builtins\rmake.rs:71:5:
assertion failed: status.success()
stack backtrace:
   0: rust_begin_unwind
             at E:\msys64\home\we\rust\library\std\src\panicking.rs:652:5
   1: core::panicking::panic_fmt
             at E:\msys64\home\we\rust\library\core\src\panicking.rs:72:14
   2: core::panicking::panic
             at E:\msys64\home\we\rust\library\core\src\panicking.rs:146:5
   3: rmake::main
   4: core::ops::function::FnOnce::call_once
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

Looks like the test suite uses a wrong temporary directory on Windows in some cases.
Or MSYS2 is to blame, or the fact that my Rust repo is on disk E:, I haven't investigated yet.
cc @ChrisDenton

@jieyouxu
Copy link
Member

Looks like the test suite uses a wrong temporary directory on Windows in some cases. Or MSYS2 is to blame, or the fact that my Rust repo is on disk E:, I haven't investigated yet.

@petrochenkov Judging from the error message, it's emitted from codegen:

let tmpdir = TempFileBuilder::new()
.prefix("rustc")
.tempdir()
.unwrap_or_else(|error| sess.dcx().emit_fatal(errors::CreateTempDir { error }));

Where somehow env::temp_dir looks messed up -- I think this might be a msys2 weird interaction with $TMPDIR problem -- because apparently compiletest uses and modifies $TMPDIR (even though that env var influences what env::temp_dir returns!)

@ChrisDenton
Copy link
Member

Oh it's using env_clear, which is always risky on Windows because there's at least a few environment variables that are assumed to always be set.

In this case either TMP or TEMP needs to be set otherwise getting the temp dir will fallback to USERPROFILE and if that's not found either then the windows directory is used as a last resort. Which will be unwritable.

@ChrisDenton
Copy link
Member

I think the helper lib could have a env_reset that preserves some necessary environment variables rather than fully clearing everything.

@jieyouxu
Copy link
Member

I think the helper lib could have a env_reset that preserves some necessary environment variables rather than fully clearing everything.

I'll work on a patch for this

@jieyouxu
Copy link
Member

jieyouxu commented May 22, 2024

I think the helper lib could have a env_reset that preserves some necessary environment variables rather than fully clearing everything.

@ChrisDenton I opened #125426, for now I only preserve TMP and TEMP on Windows, TMPDIR on non-Windows. Let me know if you know of any more "necessary" env vars.

@RalfJung
Copy link
Member

RalfJung commented May 23, 2024

In this case either TMP or TEMP needs to be set otherwise getting the temp dir will fallback to USERPROFILE and if that's not found either then the windows directory is used as a last resort. Which will be unwritable.

Isn't that a terrible fallback? If that's happening in our implementation, it seems better to error out than provide an unwriteable directory.

@ChrisDenton
Copy link
Member

@RalfJung
Copy link
Member

Ah, unfortunate. I wonder if that's worth working around on our side. But temp_dir doesn't even return a Result so there's no good way we can indicate failure either...

@jieyouxu
Copy link
Member

jieyouxu commented May 23, 2024

Ah, unfortunate. I wonder if that's worth working around on our side. But temp_dir doesn't even return a Result so there's no good way we can indicate failure either...

We could still describe this in the docs, because it is very surprising...

EDIT: filed #125439 to not forget.

bors added a commit to rust-lang-ci/rust that referenced this pull request Jun 3, 2024
…<try>

Update `compiler-builtins` test to not clear essential env vars

Noticed in rust-lang#122580 (comment), the `compiler-builtins` test failed on Windows for a `cargo` invocation because necessary env vars `TMP` and `TEMP` were cleared by `Command::env_clear`, causing temp dir eventually used by codegen to fallback to the Windows directory, which will trigger permission errors.

This PR adds a `clear_non_essential_env_vars` helper, which is a more conservative `Command::env_clear` that does not clear `TMP` or `TEMP` on Windows, and does not clear `TMPDIR` on non-Windows platforms.

cc `@ChrisDenton` do you happen to know if there are any more "essential" env vars that we should not clear (on Windows or other platforms)?

r? `@saethlin` (feel free to reroll, since you authored the test)

try-job: x86_64-msvc
try-job: test-various
bors added a commit to rust-lang-ci/rust that referenced this pull request Jun 4, 2024
…<try>

Update `compiler-builtins` test to not clear essential env vars

Noticed in rust-lang#122580 (comment), the `compiler-builtins` test failed on Windows for a `cargo` invocation because necessary env vars `TMP` and `TEMP` were cleared by `Command::env_clear`, causing temp dir eventually used by codegen to fallback to the Windows directory, which will trigger permission errors.

This PR adds a `clear_non_essential_env_vars` helper, which is a more conservative `Command::env_clear` that does not clear `TMP` or `TEMP` on Windows, and does not clear `TMPDIR` on non-Windows platforms.

cc `@ChrisDenton` do you happen to know if there are any more "essential" env vars that we should not clear (on Windows or other platforms)?

r? `@saethlin` (feel free to reroll, since you authored the test)

try-job: x86_64-msvc
try-job: test-various
bors added a commit to rust-lang-ci/rust that referenced this pull request Jun 4, 2024
…saethlin

Update `compiler-builtins` test to not clear essential env vars

Noticed in rust-lang#122580 (comment), the `compiler-builtins` test failed on Windows for a `cargo` invocation because necessary env vars `TMP` and `TEMP` were cleared by `Command::env_clear`, causing temp dir eventually used by codegen to fallback to the Windows directory, which will trigger permission errors.

This PR removes the `env_clear` on the cargo invocation.

r? `@saethlin` (feel free to reroll, since you authored the test)

try-job: x86_64-msvc
try-job: test-various
flip1995 pushed a commit to flip1995/rust-clippy that referenced this pull request Jun 28, 2024
Update `compiler-builtins` test to not clear essential env vars

Noticed in rust-lang/rust#122580 (comment), the `compiler-builtins` test failed on Windows for a `cargo` invocation because necessary env vars `TMP` and `TEMP` were cleared by `Command::env_clear`, causing temp dir eventually used by codegen to fallback to the Windows directory, which will trigger permission errors.

This PR removes the `env_clear` on the cargo invocation.

r? `@saethlin` (feel free to reroll, since you authored the test)

try-job: x86_64-msvc
try-job: test-various
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
merged-by-bors This PR was explicitly merged by bors. S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-bootstrap Relevant to the bootstrap subteam: Rust's build system (x.py and src/bootstrap) T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet