Live data from Hacker News

How expensive is integer-overflow trapping in C++?

lemire.me

81–90 of 198 posts

Re: How expensive is integer-overflow trapping in C++?

#81
post #2

Note that Rust also traps on integer overflow, and it is trivial to „hack“ the compiler to disable this, and many have done so. While on this microbenchmark you see a 3x slowdown with the LLVM backend, on large Rust projects like servo, Firefox, the rust compiler, etc. the slowdown is not even measurable. Also, Rust provides you with unsafe intrinsics to opt-out of trapping in the particular line of code in which it…

> Note that Rust also traps on integer overflow, and it is trivial to „hack“ the compiler to disable this, and many have done so.

“Hack” is a completely unsuitable term, there’s a simple and official compilation flag which can be flipped on or off.

It’s also misleading to say that Rust will trap on overflow: rustc enables overflow checking by default in debug mode, but disables it in release.

Re: How expensive is integer-overflow trapping in C++?

#82
post #31

Earlier quoted context omitted.

As I understand this is about trapping, which makes overflow checking free for non-overflowing operations. Flag checking, as opposed to trapping, incurs costs on all operations.

INTO would still need to check the flags and you would need to invoke it after every operation that could overflow. You can't configure the integer ALU to raise an interrupt automatically after any overflow.

Is there a reason to not add a new instruction to x86-64 which does interrupt the program on an integer operation overflow so no branching happens in the program? And can this instruction be made just as fast as the unchecked ones?

Re: How expensive is integer-overflow trapping in C++?

#83
post #28

Earlier quoted context omitted.

I think the GP was probably thinking of INTO(0xCE). https://en.wikipedia.org/wiki/INT_(x86_instruction)#INTO The bounds-checking was MPX, I think. > Another extremely useful instruction deleted from x86-64 tested if an array access was in bounds. https://en.wikipedia.org/wiki/Intel_MPX#Extensions

I was thinking of BOUND[0] rather than MPX. It's a much lighter solution than MPX and didn't require OS support. [0] https://hjlebbink.github.io/x86doc/html/BOUND.html

BOUND is pretty slow, and requires an odd start/end pair to be placed in memory. I don't see any reason that it would be better than the usual unsigned comparison + branch that languages with bounds checking tend to use.

Besides, much of the difficulty with memory safety in C and C++ is the existence of pointers (or wrappers around them, like iterators), which do not come with an associated length. Length checking machinery can't help with that problem whether special instructions exist or not.

In short, it's doubtful that the availability of these old instructions would make any difference to the practicality of bounds checking on modern x86 machines whatsoever.

Re: How expensive is integer-overflow trapping in C++?

#84

> adding two large integers can result in an integer that cannot be represented in the integer type. We often refer to such error conditions as overflows. There's a subtlety here that's missed in the article: In C and C++ this is only called "overflow" for signed integers. That's because that word specifically refers to the case where the behaviour is undefined, and for unsigned integers the result is always well def…

> Is it just about signed numbers or not? No. You can plug an `UInt8(255)` in an online playground and try to increment it, it’ll crash unless you use an overflowing operator. > Also, what other languages are there that are "like Swift"? In debug mode, Rust will panic on overflow (regardless of signing). You can also enable overflow-checks in release mode.

So is Swift effectively adding a jo / jump on overflow instruction after each normal integer operation?

Re: How expensive is integer-overflow trapping in C++?

#85
post #79

Earlier quoted context omitted.

It's a bad library design to rely on a process-global setting, because one day you'll have two libraries in your project that rely on opposite values of such a global setting, and then you'll start to see very funny things. And the library design that relies on an application it's used in being killed by the OS so that the library don't have to tidy things up after itself or to properly handle error conditions is rea…

I agree libraries shouldn't rely on process-global state. It's also bad library design to trigger signed overflow. In my libraries I try to handle both situations cleanly, but that's all beside the point. There's also the problem that SIG_IGN handlers are inherited across exec. So Rust programs that exec other programs without restoring the default handler could cause problems in programs where relying on SIGPIPE is…

If I were to write a program that relied on "writing to a file might terminate me and that's exactly what I want" behaviour, then yeah, I absolutely would include a call to "signal(SIGPIPE, SIG_DFL)" in the main().

Of course, if I were to actually write a filter-like program (a la cat, head, grep, etc.), I would rather have just checked the return values of my write()s. It's -1? Time to call exit(errno).

Re: How expensive is integer-overflow trapping in C++?

#86

Earlier quoted context omitted.

INTO would still need to check the flags and you would need to invoke it after every operation that could overflow. You can't configure the integer ALU to raise an interrupt automatically after any overflow.

Is there a reason to not add a new instruction to x86-64 which does interrupt the program on an integer operation overflow so no branching happens in the program? And can this instruction be made just as fast as the unchecked ones?

[deleted]

Re: How expensive is integer-overflow trapping in C++?

#87
post #75
post #60

Earlier quoted context omitted.

I fully agree with your post. I am just not sure if you are trying to make a point for larger datasets in benchmark (like I did) or you are trying to imply that this is not necessary?

I generally agree the benchmark is too small, but I have serious issues with Lemire's approach to benchmarking in general. Things get pretty nuts at that small of a timescale and things like frequency scaling can make a huge difference. I would draw absolutely zero conclusions on these reported results.

I had that sort of impression as well, but after playing with the benchmark and seeing the assembly code, and checking the actual theoretical throughputs for my microprocessor, I realized that in this case, and previous ones, there was nothing relevant to the results that had to do with the way benchmarking was implemented. These pieces of code would be thought to be in the innermost loop, and practically they might not actually process a very large part of the array. There are solutions, and better approaches, sure, but they pinpoint real issues that cause spread in your performance across microprocessors & compilers that are worth having in mind.

Re: How expensive is integer-overflow trapping in C++?

#88

Earlier quoted context omitted.

Implementation defined means that the behavior is defined. This is patently not what the existing behavior of compilers in the face of integer overflow is.

I'm trying to say that integer overflow is architecture-specific, so it _should_ have been standardized as implementation defined.

You probably know this, but by making it UB, compilers don't need to have the same behavior on every case of integer overflow. This allows compilers to apply much more optimizations.

Re: How expensive is integer-overflow trapping in C++?

#89
post #47
post #22

Earlier quoted context omitted.

This is essentially Swift’s problem on the server. If you have a service running and serving hundreds of clients, then any one of those threads can cause a trivial panic if there’s an overflow and take the entire service down. As a result, a number of use cases for swift on the server actually use heavyweight out of process threads (i.e. one process per client) so that the failure of one of them doesn’t take down the…

This reminds me of Rust unconditionally ignoring SIGPIPE. Except in this case there's a non-trivial amount of pre-existing (and even future) code that assumes a process will be terminated if it attempts to write to a closed pipe. One of Rust's selling points is ease of FFI, so it's largely irrelevant that Rust APIs wouldn't let you ignore write errors. Rust breaks the environment for libraries that rely on the behavi…

Yes, quite annoying, and I've been bitten by that before, but you are supposed to check the return of each write().

And I think the motivation is to write platform-agnostic code by default. SIGPIPE is only available on Unix, so you have to explicitly opt-in.

Re: How expensive is integer-overflow trapping in C++?

#90

Earlier quoted context omitted.

INTO would still need to check the flags and you would need to invoke it after every operation that could overflow. You can't configure the integer ALU to raise an interrupt automatically after any overflow.

Is there a reason to not add a new instruction to x86-64 which does interrupt the program on an integer operation overflow so no branching happens in the program? And can this instruction be made just as fast as the unchecked ones?

Having a mode that makes all existing arithmetic instructions interrupt sounds plausible, though there must be something I overlooked.
Post reply on HN