Integers footgun

19 May 2024

Recently, a colleague of mine proposed the following change in our code base

Change:

    memcpy(network_buffer,
           original_message,
           MIN(original_message_size, OUT_BUFFER_MAX_SIZE));

To

    memcpy(network_buffer,
           &original_message[2],
           MIN(original_message_size - 2, OUT_BUFFER_MAX_SIZE));

The original intend was to skip the first two bytes (if any) because we didn't need them.

To have the full picture,

Let's do the review:

LGTM, right ?

And of course, it's not. Because original_message_size is a uint8_t, integer promotion kicks in. Integer types smaller than int are promoted when an operation is performed on them, either in a int if int is big enough to cover all values from the original type, or unsigned int otherwise. You can see at work on C++ insight

#include <cstdio>
#include <cstdint>

int main()
{
   uint8_t x = 0;
   auto y = x - 2;

   unsigned int u = 0;
   auto v = u - 2;
}

So in our case, original_message_size is promoted to an int, such that is original_message_size - 2 is -2 when original_message is empty. And from there, memory havoc follows, likely resulting in a segfault.



RSS Feed