Home | History | Annotate | Line # | Download | only in tests
      1 /* Miscellaneous test program support routines.
      2 
      3 Copyright 2000-2003, 2005, 2013, 2015, 2019 Free Software Foundation, Inc.
      4 
      5 This file is part of the GNU MP Library test suite.
      6 
      7 The GNU MP Library test suite is free software; you can redistribute it
      8 and/or modify it under the terms of the GNU General Public License as
      9 published by the Free Software Foundation; either version 3 of the License,
     10 or (at your option) any later version.
     11 
     12 The GNU MP Library test suite is distributed in the hope that it will be
     13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
     15 Public License for more details.
     16 
     17 You should have received a copy of the GNU General Public License along with
     18 the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
     19 
     20 #include "config.h"
     21 
     22 #include <ctype.h>
     23 #include <signal.h>
     24 #include <stdio.h>
     25 #include <stdlib.h>     /* for getenv */
     26 #include <string.h>
     27 
     28 #if HAVE_FLOAT_H
     29 #include <float.h>      /* for DBL_MANT_DIG */
     30 #endif
     31 
     32 #if TIME_WITH_SYS_TIME
     33 # include <sys/time.h>  /* for struct timeval */
     34 # include <time.h>
     35 #else
     36 # if HAVE_SYS_TIME_H
     37 #  include <sys/time.h>
     38 # else
     39 #  include <time.h>
     40 # endif
     41 #endif
     42 
     43 #include "gmp-impl.h"
     44 #include "tests.h"
     45 
     46 
     47 /* The various tests setups and final checks, collected up together. */
     48 void
     49 tests_start (void)
     50 {
     51   char version[10];
     52 #if __STDC_VERSION__ >= 199901L
     53   snprintf (version, sizeof version, "%u.%u.%u",
     54 	    __GNU_MP_VERSION,
     55 	    __GNU_MP_VERSION_MINOR,
     56 	    __GNU_MP_VERSION_PATCHLEVEL);
     57 #else
     58   sprintf (version, "%u.%u.%u",
     59 	    __GNU_MP_VERSION,
     60 	    __GNU_MP_VERSION_MINOR,
     61 	    __GNU_MP_VERSION_PATCHLEVEL);
     62 #endif
     63 
     64   if (strcmp (gmp_version, version) != 0)
     65     {
     66       fprintf (stderr, "tests are not linked to the newly compiled library\n");
     67       fprintf (stderr, "  local version is: %s\n", version);
     68       fprintf (stderr, "  linked version is: %s\n", gmp_version);
     69       abort ();
     70     }
     71 
     72   /* don't buffer, so output is not lost if a test causes a segv etc */
     73   setbuf (stdout, NULL);
     74   setbuf (stderr, NULL);
     75 
     76   tests_memory_start ();
     77   tests_rand_start ();
     78 }
     79 void
     80 tests_end (void)
     81 {
     82   tests_rand_end ();
     83   tests_memory_end ();
     84 }
     85 
     86 static void
     87 seed_from_tod (gmp_randstate_ptr  rands)
     88 {
     89   unsigned long seed;
     90 #if HAVE_GETTIMEOFDAY
     91   struct timeval  tv;
     92   gettimeofday (&tv, NULL);
     93   seed = tv.tv_sec ^ ((unsigned long) tv.tv_usec << 12);
     94   seed &= 0xffffffff;
     95 #else
     96   time_t  tv;
     97   time (&tv);
     98   seed = tv;
     99 #endif
    100   gmp_randseed_ui (rands, seed);
    101   printf ("Seed GMP_CHECK_RANDOMIZE=%lu (include this in bug reports)\n", seed);
    102 }
    103 
    104 static void
    105 seed_from_urandom (gmp_randstate_ptr rands, FILE *fs)
    106 {
    107   mpz_t seed;
    108   unsigned char buf[6];
    109   fread (buf, 1, 6, fs);
    110   mpz_init (seed);
    111   mpz_import (seed, 6, 1, 1, 0, 0, buf);
    112   gmp_randseed (rands, seed);
    113   gmp_printf ("Seed GMP_CHECK_RANDOMIZE=%Zd (include this in bug reports)\n", seed);
    114   mpz_clear (seed);
    115 }
    116 
    117 void
    118 tests_rand_start (void)
    119 {
    120   gmp_randstate_ptr  rands;
    121   char           *seed_string;
    122 
    123   if (__gmp_rands_initialized)
    124     {
    125       printf ("Please let tests_start() initialize the global __gmp_rands.\n");
    126       printf ("ie. ensure that function is called before the first use of RANDS.\n");
    127       abort ();
    128     }
    129 
    130   gmp_randinit_default (__gmp_rands);
    131   __gmp_rands_initialized = 1;
    132   rands = __gmp_rands;
    133 
    134   seed_string = getenv ("GMP_CHECK_RANDOMIZE");
    135   if (seed_string != NULL)
    136     {
    137       if (strcmp (seed_string, "0") != 0 &&
    138 	  strcmp (seed_string, "1") != 0)
    139         {
    140 	  mpz_t seed;
    141 	  mpz_init_set_str (seed, seed_string, 0);
    142           gmp_printf ("Re-seeding with GMP_CHECK_RANDOMIZE=%Zd\n", seed);
    143           gmp_randseed (rands, seed);
    144 	  mpz_clear (seed);
    145         }
    146       else
    147         {
    148 	  FILE *fs = fopen ("/dev/urandom", "r");
    149 	  if (fs != NULL)
    150 	    {
    151 	      seed_from_urandom (rands, fs);
    152 	      fclose (fs);
    153 	    }
    154 	  else
    155 	    seed_from_tod (rands);
    156         }
    157       fflush (stdout);
    158     }
    159 }
    160 void
    161 tests_rand_end (void)
    162 {
    163   RANDS_CLEAR ();
    164 }
    165 
    166 
    167 /* Only used if CPU calling conventions checking is available. */
    168 mp_limb_t (*calling_conventions_function) (ANYARGS);
    169 
    170 
    171 /* Return p advanced to the next multiple of "align" bytes.  "align" must be
    172    a power of 2.  Care is taken not to assume sizeof(int)==sizeof(pointer).
    173    Using "unsigned long" avoids a warning on hpux.  */
    174 void *
    175 align_pointer (void *p, size_t align)
    176 {
    177   gmp_intptr_t d;
    178   d = ((gmp_intptr_t) p) & (align-1);
    179   d = (d != 0 ? align-d : 0);
    180   return (void *) (((char *) p) + d);
    181 }
    182 
    183 
    184 /* Note that memory allocated with this function can never be freed, because
    185    the start address of the block allocated is lost. */
    186 void *
    187 __gmp_allocate_func_aligned (size_t bytes, size_t align)
    188 {
    189   return align_pointer ((*__gmp_allocate_func) (bytes + align-1), align);
    190 }
    191 
    192 
    193 void *
    194 __gmp_allocate_or_reallocate (void *ptr, size_t oldsize, size_t newsize)
    195 {
    196   if (ptr == NULL)
    197     return (*__gmp_allocate_func) (newsize);
    198   else
    199     return (*__gmp_reallocate_func) (ptr, oldsize, newsize);
    200 }
    201 
    202 char *
    203 __gmp_allocate_strdup (const char *s)
    204 {
    205   size_t  len;
    206   char    *t;
    207   len = strlen (s);
    208   t = (char *) (*__gmp_allocate_func) (len+1);
    209   memcpy (t, s, len+1);
    210   return t;
    211 }
    212 
    213 
    214 char *
    215 strtoupper (char *s_orig)
    216 {
    217   char  *s;
    218   for (s = s_orig; *s != '\0'; s++)
    219     if (islower (*s))
    220       *s = toupper (*s);
    221   return s_orig;
    222 }
    223 
    224 
    225 void
    226 mpz_set_n (mpz_ptr z, mp_srcptr p, mp_size_t size)
    227 {
    228   ASSERT (size >= 0);
    229   MPN_NORMALIZE (p, size);
    230   MPZ_REALLOC (z, size);
    231   MPN_COPY (PTR(z), p, size);
    232   SIZ(z) = size;
    233 }
    234 
    235 void
    236 mpz_init_set_n (mpz_ptr z, mp_srcptr p, mp_size_t size)
    237 {
    238   ASSERT (size >= 0);
    239 
    240   MPN_NORMALIZE (p, size);
    241   ALLOC(z) = MAX (size, 1);
    242   PTR(z) = __GMP_ALLOCATE_FUNC_LIMBS (ALLOC(z));
    243   SIZ(z) = size;
    244   MPN_COPY (PTR(z), p, size);
    245 }
    246 
    247 
    248 /* Find least significant limb position where p1,size and p2,size differ.  */
    249 mp_size_t
    250 mpn_diff_lowest (mp_srcptr p1, mp_srcptr p2, mp_size_t size)
    251 {
    252   mp_size_t  i;
    253 
    254   for (i = 0; i < size; i++)
    255     if (p1[i] != p2[i])
    256       return i;
    257 
    258   /* no differences */
    259   return -1;
    260 }
    261 
    262 
    263 /* Find most significant limb position where p1,size and p2,size differ.  */
    264 mp_size_t
    265 mpn_diff_highest (mp_srcptr p1, mp_srcptr p2, mp_size_t size)
    266 {
    267   mp_size_t  i;
    268 
    269   for (i = size-1; i >= 0; i--)
    270     if (p1[i] != p2[i])
    271       return i;
    272 
    273   /* no differences */
    274   return -1;
    275 }
    276 
    277 
    278 /* Find least significant byte position where p1,size and p2,size differ.  */
    279 mp_size_t
    280 byte_diff_lowest (const void *p1, const void *p2, mp_size_t size)
    281 {
    282   mp_size_t  i;
    283 
    284   for (i = 0; i < size; i++)
    285     if (((const char *) p1)[i] != ((const char *) p2)[i])
    286       return i;
    287 
    288   /* no differences */
    289   return -1;
    290 }
    291 
    292 
    293 /* Find most significant byte position where p1,size and p2,size differ.  */
    294 mp_size_t
    295 byte_diff_highest (const void *p1, const void *p2, mp_size_t size)
    296 {
    297   mp_size_t  i;
    298 
    299   for (i = size-1; i >= 0; i--)
    300     if (((const char *) p1)[i] != ((const char *) p2)[i])
    301       return i;
    302 
    303   /* no differences */
    304   return -1;
    305 }
    306 
    307 
    308 void
    309 mpz_set_str_or_abort (mpz_ptr z, const char *str, int base)
    310 {
    311   if (mpz_set_str (z, str, base) != 0)
    312     {
    313       fprintf (stderr, "ERROR: mpz_set_str failed\n");
    314       fprintf (stderr, "   str  = \"%s\"\n", str);
    315       fprintf (stderr, "   base = %d\n", base);
    316       abort();
    317     }
    318 }
    319 
    320 void
    321 mpq_set_str_or_abort (mpq_ptr q, const char *str, int base)
    322 {
    323   if (mpq_set_str (q, str, base) != 0)
    324     {
    325       fprintf (stderr, "ERROR: mpq_set_str failed\n");
    326       fprintf (stderr, "   str  = \"%s\"\n", str);
    327       fprintf (stderr, "   base = %d\n", base);
    328       abort();
    329     }
    330 }
    331 
    332 void
    333 mpf_set_str_or_abort (mpf_ptr f, const char *str, int base)
    334 {
    335   if (mpf_set_str (f, str, base) != 0)
    336     {
    337       fprintf (stderr, "ERROR mpf_set_str failed\n");
    338       fprintf (stderr, "   str  = \"%s\"\n", str);
    339       fprintf (stderr, "   base = %d\n", base);
    340       abort();
    341     }
    342 }
    343 
    344 
    345 /* Whether the absolute value of z is a power of 2. */
    346 int
    347 mpz_pow2abs_p (mpz_srcptr z)
    348 {
    349   mp_size_t  size, i;
    350   mp_srcptr  ptr;
    351 
    352   size = SIZ (z);
    353   if (size == 0)
    354     return 0;  /* zero is not a power of 2 */
    355   size = ABS (size);
    356 
    357   ptr = PTR (z);
    358   for (i = 0; i < size-1; i++)
    359     if (ptr[i] != 0)
    360       return 0;  /* non-zero low limb means not a power of 2 */
    361 
    362   return POW2_P (ptr[i]);  /* high limb power of 2 */
    363 }
    364 
    365 
    366 /* Exponentially distributed between 0 and 2^nbits-1, meaning the number of
    367    bits in the result is uniformly distributed between 0 and nbits-1.
    368 
    369    FIXME: This is not a proper exponential distribution, since the
    370    probability function will have a stepped shape due to using a uniform
    371    distribution after choosing how many bits.  */
    372 
    373 void
    374 mpz_erandomb (mpz_ptr rop, gmp_randstate_t rstate, unsigned long nbits)
    375 {
    376   mpz_urandomb (rop, rstate, gmp_urandomm_ui (rstate, nbits));
    377 }
    378 
    379 void
    380 mpz_erandomb_nonzero (mpz_ptr rop, gmp_randstate_t rstate, unsigned long nbits)
    381 {
    382   mpz_erandomb (rop, rstate, nbits);
    383   if (mpz_sgn (rop) == 0)
    384     mpz_set_ui (rop, 1L);
    385 }
    386 
    387 void
    388 mpz_errandomb (mpz_ptr rop, gmp_randstate_t rstate, unsigned long nbits)
    389 {
    390   mpz_rrandomb (rop, rstate, gmp_urandomm_ui (rstate, nbits));
    391 }
    392 
    393 void
    394 mpz_errandomb_nonzero (mpz_ptr rop, gmp_randstate_t rstate, unsigned long nbits)
    395 {
    396   mpz_errandomb (rop, rstate, nbits);
    397   if (mpz_sgn (rop) == 0)
    398     mpz_set_ui (rop, 1L);
    399 }
    400 
    401 void
    402 mpz_negrandom (mpz_ptr rop, gmp_randstate_t rstate)
    403 {
    404   mp_limb_t  n;
    405   _gmp_rand (&n, rstate, 1);
    406   if (n != 0)
    407     mpz_neg (rop, rop);
    408 }
    409 
    410 void
    411 mpz_clobber(mpz_ptr rop)
    412 {
    413   MPN_ZERO(PTR(rop), ALLOC(rop));
    414   PTR(rop)[0] = 0xDEADBEEF;
    415   SIZ(rop) = 0xDEFACE;
    416 }
    417 
    418 mp_limb_t
    419 urandom (void)
    420 {
    421 #if GMP_NAIL_BITS == 0
    422   mp_limb_t  n;
    423   _gmp_rand (&n, RANDS, GMP_LIMB_BITS);
    424   return n;
    425 #else
    426   mp_limb_t n[2];
    427   _gmp_rand (n, RANDS, GMP_LIMB_BITS);
    428   return n[0] + (n[1] << GMP_NUMB_BITS);
    429 #endif
    430 }
    431 
    432 
    433 /* Call (*func)() with various random number generators. */
    434 void
    435 call_rand_algs (void (*func) (const char *, gmp_randstate_ptr))
    436 {
    437   gmp_randstate_t  rstate;
    438   mpz_t            a;
    439 
    440   mpz_init (a);
    441 
    442   gmp_randinit_default (rstate);
    443   (*func) ("gmp_randinit_default", rstate);
    444   gmp_randclear (rstate);
    445 
    446   gmp_randinit_mt (rstate);
    447   (*func) ("gmp_randinit_mt", rstate);
    448   gmp_randclear (rstate);
    449 
    450   gmp_randinit_lc_2exp_size (rstate, 8L);
    451   (*func) ("gmp_randinit_lc_2exp_size 8", rstate);
    452   gmp_randclear (rstate);
    453 
    454   gmp_randinit_lc_2exp_size (rstate, 16L);
    455   (*func) ("gmp_randinit_lc_2exp_size 16", rstate);
    456   gmp_randclear (rstate);
    457 
    458   gmp_randinit_lc_2exp_size (rstate, 128L);
    459   (*func) ("gmp_randinit_lc_2exp_size 128", rstate);
    460   gmp_randclear (rstate);
    461 
    462   /* degenerate always zeros */
    463   mpz_set_ui (a, 0L);
    464   gmp_randinit_lc_2exp (rstate, a, 0L, 8L);
    465   (*func) ("gmp_randinit_lc_2exp a=0 c=0 m=8", rstate);
    466   gmp_randclear (rstate);
    467 
    468   /* degenerate always FFs */
    469   mpz_set_ui (a, 0L);
    470   gmp_randinit_lc_2exp (rstate, a, 0xFFL, 8L);
    471   (*func) ("gmp_randinit_lc_2exp a=0 c=0xFF m=8", rstate);
    472   gmp_randclear (rstate);
    473 
    474   mpz_clear (a);
    475 }
    476 
    477 
    478 /* Return +infinity if available, or 0 if not.
    479    We don't want to use libm, so INFINITY or other system values are not
    480    used here.  */
    481 double
    482 tests_infinity_d (void)
    483 {
    484 #if _GMP_IEEE_FLOATS
    485   union ieee_double_extract x;
    486   x.s.exp = 2047;
    487   x.s.manl = 0;
    488   x.s.manh = 0;
    489   x.s.sig = 0;
    490   return x.d;
    491 #else
    492   return 0;
    493 #endif
    494 }
    495 
    496 
    497 /* Return non-zero if d is an infinity (either positive or negative).
    498    Don't want libm, so don't use isinf() or other system tests.  */
    499 int
    500 tests_isinf (double d)
    501 {
    502 #if _GMP_IEEE_FLOATS
    503   union ieee_double_extract x;
    504   x.d = d;
    505   return (x.s.exp == 2047 && x.s.manl == 0 && x.s.manh == 0);
    506 #else
    507   return 0;
    508 #endif
    509 }
    510 
    511 
    512 /* Set the hardware floating point rounding mode.  Same mode values as mpfr,
    513    namely 0=nearest, 1=tozero, 2=up, 3=down.  Return 1 if successful, 0 if
    514    not.  */
    515 int
    516 tests_hardware_setround (int mode)
    517 {
    518 #if ! defined NO_ASM && HAVE_HOST_CPU_FAMILY_x86
    519   int  rc;
    520   switch (mode) {
    521   case 0: rc = 0; break;  /* nearest */
    522   case 1: rc = 3; break;  /* tozero  */
    523   case 2: rc = 2; break;  /* up      */
    524   case 3: rc = 1; break;  /* down    */
    525   default:
    526     return 0;
    527   }
    528   x86_fldcw ((x86_fstcw () & ~0xC00) | (rc << 10));
    529   return 1;
    530 #endif
    531 
    532   return 0;
    533 }
    534 
    535 /* Return the hardware floating point rounding mode, or -1 if unknown. */
    536 int
    537 tests_hardware_getround (void)
    538 {
    539 #if ! defined NO_ASM && HAVE_HOST_CPU_FAMILY_x86
    540   switch ((x86_fstcw () & ~0xC00) >> 10) {
    541   case 0: return 0; break;  /* nearest */
    542   case 1: return 3; break;  /* down    */
    543   case 2: return 2; break;  /* up      */
    544   case 3: return 1; break;  /* tozero  */
    545   }
    546 #endif
    547 
    548   return -1;
    549 }
    550 
    551 
    552 /* tests_dbl_mant_bits() determines by experiment the number of bits in the
    553    mantissa of a "double".  If it's not possible to find a value (perhaps
    554    due to the compiler optimizing too aggressively), then return 0.
    555 
    556    This code is used rather than DBL_MANT_DIG from <float.h> since ancient
    557    systems like SunOS don't have that file, and since one GNU/Linux ARM
    558    system was seen where the float emulation seemed to have only 32 working
    559    bits, not the 53 float.h claimed.  */
    560 
    561 int
    562 tests_dbl_mant_bits (void)
    563 {
    564   static int n = -1;
    565   volatile double x, y, d;
    566 
    567   if (n != -1)
    568     return n;
    569 
    570   n = 1;
    571   x = 2.0;
    572   for (;;)
    573     {
    574       /* see if 2^(n+1)+1 can be formed without rounding, if so then
    575          continue, if not then "n" is the answer */
    576       y = x + 1.0;
    577       d = y - x;
    578       if (d != 1.0)
    579         {
    580 #if defined (DBL_MANT_DIG) && DBL_RADIX == 2
    581           if (n != DBL_MANT_DIG)
    582             printf ("Warning, tests_dbl_mant_bits got %d but DBL_MANT_DIG says %d\n", n, DBL_MANT_DIG);
    583 #endif
    584           break;
    585         }
    586 
    587       x *= 2;
    588       n++;
    589 
    590       if (n > 1000)
    591         {
    592           printf ("Oops, tests_dbl_mant_bits can't determine mantissa size\n");
    593           n = 0;
    594           break;
    595         }
    596     }
    597   return n;
    598 }
    599 
    600 
    601 /* See tests_setjmp_sigfpe in tests.h. */
    602 
    603 jmp_buf    tests_sigfpe_target;
    604 
    605 RETSIGTYPE
    606 tests_sigfpe_handler (int sig)
    607 {
    608   longjmp (tests_sigfpe_target, 1);
    609 }
    610 
    611 void
    612 tests_sigfpe_done (void)
    613 {
    614   signal (SIGFPE, SIG_DFL);
    615 }
    616