diff options
author | Aleksander Morgado <aleksander@lanedo.com> | 2012-09-25 21:31:57 +0200 |
---|---|---|
committer | Aleksander Morgado <aleksander@lanedo.com> | 2012-09-25 21:31:57 +0200 |
commit | 3c1bf922804992b103fb3caac7f9669467f8a466 (patch) | |
tree | d40edee6cb3f3b0ab23459a7d5f8f4ddc25022a6 | |
parent | b4f01b63ddfb0130e5d34d7cb4222b7aa31b46cc (diff) |
libqmi-glib,utils: handle alignment issues when reading integers from the buffer
Some architectures require that the value of a pointer is aligned in memory.
Given that we're reading from a raw buffer, the integers in may not end up
aligned so we cannot safely cast any address to a valid 16/32/64 bit integer
value. Handle this by copying the integer from the raw buffer to an intermediate
properly aligned variable, before applying the endianness fix and returning it.
Also added new test cases to check this.
-rw-r--r-- | libqmi-glib/qmi-utils.c | 62 | ||||
-rw-r--r-- | libqmi-glib/test/test-utils.c | 300 |
2 files changed, 341 insertions, 21 deletions
diff --git a/libqmi-glib/qmi-utils.c b/libqmi-glib/qmi-utils.c index 4f0b292..c46f9d7 100644 --- a/libqmi-glib/qmi-utils.c +++ b/libqmi-glib/qmi-utils.c @@ -98,12 +98,15 @@ qmi_utils_read_guint16_from_buffer (guint8 **buffer, guint16 *buffer_size, guint16 *out) { + guint16 tmp; + g_assert (out != NULL); g_assert (buffer != NULL); g_assert (buffer_size != NULL); g_assert (*buffer_size >= 2); - *out = GUINT16_FROM_LE (*((guint16 *)&((*buffer)[0]))); + memcpy (&tmp, &((*buffer)[0]), sizeof (tmp)); + *out = GUINT16_FROM_LE (tmp); *buffer = &((*buffer)[2]); *buffer_size = (*buffer_size) - 2; @@ -114,12 +117,15 @@ qmi_utils_read_gint16_from_buffer (guint8 **buffer, guint16 *buffer_size, gint16 *out) { + gint16 tmp; + g_assert (out != NULL); g_assert (buffer != NULL); g_assert (buffer_size != NULL); g_assert (*buffer_size >= 2); - *out = GINT16_FROM_LE (*((guint16 *)&((*buffer)[0]))); + memcpy (&tmp, &((*buffer)[0]), sizeof (tmp)); + *out = GINT16_FROM_LE (tmp); *buffer = &((*buffer)[2]); *buffer_size = (*buffer_size) - 2; @@ -130,12 +136,15 @@ qmi_utils_read_guint32_from_buffer (guint8 **buffer, guint16 *buffer_size, guint32 *out) { + guint32 tmp; + g_assert (out != NULL); g_assert (buffer != NULL); g_assert (buffer_size != NULL); g_assert (*buffer_size >= 4); - *out = GUINT32_FROM_LE (*((guint32 *)&((*buffer)[0]))); + memcpy (&tmp, &((*buffer)[0]), sizeof (tmp)); + *out = GUINT32_FROM_LE (tmp); *buffer = &((*buffer)[4]); *buffer_size = (*buffer_size) - 4; @@ -146,12 +155,15 @@ qmi_utils_read_gint32_from_buffer (guint8 **buffer, guint16 *buffer_size, gint32 *out) { + gint32 tmp; + g_assert (out != NULL); g_assert (buffer != NULL); g_assert (buffer_size != NULL); g_assert (*buffer_size >= 4); - *out = GUINT32_FROM_LE (*((guint32 *)&((*buffer)[0]))); + memcpy (&tmp, &((*buffer)[0]), sizeof (tmp)); + *out = GUINT32_FROM_LE (tmp); *buffer = &((*buffer)[4]); *buffer_size = (*buffer_size) - 4; @@ -162,11 +174,14 @@ qmi_utils_read_guint64_from_buffer (guint8 **buffer, guint16 *buffer_size, guint64 *out) { + guint64 tmp; + g_assert (out != NULL); g_assert (buffer != NULL); g_assert (buffer_size != NULL); g_assert (*buffer_size >= 8); + memcpy (&tmp, &((*buffer)[0]), sizeof (tmp)); *out = GUINT64_FROM_LE (*((guint64 *)&((*buffer)[0]))); *buffer = &((*buffer)[8]); @@ -178,12 +193,15 @@ qmi_utils_read_gint64_from_buffer (guint8 **buffer, guint16 *buffer_size, gint64 *out) { + gint64 tmp; + g_assert (out != NULL); g_assert (buffer != NULL); g_assert (buffer_size != NULL); g_assert (*buffer_size >= 8); - *out = GUINT64_FROM_LE (*((guint64 *)&((*buffer)[0]))); + memcpy (&tmp, &((*buffer)[0]), sizeof (tmp)); + *out = GUINT64_FROM_LE (tmp); *buffer = &((*buffer)[8]); *buffer_size = (*buffer_size) - 8; @@ -219,7 +237,7 @@ qmi_utils_write_guint8_to_buffer (guint8 **buffer, g_assert (buffer_size != NULL); g_assert (*buffer_size >= 1); - (*buffer)[0] = *in; + memcpy (&(*buffer)[0], in, sizeof (*in)); *buffer = &((*buffer)[1]); *buffer_size = (*buffer_size) - 1; @@ -235,7 +253,7 @@ qmi_utils_write_gint8_to_buffer (guint8 **buffer, g_assert (buffer_size != NULL); g_assert (*buffer_size >= 1); - *((gint8 *)(&((*buffer)[0]))) = *in; + memcpy (&(*buffer)[0], in, sizeof (*in)); *buffer = &((*buffer)[1]); *buffer_size = (*buffer_size) - 1; @@ -246,12 +264,15 @@ qmi_utils_write_guint16_to_buffer (guint8 **buffer, guint16 *buffer_size, guint16 *in) { + guint16 tmp; + g_assert (in != NULL); g_assert (buffer != NULL); g_assert (buffer_size != NULL); g_assert (*buffer_size >= 2); - *((guint16 *)(&((*buffer)[0]))) = GUINT16_TO_LE (*in); + tmp = GUINT16_TO_LE (*in); + memcpy (&(*buffer)[0], &tmp, sizeof (tmp)); *buffer = &((*buffer)[2]); *buffer_size = (*buffer_size) - 2; @@ -262,12 +283,15 @@ qmi_utils_write_gint16_to_buffer (guint8 **buffer, guint16 *buffer_size, gint16 *in) { + gint16 tmp; + g_assert (in != NULL); g_assert (buffer != NULL); g_assert (buffer_size != NULL); g_assert (*buffer_size >= 2); - *((gint16 *)(&((*buffer)[0]))) = GINT16_TO_LE (*in); + tmp = GINT16_TO_LE (*in); + memcpy (&(*buffer)[0], &tmp, sizeof (tmp)); *buffer = &((*buffer)[2]); *buffer_size = (*buffer_size) - 2; @@ -278,12 +302,15 @@ qmi_utils_write_guint32_to_buffer (guint8 **buffer, guint16 *buffer_size, guint32 *in) { + guint32 tmp; + g_assert (in != NULL); g_assert (buffer != NULL); g_assert (buffer_size != NULL); g_assert (*buffer_size >= 4); - *((guint32 *)(&((*buffer)[0]))) = GUINT32_TO_LE (*in); + tmp = GUINT32_TO_LE (*in); + memcpy (&(*buffer)[0], &tmp, sizeof (tmp)); *buffer = &((*buffer)[4]); *buffer_size = (*buffer_size) - 4; @@ -294,12 +321,15 @@ qmi_utils_write_gint32_to_buffer (guint8 **buffer, guint16 *buffer_size, gint32 *in) { + gint32 tmp; + g_assert (in != NULL); g_assert (buffer != NULL); g_assert (buffer_size != NULL); g_assert (*buffer_size >= 4); - *((gint32 *)(&((*buffer)[0]))) = GINT32_TO_LE (*in); + tmp = GINT32_TO_LE (*in); + memcpy (&(*buffer)[0], &tmp, sizeof (tmp)); *buffer = &((*buffer)[4]); *buffer_size = (*buffer_size) - 4; @@ -310,12 +340,15 @@ qmi_utils_write_guint64_to_buffer (guint8 **buffer, guint16 *buffer_size, guint64 *in) { + guint64 tmp; + g_assert (in != NULL); g_assert (buffer != NULL); g_assert (buffer_size != NULL); g_assert (*buffer_size >= 8); - *((guint64 *)(&((*buffer)[0]))) = GUINT64_TO_LE (*in); + tmp = GUINT64_TO_LE (*in); + memcpy (&(*buffer)[0], &tmp, sizeof (tmp)); *buffer = &((*buffer)[8]); *buffer_size = (*buffer_size) - 8; @@ -326,12 +359,15 @@ qmi_utils_write_gint64_to_buffer (guint8 **buffer, guint16 *buffer_size, gint64 *in) { + gint64 tmp; + g_assert (in != NULL); g_assert (buffer != NULL); g_assert (buffer_size != NULL); g_assert (*buffer_size >= 8); - *((gint64 *)(&((*buffer)[0]))) = GINT64_TO_LE (*in); + tmp = GINT64_TO_LE (*in); + memcpy (&(*buffer)[0], &tmp, sizeof (tmp)); *buffer = &((*buffer)[8]); *buffer_size = (*buffer_size) - 8; diff --git a/libqmi-glib/test/test-utils.c b/libqmi-glib/test/test-utils.c index d64ae04..0a36172 100644 --- a/libqmi-glib/test/test-utils.c +++ b/libqmi-glib/test/test-utils.c @@ -150,6 +150,80 @@ test_utils_int16 (void) } static void +test_utils_uint16_unaligned (void) +{ + static guint8 in_buffer[9] = { + 0x00, 0x0F, 0x50, 0xEB, 0xE2, 0xB6, 0x00, 0x00, 0x00 + }; + static guint16 values[4] = { + 0x500F, 0xE2EB, 0x00B6, 0x0000 + }; + guint8 out_buffer[8] = { 0 }; + + guint i; + guint16 in_buffer_size; + guint8 *in_buffer_walker; + guint16 out_buffer_size; + guint8 *out_buffer_walker; + + in_buffer_size = sizeof (in_buffer) - 1; + in_buffer_walker = &in_buffer[1]; + out_buffer_size = sizeof (out_buffer); + out_buffer_walker = &out_buffer[0]; + i = 0; + + while (in_buffer_size) { + guint16 tmp; + + qmi_utils_read_guint16_from_buffer (&in_buffer_walker, &in_buffer_size, &tmp); + + g_assert (tmp == values[i++]); + + qmi_utils_write_guint16_to_buffer (&out_buffer_walker, &out_buffer_size, &tmp); + } + + g_assert_cmpuint (out_buffer_size, ==, 0); + g_assert (memcmp (&in_buffer[1], out_buffer, sizeof (in_buffer)) == 0); +} + +static void +test_utils_int16_unaligned (void) +{ + static guint8 in_buffer[9] = { + 0x00, 0x0F, 0x50, 0xEB, 0xE2, 0xB6, 0x00, 0x00, 0x00 + }; + static gint16 values[4] = { + 0x500F, 0xE2EB, 0x00B6, 0x0000 + }; + guint8 out_buffer[8] = { 0 }; + + guint i; + guint16 in_buffer_size; + guint8 *in_buffer_walker; + guint16 out_buffer_size; + guint8 *out_buffer_walker; + + in_buffer_size = sizeof (in_buffer) - 1; + in_buffer_walker = &in_buffer[1]; + out_buffer_size = sizeof (out_buffer); + out_buffer_walker = &out_buffer[0]; + i = 0; + + while (in_buffer_size) { + gint16 tmp; + + qmi_utils_read_gint16_from_buffer (&in_buffer_walker, &in_buffer_size, &tmp); + + g_assert (tmp == values[i++]); + + qmi_utils_write_gint16_to_buffer (&out_buffer_walker, &out_buffer_size, &tmp); + } + + g_assert_cmpuint (out_buffer_size, ==, 0); + g_assert (memcmp (&in_buffer[1], out_buffer, sizeof (in_buffer)) == 0); +} + +static void test_utils_uint32 (void) { static guint8 in_buffer[8] = { @@ -224,6 +298,80 @@ test_utils_int32 (void) } static void +test_utils_uint32_unaligned (void) +{ + static guint8 in_buffer[9] = { + 0x00, 0x0F, 0x50, 0xEB, 0xE2, 0xB6, 0x00, 0x00, 0x00 + }; + static guint32 values[2] = { + 0xE2EB500F, 0x000000B6 + }; + guint8 out_buffer[8] = { 0 }; + + guint i; + guint16 in_buffer_size; + guint8 *in_buffer_walker; + guint16 out_buffer_size; + guint8 *out_buffer_walker; + + in_buffer_size = sizeof (in_buffer) - 1; + in_buffer_walker = &in_buffer[1]; + out_buffer_size = sizeof (out_buffer); + out_buffer_walker = &out_buffer[0]; + i = 0; + + while (in_buffer_size) { + guint32 tmp; + + qmi_utils_read_guint32_from_buffer (&in_buffer_walker, &in_buffer_size, &tmp); + + g_assert (tmp == values[i++]); + + qmi_utils_write_guint32_to_buffer (&out_buffer_walker, &out_buffer_size, &tmp); + } + + g_assert_cmpuint (out_buffer_size, ==, 0); + g_assert (memcmp (&in_buffer[1], out_buffer, sizeof (in_buffer)) == 0); +} + +static void +test_utils_int32_unaligned (void) +{ + static guint8 in_buffer[9] = { + 0x00, 0x0F, 0x50, 0xEB, 0xE2, 0xB6, 0x00, 0x00, 0x00 + }; + static gint32 values[2] = { + 0xE2EB500F, 0x000000B6 + }; + guint8 out_buffer[8] = { 0 }; + + guint i; + guint16 in_buffer_size; + guint8 *in_buffer_walker; + guint16 out_buffer_size; + guint8 *out_buffer_walker; + + in_buffer_size = sizeof (in_buffer) - 1; + in_buffer_walker = &in_buffer[1]; + out_buffer_size = sizeof (out_buffer); + out_buffer_walker = &out_buffer[0]; + i = 0; + + while (in_buffer_size) { + gint32 tmp; + + qmi_utils_read_gint32_from_buffer (&in_buffer_walker, &in_buffer_size, &tmp); + + g_assert (tmp == values[i++]); + + qmi_utils_write_gint32_to_buffer (&out_buffer_walker, &out_buffer_size, &tmp); + } + + g_assert_cmpuint (out_buffer_size, ==, 0); + g_assert (memcmp (&in_buffer[1], out_buffer, sizeof (in_buffer)) == 0); +} + +static void test_utils_uint64 (void) { static guint8 in_buffer[8] = { @@ -298,6 +446,80 @@ test_utils_int64 (void) } static void +test_utils_uint64_unaligned (void) +{ + static guint8 in_buffer[9] = { + 0x00, 0x0F, 0x50, 0xEB, 0xE2, 0xB6, 0x00, 0x00, 0x00 + }; + static guint64 values[1] = { + 0x000000B6E2EB500FULL + }; + guint8 out_buffer[8] = { 0 }; + + guint i; + guint16 in_buffer_size; + guint8 *in_buffer_walker; + guint16 out_buffer_size; + guint8 *out_buffer_walker; + + in_buffer_size = sizeof (in_buffer) - 1; + in_buffer_walker = &in_buffer[1]; + out_buffer_size = sizeof (out_buffer); + out_buffer_walker = &out_buffer[0]; + i = 0; + + while (in_buffer_size) { + guint64 tmp; + + qmi_utils_read_guint64_from_buffer (&in_buffer_walker, &in_buffer_size, &tmp); + + g_assert (tmp == values[i++]); + + qmi_utils_write_guint64_to_buffer (&out_buffer_walker, &out_buffer_size, &tmp); + } + + g_assert_cmpuint (out_buffer_size, ==, 0); + g_assert (memcmp (&in_buffer[1], out_buffer, sizeof (in_buffer)) == 0); +} + +static void +test_utils_int64_unaligned (void) +{ + static guint8 in_buffer[9] = { + 0x00, 0x0F, 0x50, 0xEB, 0xE2, 0xB6, 0x00, 0x00, 0x00 + }; + static gint64 values[1] = { + 0x000000B6E2EB500FLL + }; + guint8 out_buffer[8] = { 0 }; + + guint i; + guint16 in_buffer_size; + guint8 *in_buffer_walker; + guint16 out_buffer_size; + guint8 *out_buffer_walker; + + in_buffer_size = sizeof (in_buffer) - 1; + in_buffer_walker = &in_buffer[1]; + out_buffer_size = sizeof (out_buffer); + out_buffer_walker = &out_buffer[0]; + i = 0; + + while (in_buffer_size) { + gint64 tmp; + + qmi_utils_read_gint64_from_buffer (&in_buffer_walker, &in_buffer_size, &tmp); + + g_assert (tmp == values[i++]); + + qmi_utils_write_gint64_to_buffer (&out_buffer_walker, &out_buffer_size, &tmp); + } + + g_assert_cmpuint (out_buffer_size, ==, 0); + g_assert (memcmp (&in_buffer[1], out_buffer, sizeof (in_buffer)) == 0); +} + +static void common_test_utils_uint_sized (guint n_bytes) { static guint8 in_buffer[8] = { @@ -349,6 +571,58 @@ test_utils_uint_sized (void) } } +static void +common_test_utils_uint_sized_unaligned (guint n_bytes) +{ + static guint8 in_buffer[9] = { + 0x00, 0x0F, 0x50, 0xEB, 0xE2, 0xB6, 0x00, 0x00, 0x00 + }; + guint64 value = 0x000000B6E2EB500FULL; + guint8 expected_out_buffer[8] = { 0 }; + guint8 out_buffer[8] = { 0 }; + + guint64 tmp; + guint i; + guint16 in_buffer_size; + guint8 *in_buffer_walker; + guint16 out_buffer_size; + guint8 *out_buffer_walker; + + /* Build expected intermediate value */ + tmp = 0xFF; + for (i = 1; i < n_bytes; i++) { + tmp <<= 8; + tmp |= 0xFF; + } + value &= tmp; + + /* Build expected output buffer */ + memcpy (expected_out_buffer, &in_buffer[1], n_bytes); + + in_buffer_size = sizeof (in_buffer) - 1; + in_buffer_walker = &in_buffer[1]; + out_buffer_size = sizeof (out_buffer); + out_buffer_walker = &out_buffer[0]; + i = 0; + + qmi_utils_read_sized_guint_from_buffer (&in_buffer_walker, &in_buffer_size, n_bytes, &tmp); + g_assert (tmp == value); + qmi_utils_write_sized_guint_to_buffer (&out_buffer_walker, &out_buffer_size, n_bytes, &tmp); + + g_assert_cmpuint (out_buffer_size, ==, 8 - n_bytes); + g_assert (memcmp (expected_out_buffer, out_buffer, sizeof (expected_out_buffer)) == 0); +} + +static void +test_utils_uint_sized_unaligned (void) +{ + guint i; + + for (i = 1; i <= 8; i++) { + common_test_utils_uint_sized_unaligned (i); + } +} + int main (int argc, char **argv) { g_type_init (); @@ -356,14 +630,24 @@ int main (int argc, char **argv) g_test_add_func ("/libqmi-glib/utils/uint8", test_utils_uint8); g_test_add_func ("/libqmi-glib/utils/int8", test_utils_int8); - g_test_add_func ("/libqmi-glib/utils/uint16", test_utils_uint16); - g_test_add_func ("/libqmi-glib/utils/int16", test_utils_int16); - g_test_add_func ("/libqmi-glib/utils/uint32", test_utils_uint32); - g_test_add_func ("/libqmi-glib/utils/int32", test_utils_int32); - g_test_add_func ("/libqmi-glib/utils/uint64", test_utils_uint64); - g_test_add_func ("/libqmi-glib/utils/int64", test_utils_int64); - - g_test_add_func ("/libqmi-glib/utils/uint-sized", test_utils_uint_sized); + + g_test_add_func ("/libqmi-glib/utils/uint16", test_utils_uint16); + g_test_add_func ("/libqmi-glib/utils/int16", test_utils_int16); + g_test_add_func ("/libqmi-glib/utils/uint16-unaligned", test_utils_uint16_unaligned); + g_test_add_func ("/libqmi-glib/utils/int16-unaligned", test_utils_int16_unaligned); + + g_test_add_func ("/libqmi-glib/utils/uint32", test_utils_uint32); + g_test_add_func ("/libqmi-glib/utils/int32", test_utils_int32); + g_test_add_func ("/libqmi-glib/utils/uint32/unaligned", test_utils_uint32_unaligned); + g_test_add_func ("/libqmi-glib/utils/int32/unaligned", test_utils_int32_unaligned); + + g_test_add_func ("/libqmi-glib/utils/uint64", test_utils_uint64); + g_test_add_func ("/libqmi-glib/utils/int64", test_utils_int64); + g_test_add_func ("/libqmi-glib/utils/uint64/unaligned", test_utils_uint64_unaligned); + g_test_add_func ("/libqmi-glib/utils/int64/unaligned", test_utils_int64_unaligned); + + g_test_add_func ("/libqmi-glib/utils/uint-sized", test_utils_uint_sized); + g_test_add_func ("/libqmi-glib/utils/uint-sized/unaligned", test_utils_uint_sized_unaligned); return g_test_run (); } |