utils: avoid unexpected side-effects of GST_WRITE_* macros

Make sure the data argument is only evaluated once.
This commit is contained in:
Tim-Philipp Müller 2013-02-19 18:00:48 +00:00
parent 22b7c0bf58
commit 0cbe23995f
2 changed files with 119 additions and 34 deletions

View 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)
/**

View 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;
}