1/* Memory allocation used during tests.
2
3Copyright 2001, 2002, 2007, 2013 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 <stdio.h>
21#include <stdlib.h>		/* for abort */
22#include <string.h>		/* for memcpy, memcmp */
23#include "gmp-impl.h"
24#include "tests.h"
25
26#if GMP_LIMB_BITS == 64
27#define PATTERN1 CNST_LIMB(0xcafebabedeadbeef)
28#define PATTERN2 CNST_LIMB(0xabacadabaedeedab)
29#else
30#define PATTERN1 CNST_LIMB(0xcafebabe)
31#define PATTERN2 CNST_LIMB(0xdeadbeef)
32#endif
33
34#if HAVE_INTPTR_T
35#define PTRLIMB(p)  ((mp_limb_t) (intptr_t) p)
36#else
37#define PTRLIMB(p)  ((mp_limb_t) (size_t) p)
38#endif
39
40/* Each block allocated is a separate malloc, for the benefit of a redzoning
41   malloc debugger during development or when bug hunting.
42
43   Sizes passed when reallocating or freeing are checked (the default
44   routines don't care about these).
45
46   Memory leaks are checked by requiring that all blocks have been freed
47   when tests_memory_end() is called.  Test programs must be sure to have
48   "clear"s for all temporary variables used.  */
49
50
51struct header {
52  void           *ptr;
53  size_t         size;
54  struct header  *next;
55};
56
57struct header  *tests_memory_list = NULL;
58
59/* Return a pointer to a pointer to the found block (so it can be updated
60   when unlinking). */
61struct header **
62tests_memory_find (void *ptr)
63{
64  struct header  **hp;
65
66  for (hp = &tests_memory_list; *hp != NULL; hp = &((*hp)->next))
67    if ((*hp)->ptr == ptr)
68      return hp;
69
70  return NULL;
71}
72
73int
74tests_memory_valid (void *ptr)
75{
76  return (tests_memory_find (ptr) != NULL);
77}
78
79void *
80tests_allocate (size_t size)
81{
82  struct header  *h;
83  void *rptr, *ptr;
84  mp_limb_t PATTERN2_var;
85
86  if (size == 0)
87    {
88      fprintf (stderr, "tests_allocate(): attempt to allocate 0 bytes\n");
89      abort ();
90    }
91
92  h = (struct header *) __gmp_default_allocate (sizeof (*h));
93  h->next = tests_memory_list;
94  tests_memory_list = h;
95
96  rptr = __gmp_default_allocate (size + 2 * sizeof (mp_limb_t));
97  ptr = (void *) ((gmp_intptr_t) rptr + sizeof (mp_limb_t));
98
99  *((mp_limb_t *) ((gmp_intptr_t) ptr - sizeof (mp_limb_t)))
100    = PATTERN1 - PTRLIMB (ptr);
101  PATTERN2_var = PATTERN2 - PTRLIMB (ptr);
102  memcpy ((void *) ((gmp_intptr_t) ptr + size), &PATTERN2_var, sizeof (mp_limb_t));
103
104  h->size = size;
105  h->ptr = ptr;
106  return h->ptr;
107}
108
109void *
110tests_reallocate (void *ptr, size_t old_size, size_t new_size)
111{
112  struct header  **hp, *h;
113  void *rptr;
114  mp_limb_t PATTERN2_var;
115
116  if (new_size == 0)
117    {
118      fprintf (stderr, "tests_reallocate(): attempt to reallocate %p to 0 bytes\n",
119	       ptr);
120      abort ();
121    }
122
123  hp = tests_memory_find (ptr);
124  if (hp == NULL)
125    {
126      fprintf (stderr, "tests_reallocate(): attempt to reallocate bad pointer %p\n",
127	       ptr);
128      abort ();
129    }
130  h = *hp;
131
132  if (h->size != old_size)
133    {
134      fprintf (stderr, "tests_reallocate(): bad old size %lu, should be %lu\n",
135	       (unsigned long) old_size, (unsigned long) h->size);
136      abort ();
137    }
138
139  if (*((mp_limb_t *) ((gmp_intptr_t) ptr - sizeof (mp_limb_t)))
140      != PATTERN1 - PTRLIMB (ptr))
141    {
142      fprintf (stderr, "in realloc: redzone clobbered before block\n");
143      abort ();
144    }
145  PATTERN2_var = PATTERN2 - PTRLIMB (ptr);
146  if (memcmp ((void *) ((gmp_intptr_t) ptr + h->size), &PATTERN2_var, sizeof (mp_limb_t)))
147    {
148      fprintf (stderr, "in realloc: redzone clobbered after block\n");
149      abort ();
150    }
151
152  rptr = __gmp_default_reallocate ((void *) ((gmp_intptr_t) ptr - sizeof (mp_limb_t)),
153				 old_size + 2 * sizeof (mp_limb_t),
154				 new_size + 2 * sizeof (mp_limb_t));
155  ptr = (void *) ((gmp_intptr_t) rptr + sizeof (mp_limb_t));
156
157  *((mp_limb_t *) ((gmp_intptr_t) ptr - sizeof (mp_limb_t)))
158    = PATTERN1 - PTRLIMB (ptr);
159  PATTERN2_var = PATTERN2 - PTRLIMB (ptr);
160  memcpy ((void *) ((gmp_intptr_t) ptr + new_size), &PATTERN2_var, sizeof (mp_limb_t));
161
162  h->size = new_size;
163  h->ptr = ptr;
164  return h->ptr;
165}
166
167struct header **
168tests_free_find (void *ptr)
169{
170  struct header  **hp = tests_memory_find (ptr);
171  if (hp == NULL)
172    {
173      fprintf (stderr, "tests_free(): attempt to free bad pointer %p\n",
174	       ptr);
175      abort ();
176    }
177  return hp;
178}
179
180void
181tests_free_nosize (void *ptr)
182{
183  struct header  **hp = tests_free_find (ptr);
184  struct header  *h = *hp;
185  mp_limb_t PATTERN2_var;
186
187  *hp = h->next;  /* unlink */
188
189  if (*((mp_limb_t *) ((gmp_intptr_t) ptr - sizeof (mp_limb_t)))
190      != PATTERN1 - PTRLIMB (ptr))
191    {
192      fprintf (stderr, "in free: redzone clobbered before block\n");
193      abort ();
194    }
195  PATTERN2_var = PATTERN2 - PTRLIMB (ptr);
196  if (memcmp ((void *) ((gmp_intptr_t) ptr + h->size), &PATTERN2_var, sizeof (mp_limb_t)))
197    {
198      fprintf (stderr, "in free: redzone clobbered after block\n");
199      abort ();
200    }
201
202  __gmp_default_free ((void *) ((gmp_intptr_t) ptr - sizeof(mp_limb_t)),
203		      h->size + 2 * sizeof (mp_limb_t));
204  __gmp_default_free (h, sizeof (*h));
205}
206
207void
208tests_free (void *ptr, size_t size)
209{
210  struct header  **hp = tests_free_find (ptr);
211  struct header  *h = *hp;
212
213  if (h->size != size)
214    {
215      fprintf (stderr, "tests_free(): bad size %lu, should be %lu\n",
216	       (unsigned long) size, (unsigned long) h->size);
217      abort ();
218    }
219
220  tests_free_nosize (ptr);
221}
222
223void
224tests_memory_start (void)
225{
226  mp_set_memory_functions (tests_allocate, tests_reallocate, tests_free);
227}
228
229void
230tests_memory_end (void)
231{
232  if (tests_memory_list != NULL)
233    {
234      struct header  *h;
235      unsigned  count;
236
237      fprintf (stderr, "tests_memory_end(): not all memory freed\n");
238
239      count = 0;
240      for (h = tests_memory_list; h != NULL; h = h->next)
241	count++;
242
243      fprintf (stderr, "    %u blocks remaining\n", count);
244      abort ();
245    }
246}
247