Improve handling of varint overflows.
This satisfies clang integer sanitizer and also detects
some real varint overflows that were missed earlier.
diff --git a/pb_decode.c b/pb_decode.c
index ce3a8b4..28059be 100644
--- a/pb_decode.c
+++ b/pb_decode.c
@@ -209,18 +209,20 @@
PB_RETURN_ERROR(stream, "varint overflow");
}
}
+ else if (bitpos == 28)
+ {
+ if ((byte & 0x70) != 0 && (byte & 0x78) != 0x78)
+ {
+ PB_RETURN_ERROR(stream, "varint overflow");
+ }
+ result |= (uint32_t)(byte & 0x0F) << bitpos;
+ }
else
{
result |= (uint32_t)(byte & 0x7F) << bitpos;
}
bitpos = (uint_fast8_t)(bitpos + 7);
} while (byte & 0x80);
-
- if (bitpos == 35 && (byte & 0x70) != 0)
- {
- /* The last byte was at bitpos=28, so only bottom 4 bits fit. */
- PB_RETURN_ERROR(stream, "varint overflow");
- }
}
*dest = result;
@@ -241,12 +243,12 @@
do
{
- if (bitpos >= 64)
- PB_RETURN_ERROR(stream, "varint overflow");
-
if (!pb_readbyte(stream, &byte))
return false;
+ if (bitpos >= 63 && (byte & 0xFE) != 0)
+ PB_RETURN_ERROR(stream, "varint overflow");
+
result |= (uint64_t)(byte & 0x7F) << bitpos;
bitpos = (uint_fast8_t)(bitpos + 7);
} while (byte & 0x80);
diff --git a/pb_encode.c b/pb_encode.c
index c30d3d7..7f56201 100644
--- a/pb_encode.c
+++ b/pb_encode.c
@@ -624,8 +624,9 @@
bool checkreturn pb_encode_svarint(pb_ostream_t *stream, pb_int64_t value)
{
pb_uint64_t zigzagged;
+ pb_uint64_t mask = ((pb_uint64_t)-1) >> 1; /* Satisfy clang -fsanitize=integer */
if (value < 0)
- zigzagged = ~((pb_uint64_t)value << 1);
+ zigzagged = ~(((pb_uint64_t)value & mask) << 1);
else
zigzagged = (pb_uint64_t)value << 1;