bitfield-internal.h: fix negative value shifting warnings
authorPhilippe Proulx <eeppeliteloop@gmail.com>
Wed, 31 May 2017 00:13:37 +0000 (20:13 -0400)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Fri, 9 Jun 2017 20:58:13 +0000 (16:58 -0400)
This patch makes _bt_unsigned_cast() shift the complement of 0 casted to
uint64_t instead of the complement of 0 casted to a possibly signed
type, which results in shifting a negative value, an undefined operation
in C.

Because we're imposing uint64_t now, the size of the type and value's
type cannot be greater than the size of uint64_t... not a considerable
worry with the current state of commercial computing. Having said that,
the new _bt_check_max_64bit() macro, a static assertion, checks that
those type sizes are not greater than the size of uint64_t at build
time.

Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
include/babeltrace/bitfield-internal.h

index d3609e3c99ca9d67885cc57a6d337263af9abb8a..122ccda6450f875120bd257f1789915d4c29c04e 100644 (file)
 
 #define _bt_is_signed_type(type)       ((type) -1 < (type) 0)
 
+/*
+ * NOTE: The cast to (uint64_t) below ensures that we're not casting a
+ * negative value, which is undefined in C. However, this limits the
+ * maximum type size of `type` and `v` to 64-bit. The
+ * _bt_check_max_64bit() is used to check that the users of this header
+ * do not use types with a size greater than 64-bit.
+ */
 #define _bt_unsigned_cast(type, v)                                     \
 ({                                                                     \
        (sizeof(v) < sizeof(type)) ?                                    \
-               ((type) (v)) & (~(~(type) 0 << (sizeof(v) * CHAR_BIT))) : \
+               ((type) (v)) & ((type) (~(~(uint64_t) 0 << (sizeof(v) * CHAR_BIT)))) : \
                (type) (v);                                             \
 })
 
+#define _bt_check_max_64bit(type)                                      \
+       char _max_64bit_assertion[sizeof(type) <= sizeof(uint64_t) ? 1 : -1] __attribute__((unused))
+
 /*
  * bt_bitfield_write - write integer to a bitfield in native endianness
  *
@@ -215,7 +225,7 @@ do {                                                                        \
 
 #define bt_bitfield_write_le(ptr, type, _start, _length, _v)           \
        _bt_bitfield_write_le(ptr, type, _start, _length, _v)
-       
+
 #define bt_bitfield_write_be(ptr, type, _start, _length, _v)           \
        _bt_bitfield_write_be(ptr, unsigned char, _start, _length, _v)
 
@@ -226,7 +236,7 @@ do {                                                                        \
 
 #define bt_bitfield_write_le(ptr, type, _start, _length, _v)           \
        _bt_bitfield_write_le(ptr, unsigned char, _start, _length, _v)
-       
+
 #define bt_bitfield_write_be(ptr, type, _start, _length, _v)           \
        _bt_bitfield_write_be(ptr, type, _start, _length, _v)
 
@@ -247,6 +257,10 @@ do {                                                                       \
        unsigned long start_unit, end_unit, this_unit;                  \
        unsigned long end, cshift; /* cshift is "complement shift" */   \
                                                                        \
+       { _bt_check_max_64bit(type); }                                  \
+       { _bt_check_max_64bit(typeof(*_vptr)); }                        \
+       { _bt_check_max_64bit(typeof(*_ptr)); }                         \
+                                                                       \
        if (!__length) {                                                \
                *__vptr = 0;                                            \
                break;                                                  \
@@ -314,6 +328,10 @@ do {                                                                       \
        unsigned long start_unit, end_unit, this_unit;                  \
        unsigned long end, cshift; /* cshift is "complement shift" */   \
                                                                        \
+       { _bt_check_max_64bit(type); }                                  \
+       { _bt_check_max_64bit(typeof(*_vptr)); }                        \
+       { _bt_check_max_64bit(typeof(*_ptr)); }                         \
+                                                                       \
        if (!__length) {                                                \
                *__vptr = 0;                                            \
                break;                                                  \
@@ -383,7 +401,7 @@ do {                                                                        \
 
 #define bt_bitfield_read_le(_ptr, type, _start, _length, _vptr)                \
        _bt_bitfield_read_le(_ptr, type, _start, _length, _vptr)
-       
+
 #define bt_bitfield_read_be(_ptr, type, _start, _length, _vptr)                \
        _bt_bitfield_read_be(_ptr, unsigned char, _start, _length, _vptr)
 
@@ -394,7 +412,7 @@ do {                                                                        \
 
 #define bt_bitfield_read_le(_ptr, type, _start, _length, _vptr)                \
        _bt_bitfield_read_le(_ptr, unsigned char, _start, _length, _vptr)
-       
+
 #define bt_bitfield_read_be(_ptr, type, _start, _length, _vptr)                \
        _bt_bitfield_read_be(_ptr, type, _start, _length, _vptr)
 
This page took 0.025596 seconds and 4 git commands to generate.