瀏覽代碼

libarchive: fixed undefined left shift with signed ints

caught by clang's -fsanitize=shift. A small unsigned int was
promoted, according to C's regular promotion rules, to a signed
int, it was then left shifted.  This sometimes pushed a 1 into
the sign bit, which is undefined behaviour. Fixed by using
unsigned temporaries.
Sean McBride 13 年之前
父節點
當前提交
6a6a6f3670
共有 1 個文件被更改,包括 32 次插入4 次删除
  1. 32 4
      Utilities/cmlibarchive/libarchive/archive_endian.h

+ 32 - 4
Utilities/cmlibarchive/libarchive/archive_endian.h

@@ -64,7 +64,13 @@ archive_be16dec(const void *pp)
 {
 	unsigned char const *p = (unsigned char const *)pp;
 
-	return ((p[0] << 8) | p[1]);
+	/* Store into unsigned temporaries before left shifting, to avoid
+	promotion to signed int and then left shifting into the sign bit,
+	which is undefined behaviour. */
+	unsigned int p1 = p[1];
+	unsigned int p0 = p[0];
+
+	return ((p0 << 8) | p1);
 }
 
 static inline uint32_t
@@ -72,7 +78,15 @@ archive_be32dec(const void *pp)
 {
 	unsigned char const *p = (unsigned char const *)pp;
 
-	return ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
+	/* Store into unsigned temporaries before left shifting, to avoid
+	promotion to signed int and then left shifting into the sign bit,
+	which is undefined behaviour. */
+	unsigned int p3 = p[3];
+	unsigned int p2 = p[2];
+	unsigned int p1 = p[1];
+	unsigned int p0 = p[0];
+
+	return ((p0 << 24) | (p1 << 16) | (p2 << 8) | p3);
 }
 
 static inline uint64_t
@@ -88,7 +102,13 @@ archive_le16dec(const void *pp)
 {
 	unsigned char const *p = (unsigned char const *)pp;
 
-	return ((p[1] << 8) | p[0]);
+	/* Store into unsigned temporaries before left shifting, to avoid
+	promotion to signed int and then left shifting into the sign bit,
+	which is undefined behaviour. */
+	unsigned int p1 = p[1];
+	unsigned int p0 = p[0];
+
+	return ((p1 << 8) | p0);
 }
 
 static inline uint32_t
@@ -96,7 +116,15 @@ archive_le32dec(const void *pp)
 {
 	unsigned char const *p = (unsigned char const *)pp;
 
-	return ((p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]);
+	/* Store into unsigned temporaries before left shifting, to avoid
+	promotion to signed int and then left shifting into the sign bit,
+	which is undefined behaviour. */
+	unsigned int p3 = p[3];
+	unsigned int p2 = p[2];
+	unsigned int p1 = p[1];
+	unsigned int p0 = p[0];
+
+	return ((p3 << 24) | (p2 << 16) | (p1 << 8) | p0);
 }
 
 static inline uint64_t