Description
Minimal example:
#include "raylib.h"
int main(void)
{
ColorToInt(RED);
return 0;
}
Produces the following error:
../raylib/src\rtextures.c:4513:33: runtime error: left shift of 230 by 24 places cannot be represented in type 'int'
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior ../raylib/src\rtextures.c:4513:33 in
The issue is that any color with a high enough RED value causes the signed integer to overflow which is undefined as per the C standard.
This happens here:
int ColorToInt(Color color)
{
int result = (((int)color.r << 24) | ((int)color.g << 16) | ((int)color.b << 8) | (int)color.a);
return result;
}
I tired rewriting it either to:
int ColorToInt(Color color)
{
unsigned int unsinged_result = (((unsigned int)color.r << 24) | ((unsigned int)color.g << 16) | ((unsigned int)color.b << 8) | (unsigned int)color.a);
int result;
memcpy(&result, &unsigned_result, 4);
return result;
}
which assumes that int is 4 bytes and stored as two's complement. (That would be UB on another machine but that does not affect me, the signed overflow affects me though)
Or this ugly dance around (https://stackoverflow.com/questions/5129498/how-to-cast-or-convert-an-unsigned-int-to-int-in-c):
int result;
if (unsigned_result < INT_MAX) {
result = unsigned_result;
}
else {
result = -(unsigned int)(~unsigend_result) -1;
}
(which also assume 2's complement which is only guaranteed in the latest C standard (but I am compiling with -std=c2x, so that would not be an issue for bleeding edge people like me)
Both run fine without triggering UBSAN for the entire range of uints (though retyping them in this issue may have introduced errors)
Or should the ColorToInt signature to be changed to return an unsigned int (probably a breaking change)?