Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is detecting unsigned wraparound via cast to signed undefined behavior?

I'm using a uint16_t as a sequence counter in a network protocol. This counter commonly wraps around as expected. When a receiver gets a packet it checks this counter against the most recently received to see whether it's a new packet or an out of order packet.

Wraparound needs to be taken into account when comparing sequence numbers. So if for example the last sequence number was 0x4000, then a sequence number from 0x4001 to 0xBFFF is newer, and a sequence number from 0xC000 to 0xFFFF and from 0x0000 to 0x3FFF is smaller.

The way I'm currently doing this is as follows:

uint16_t last;
uint16_t current;
...
// read in values for last and current
...
if ((int16_t)(current - last) > 0) {
    printf("current is newer\n");
} else {
    printf("current is older (or same)\n");
}

By subtracting the two and treating the result as a int16_t, I can easily see which is greater and by how much. So for example if the current sequence number is at least 5 less that the last, i.e ((int16_t)(current - last) < -5), I can assume this is not due to normal packet reordering and drop the packet.

I realize that signed wraparound is undefined, however in this case I'm treating an unsigned value as signed for the sake of doing comparisons. Does this invoke undefined behavior, and if so what would be a better way to do this type of comparison?

like image 491
dbush Avatar asked Aug 12 '15 13:08

dbush


People also ask

Is unsigned overflow undefined Behaviour?

-fsanitize=unsigned-integer-overflow : Unsigned integer overflow, where the result of an unsigned integer computation cannot be represented in its type. Unlike signed integer overflow, this is not undefined behavior, but it is often unintentional.

What happens when you cast a signed int to an unsigned int?

If you mix signed and unsigned int, the signed int will be converted to unsigned (which means a large positive number if the signed int has a negative value).

Is signed integer overflow undefined?

12.2. 1 Basics of Integer Overflow In contrast, the C standard says that signed integer overflow leads to undefined behavior where a program can do anything, including dumping core or overrunning a buffer. The misbehavior can even precede the overflow.

Is signed integral overflow undefined behavior in C++?

And unfortunately, signed integral overflow is undefined behavior. It doesn’t matter that overflow of unsigned integral types is well-defined behavior in C and C++. No multiplication of values of type unsigned short ever occurs in this function.

What happens when a function has undefined behavior?

An interesting consequence of the potential for undefined behavior in Figure 4 is that any compiler would be within its rights to generate “optimized” object code for the function (if the static_assert succeeds) that is very fast and almost certainly unintended by the programmer, equivalent to

Is there any undefined behavior in the compiler bugs?

There’s no undefined behavior in the program or compiler bugs. The surprising result occurs due to “integral promotion”.

What happens when an unsigned type is promoted to INT?

They will usually be promoted to type int during operations and comparisons, and so they will be vulnerable to all the undefined behavior of the signed type int. They won’t be protected by any well-defined behavior of the original unsigned type, since after promotion the types are no longer unsigned.


1 Answers

The behaviour of out-of-range conversion is implementation-defined.

Why don't you just avoid this issue entirely and write:

if ( current != last && current - last < 0x8000 )
    printf("current is newer\n");
else
    printf("current is older (or same)\n");

Note: This answer only applies to the specific question involving uint16_t. For other types, different code would be required.

like image 62
M.M Avatar answered Sep 28 '22 09:09

M.M