1 /*
2
3 Copyright 2013-2015, 2018 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 "testutils.h"
21
22 /* Include it here, so we we could tweak, e.g., how MPZ_REALLOC
23 works. */
24 #include "../mini-gmp.c"
25 #include "../mini-mpq.c"
26
27 static size_t total_alloc = 0;
28
29 /* Custom memory allocation to track memory usage, and add a small red
30 zone.
31
32 About alignment: In general, getting a block from malloc, and
33 incrementing it by sizeof(size_t), like we do here, might give a
34 pointer which is not properly aligned for all types. But the
35 largest type we allocate space for is unsigned long (mp_limb_t),
36 which shouldn't have stricter alignment requirements than
37 size_t. */
38
39 static unsigned char block_end[8] =
40 { 0x7c, 0x37, 0xd6, 0x12, 0xa8, 0x6c, 0x01, 0xd1 };
41
42 static void *
43 block_init (size_t *block, size_t size)
44 {
45 char *p;
46 *block++ = size;
47
48 p = (char *) block;
49 memcpy (p + size, block_end, sizeof(block_end));
50
51 total_alloc += size;
52 return p;
53 }
54
55 /* Check small redzone, return pointer to malloced block. */
56 static size_t *
57 block_check (void *p)
58 {
59 size_t *block = (size_t *) p - 1;
60 size_t size = block[0];
61
62 if (memcmp ((char *)p + size, block_end, sizeof(block_end)) != 0)
63 {
64 fprintf (stderr, "red zone overwritten.\n");
65 abort ();
66 }
67 total_alloc -= size;
68 return block;
69 }
70
71 static void *
72 tu_alloc (size_t size)
73 {
74 size_t *block = (size_t *) malloc (sizeof(size_t) + size + sizeof(block_end));
75 if (!block)
76 {
77 fprintf (stderr, "Virtual memory exhausted.\n");
78 abort ();
79 }
80
81 return block_init (block, size);
82 }
83
84 static void *
85 tu_realloc (void *p, size_t old_size, size_t new_size)
86 {
87 size_t *block;
88 size_t *old_block = block_check (p);
89 if (old_block[0] != old_size)
90 {
91 fprintf (stderr, "%s:%d: bad old_size: want %ld, got %ld.\n", __FILE__, __LINE__,
92 (long)old_block[0], (long)old_size);
93 abort ();
94 }
95
96 block = (size_t *) realloc (old_block, sizeof(size_t) + new_size + sizeof(block_end));
97 if (!block)
98 {
99 fprintf (stderr, "Virtual memory exhausted.\n");
100 abort ();
101 }
102
103 return block_init (block, new_size);
104 }
105
106 static void
107 tu_free (void *p, size_t old_size)
108 {
109 size_t *old_block = block_check (p);
110 if (old_block[0] != old_size && old_size != 0)
111 {
112 fprintf (stderr, "%s:%d: bad old_size: want %ld, got %ld.\n", __FILE__, __LINE__,
113 (long)old_block[0], (long)old_size);
114 abort ();
115 }
116 free (old_block);
117 }
118
119 /* Free memory allocated via mini-gmp allocation function. */
120 void
121 testfree (void *p, size_t size)
122 {
123 void (*freefunc) (void *, size_t);
124 mp_get_memory_functions (NULL, NULL, &freefunc);
125
126 freefunc (p, size);
127 }
128
129 int
130 main (int argc, char **argv)
131 {
132 hex_random_init ();
133
134 mp_set_memory_functions (tu_alloc, tu_realloc, tu_free);
135
136 /* Currently, t-comb seems to be the only program accepting any
137 arguments. It might make sense to parse common arguments here. */
138 testmain (argc, argv);
139
140 if (total_alloc != 0)
141 {
142 fprintf (stderr, "Memory leaked: %lu bytes.\n",
143 (unsigned long) total_alloc);
144 abort ();
145 }
146 return 0;
147 }
148
149 void
150 testhalves (int count, void (*tested_fun) (int))
151 {
152 void (*freefunc) (void *, size_t);
153 void *(*reallocfunc) (void *, size_t, size_t);
154 void *(*allocfunc) (size_t);
155 size_t initial_alloc;
156
157 mp_get_memory_functions (&allocfunc, &reallocfunc, &freefunc);
158 initial_alloc = total_alloc;
159 (*tested_fun) (count / 2);
160 if (initial_alloc != total_alloc)
161 {
162 fprintf (stderr, "First half, memory leaked: %lu bytes.\n",
163 (unsigned long) total_alloc - initial_alloc);
164 abort ();
165 }
166 mp_set_memory_functions (NULL, NULL, NULL);
167 (*tested_fun) (count / 2);
168 mp_set_memory_functions (allocfunc, reallocfunc, freefunc);
169 }
170
171 void
172 dump (const char *label, const mpz_t x)
173 {
174 char *buf = mpz_get_str (NULL, 16, x);
175 fprintf (stderr, "%s: %s\n", label, buf);
176 testfree (buf, strlen(buf) + 1);
177 }
178
179 void
180 mpz_set_str_or_abort (mpz_ptr z, const char *str, int base)
181 {
182 if (mpz_set_str (z, str, base) != 0)
183 {
184 fprintf (stderr, "ERROR: mpz_set_str failed\n");
185 fprintf (stderr, " str = \"%s\"\n", str);
186 fprintf (stderr, " base = %d\n", base);
187 abort();
188 }
189 }
190
191 int
192 mpz_lucas_mod (mpz_t V, mpz_t Qk, long Q,
193 mp_bitcnt_t b0, const mpz_t n)
194 {
195 return gmp_lucas_mod (V, Qk, Q, b0, n);
196 }