diff options
author | Paul Dreik <github@pauldreik.se> | 2019-09-13 20:06:21 +0200 |
---|---|---|
committer | Daniel Stenberg <daniel@haxx.se> | 2019-09-15 23:27:45 +0200 |
commit | dda418266c99ceab368d723facb52069cbb9c8d5 (patch) | |
tree | 51d6bcfe1b2edc90edbe59dbfce5548368b26ac8 | |
parent | b7666027296a4f89a8ce6b22af335e8aee7a7782 (diff) |
doh: fix undefined behaviour and open up for gcc and clang optimization
The undefined behaviour is annoying when running fuzzing with
sanitizers. The codegen is the same, but the meaning is now not up for
dispute. See https://cppinsights.io/s/516a2ff4
By incrementing the pointer first, both gcc and clang recognize this as
a bswap and optimizes it to a single instruction. See
https://godbolt.org/z/994Zpx
Closes #4350
-rw-r--r-- | lib/doh.c | 10 |
1 files changed, 8 insertions, 2 deletions
@@ -432,8 +432,14 @@ static unsigned short get16bit(unsigned char *doh, int index) static unsigned int get32bit(unsigned char *doh, int index) { - return (doh[index] << 24) | (doh[index + 1] << 16) | - (doh[index + 2] << 8) | doh[index + 3]; + /* make clang and gcc optimize this to bswap by incrementing + the pointer first. */ + doh += index; + + /* avoid undefined behaviour by casting to unsigned before shifting + 24 bits, possibly into the sign bit. codegen is same, but + ub sanitizer won't be upset */ + return ( (unsigned)doh[0] << 24) | (doh[1] << 16) |(doh[2] << 8) | doh[3]; } static DOHcode store_a(unsigned char *doh, int index, struct dohentry *d) |