LAL  7.5.0.1-b72065a
LALMallocTest.c
Go to the documentation of this file.
1 /*
2 * Copyright (C) 2007 Bernd Machenschalk, Jolien Creighton
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with with program; see the file COPYING. If not, write to the
16 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17 * MA 02110-1301 USA
18 */
19 
20 /**
21  * \file
22  * \ingroup LALMalloc_h
23  *
24  * \brief Tests the routines in \ref LALMalloc_h.
25  *
26  * ### Usage ###
27  *
28  * \code
29  * LALMallocTest
30  * \endcode
31  *
32  * ### Description ###
33  *
34  * This program has ugly code for testing the LAL memory allocation and freeing
35  * routines.
36  *
37  * ### Exit codes ###
38  *
39  * <table>
40  * <tr><th>Code</th><th>Explanation</th></tr>
41  * <tr><td> 0</td><td>Success.</td></tr>
42  * <tr><td> 1</td><td>Failure.</td></tr>
43  * </table>
44  *
45  */
46 
47 /** \cond DONT_DOXYGEN */
48 
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <stdarg.h>
53 #include <setjmp.h>
54 #include <signal.h>
55 #include <lal/LALStdio.h>
56 #include <lal/LALStdlib.h>
57 
58 /* never use this... never! */
59 void XLALClobberDebugLevel(int);
60 
61 char caughtMessage[1024];
62 jmp_buf jump;
63 FILE *mystderr;
64 
65 /* replacement for LALRaise */
66 static int TestRaise( int sig, const char *fmt, ... )
67 {
68  va_list ap;
69  va_start( ap, fmt );
70  vsnprintf( caughtMessage, sizeof( caughtMessage ), fmt, ap );
71  va_end( ap );
72  longjmp( jump, sig );
73  return -1;
74 }
75 
76 #define STR( a ) #a
77 #define XSTR( a ) STR( a )
78 #define LINE ":" XSTR( __LINE__ ) ")\n"
79 #define trial( func, sig, msg ) \
80 do { \
81  int val; \
82  if ( ! ( val = setjmp( jump ) ) ) \
83  { \
84  func; \
85  if ( sig ) \
86  { \
87  fprintf( mystderr, "Error: no signal raised! (" #func LINE ); \
88  return 1; \
89  } \
90  } \
91  else \
92  { \
93  if ( val != sig ) \
94  { \
95  fprintf( mystderr, "Error: wrong signal raised! (" #func LINE ); \
96  fprintf( mystderr, "Received: %d %s", val, caughtMessage ); \
97  fprintf( mystderr, "Expected: %d %s\n", sig, msg ); \
98  return 1; \
99  } \
100  if ( NULL == strstr( caughtMessage, msg ) ) \
101  { \
102  fprintf( mystderr, "Error: wrong message! (" #func LINE ); \
103  fprintf( mystderr, "Received: %d %s", val, caughtMessage ); \
104  fprintf( mystderr, "Expected: %d %s\n", sig, msg ); \
105  return 1; \
106  } \
107  } \
108 } \
109 while ( 0 )
110 #define die(msg) \
111  do { \
112  fputs("Error: " #msg "\n", mystderr); \
113  exit(1); \
114  } while (0)
115 
116 /* make these global so they don't get clobbered by longjmp */
117 size_t i;
118 size_t j;
119 size_t n;
120 size_t *p;
121 size_t *q;
122 size_t *r;
123 size_t *s;
124 size_t **v;
125 
126 static int testOK( void )
127 {
128  int keep = lalDebugLevel;
129 
131  trial( p = LALMalloc( 1024 * sizeof( *p ) ), 0, "" );
132  for ( i = 0; i < 1024; ++i ) p[i] = i;
133  trial( q = LALCalloc( 1024, sizeof( *q ) ), 0, "" );
134  for ( i = 0; i < 1024; ++i ) if ( q[i] ) die( memory not blanked );
135  trial( p = LALRealloc( p, 4096 * sizeof( *p ) ), 0, "" );
136  for ( i = 0; i < 1024; ++i ) if ( p[i] != i ) die( memory not copied );
137  trial( q = LALRealloc( q, 0 ), 0, "" );
138  if ( q ) die( memory not freed );
139  trial( LALCheckMemoryLeaks(), SIGSEGV, "LALCheckMemoryLeaks: memory leak\n" );
140  if ( *( p - 1 ) != (size_t)0xABadCafe ) die( wrong magic );
141  if ( *( p - 2 ) != 4096 * sizeof( *p ) ) die( wrong size );
142  trial( LALFree( p ), 0, "" );
143  trial( LALCheckMemoryLeaks(), 0, "" );
144 
146  trial( p = LALMalloc( 1024 * sizeof( *p ) ), 0, "" );
147  for ( i = 0; i < 1024; ++i ) p[i] = i;
148  trial( q = LALCalloc( 1024, sizeof( *q ) ), 0, "" );
149  for ( i = 0; i < 1024; ++i ) if ( q[i] ) die( memory not blanked );
150  trial( p = LALRealloc( p, 4096 * sizeof( *p ) ), 0, "" );
151  for ( i = 0; i < 1024; ++i ) if ( p[i] != i ) die( memory not copied );
152  trial( q = LALRealloc( q, 0 ), 0, "" );
153  if ( q ) die( memory not freed );
154  trial( LALCheckMemoryLeaks(), SIGSEGV, "LALCheckMemoryLeaks: memory leak\n" );
155  trial( LALFree( p ), 0, "" );
156  trial( LALCheckMemoryLeaks(), 0, "" );
157 
160  trial( p = LALMalloc( 1024 * sizeof( *p ) ), 0, "" );
161  for ( i = 0; i < 1024; ++i ) p[i] = i;
162  trial( q = LALCalloc( 1024, sizeof( *q ) ), 0, "" );
163  for ( i = 0; i < 1024; ++i ) if ( q[i] ) die( memory not blanked );
164  trial( p = LALRealloc( p, 4096 * sizeof( *p ) ), 0, "" );
165  for ( i = 0; i < 1024; ++i ) if ( p[i] != i ) die( memory not copied );
166  trial( q = LALRealloc( q, 0 ), 0, "" );
167  if ( q ) die( memory not freed );
168  trial( LALCheckMemoryLeaks(), SIGSEGV, "LALCheckMemoryLeaks: memory leak\n" );
169  if ( *( p - 1 ) != (size_t)0xABadCafe ) die( wrong magic );
170  if ( *( p - 2 ) != 4096 * sizeof( *p ) ) die( wrong size );
171  trial( LALFree( p ), 0, "" );
172  trial( LALCheckMemoryLeaks(), 0, "" );
173 
175  trial( p = LALMalloc( 1024 * sizeof( *p ) ), 0, "" );
176  for ( i = 0; i < 1024; ++i ) p[i] = i;
177  trial( q = LALCalloc( 1024, sizeof( *q ) ), 0, "" );
178  for ( i = 0; i < 1024; ++i ) if ( q[i] ) die( memory not blanked );
179  trial( p = LALRealloc( p, 4096 * sizeof( *p ) ), 0, "" );
180  for ( i = 0; i < 1024; ++i ) if ( p[i] != i ) die( memory not copied );
181  trial( q = LALRealloc( q, 0 ), 0, "" );
182  /* if ( q ) die( memory not freed ); */
183  trial( LALCheckMemoryLeaks(), 0, "" );
184  trial( LALFree( p ), 0, "" );
185  trial( LALCheckMemoryLeaks(), 0, "" );
186 
187  XLALClobberDebugLevel(keep);
188  return 0;
189 }
190 
191 
192 /* test to make sure padding does what it's supposed to do */
193 static int testPadding( void )
194 {
195  int keep = lalDebugLevel;
196 
199 
200  /* try to free NULL pointer */
201  /* changed behaviour: LALFree is a no-op when passed NULL */
202  // trial( LALFree( NULL ), SIGSEGV, "error: tried to free NULL pointer" );
203 
204  /* double free */
205  /* actually, this cannot be done robustly -- system can change values
206  * in unallocated space at will */
207  //trial( p = LALMalloc( 2 * sizeof( *p ) ), 0, "" );
208  //trial( LALFree( p ), 0, "" );
209  //trial( LALFree( p ), SIGSEGV, "error: tried to free a freed pointer" );
210  //trial( LALCheckMemoryLeaks(), 0, "" );
211 
212  /* wrong magic */
213  trial( p = LALMalloc( 2 * sizeof( *p ) ), 0, "" );
214  p[-1] = 4;
215  trial( LALFree( p ), SIGSEGV, "error: wrong magic" );
216  p[-1] = 0xABadCafe;
217  trial( LALFree( p ), 0, "" );
218  trial( LALCheckMemoryLeaks(), 0, "" );
219 
220  /* corrupt size */
221  trial( p = LALMalloc( 4 * sizeof( *p ) ), 0, "");
222  n = p[-2];
223  p[-2] = -2;
224  trial( LALFree( p ), SIGSEGV, "error: corrupt size descriptor" );
225  p[-2] = n;
226  trial( LALFree( p ), 0, "" );
227  trial( LALCheckMemoryLeaks(), 0, "" );
228 
229  /* overwritten array bounds */
230  trial( p = LALMalloc( 8 * sizeof( *p ) ), 0, "" );
231  n = p[8];
232  p[8] = 0;
233  trial( LALFree( p ), SIGSEGV, "error: array bounds overwritten" );
234  p[8] = n;
235  trial( LALFree( p ), 0, "" );
236  trial( LALCheckMemoryLeaks(), 0, "" );
237 
238  /* free too much memory */
239  q = malloc( 4 * sizeof( *p ) );
240  trial( p = LALMalloc( sizeof( *p ) ), 0, "" );
241  memcpy( q, p - 2, 4 * sizeof( *p ) );
242  trial( LALFree( p ), 0, "" );
243  trial( LALFree( q + 2 ), SIGSEGV, "error: lalMallocTotal too small" );
244  free( q );
245  trial( LALCheckMemoryLeaks(), 0, "" );
246 
247  XLALClobberDebugLevel(keep);
248  return 0;
249 }
250 
251 /* test to make sure alloc list does what it's supposed to do */
252 static int testAllocList( void )
253 {
254  int keep = lalDebugLevel;
255 
256  s = malloc( sizeof( *s ) );
257 
260 
261  /* empty allocation list */
262  trial( LALCheckMemoryLeaks(), 0, "" );
263  trial( LALFree( s ), SIGSEGV, "not found" );
264 
265  /* can't find allocation in PopAlloc */
266  trial( p = LALMalloc( 2 * sizeof( *p ) ), 0, "" );
267  trial( q = LALMalloc( 4 * sizeof( *q ) ), 0, "" );
268  trial( r = LALMalloc( 8 * sizeof( *r ) ), 0, "" );
269  trial( LALFree( s ), SIGSEGV, "not found" );
270  trial( LALFree( p ), 0, "" );
271  trial( LALFree( r ), 0, "" );
272  trial( LALCheckMemoryLeaks(), SIGSEGV, "memory leak" );
273  trial( LALFree( q ), 0, "" );
274  trial( LALCheckMemoryLeaks(), 0, "" );
275 
276  /* can't find allocation in ModAlloc */
277  /* For some reason this next test fails on Snow Leopard... */
278  /* trial( s = LALRealloc( s, 1024 ), SIGSEGV, "not found" ); */
279  trial( p = LALRealloc( NULL, 2 * sizeof( *p ) ), 0, "" );
280  /* trial( s = LALRealloc( s, 1024 ), SIGSEGV, "not found" ); */
281  trial( LALFree( p ), 0, "" );
282  trial( LALCheckMemoryLeaks(), 0, "" );
283 
284  free( s );
285  XLALClobberDebugLevel(keep);
286  return 0;
287 }
288 
289 /* stress test the realloc routine */
290 static int stressTestRealloc( void )
291 {
292  const size_t nmax = 256;
293  int keep = lalDebugLevel;
294 
295  v = NULL;
296 
299 
300  /* ascending */
301  for ( n = 1; n <= nmax; ++n )
302  {
303  size_t *u;
304  trial( v = LALRealloc( v, n * sizeof( *v ) ), 0, "" );
305  trial( u = v[n - 1] = LALRealloc( NULL, n * sizeof( **v ) ), 0, "" );
306  for ( i = 0; i < n; ++i ) u[i] = n - 1;
307  for ( i = 0; i < n; ++i )
308  {
309  trial( u = v[i] = LALRealloc( v[i], n * sizeof( *u ) ), 0, "" );
310  for ( j = 0; j < n - 1; ++j )
311  if ( u[j] != n - 1 ) die( wrong contents );
312  for ( j = 0; j < n; ++j )
313  u[j] = n;
314  }
315  }
316 
317  for ( n = 0; n < nmax; ++n )
318  {
319  trial( v[n] = LALRealloc( v[n], 0 ), 0, "" );
320  }
321  trial( v = LALRealloc( v, 0 ), 0, "" );
322 
323  trial( LALCheckMemoryLeaks(), 0, "" );
324  XLALClobberDebugLevel(keep);
325  return 0;
326 }
327 
328 
329 int main( void )
330 {
333 
334  /* get rid of annoying messages from elsewhere */
335  setvbuf( mystderr = stdout, NULL, _IONBF, 0 );
336  FILE *fp = freopen( "/dev/null", "w", stderr );
337  if (fp == NULL) die ( unable to open /dev/null );
338 
339  lalRaiseHook = TestRaise;
340 
341  if ( testOK() ) return 1;
342  if ( testPadding() ) return 1;
343  if ( testAllocList() ) return 1;
344  if ( stressTestRealloc() ) return 1;
345 
346  trial( LALCheckMemoryLeaks(), 0, "" );
347 
348  return 0;
349 }
350 
351 /** \endcond */
int(* lalRaiseHook)(int, const char *,...)
Definition: LALError.c:57
static const size_t magic
Definition: LALMalloc.c:260
void LALCheckMemoryLeaks(void)
Definition: LALMalloc.c:784
#define LALRealloc(p, n)
Definition: LALMalloc.h:95
#define LALCalloc(m, n)
Definition: LALMalloc.h:94
#define LALMalloc(n)
Definition: LALMalloc.h:93
#define LALFree(p)
Definition: LALMalloc.h:96
int main(int argc, char *argv[])
Definition: cache.c:25
void XLALClobberDebugLevel(int level)
Definition: LALDebugLevel.c:54
int XLALGetDebugLevel(void)
#define lalDebugLevel
Definition: LALDebugLevel.h:58
@ LALMEMDBG
enable memory debugging tools
Definition: LALDebugLevel.h:53
@ LALMEMINFOBIT
enable memory info messages
Definition: LALDebugLevel.h:40
@ LALMEMPADBIT
enable memory padding
Definition: LALDebugLevel.h:38
@ LALMEMTRKBIT
enable memory tracking
Definition: LALDebugLevel.h:39
@ LALMEMDBGBIT
enable memory debugging routines
Definition: LALDebugLevel.h:37
static const INT4 r
Definition: Random.c:82
static const INT4 q
Definition: Random.c:81
FILE * fp
Definition: tconvert.c:105