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