From d2f78ba3782534f2a2719fdbda20275f6c40c073 Mon Sep 17 00:00:00 2001 From: Vratislav Podzimek Date: Thu, 5 May 2016 15:20:43 +0200 Subject: [PATCH] Beware of unsigned long int on 32bit arches (#1333149) GMP has no function to assign an mpz_t instance from usigned long long int and unsigned long int may be just a 32bit number on some architectures. So let's just convert the number we get into a string and use the initializer from string instead. Signed-off-by: Vratislav Podzimek --- src/bs_size.c | 38 +++++++++++++++++++++++++++++++++++--- src/bs_size.h | 1 + tests/libbytesize_unittest.py | 6 ++++++ 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/src/bs_size.c b/src/bs_size.c index 71d7b48..8c55678 100644 --- a/src/bs_size.c +++ b/src/bs_size.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -329,8 +330,16 @@ BSSize bs_size_new (void) { * Returns: a new #BSSize */ BSSize bs_size_new_from_bytes (uint64_t bytes, int sgn) { + char *num_str = NULL; BSSize ret = bs_size_new (); - mpz_set_ui (ret->bytes, bytes); + int ok = 0; + + ok = asprintf (&num_str, "%"PRIu64, bytes); + if (ok == -1) + /* probably cannot allocate memory, there's nothing more we can do */ + return ret; + mpz_set_str (ret->bytes, num_str, 10); + free (num_str); if (sgn == -1) mpz_neg (ret->bytes, ret->bytes); return ret; @@ -475,13 +484,36 @@ BSSize bs_size_new_from_size (const BSSize size) { * Returns: the @size in a number of bytes */ uint64_t bs_size_get_bytes (const BSSize size, int *sgn, BSError **error) { - if (mpz_cmp_ui (size->bytes, UINT64_MAX) > 0) { + char *num_str = NULL; + mpz_t max; + uint64_t ret = 0; + int ok = 0; + + mpz_init2 (max, (mp_bitcnt_t) 64); + ok = asprintf (&num_str, "%"PRIu64, UINT64_MAX); + if (ok == -1) { + /* we probably cannot allocate memory so we are doomed */ + set_error (error, BS_ERROR_FAIL, strdup("Failed to allocate memory")); + mpz_clear (max); + return 0; + } + mpz_set_str (max, num_str, 10); + free (num_str); + if (mpz_cmp (size->bytes, max) > 0) { set_error (error, BS_ERROR_OVER, strdup("The size is too big, cannot be returned as a 64bit number of bytes")); return 0; } + mpz_clear (max); if (sgn) *sgn = mpz_sgn (size->bytes); - return (uint64_t) mpz_get_ui (size->bytes); + if (mpz_cmp_ui (size->bytes, UINT64_MAX) <= 0) + return (uint64_t) mpz_get_ui (size->bytes); + else { + num_str = bs_size_get_bytes_str (size); + ret = strtoull (num_str, NULL, 10); + free (num_str); + return ret; + } } /** diff --git a/src/bs_size.h b/src/bs_size.h index 0a961df..e7e29c6 100644 --- a/src/bs_size.h +++ b/src/bs_size.h @@ -24,6 +24,7 @@ typedef enum { BS_ERROR_INVALID_SPEC, BS_ERROR_OVER, BS_ERROR_ZERO_DIV, + BS_ERROR_FAIL } BSErrorCode; /** diff --git a/tests/libbytesize_unittest.py b/tests/libbytesize_unittest.py index ce4b01d..e57dc0b 100755 --- a/tests/libbytesize_unittest.py +++ b/tests/libbytesize_unittest.py @@ -123,6 +123,12 @@ class SizeTestCase(unittest.TestCase): actual = SizeStruct.new_from_bytes(1024, -1).get_bytes() expected = (1024, -1) self.assertEqual(actual, expected) + + # now let's try something bigger than MAXUINT32 + actual = SizeStruct.new_from_bytes(5718360*1024, 1).get_bytes() + expected = (5718360*1024, 1) + self.assertEqual(actual, expected) + #enddef def testNewFromSizeStruct(self): -- 2.5.5