[Gmp-commit] /var/hg/gmp: Avoid signed overflow (undefined behaviour) in mini...
mercurial at gmplib.org
mercurial at gmplib.org
Sun Nov 20 21:09:21 UTC 2016
details: /var/hg/gmp/rev/6a2a9d2f639c
changeset: 17120:6a2a9d2f639c
user: Niels M?ller <nisse at lysator.liu.se>
date: Sun Nov 20 22:09:04 2016 +0100
description:
Avoid signed overflow (undefined behaviour) in mini-gmp/tests/t-signed.
diffstat:
mini-gmp/ChangeLog | 5 +
mini-gmp/tests/t-signed.c | 188 +++++++++++++++++++++++++++++----------------
2 files changed, 124 insertions(+), 69 deletions(-)
diffs (261 lines):
diff -r 2e2072f55b3f -r 6a2a9d2f639c mini-gmp/ChangeLog
--- a/mini-gmp/ChangeLog Sat Nov 19 21:23:06 2016 +0100
+++ b/mini-gmp/ChangeLog Sun Nov 20 22:09:04 2016 +0100
@@ -1,3 +1,8 @@
+2016-11-20 Niels Möller <nisse at lysator.liu.se>
+
+ * tests/t-signed.c: Reorganize testcase, to avoid undefined
+ behaviour with signed overflow.
+
2016-11-19 Niels Möller <nisse at lysator.liu.se>
* tests/run-tests: Set up LD_LIBRARY_PATH and DYLD_LIBRARY_PATH
diff -r 2e2072f55b3f -r 6a2a9d2f639c mini-gmp/tests/t-signed.c
--- a/mini-gmp/tests/t-signed.c Sat Nov 19 21:23:06 2016 +0100
+++ b/mini-gmp/tests/t-signed.c Sun Nov 20 22:09:04 2016 +0100
@@ -17,55 +17,83 @@
You should have received a copy of the GNU General Public License along with
the GNU MP Library test suite. If not, see https://www.gnu.org/licenses/. */
+#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include "testutils.h"
+/* Always called with sz fitting in a signed long, and si is the
+ corresponding value. */
int
-check_si (mpz_t sz, mpz_t oz, long si, long oi, int c)
+check_si (const mpz_t sz, long si)
{
mpz_t t;
- int fail;
- if (mpz_cmp_si (sz, oi) != c)
+ /* Checks on sz/si */
+ if ((mpz_cmp_si (sz, si)) != 0)
{
- printf ("mpz_cmp_si (sz, %ld) != %i.\n", oi, c);
- printf (" sz="); mpz_out_str (stdout, 10, sz); printf ("\n");
- abort ();
+ printf ("mpz_cmp_si (sz, %ld) != 0.\n", si);
+ return 0;
}
-
- if ((si < oi ? -1 : si > oi) != c)
- return 1;
+ if (mpz_get_si (sz) != si)
+ {
+ printf ("mpz_get_si (sz) != %ld.\n", si);
+ return 0;
+ }
mpz_init_set_si (t, si);
- if ((fail = mpz_cmp_si (sz, si)) != 0)
- printf ("mpz_cmp_si (sz, %ld) != 0.\n", si);
- if (mpz_cmp_si (oz, si) != -c)
- printf ("mpz_cmp_si (oz, %ld) != %i.\n", si, -c), fail = 1;
- if (! mpz_fits_slong_p (sz))
- printf ("mpz_fits_slong_p (sz) != 1.\n"), fail = 1;
- if (mpz_get_si (sz) != si)
- printf ("mpz_get_si (sz) != %ld.\n", si), fail = 1;
if (mpz_cmp (t, sz) != 0)
{
printf ("mpz_init_set_si (%ld) failed.\n", si);
printf (" got="); mpz_out_str (stdout, 10, t); printf ("\n");
- fail = 1;
+ return 0;
}
mpz_clear (t);
+ return 1;
+}
- if (fail)
+/* Called with mpz_cmp (sz, oz) == c. If sz fits in a signed long,
+ si is the coresponding value, and similarly for oz and oi. */
+void
+check_si_cmp (const mpz_t sz, const mpz_t oz, long si, long oi, int c)
+{
+ if (mpz_cmp (sz, oz) != c)
{
- printf (" sz="); mpz_out_str (stdout, 10, sz); printf ("\n");
- printf (" oz="); mpz_out_str (stdout, 10, oz); printf ("\n");
- printf (" si=%ld\n", si);
- abort ();
+ printf ("mpz_cmp_si (sz, oz) != %i.\n", -c);
+ goto fail;
}
- return 0;
+ if (mpz_fits_slong_p (sz))
+ {
+ if (!check_si (sz, si))
+ goto fail;
+ if (mpz_cmp_si (oz, si) != -c)
+ {
+ printf ("mpz_cmp_si (oz, %ld) != %i.\n", si, -c);
+ goto fail;
+ }
+ }
+ if (mpz_fits_slong_p (oz))
+ {
+ if (!check_si (oz, oi))
+ goto fail;
+ if (mpz_cmp_si (sz, oi) != c)
+ {
+ printf ("mpz_cmp_si (sz, %ld) != %i.\n", oi, c);
+ goto fail;
+ }
+ }
+ return;
+
+ fail:
+ printf (" sz="); mpz_out_str (stdout, 10, sz); printf ("\n");
+ printf (" si=%ld\n", si);
+ printf (" oz="); mpz_out_str (stdout, 10, oz); printf ("\n");
+ printf (" oi=%ld\n", si);
+ abort ();
}
void
@@ -73,6 +101,7 @@
{
long si, oi;
mpz_t sz, oz;
+ unsigned overflow_count;
si = c;
mpz_init_set_si (sz, si);
@@ -80,63 +109,84 @@
oi = si;
mpz_init_set (oz, sz);
- do {
- si *= 2; /* c * 2^k */
- mpz_mul_2exp (sz, sz, 1);
-
- if (check_si (sz, oz, si, oi, c))
- {
- mpz_set (oz, sz);
- break;
- }
-
- oi = si + c; /* c * (2^k + 1) */
- if (c == -1)
- mpz_sub_ui (oz, sz, 1);
- else
- mpz_add_ui (oz, sz, 1);
+ /* To get a few tests with operands straddling the border, don't
+ stop at the very first operand exceeding a signed long. */
+ for (overflow_count = 0; overflow_count < 10; )
+ {
+ /* c * 2^k */
+ mpz_mul_2exp (sz, sz, 1);
+ if (mpz_fits_slong_p (sz))
+ si *= 2;
+ else
+ overflow_count++;
- if (check_si (oz, sz, oi, si, c))
- break;
+ check_si_cmp (sz, oz, si, oi, c);
+
+ /* c * (2^k + 1) */
+ if (c == -1)
+ mpz_sub_ui (oz, sz, 1);
+ else
+ mpz_add_ui (oz, sz, 1);
+ if (mpz_fits_slong_p (oz))
+ oi = si + c;
+ else
+ overflow_count++;
+ check_si_cmp (oz, sz, oi, si, c);
- oi = (si - c) * 2 + c; /* c * (2^K - 1) */
- mpz_mul_si (oz, sz, 2*c);
- if (c == -1)
- mpz_ui_sub (oz, 1, oz); /* oz = sz * 2 + 1 */
- else
- mpz_sub_ui (oz, oz, 1); /* oz = sz * 2 - 1 */
- } while (check_si (oz, sz, oi, si, c) == 0);
+ /* c * (2^K - 1) */
+ mpz_mul_si (oz, sz, 2*c);
+ if (c == -1)
+ mpz_ui_sub (oz, 1, oz); /* oz = sz * 2 + 1 */
+ else
+ mpz_sub_ui (oz, oz, 1); /* oz = sz * 2 - 1 */
+ if (mpz_fits_slong_p (oz))
+ oi = (si - c) * 2 + c;
+ else
+ overflow_count++;
+
+ check_si_cmp (oz, sz, oi, si, c);
+ };
+
+ mpz_clear (sz);
+ mpz_clear (oz);
+}
- mpz_clear (sz);
-
- if (mpz_fits_slong_p (oz))
+void
+try_fits_slong_p (void)
+{
+ mpz_t x;
+ mpz_init_set_si (x, LONG_MAX);
+ if (!mpz_fits_slong_p (x))
{
- printf ("Should not fit a signed long any more.\n");
- printf (" oz="); mpz_out_str (stdout, 10, oz); printf ("\n");
+ printf ("mpz_fits_slong_p (LONG_MAX) false!\n");
+ abort ();
+ }
+ mpz_add_ui (x, x, 1);
+ if (mpz_fits_slong_p (x))
+ {
+ printf ("mpz_fits_slong_p (LONG_MAX + 1) true!\n");
+ abort ();
+ }
+ mpz_set_si (x, LONG_MIN);
+ if (!mpz_fits_slong_p (x))
+ {
+ printf ("mpz_fits_slong_p (LONG_MIN) false!\n");
+ abort ();
+ }
+ mpz_sub_ui (x, x, 1);
+ if (mpz_fits_slong_p (x))
+ {
+ printf ("mpz_fits_slong_p (LONG_MIN - 1) true!\n");
abort ();
}
- if (mpz_cmp_si (oz, -c) != c)
- {
- printf ("mpz_cmp_si (oz, %i) != %i.\n", c, c);
- printf (" oz="); mpz_out_str (stdout, 10, oz); printf ("\n");
- abort ();
- }
-
- mpz_mul_2exp (oz, oz, 1);
- if (mpz_cmp_si (oz, -c) != c)
- {
- printf ("mpz_cmp_si (oz, %i) != %i.\n", c, c);
- printf (" oz="); mpz_out_str (stdout, 10, oz); printf ("\n");
- abort ();
- }
-
- mpz_clear (oz);
+ mpz_clear (x);
}
void
testmain (int argc, char *argv[])
{
+ try_fits_slong_p ();
try_op_si (-1);
try_op_si (1);
}
More information about the gmp-commit
mailing list