Live data from Hacker News

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

lemire.me

101–110 of 198 posts

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

#101
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.

That’s unfortunately incorrect. That flag does not turn integer overflow into UB, which is what allows the C++ optimizations that assume it cannot happen, and can be used to prove that loops terminate, etc.

That flag changes the behavior of integer overflow from trapping to “modulo 2 arithmetic”.

If you want to change the behavior of integer overflow in Rust to “always assume it cannot happen”, you need to “hack” the compiler AFAIK.

If you believe this is incorrect, provide the flag that proves that (hint: such a flag makes safe Rust unsound and it therefore does not exist).

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

#102
post #99

Earlier quoted context omitted.

> 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.

Huh. That would make classic LCG PRNGs pretty useless. I guess it's "safer" in that it prevents rare dangerous edge cases at the expense of common everyday safe operations, but that's a tradeoff.

For your LCG you would use an explicitly wrapping type: https://doc.rust-lang.org/std/num/struct.Wrapping.html

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

#103
post #6
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…

Rust wraps in release mode and traps in debug mode[0][1]. All large projects that I know of ship in release mode. Though I'd be interested to see a source for it not pessimizing badly. [0] https://play.rust-lang.org/?version=stable&mode=release&edit... [1] https://github.com/rust-lang/rfcs/pull/560

See my reply to masklin in this thread for why this is incorrect. In release mode, the behavior of integer overflow in Rust is not UB/cannot happen, but modulo two arithmetic.

These two are not the same thing.

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

#104

> 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.

Thanks for answering about unsigned numbers.

I don't believe Rust is anything like Swift. Do you think that by "like Swift" it just meant "languages where an overflow will result in the program aborting its execution"? If so then that was a pretty useless tautology. (I had assumed it meant something like "like Java" meaning any language that uses the JVM.)

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

#105
post #4
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…

I dont think Rust traps on overflow in release builds

. In release mode, the behavior of integer overflow in Rust is modulo two arithmetic instead of not UB/cannot happen.

These two are not the same thing. See my reply to masklin.

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

#106

> 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…

How does this relate to the change in the C++20 standard about two's complement? "signed integers are now defined to be represented using two's complement (signed integer overflow remains undefined behavior)"

That change was simply to reflect de facto reality, removing some undefined behavior in order to make life easier for people writing portable code. I haven’t seen a ones complement machine in decades.

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

#107
post #99

Earlier quoted context omitted.

> 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.

Huh. That would make classic LCG PRNGs pretty useless. I guess it's "safer" in that it prevents rare dangerous edge cases at the expense of common everyday safe operations, but that's a tradeoff.

If you want the wrapping behaviour (like with an LCG), you can prepend the operator with an ampersand(i.e &+ instead of +).

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

#108
post #63

> 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…

So overflow means overflow, but underflow as well, while underflow means precision loss. What a bad case of misnomers.

To be fair it's not just underflow, but equality that differs between numeric types. The equality of signed and unsigned integers might not mean what you think it means, but it's exact. The equality of real-valued types always means what you think it means, but it's inexact so you need to write it as "close enough to" instead of "equals".

With integers, "overflow" means "wrap around because the internal representation is really on a modulo field" whereas with floating point "overflow" means "the result is NAN or INF" and undeflow means "the result is NAN or zero or DENORM" but it's awkward to use such phrases in everyday conversation. Especially to your boss, whose eyes glaze over when you start using such words and he'll just interrupt with a "when will the JIRA be done? I have another meeting in five."

The rule of thumb is that you have to know what you're doing to use lower-level languages like C++. That already eliminates 80% of the programmers out there but thank goodness there are high-level languages that reduce to simplistic concepts and let software be churned out at a rapid pace.

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

#109

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?

Maybe is possible and it would be very useful.

I know nothing about micro-architectural implementations, but as far as I can remember, all instructions that can trap (load/stores, divs, etc) take more than one clock cycle. Simple sub/adds usually have 1 cycle latency; there just might not be enough latency budget to fit the trapping machinery.

I guess that the trapping doesn't actually need happen in the critical path (i.e. the results might be available earlier) but this would mean that even ALU instructions cause speculation.

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

#110

So what's the correct way to tell the C++ compiler you want integer overflow to occur in a particular spot when overflow trapping is enabled?

Since most compiler vendors provide an implementation-specific way to define the undefined behaviour of signed integer overflow as a vendor extension, you will need to resort to compiler-specific means to control that.

For example, in GCC you could use a `#pragma push_options("-fno-trapv")/#pragma GCC pop_options` pair to surround the offending code.

Post reply on HN