aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Dreik <github@pauldreik.se>2019-09-13 20:06:21 +0200
committerDaniel Stenberg <daniel@haxx.se>2019-09-15 23:27:45 +0200
commitdda418266c99ceab368d723facb52069cbb9c8d5 (patch)
tree51d6bcfe1b2edc90edbe59dbfce5548368b26ac8
parentb7666027296a4f89a8ce6b22af335e8aee7a7782 (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.c10
1 files changed, 8 insertions, 2 deletions
diff --git a/lib/doh.c b/lib/doh.c
index e84c9b0ad..6f06d0a35 100644
--- a/lib/doh.c
+++ b/lib/doh.c
@@ -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)