Commit f313930b for libheif
commit f313930be3980a2b92f79179a99cabda176a84ca
Author: Dirk Farin <dirk.farin@gmail.com>
Date: Mon Sep 21 00:45:07 2026 +0200
Fix sign extension of 16-bit overlay offsets
readvec_signed() complemented all 32 bits of the loaded value, which is
only correct for the 4-byte fields selected by flags bit 0. In the common
2-byte form a negative offset such as -640 (0xFD80) came out as about
-2^31, so the input image was placed far outside the canvas and silently
skipped. Every 'iovl' with a negative 16-bit offset lost that layer, for
example conformance files C019 and C021.
Introduced by ab0565a6 (v1.19.2), which replaced a correct computation.
diff --git a/libheif/image-items/overlay.cc b/libheif/image-items/overlay.cc
index 5ab6ab20..ece7bc27 100644
--- a/libheif/image-items/overlay.cc
+++ b/libheif/image-items/overlay.cc
@@ -38,26 +38,27 @@ void writevec(uint8_t* data, size_t& idx, I value, int len)
}
+// Read a two's complement field of 'len' (2 or 4) bytes.
+// Note: the former implementation complemented all 32 bits of the loaded value,
+// which is only correct for 4-byte fields. A negative 2-byte offset such as -640
+// (0xFD80) came out as about -2^31, so the overlay image was placed far outside
+// the canvas and silently skipped (conformance files C019 and C021).
static int32_t readvec_signed(const std::vector<uint8_t>& data, int& ptr, int len)
{
- const uint32_t high_bit = UINT32_C(0x80) << ((len - 1) * 8);
+ assert(len == 2 || len == 4);
uint32_t val = 0;
- while (len--) {
+ for (int i = 0; i < len; i++) {
val <<= 8;
val |= data[ptr++];
}
- bool negative = (val & high_bit) != 0;
-
- if (negative) {
- return -static_cast<int32_t>((~val) & 0x7fffffff) -1;
+ if (len == 2) {
+ return static_cast<int16_t>(val);
}
else {
return static_cast<int32_t>(val);
}
-
- return val;
}