Commit 7ecce712 for libheif
commit 7ecce712b3f67231496ec5f82c4d618219ee20da
Author: Dirk Farin <dirk.farin@gmail.com>
Date: Mon Aug 24 21:47:47 2026 +0200
fix sign of NAL unit length in the openh264 decoder
The four length bytes are uint8_t and promote to 'int' before shifting, so a
leading byte >= 0x80 shifted left by 24 lands in the sign bit. The
OR-expression is then a negative int that is implicitly converted to the
uint32_t it gets assigned to, meaning the bounds check on the following line
works on a value that arrived by accident.
C++20 defines the shift itself, so only the 'integer' sanitizer catches this,
not 'shift'. Compute in uint32_t instead.
diff --git a/libheif/plugins/decoder_openh264.cc b/libheif/plugins/decoder_openh264.cc
index d3063055..28793815 100644
--- a/libheif/plugins/decoder_openh264.cc
+++ b/libheif/plugins/decoder_openh264.cc
@@ -235,7 +235,12 @@ heif_error openh264_decode_next_image2(void* decoder_raw, heif_image** out_img,
return kError_EOF;
}
- uint32_t size = ((indata[idx] << 24) | (indata[idx + 1] << 16) | (indata[idx + 2] << 8) | indata[idx + 3]);
+ // Compute in uint32_t. The bytes promote to 'int', so a leading byte >= 0x80
+ // shifted left by 24 lands in the sign bit and the result would be negative.
+ uint32_t size = (static_cast<uint32_t>(indata[idx]) << 24) |
+ (static_cast<uint32_t>(indata[idx + 1]) << 16) |
+ (static_cast<uint32_t>(indata[idx + 2]) << 8) |
+ static_cast<uint32_t>(indata[idx + 3]);
idx += 4;
if (indata.size() < size || indata.size() - size < idx) {