xref: /netbsd-src/external/lgpl3/gmp/dist/tests/misc.c (revision 1daf83e636cd998f45e5597a8f995a540e2d5b4a)
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
tests_start(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
tests_end(void)80 tests_end (void)
81 {
82   tests_rand_end ();
83   tests_memory_end ();
84 }
85 
86 static void
seed_from_tod(gmp_randstate_ptr rands)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
seed_from_urandom(gmp_randstate_ptr rands,FILE * fs)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
tests_rand_start(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
tests_rand_end(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 *
align_pointer(void * p,size_t align)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 *
__gmp_allocate_func_aligned(size_t bytes,size_t align)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 *
__gmp_allocate_or_reallocate(void * ptr,size_t oldsize,size_t newsize)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 *
__gmp_allocate_strdup(const char * s)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 *
strtoupper(char * s_orig)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
mpz_set_n(mpz_ptr z,mp_srcptr p,mp_size_t size)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
mpz_init_set_n(mpz_ptr z,mp_srcptr p,mp_size_t size)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
mpn_diff_lowest(mp_srcptr p1,mp_srcptr p2,mp_size_t size)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
mpn_diff_highest(mp_srcptr p1,mp_srcptr p2,mp_size_t size)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
byte_diff_lowest(const void * p1,const void * p2,mp_size_t size)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
byte_diff_highest(const void * p1,const void * p2,mp_size_t size)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
mpz_set_str_or_abort(mpz_ptr z,const char * str,int base)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
mpq_set_str_or_abort(mpq_ptr q,const char * str,int base)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
mpf_set_str_or_abort(mpf_ptr f,const char * str,int base)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
mpz_pow2abs_p(mpz_srcptr z)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
mpz_erandomb(mpz_ptr rop,gmp_randstate_t rstate,unsigned long nbits)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
mpz_erandomb_nonzero(mpz_ptr rop,gmp_randstate_t rstate,unsigned long nbits)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
mpz_errandomb(mpz_ptr rop,gmp_randstate_t rstate,unsigned long nbits)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
mpz_errandomb_nonzero(mpz_ptr rop,gmp_randstate_t rstate,unsigned long nbits)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
mpz_negrandom(mpz_ptr rop,gmp_randstate_t rstate)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
mpz_clobber(mpz_ptr rop)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
urandom(void)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
call_rand_algs(void (* func)(const char *,gmp_randstate_ptr))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
tests_infinity_d(void)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
tests_isinf(double d)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
tests_hardware_setround(int mode)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
tests_hardware_getround(void)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
tests_dbl_mant_bits(void)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
tests_sigfpe_handler(int sig)606 tests_sigfpe_handler (int sig)
607 {
608   longjmp (tests_sigfpe_target, 1);
609 }
610 
611 void
tests_sigfpe_done(void)612 tests_sigfpe_done (void)
613 {
614   signal (SIGFPE, SIG_DFL);
615 }
616