avoid UB in bit shifts
unsigned char* gets promoted to `int`, which cannot always be shifted by 24 bits. Justine Tunney blogs about it here: https://justine.lol/endian.html Example: ```deserialize.c #include <stdlib.h> #include <stdio.h> #include <stdint.h> uint32_t file_deserialize_uint32_ok(unsigned char *buf) { return ((uint32_t)buf[0] << 24) | ((uint32_t)buf[1] << 16) | ((uint32_t)buf[2] << 8) | (uint32_t)buf[3]; } uint32_t file_deserialize_uint32(unsigned char *buf) { return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; } int main() { unsigned char arr[4] = {0xaa, 0xaa, 0xaa, 0xaa}; printf("%d\n", file_deserialize_uint32_ok((unsigned char*)arr)); printf("%d\n", file_deserialize_uint32((unsigned char*)arr)); } ``` Output: ``` $ clang-16 -fsanitize=undefined ./deserialize.c -o deserialize && ./deserialize -1431655766 deserialize.c:10:20: runtime error: left shift of 170 by 24 places cannot be represented in type 'int' SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior deserialize.c:10:20 in -1431655766 ```
This commit is contained in:
@@ -198,7 +198,7 @@ bool file_write_float(FILE *file, float value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline uint32_t file_deserialize_uint32(unsigned char *buf) {
|
inline uint32_t file_deserialize_uint32(unsigned char *buf) {
|
||||||
return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
|
return ((uint32_t)buf[0] << 24) | ((uint32_t)buf[1] << 16) | ((uint32_t)buf[2] << 8) | (uint32_t)buf[3];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool file_read_uint32(FILE *file, uint32_t *value) {
|
bool file_read_uint32(FILE *file, uint32_t *value) {
|
||||||
@@ -243,7 +243,7 @@ bool file_write_uint32(FILE *file, uint32_t value) {
|
|||||||
|
|
||||||
|
|
||||||
inline uint16_t file_deserialize_uint16(unsigned char *buf) {
|
inline uint16_t file_deserialize_uint16(unsigned char *buf) {
|
||||||
return (buf[0] << 8) | buf[1];
|
return ((uint16_t)buf[0] << 8) | buf[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user