Commit cf0396a563ce9ac81eb550d83d53fda519fa4a6f

Patrick Steinhardt 2016-05-02T16:49:59

delta-apply: fix sign extension We compute offsets by executing `off |= (*delta++ << 24)` for multiple constants, where `off` is of type `size_t` and `delta` is of type `unsigned char`. The usual arithmetic conversions (see ISO C89 ยง3.2.1.5 "Usual arithmetic conversions") kick in here, causing us to promote both operands to `int` and then extending the result to an `unsigned long` when OR'ing it with `off`. The integer promotion to `int` may result in wrong size calculations for big values. Fix the issue by making the constants `unsigned long`, causing both operands to be promoted to `unsigned long`.

diff --git a/src/delta-apply.c b/src/delta-apply.c
index 6e86a81..02ec7b7 100644
--- a/src/delta-apply.c
+++ b/src/delta-apply.c
@@ -121,13 +121,13 @@ int git__delta_apply(
 			size_t off = 0, len = 0;
 
 			if (cmd & 0x01) off = *delta++;
-			if (cmd & 0x02) off |= *delta++ << 8;
-			if (cmd & 0x04) off |= *delta++ << 16;
-			if (cmd & 0x08) off |= *delta++ << 24;
+			if (cmd & 0x02) off |= *delta++ << 8UL;
+			if (cmd & 0x04) off |= *delta++ << 16UL;
+			if (cmd & 0x08) off |= *delta++ << 24UL;
 
 			if (cmd & 0x10) len = *delta++;
-			if (cmd & 0x20) len |= *delta++ << 8;
-			if (cmd & 0x40) len |= *delta++ << 16;
+			if (cmd & 0x20) len |= *delta++ << 8UL;
+			if (cmd & 0x40) len |= *delta++ << 16UL;
 			if (!len)		len = 0x10000;
 
 			if (base_len < off + len || res_sz < len)