diff options
author | Marco Bodrato <bodrato@mail.dm.unipi.it> | 2019-11-09 15:22:02 +0100 |
---|---|---|
committer | Marco Bodrato <bodrato@mail.dm.unipi.it> | 2019-11-09 15:22:02 +0100 |
commit | a415c112f4d7ca8078f82a52f90a3a35e3c557c7 (patch) | |
tree | 544a5a1f48038d0a33b226a78dae7256edace9cf /mini-gmp | |
parent | 88b47aa8fd1dd3bfc9d0f046dd9aa0994f6ac280 (diff) | |
download | gmp-a415c112f4d7ca8078f82a52f90a3a35e3c557c7.tar.gz |
mini-gmp: Avoid undefined behaviour with small limb sizes
Diffstat (limited to 'mini-gmp')
-rw-r--r-- | mini-gmp/ChangeLog | 5 | ||||
-rw-r--r-- | mini-gmp/mini-gmp.c | 57 |
2 files changed, 45 insertions, 17 deletions
diff --git a/mini-gmp/ChangeLog b/mini-gmp/ChangeLog index 631b76b1b..b19c71f6c 100644 --- a/mini-gmp/ChangeLog +++ b/mini-gmp/ChangeLog @@ -1,3 +1,8 @@ +2018-10-09 Marco Bodrato <bodrato@mail.dm.unipi.it> + + * mini-gmp/mini-gmp.c (gmp_clz, gmp_popcount_limb, mpz_export): + Avoid undefined behaviour with small limb sizes. + 2019-09-30 Niels Möller <nisse@lysator.liu.se> * tests/t-gcd.c (gcdext_valid_p): Stricter checks for gcdext diff --git a/mini-gmp/mini-gmp.c b/mini-gmp/mini-gmp.c index e92e7cf9c..bb12acb07 100644 --- a/mini-gmp/mini-gmp.c +++ b/mini-gmp/mini-gmp.c @@ -94,11 +94,13 @@ see https://www.gnu.org/licenses/. */ #define gmp_clz(count, x) do { \ mp_limb_t __clz_x = (x); \ - unsigned __clz_c; \ - for (__clz_c = 0; \ - (__clz_x & ((mp_limb_t) 0xff << (GMP_LIMB_BITS - 8))) == 0; \ - __clz_c += 8) \ - __clz_x <<= 8; \ + unsigned __clz_c = 0; \ + int LOCAL_SHIFT_BITS = 8; \ + if (sizeof(mp_limb_t) * CHAR_BIT > LOCAL_SHIFT_BITS) \ + for (; \ + (__clz_x & ((mp_limb_t) 0xff << (GMP_LIMB_BITS - 8))) == 0; \ + __clz_c += 8) \ + { __clz_x <<= LOCAL_SHIFT_BITS; } \ for (; (__clz_x & GMP_LIMB_HIGHBIT) == 0; __clz_c++) \ __clz_x <<= 1; \ (count) = __clz_c; \ @@ -3990,13 +3992,18 @@ gmp_popcount_limb (mp_limb_t x) unsigned c; /* Do 16 bits at a time, to avoid limb-sized constants. */ - for (c = 0; x > 0; x >>= 16) + int LOCAL_SHIFT_BITS = 16; + for (c = 0; x > 0;) { unsigned w = x - ((x >> 1) & 0x5555); w = ((w >> 2) & 0x3333) + (w & 0x3333); w = (w >> 4) + w; w = ((w >> 8) & 0x000f) + (w & 0x000f); c += w; + if (sizeof(mp_limb_t) * CHAR_BIT > LOCAL_SHIFT_BITS) + x >>= LOCAL_SHIFT_BITS; + else + x = 0; } return c; } @@ -4503,10 +4510,15 @@ mpz_export (void *r, size_t *countp, int order, size_t size, int endian, limb = u->_mp_d[un-1]; assert (limb != 0); - k = 0; - do { - k++; limb >>= CHAR_BIT; - } while (limb != 0); + k = (sizeof (mp_limb_t) == 1); + if (!k) + { + do { + int LOCAL_CHAR_BIT = CHAR_BIT; + k++; limb >>= LOCAL_CHAR_BIT; + } while (limb != 0); + } + /* else limb = 0; */ count = (k + (un-1) * sizeof (mp_limb_t) + size - 1) / size; @@ -4535,17 +4547,28 @@ mpz_export (void *r, size_t *countp, int order, size_t size, int endian, for (bytes = 0, i = 0, k = 0; k < count; k++, p += word_step) { size_t j; - for (j = 0; j < size; j++, p -= (ptrdiff_t) endian) + for (j = 0; j < size; ++j, p -= (ptrdiff_t) endian) { - if (bytes == 0) + if (sizeof (mp_limb_t) == 1) { if (i < un) - limb = u->_mp_d[i++]; - bytes = sizeof (mp_limb_t); + *p = u->_mp_d[i++]; + else + *p = 0; + } + else + { + int LOCAL_CHAR_BIT = CHAR_BIT; + if (bytes == 0) + { + if (i < un) + limb = u->_mp_d[i++]; + bytes = sizeof (mp_limb_t); + } + *p = limb; + limb >>= LOCAL_CHAR_BIT; + bytes--; } - *p = limb; - limb >>= CHAR_BIT; - bytes--; } } assert (i == un); |