summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNeil Roberts <neil@linux.intel.com>2011-11-22 15:59:58 +0000
committerNeil Roberts <neil@linux.intel.com>2011-11-22 16:07:21 +0000
commit61d71c0926bf5bf7c78bc27e4da726e0e0084a36 (patch)
tree83f1cfc734f0c1fedc059e87ee0a14d8ad52d88c
parent3e56883c98584034f249b8eb938e65a129ccf8c4 (diff)
downloadcogl-61d71c0926bf5bf7c78bc27e4da726e0e0084a36.tar.gz
cogl-flags: Fix iterating flag when the most-significant bit is set
When the flags contain a value that only has the most-significant bit set then ffsl will return the size of an unsigned long. According to the C spec it is undefined what happens when shifting by a number greater than or equal to the size of the left operand. On Intel (and probably others) this seems to end up being a no-op so the iteration breaks. To fix this we can split the shift into two separate shifts. We always need to shift by at least one bit so we can put this one bit shift into a separate operator. Reviewed-by: Robert Bragg <robert@linux.intel.com>
-rw-r--r--cogl/cogl-flags.h7
1 files changed, 6 insertions, 1 deletions
diff --git a/cogl/cogl-flags.h b/cogl/cogl-flags.h
index bf5eadd4..d62294af 100644
--- a/cogl/cogl-flags.h
+++ b/cogl/cogl-flags.h
@@ -109,7 +109,12 @@ G_BEGIN_DECLS
{ \
int _next_bit = _cogl_util_ffsl (_mask); \
(bit) += _next_bit; \
- _mask >>= _next_bit;
+ /* This odd two-part shift is to avoid */ \
+ /* shifting by sizeof (long)*8 which has */ \
+ /* undefined results according to the */ \
+ /* C spec (and seems to be a no-op in */ \
+ /* practice) */ \
+ _mask = (_mask >> (_next_bit - 1)) >> 1; \
#define COGL_FLAGS_FOREACH_END \
} } } G_STMT_END