utils: avoid unexpected side-effects of GST_WRITE_* macros
authorTim-Philipp Müller <tim.muller@collabora.co.uk>
Tue, 19 Feb 2013 18:00:48 +0000 (18:00 +0000)
committerTim-Philipp Müller <tim.muller@collabora.co.uk>
Tue, 19 Feb 2013 18:00:48 +0000 (18:00 +0000)
Make sure the data argument is only evaluated once.

gst/gstutils.h
tests/check/gst/gstutils.c

index 219e607..d40d450 100644 (file)
@@ -274,14 +274,15 @@ static inline guint64 __gst_fast_read_swap64(const guint8 *v) {
  * Store a 64 bit unsigned integer value in big endian format into the memory buffer.
  */
 #define GST_WRITE_UINT64_BE(data, num)  do { \
-                                          _GST_PUT (data, 0, 64, 56, num); \
-                                          _GST_PUT (data, 1, 64, 48, num); \
-                                          _GST_PUT (data, 2, 64, 40, num); \
-                                          _GST_PUT (data, 3, 64, 32, num); \
-                                          _GST_PUT (data, 4, 64, 24, num); \
-                                          _GST_PUT (data, 5, 64, 16, num); \
-                                          _GST_PUT (data, 6, 64,  8, num); \
-                                          _GST_PUT (data, 7, 64,  0, num); \
+                                          gpointer __put_data = data; \
+                                          _GST_PUT (__put_data, 0, 64, 56, num); \
+                                          _GST_PUT (__put_data, 1, 64, 48, num); \
+                                          _GST_PUT (__put_data, 2, 64, 40, num); \
+                                          _GST_PUT (__put_data, 3, 64, 32, num); \
+                                          _GST_PUT (__put_data, 4, 64, 24, num); \
+                                          _GST_PUT (__put_data, 5, 64, 16, num); \
+                                          _GST_PUT (__put_data, 6, 64,  8, num); \
+                                          _GST_PUT (__put_data, 7, 64,  0, num); \
                                         } while (0)
 
 /**
@@ -292,14 +293,15 @@ static inline guint64 __gst_fast_read_swap64(const guint8 *v) {
  * Store a 64 bit unsigned integer value in little endian format into the memory buffer.
  */
 #define GST_WRITE_UINT64_LE(data, num)  do { \
-                                          _GST_PUT (data, 0, 64,  0, num); \
-                                          _GST_PUT (data, 1, 64,  8, num); \
-                                          _GST_PUT (data, 2, 64, 16, num); \
-                                          _GST_PUT (data, 3, 64, 24, num); \
-                                          _GST_PUT (data, 4, 64, 32, num); \
-                                          _GST_PUT (data, 5, 64, 40, num); \
-                                          _GST_PUT (data, 6, 64, 48, num); \
-                                          _GST_PUT (data, 7, 64, 56, num); \
+                                          gpointer __put_data = data; \
+                                          _GST_PUT (__put_data, 0, 64,  0, num); \
+                                          _GST_PUT (__put_data, 1, 64,  8, num); \
+                                          _GST_PUT (__put_data, 2, 64, 16, num); \
+                                          _GST_PUT (__put_data, 3, 64, 24, num); \
+                                          _GST_PUT (__put_data, 4, 64, 32, num); \
+                                          _GST_PUT (__put_data, 5, 64, 40, num); \
+                                          _GST_PUT (__put_data, 6, 64, 48, num); \
+                                          _GST_PUT (__put_data, 7, 64, 56, num); \
                                         } while (0)
 
 /**
@@ -310,10 +312,11 @@ static inline guint64 __gst_fast_read_swap64(const guint8 *v) {
  * Store a 32 bit unsigned integer value in big endian format into the memory buffer.
  */
 #define GST_WRITE_UINT32_BE(data, num)  do { \
-                                          _GST_PUT (data, 0, 32, 24, num); \
-                                          _GST_PUT (data, 1, 32, 16, num); \
-                                          _GST_PUT (data, 2, 32,  8, num); \
-                                          _GST_PUT (data, 3, 32,  0, num); \
+                                          gpointer __put_data = data; \
+                                          _GST_PUT (__put_data, 0, 32, 24, num); \
+                                          _GST_PUT (__put_data, 1, 32, 16, num); \
+                                          _GST_PUT (__put_data, 2, 32,  8, num); \
+                                          _GST_PUT (__put_data, 3, 32,  0, num); \
                                         } while (0)
 
 /**
@@ -324,10 +327,11 @@ static inline guint64 __gst_fast_read_swap64(const guint8 *v) {
  * Store a 32 bit unsigned integer value in little endian format into the memory buffer.
  */
 #define GST_WRITE_UINT32_LE(data, num)  do { \
-                                          _GST_PUT (data, 0, 32,  0, num); \
-                                          _GST_PUT (data, 1, 32,  8, num); \
-                                          _GST_PUT (data, 2, 32, 16, num); \
-                                          _GST_PUT (data, 3, 32, 24, num); \
+                                          gpointer __put_data = data; \
+                                          _GST_PUT (__put_data, 0, 32,  0, num); \
+                                          _GST_PUT (__put_data, 1, 32,  8, num); \
+                                          _GST_PUT (__put_data, 2, 32, 16, num); \
+                                          _GST_PUT (__put_data, 3, 32, 24, num); \
                                         } while (0)
 
 /**
@@ -338,9 +342,10 @@ static inline guint64 __gst_fast_read_swap64(const guint8 *v) {
  * Store a 24 bit unsigned integer value in big endian format into the memory buffer.
  */
 #define GST_WRITE_UINT24_BE(data, num)  do { \
-                                          _GST_PUT (data, 0, 32,  16, num); \
-                                          _GST_PUT (data, 1, 32,  8, num); \
-                                          _GST_PUT (data, 2, 32,  0, num); \
+                                          gpointer __put_data = data; \
+                                          _GST_PUT (__put_data, 0, 32,  16, num); \
+                                          _GST_PUT (__put_data, 1, 32,  8, num); \
+                                          _GST_PUT (__put_data, 2, 32,  0, num); \
                                         } while (0)
 
 /**
@@ -351,9 +356,10 @@ static inline guint64 __gst_fast_read_swap64(const guint8 *v) {
  * Store a 24 bit unsigned integer value in little endian format into the memory buffer.
  */
 #define GST_WRITE_UINT24_LE(data, num)  do { \
-                                          _GST_PUT (data, 0, 32,  0, num); \
-                                          _GST_PUT (data, 1, 32,  8, num); \
-                                          _GST_PUT (data, 2, 32,  16, num); \
+                                          gpointer __put_data = data; \
+                                          _GST_PUT (__put_data, 0, 32,  0, num); \
+                                          _GST_PUT (__put_data, 1, 32,  8, num); \
+                                          _GST_PUT (__put_data, 2, 32,  16, num); \
                                         } while (0)
 
 /**
@@ -364,8 +370,9 @@ static inline guint64 __gst_fast_read_swap64(const guint8 *v) {
  * Store a 16 bit unsigned integer value in big endian format into the memory buffer.
  */
 #define GST_WRITE_UINT16_BE(data, num)  do { \
-                                          _GST_PUT (data, 0, 16,  8, num); \
-                                          _GST_PUT (data, 1, 16,  0, num); \
+                                          gpointer __put_data = data; \
+                                          _GST_PUT (__put_data, 0, 16,  8, num); \
+                                          _GST_PUT (__put_data, 1, 16,  0, num); \
                                         } while (0)
 
 /**
@@ -376,8 +383,9 @@ static inline guint64 __gst_fast_read_swap64(const guint8 *v) {
  * Store a 16 bit unsigned integer value in little endian format into the memory buffer.
  */
 #define GST_WRITE_UINT16_LE(data, num)  do { \
-                                          _GST_PUT (data, 0, 16,  0, num); \
-                                          _GST_PUT (data, 1, 16,  8, num); \
+                                          gpointer __put_data = data; \
+                                          _GST_PUT (__put_data, 0, 16,  0, num); \
+                                          _GST_PUT (__put_data, 1, 16,  8, num); \
                                         } while (0)
 
 /**
index 35045f0..b1daf39 100644 (file)
@@ -1224,10 +1224,86 @@ GST_START_TEST (test_read_macros)
       0x4142434445464748);
   fail_unless_equals_int64_hex (GST_READ_UINT64_LE (uarray),
       0x4847464544434241);
+
+  /* make sure the data argument is not duplicated inside the macro
+   * with possibly unexpected side-effects */
+  cpointer = carray;
+  fail_unless_equals_int (GST_READ_UINT8 (cpointer++), 'A');
+  fail_unless (cpointer == carray + 1);
+
+  cpointer = carray;
+  fail_unless_equals_int_hex (GST_READ_UINT16_BE (cpointer++), 0x4142);
+  fail_unless (cpointer == carray + 1);
+
+  cpointer = carray;
+  fail_unless_equals_int_hex (GST_READ_UINT32_BE (cpointer++), 0x41424344);
+  fail_unless (cpointer == carray + 1);
+
+  cpointer = carray;
+  fail_unless_equals_int64_hex (GST_READ_UINT64_BE (cpointer++),
+      0x4142434445464748);
+  fail_unless (cpointer == carray + 1);
 }
 
 GST_END_TEST;
 
+GST_START_TEST (test_write_macros)
+{
+  guint8 carray[8];
+  guint8 *cpointer;
+
+  /* make sure the data argument is not duplicated inside the macro
+   * with possibly unexpected side-effects */
+  memset (carray, 0, sizeof (carray));
+  cpointer = carray;
+  GST_WRITE_UINT8 (cpointer++, 'A');
+  fail_unless_equals_pointer (cpointer, carray + 1);
+  fail_unless_equals_int (carray[0], 'A');
+
+  memset (carray, 0, sizeof (carray));
+  cpointer = carray;
+  GST_WRITE_UINT16_BE (cpointer++, 0x4142);
+  fail_unless_equals_pointer (cpointer, carray + 1);
+  fail_unless_equals_int (carray[0], 'A');
+  fail_unless_equals_int (carray[1], 'B');
+
+  memset (carray, 0, sizeof (carray));
+  cpointer = carray;
+  GST_WRITE_UINT32_BE (cpointer++, 0x41424344);
+  fail_unless_equals_pointer (cpointer, carray + 1);
+  fail_unless_equals_int (carray[0], 'A');
+  fail_unless_equals_int (carray[3], 'D');
+
+  memset (carray, 0, sizeof (carray));
+  cpointer = carray;
+  GST_WRITE_UINT64_BE (cpointer++, 0x4142434445464748);
+  fail_unless_equals_pointer (cpointer, carray + 1);
+  fail_unless_equals_int (carray[0], 'A');
+  fail_unless_equals_int (carray[7], 'H');
+
+  memset (carray, 0, sizeof (carray));
+  cpointer = carray;
+  GST_WRITE_UINT16_LE (cpointer++, 0x4142);
+  fail_unless_equals_pointer (cpointer, carray + 1);
+  fail_unless_equals_int (carray[0], 'B');
+  fail_unless_equals_int (carray[1], 'A');
+
+  memset (carray, 0, sizeof (carray));
+  cpointer = carray;
+  GST_WRITE_UINT32_LE (cpointer++, 0x41424344);
+  fail_unless_equals_pointer (cpointer, carray + 1);
+  fail_unless_equals_int (carray[0], 'D');
+  fail_unless_equals_int (carray[3], 'A');
+
+  memset (carray, 0, sizeof (carray));
+  cpointer = carray;
+  GST_WRITE_UINT64_LE (cpointer++, 0x4142434445464748);
+  fail_unless_equals_pointer (cpointer, carray + 1);
+  fail_unless_equals_int (carray[0], 'H');
+  fail_unless_equals_int (carray[7], 'A');
+}
+
+GST_END_TEST;
 static Suite *
 gst_utils_suite (void)
 {
@@ -1263,6 +1339,7 @@ gst_utils_suite (void)
   tcase_add_test (tc_chain, test_greatest_common_divisor);
 
   tcase_add_test (tc_chain, test_read_macros);
+  tcase_add_test (tc_chain, test_write_macros);
   return s;
 }