Stream: general

Topic: Bound checks abort


gnzlbg (Sep 12 2019 at 10:42, on Zulip):

Why do bound checks panic instead of aborting ?

rkruppe (Sep 12 2019 at 10:56, on Zulip):

Why pick out bounds checks? You could just as well ask the same for most programming errors (~= sources of panics), right?

gnzlbg (Sep 12 2019 at 11:11, on Zulip):

Well an access out-of-bounds is a classic instance of undefined behavior in C

gnzlbg (Sep 12 2019 at 11:12, on Zulip):

So the minimal solution to avoid this undefined behavior would be to just abort the process, as opposed to doing something more complex, like unwinding

gnzlbg (Sep 12 2019 at 11:12, on Zulip):

Other sources of panics, like OOM, aren't necessary due to undefined behavior

gnzlbg (Sep 12 2019 at 11:17, on Zulip):

For context, I was looking at how we implement the bound checks: https://github.com/rust-lang/rust/blob/316a391dcb7d66dc25f1f9a4ec9d368ef7615005/src/libcore/panicking.rs#L55

gnzlbg (Sep 12 2019 at 11:21, on Zulip):

There appears to be a libcore feature that does just that

oli (Sep 12 2019 at 11:33, on Zulip):

you can turn all panics into aborts

oli (Sep 12 2019 at 11:33, on Zulip):

not sure if you can turn just some of them

oli (Sep 12 2019 at 11:34, on Zulip):

the reason some of them are panics is that things like servo want each tab to fail in the worst case via a panic

oli (Sep 12 2019 at 11:34, on Zulip):

instead of terminating the entire browser

gnzlbg (Sep 12 2019 at 11:48, on Zulip):

Yes the libcore feature applies to all panics

gnzlbg (Sep 12 2019 at 12:02, on Zulip):

Turning them into aborts does not make a big difference code-size wise

gnzlbg (Sep 12 2019 at 12:03, on Zulip):

That libcore feature makes quite a difference

gnzlbg (Sep 12 2019 at 12:03, on Zulip):

TIL

rkruppe (Sep 12 2019 at 12:14, on Zulip):

Well an access out-of-bounds is a classic instance of undefined behavior in C

This seems to come from a perspective that's entirely alien to me. Rust isn't "C with the UB papered over minimally", it's its own language with its own design decisions. Signed int overflow is also UB in C, but Rust alternatively makes it defined or panic instead of aborting.

gnzlbg (Sep 12 2019 at 12:21, on Zulip):

I wasn't suggesting that Rust is C. I was wondering why the particular trade-off of panicking was picked up for this.

gnzlbg (Sep 12 2019 at 12:23, on Zulip):

The difference between -C panic=abort/-C panic=unwind and libcore+panic_immediate_abort is quite large

rkruppe (Sep 12 2019 at 12:23, on Zulip):

A reasonable question, I'm just mildly confused by the C reference if the was the point you wanted to make, as it's entirely unrelated.

gnzlbg (Sep 12 2019 at 12:23, on Zulip):

I wouldn't know how to actually implement a panic runtime that behaves like panic_immediate_abort

rkruppe (Sep 12 2019 at 12:24, on Zulip):

Probably most of the code size difference is in not needing the panic message (assuming LTO or if you're only measuring libcore code size)

gnzlbg (Sep 12 2019 at 12:25, on Zulip):

Yes, I think it might suffice to allow users to specify whether their panic hooks should be inline or not.

rkruppe (Sep 12 2019 at 12:26, on Zulip):

I don't follow

gnzlbg (Sep 12 2019 at 12:27, on Zulip):

When calling the core::panic:: APIs that panic, the panic message formatting is implemented within them, most of the message is only stored once per binary

gnzlbg (Sep 12 2019 at 12:28, on Zulip):

On the call site, we store the line number as a string in static memory

gnzlbg (Sep 12 2019 at 12:28, on Zulip):

since the panic methods are #[inline(never)], an implementation that would just abort without printing anything would still contain that (line number, file name, passing those to the call, etc.)

gnzlbg (Sep 12 2019 at 12:29, on Zulip):

What panic_immediate_abort does is it makes these methods in libcore #[inline]

gnzlbg (Sep 12 2019 at 12:29, on Zulip):

These methods don't use the line numbers for anything, and LLVM removes them

rkruppe (Sep 12 2019 at 12:30, on Zulip):

Inlining's not main/only point though, it also has to actually ignore the panic hook (which can be set dynamically and do anything with the PanicInfo).

rkruppe (Sep 12 2019 at 12:31, on Zulip):

You can't just #[inline] it and let it call the hook and get the code size benefits because LLVM can't know what the panic hook does.

gnzlbg (Sep 12 2019 at 12:33, on Zulip):

I did not know that it could be set dynamically.

gnzlbg (Sep 12 2019 at 12:33, on Zulip):

I thought that the panic_impl lang item just dispatched to #[panic_handler]

rkruppe (Sep 12 2019 at 12:34, on Zulip):

How the panic is eventually resolved (aborting, unwinding, etc.) is decided by the panic_handler. The panic_hook gets to look at the panic message and decide to print it (default), log it, silently swallow it, etc.

rkruppe (Sep 12 2019 at 12:36, on Zulip):

Wait no, that's not quite right

rkruppe (Sep 12 2019 at 12:37, on Zulip):

Oh nvm it is, I was just looking at the wrong part of panicking.rs

gnzlbg (Sep 12 2019 at 12:38, on Zulip):

https://doc.rust-lang.org/nomicon/panic-handler.html

gnzlbg (Sep 12 2019 at 12:38, on Zulip):

That says that such a function must only appear once in the dependency graph of a crate

gnzlbg (Sep 12 2019 at 12:38, on Zulip):

I think that the methods in panicking.rs just import the symbol using extern "Rust" { ... }

gnzlbg (Sep 12 2019 at 12:39, on Zulip):

I think that without LTO you are right in that it inlining the functions of panicking wouldn't be enough

gnzlbg (Sep 12 2019 at 12:39, on Zulip):

but I would hope that LTO would inline the #[panic_handler] there

gnzlbg (Sep 12 2019 at 12:40, on Zulip):

and if the panic handler doesn't use the panic message for anything, that the panic messages are discarded

gnzlbg (Sep 12 2019 at 12:41, on Zulip):

Ah wait, this exists: https://doc.rust-lang.org/std/panic/fn.set_hook.html

rkruppe (Sep 12 2019 at 12:42, on Zulip):

Ohhhhhhhh

rkruppe (Sep 12 2019 at 12:42, on Zulip):

I mixed up panic_handler and panic_runtime

gnzlbg (Sep 12 2019 at 12:43, on Zulip):

I thought I knew how this worked, but now I'm confused. Is there a summary somewhere explaining how this works ?

rkruppe (Sep 12 2019 at 12:43, on Zulip):

panic_handler is only available for applications that don't link in libstd anywhere and allows bypassing the hook (which doesn't exist at all w/o std) and other infrastructure.

gnzlbg (Sep 12 2019 at 12:43, on Zulip):

So when is the hook called ?

rkruppe (Sep 12 2019 at 12:43, on Zulip):

panic runtime is what allows customizing abort/unwind/etc. in an application using libstd, but can't bypass the panic hook

gnzlbg (Sep 12 2019 at 12:44, on Zulip):

That should be this: https://github.com/rust-lang/rust/blob/9ebf47851a357faa4cd97f4b1dc7835f6376e639/src/libpanic_abort/lib.rs

gnzlbg (Sep 12 2019 at 12:44, on Zulip):

(for the abort run-time)

rkruppe (Sep 12 2019 at 12:44, on Zulip):

I'm reluctant to answer because I was so wrong before, but AFAIK: the hook is called in libstd's panic_handler, before entering the panic runtime (what you linked, for panic=abort)

gnzlbg (Sep 12 2019 at 12:46, on Zulip):

https://github.com/rust-lang/rust/blob/9ebf47851a357faa4cd97f4b1dc7835f6376e639/src/libstd/panicking.rs#L381

gnzlbg (Sep 12 2019 at 12:46, on Zulip):

I think now I get it, the hook is called there

rkruppe (Sep 12 2019 at 12:47, on Zulip):

So to get back to the original topic, a custom panic_handler that ignores the &PanicInfo argument gets you all the code size benefits (with LTO), but you can't do that if libstd is present anywhere in your application.

gnzlbg (Sep 12 2019 at 12:47, on Zulip):

Yes, that sounds about right.

gnzlbg (Sep 12 2019 at 12:48, on Zulip):

libstd also has the same cargo feature as libcore, to opt out of this

gnzlbg (Sep 12 2019 at 12:50, on Zulip):

I wonder why libstd needs to keep track of the panic count

gnzlbg (Sep 12 2019 at 12:50, on Zulip):

I thought this would be done in the panic run-time itself

rkruppe (Sep 12 2019 at 12:51, on Zulip):

idk

rkruppe (Sep 12 2019 at 12:51, on Zulip):

Maybe historical cruft

gnzlbg (Sep 12 2019 at 12:51, on Zulip):

Like, i can't find a panic count in libcore

gnzlbg (Sep 12 2019 at 12:52, on Zulip):

But I'd expect that to be required to detect double panics

gnzlbg (Sep 12 2019 at 12:54, on Zulip):

maybe that's handled by libunwind

rkruppe (Sep 12 2019 at 12:54, on Zulip):

Unwinding requires libstd anyway I think

rkruppe (Sep 12 2019 at 12:54, on Zulip):

I mean, going without libstd and defining a panic_handler that unwinds is entirely unsupported

rkruppe (Sep 12 2019 at 12:55, on Zulip):

The only supported unwinding is the panic=unwind runtime and that's a runtime, not a handler, so you'll only get it by using libstd

gnzlbg (Sep 12 2019 at 12:59, on Zulip):

Ah that explains it. I thought that one could build a #![no_std] binary not only with -C panic=abort but also wit h-C panic=unwind by only linking the libpanic_unwind crate, and not libstd

Last update: Nov 21 2019 at 23:45UTC