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