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