Is over / underflow behavior undefined at runtime?

I read about undefined behavior, and I'm not sure if this is just a compile-time function, or if it could happen at runtime.

I understand this example well (this is extracted from the Undefined Wikipedia behavior page ):

Example for C language:

int foo(unsigned x) { int value = 5; value += x; if (value < 5) bar(); return value; } 

The value of x cannot be negative and, given that the opposite integer overflow is undefined behavior in C, the compiler may assume that if value >= 5 in the check string. Thus, if and calling the bar function can be ignored by the compiler, since if has no side effects and its condition will never be met. Therefore, the above code is semantically equivalent:

 int foo(unsigned x) { int value = 5; value += x; return value; } 

But this happens at compile time.

What if I write, for example:

 void foo(int x) { if (x + 150 < 5) bar(); } int main() { int x; std::cin >> x; foo(x); } 

and then enter the user type MAX_INT - 100 ("2147483547" if 32 integer bits).

There will be an integer overflow, but AFAIK, this is the arithmetic logical unit of the processor that will make the overflow, so the compiler is not involved.

Is this behavior still undefined?

If so, how does the compiler detect overflow?

The best I could imagine was a CPU overflow flag. If so, does this mean that the compiler can do whatever it wants if the CPU overflow flag is set at any time at runtime?

+5
source share
1 answer

Yes, but not necessarily the way I think you could keep this in mind, that is, if there is an addition to the machine code and at runtime that the addition wraps (or otherwise overflows, but on most architectures it completes), which is not UB in itself. UB is exclusively in the C domain (or C ++). This add-on may have added unsigned integers or there were some optimizations that the compiler can do because it knows the semantics of the target platform and can safely use optimizations that rely on packaging (but you cannot, unless of course you don't do this with unsigned types).

Of course, this does not mean at all that it is safe to use constructs that are "carried only at runtime," because these code codes are also poisoned at compile time. For example, in your example

 extern void bar(void); void foo(int x) { if (x + 150 < 5) bar(); } 

Compiled GCC 6.3 with x64 targeting

 foo: cmp edi, -145 jl .L4 ret .L4: jmp bar 

Which is equivalent

 void foo(int x) { if (x < -145) bar(); // with tail call optimization } 

.. the same if you assume that an invalid integer overflow of signatures is not possible (in the sense that it places an implicit precondition on the inputs such that the overflow does not occur).

+6
source

Source: https://habr.com/ru/post/1262547/


All Articles