blob: 6c40d78b82992d19d3e0d26768203884e8172b6b [file] [log] [blame]
Austin Schuhbb1338c2024-06-15 19:31:16 -07001/* Miscellaneous test program support routines.
2
3Copyright 2000-2003, 2005, 2013, 2015, 2019 Free Software Foundation, Inc.
4
5This file is part of the GNU MP Library test suite.
6
7The GNU MP Library test suite is free software; you can redistribute it
8and/or modify it under the terms of the GNU General Public License as
9published by the Free Software Foundation; either version 3 of the License,
10or (at your option) any later version.
11
12The GNU MP Library test suite is distributed in the hope that it will be
13useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
15Public License for more details.
16
17You should have received a copy of the GNU General Public License along with
18the 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. */
48void
49tests_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}
72void
73tests_end (void)
74{
75 tests_rand_end ();
76 tests_memory_end ();
77}
78
79static void
80seed_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
97static void
98seed_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
110void
111tests_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}
153void
154tests_rand_end (void)
155{
156 RANDS_CLEAR ();
157}
158
159
160/* Only used if CPU calling conventions checking is available. */
161mp_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. */
167void *
168align_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. */
179void *
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
186void *
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
195char *
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
207char *
208strtoupper (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
218void
219mpz_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
228void
229mpz_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. */
242mp_size_t
243mpn_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. */
257mp_size_t
258mpn_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. */
272mp_size_t
273byte_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. */
287mp_size_t
288byte_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
301void
302mpz_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
313void
314mpq_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
325void
326mpf_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. */
339int
340mpz_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
366void
367mpz_erandomb (mpz_ptr rop, gmp_randstate_t rstate, unsigned long nbits)
368{
369 mpz_urandomb (rop, rstate, gmp_urandomm_ui (rstate, nbits));
370}
371
372void
373mpz_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
380void
381mpz_errandomb (mpz_ptr rop, gmp_randstate_t rstate, unsigned long nbits)
382{
383 mpz_rrandomb (rop, rstate, gmp_urandomm_ui (rstate, nbits));
384}
385
386void
387mpz_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
394void
395mpz_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
403void
404mpz_clobber(mpz_ptr rop)
405{
406 MPN_ZERO(PTR(rop), ALLOC(rop));
407 PTR(rop)[0] = 0xDEADBEEF;
408 SIZ(rop) = 0xDEFACE;
409}
410
411mp_limb_t
412urandom (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. */
427void
428call_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. */
474double
475tests_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. */
492int
493tests_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. */
508int
509tests_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. */
529int
530tests_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
554int
555tests_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
596jmp_buf tests_sigfpe_target;
597
598RETSIGTYPE
599tests_sigfpe_handler (int sig)
600{
601 longjmp (tests_sigfpe_target, 1);
602}
603
604void
605tests_sigfpe_done (void)
606{
607 signal (SIGFPE, SIG_DFL);
608}