Skip to content

avoid signed left-shift overflow in binary long/float/double readers - #4044

Open
ArjunD3456 wants to merge 1 commit into
apache:mainfrom
ArjunD3456:binary-reader-unsigned-shift
Open

ArjunD3456 wants to merge 1 commit into
apache:mainfrom
ArjunD3456:binary-reader-unsigned-shift

Conversation

@ArjunD3456

Copy link
Copy Markdown

What is the purpose of the change

read_long in lang/c/src/encoding_binary.c builds a varint with value |= (int64_t)(b & 0x7F) << (7 * offset). On a 10-byte varint the last byte is shifted by 63 into a signed int64_t, so a payload bit lands on the sign bit and the shift overflows, which is undefined behavior. The big-endian branches of read_float and read_double have the same shape, shifting a byte into bit 31 of a signed int32_t (read_float) and bit 63 of a signed int64_t (read_double). All three feed on bytes taken straight from the input stream, so any Avro datum carrying a full-width long, or a float/double read on a big-endian build, trips it. -fsanitize=undefined reports left shift of ... cannot be represented in type 'long' on read_long while decoding INT64_MIN/INT64_MAX. The C++ BinaryDecoder::doDecodeLong already accumulates into an unsigned uint64_t for this reason, so this brings the C reader in line: shift in unsigned and assign to the signed destination. Decoded values are unchanged on the platforms Avro targets.

Verifying this change

This change is already covered by existing tests: the long, float, and double round-trip cases in lang/c/tests/test_avro_values.c exercise these readers (the long case decodes maximal 10-byte varints), and a -fsanitize=undefined build of that suite is clean after the change where it previously reported the shift overflow. Behavior is unchanged for valid input.

Documentation

  • Does this pull request introduce a new feature? no

read_long shifts each varint byte into a signed int64_t, and the
big-endian branches of read_float and read_double shift a byte into
the sign bit of a signed int32_t/int64_t. A full-width value shifts
into bit 31/63, which is signed left-shift overflow and undefined.
Accumulate in unsigned and assign to the signed destination, matching
how the C++ BinaryDecoder already decodes varints.
@github-actions github-actions Bot added the C label Oct 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant