]> git.sur5r.net Git - openldap/blob - libraries/liblber/memory.c
a500569cdc59feac0eb18055211849f4c7c5e937
[openldap] / libraries / liblber / memory.c
1 /* $OpenLDAP$ */
2 /*
3  * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
4  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5  */
6 #include "portable.h"
7
8 #include <ac/stdlib.h>
9 #include <ac/string.h>
10
11 #include "lber-int.h"
12
13 #ifdef LDAP_MEMORY_TRACE
14 # ifndef LDAP_MEMORY_DEBUG
15 #  define LDAP_MEMORY_DEBUG 1
16 # endif
17 #include <stdio.h>
18 #endif
19
20 #if LDAP_MEMORY_DEBUG
21 /*
22  * LDAP_MEMORY_DEBUG should only be enabled for the purposes of
23  * debugging memory management within OpenLDAP libraries and slapd.
24  * It should only be enabled by an experienced developer as it
25  * causes the inclusion of numerous assert()'s, many of which may
26  * be triggered by a prefectly valid program.
27  *
28  * The code behind this macro is subject to change as needed to
29  * support this testing.
30  */
31
32 struct ber_mem_hdr {
33         ber_int_t       bm_top; /* Pattern to detect buf overrun from prev buffer */
34         ber_int_t       bm_length; /* Length of user allocated area */
35 #ifdef LDAP_MEMORY_TRACE
36         ber_int_t       bm_sequence; /* Allocation sequence number */
37 #endif
38         union bmu_align_u {     /* Force alignment, pattern to detect back clobber */
39                 ber_len_t       bmu_len_t;
40                 ber_tag_t       bmu_tag_t;
41                 ber_int_t       bmu_int_t;
42
43                 size_t  bmu_size_t;
44                 void *  bmu_voidp;
45                 double  bmu_double;
46                 long    bmu_long;
47                 long    (*bmu_funcp)( double );
48                 unsigned char   bmu_char[4];
49         } ber_align;
50 #define bm_junk ber_align.bmu_len_t
51 #define bm_data ber_align.bmu_char[1]
52 #define bm_char ber_align.bmu_char
53 };
54
55 /* Pattern at top of allocated space */
56 #define BER_MEM_JUNK 0xdeaddadaU
57
58 static const struct ber_mem_hdr ber_int_mem_hdr = { BER_MEM_JUNK, 0, 0 };
59
60 /* Note sequence and ber_int_options.lbu_meminuse are counters, but are not
61  * thread safe.  If you want to use these values for multithreaded applications,
62  * you must put mutexes around them, otherwise they will have incorrect values.
63  * When debugging, if you sort the debug output, the sequence number will 
64  * put allocations/frees together.  It is then a simple matter to write a script
65  * to find any allocations that don't have a buffer free function.
66  */
67 #ifdef LDAP_MEMORY_TRACE
68 static ber_int_t sequence = 0;
69 #endif
70
71 /* Pattern placed just before user data */
72 static unsigned char toppattern[4] = { 0xde, 0xad, 0xba, 0xde };
73 /* Pattern placed just after user data */
74 static unsigned char endpattern[4] = { 0xd1, 0xed, 0xde, 0xca };
75
76 #define mbu_len sizeof(ber_int_mem_hdr.ber_align)
77
78 /* Test if pattern placed just before user data is good */
79 #define testdatatop(val) ( \
80         *(val->bm_char+mbu_len-4)==toppattern[0] && \
81         *(val->bm_char+mbu_len-3)==toppattern[1] && \
82         *(val->bm_char+mbu_len-2)==toppattern[2] && \
83         *(val->bm_char+mbu_len-1)==toppattern[3] )
84
85 /* Place pattern just before user data */
86 #define setdatatop(val) *(val->bm_char+mbu_len-4)=toppattern[0]; \
87         *(val->bm_char+mbu_len-3)=toppattern[1]; \
88         *(val->bm_char+mbu_len-2)=toppattern[2]; \
89         *(val->bm_char+mbu_len-1)=toppattern[3];
90
91 /* Test if pattern placed just after user data is good */
92 #define testend(val) (  *((unsigned char *)val+0)==endpattern[0] && \
93         *((unsigned char *)val+1)==endpattern[1] && \
94         *((unsigned char *)val+2)==endpattern[2] && \
95         *((unsigned char *)val+3)==endpattern[3] )
96
97 /* Place pattern just after user data */
98 #define setend(val)     *((unsigned char *)val+0)=endpattern[0]; \
99         *((unsigned char *)val+1)=endpattern[1]; \
100         *((unsigned char *)val+2)=endpattern[2]; \
101         *((unsigned char *)val+3)=endpattern[3];
102
103 #define BER_MEM_BADADDR ((void *) &ber_int_mem_hdr.bm_data)
104 #define BER_MEM_VALID(p)        do { \
105                 assert( (p) != BER_MEM_BADADDR );       \
106                 assert( (p) != (void *) &ber_int_mem_hdr );     \
107         } while(0)
108
109 #else
110 #define BER_MEM_VALID(p)        /* no-op */
111 #endif
112
113 BerMemoryFunctions *ber_int_memory_fns = NULL;
114
115 #if 0 && defined( LDAP_MEMORY_DEBUG )
116 void
117 ber_int_memfree( void **p )
118 {
119         assert( p != NULL );
120         BER_MEM_VALID( *p );
121
122         ber_memfree( p );
123
124         *p = BER_MEM_BADADDR;
125 }
126 #endif
127
128 void
129 ber_memfree( void *p )
130 {
131     ber_int_options.lbo_valid = LBER_INITIALIZED;
132
133         if( p == NULL ) {
134                 return;
135         }
136
137         BER_MEM_VALID( p );
138
139         if( ber_int_memory_fns == NULL ) {
140 #ifdef LDAP_MEMORY_DEBUG
141                 struct ber_mem_hdr *mh = (struct ber_mem_hdr *)
142                         ((char *)p - sizeof(struct ber_mem_hdr));
143                 assert( mh->bm_top == BER_MEM_JUNK);
144                 assert( testdatatop( mh));
145                 assert( testend( (char *)&mh[1] + mh->bm_length) );
146                 ber_int_options.lbo_meminuse -= mh->bm_length;
147
148 #ifdef LDAP_MEMORY_TRACE
149                 fprintf(stderr, "0x%08x 0x%08x -f- %d ber_memfree %d\n",
150                         mh->bm_sequence, mh, mh->bm_length, ber_int_options.lbo_meminuse);
151 #endif
152                 /* Fill the free space with poison */
153                 memset( mh, 0xff, mh->bm_length + sizeof(struct ber_mem_hdr) + sizeof( ber_int_t));
154                 free( mh );
155 #else
156                 free( p );
157 #endif
158                 return;
159         }
160
161         assert( ber_int_memory_fns->bmf_free );
162
163         (*ber_int_memory_fns->bmf_free)( p );
164 }
165
166
167 void
168 ber_memvfree( void **vec )
169 {
170         int     i;
171
172     ber_int_options.lbo_valid = LBER_INITIALIZED;
173
174         if( vec == NULL ) {
175                 return;
176         }
177
178         BER_MEM_VALID( vec );
179
180         for ( i = 0; vec[i] != NULL; i++ ) {
181                 LBER_FREE( vec[i] );
182         }
183
184         LBER_FREE( vec );
185 }
186
187
188 void *
189 ber_memalloc( ber_len_t s )
190 {
191         void *new;
192     ber_int_options.lbo_valid = LBER_INITIALIZED;
193
194 #ifdef LDAP_MEMORY_DEBUG
195         assert( s != 0 );
196 #endif
197
198         if( s == 0 ) {
199                 return NULL;
200         }
201
202         if( ber_int_memory_fns == NULL ) {
203 #ifdef LDAP_MEMORY_DEBUG
204                 struct ber_mem_hdr *mh = malloc(s + sizeof(struct ber_mem_hdr) + sizeof( ber_int_t));
205                 if( mh == NULL ) return NULL;
206
207                 mh->bm_top = BER_MEM_JUNK;
208                 mh->bm_length = s;
209                 setdatatop( mh);
210                 setend( (char *)&mh[1] + mh->bm_length );
211
212                 ber_int_options.lbo_meminuse += mh->bm_length;  /* Count mem inuse */
213
214 #ifdef LDAP_MEMORY_TRACE
215                 mh->bm_sequence = sequence++;
216                 fprintf(stderr, "0x%08x 0x%08x -a- %d ber_memalloc %d\n",
217                         mh->bm_sequence, mh, mh->bm_length, ber_int_options.lbo_meminuse);
218 #endif
219                 /* poison new memory */
220                 memset( (char *)&mh[1], 0xff, s);
221
222                 BER_MEM_VALID( &mh[1] );
223                 new = &mh[1];
224 #else
225                 new = malloc( s );
226 #endif
227         } else {
228                 new = (*ber_int_memory_fns->bmf_malloc)( s );
229         }
230
231         if( new == NULL ) {
232                 ber_errno = LBER_ERROR_MEMORY;
233         }
234
235         return new;
236 }
237
238
239 void *
240 ber_memcalloc( ber_len_t n, ber_len_t s )
241 {
242         void *new;
243     ber_int_options.lbo_valid = LBER_INITIALIZED;
244
245 #ifdef LDAP_MEMORY_DEBUG
246         assert( n != 0 && s != 0);
247 #endif
248
249         if( n == 0 || s == 0 ) {
250                 return NULL;
251         }
252
253         if( ber_int_memory_fns == NULL ) {
254 #ifdef LDAP_MEMORY_DEBUG
255                 struct ber_mem_hdr *mh = calloc(1,
256                         (n * s) + sizeof(struct ber_mem_hdr) + sizeof(ber_int_t) );
257                 if( mh == NULL ) return NULL;
258
259                 mh->bm_top = BER_MEM_JUNK;
260                 mh->bm_length = n*s;
261                 setdatatop( mh);
262                 setend( (char *)&mh[1] + mh->bm_length );
263
264                 ber_int_options.lbo_meminuse += mh->bm_length;
265
266 #ifdef LDAP_MEMORY_TRACE
267                 mh->bm_sequence = sequence++;
268                 fprintf(stderr, "0x%08x 0x%08x -a- %d ber_memcalloc %d\n",
269                         mh->bm_sequence, mh, mh->bm_length, ber_int_options.lbo_meminuse);
270 #endif
271                 BER_MEM_VALID( &mh[1] );
272                 new = &mh[1];
273 #else
274                 new = calloc( n, s );
275 #endif
276
277         } else {
278                 new = (*ber_int_memory_fns->bmf_calloc)( n, s );
279         }
280
281         if( new == NULL ) {
282                 ber_errno = LBER_ERROR_MEMORY;
283         }
284
285         return new;
286 }
287
288
289 void *
290 ber_memrealloc( void* p, ber_len_t s )
291 {
292         void *new = NULL;
293     ber_int_options.lbo_valid = LBER_INITIALIZED;
294
295         /* realloc(NULL,s) -> malloc(s) */
296         if( p == NULL ) {
297                 return ber_memalloc( s );
298         }
299         
300         /* realloc(p,0) -> free(p) */
301         if( s == 0 ) {
302                 ber_memfree( p );
303                 return NULL;
304         }
305
306         BER_MEM_VALID( p );
307
308         if( ber_int_memory_fns == NULL ) {
309 #ifdef LDAP_MEMORY_DEBUG
310                 ber_int_t oldlen;
311                 struct ber_mem_hdr *mh = (struct ber_mem_hdr *)
312                         ((char *)p - sizeof(struct ber_mem_hdr));
313                 assert( mh->bm_top == BER_MEM_JUNK);
314                 assert( testdatatop( mh));
315                 assert( testend( (char *)&mh[1] + mh->bm_length) );
316                 oldlen = mh->bm_length;
317
318                 p = realloc( mh, s + sizeof(struct ber_mem_hdr) + sizeof(ber_int_t) );
319                 if( p == NULL ) {
320                         ber_errno = LBER_ERROR_MEMORY;
321                         return NULL;
322                 }
323
324                         mh = p;
325                 mh->bm_length = s;
326                 setend( (char *)&mh[1] + mh->bm_length );
327                 if( (s - oldlen) > 0 ) {
328                         /* poison any new memory */
329                         memset( (char *)&mh[1] + oldlen, 0xff, s - oldlen);
330                 }
331
332                 assert( mh->bm_top == BER_MEM_JUNK);
333                 assert( testdatatop( mh));
334
335                 ber_int_options.lbo_meminuse += s - oldlen;
336 #ifdef LDAP_MEMORY_TRACE
337                 fprintf(stderr, "0x%08x 0x%08x -a- %d ber_memrealloc %d\n",
338                         mh->bm_sequence, mh, mh->bm_length, ber_int_options.lbo_meminuse);
339 #endif
340                         BER_MEM_VALID( &mh[1] );
341                 return &mh[1];
342 #else
343                 new = realloc( p, s );
344 #endif
345         } else {
346                 new = (*ber_int_memory_fns->bmf_realloc)( p, s );
347         }
348
349         if( new == NULL ) {
350                 ber_errno = LBER_ERROR_MEMORY;
351         }
352
353         return new;
354 }
355
356
357 void
358 ber_bvfree( struct berval *bv )
359 {
360         ber_int_options.lbo_valid = LBER_INITIALIZED;
361
362         if( bv == NULL ) {
363                 return;
364         }
365
366         BER_MEM_VALID( bv );
367
368         if ( bv->bv_val != NULL )
369                 LBER_FREE( bv->bv_val );
370
371         LBER_FREE( (char *) bv );
372 }
373
374
375 void
376 ber_bvecfree( struct berval **bv )
377 {
378         int     i;
379
380         ber_int_options.lbo_valid = LBER_INITIALIZED;
381
382         if( bv == NULL ) {
383                 return;
384         }
385
386         BER_MEM_VALID( bv );
387
388         for ( i = 0; bv[i] != NULL; i++ )
389                 ber_bvfree( bv[i] );
390
391         LBER_FREE( (char *) bv );
392 }
393
394 int
395 ber_bvecadd( struct berval ***bvec, struct berval *bv )
396 {
397         ber_len_t i;
398         struct berval **new;
399
400         ber_int_options.lbo_valid = LBER_INITIALIZED;
401
402         if( bvec == NULL ) {
403                 if( bv == NULL ) {
404                         /* nothing to add */
405                         return 0;
406                 }
407
408                 *bvec = ber_memalloc( 2 * sizeof(struct berval *) );
409
410                 if( *bvec == NULL ) {
411                         return -1;
412                 }
413
414                 (*bvec)[0] = bv;
415                 (*bvec)[1] = NULL;
416
417                 return 1;
418         }
419
420         BER_MEM_VALID( bvec );
421
422         /* count entries */
423         for ( i = 0; bvec[i] != NULL; i++ ) {
424                 /* EMPTY */;
425         }
426
427         if( bv == NULL ) {
428                 return i;
429         }
430
431         new = ber_memrealloc( *bvec, (i+2) * sizeof(struct berval *));
432
433         if( new == NULL ) {
434                 return -1;
435         }
436
437         *bvec = new;
438
439         (*bvec)[i++] = bv;
440         (*bvec)[i] = NULL;
441
442         return i;
443 }
444
445
446 struct berval *
447 ber_bvdup(
448         LDAP_CONST struct berval *bv )
449 {
450         struct berval *new;
451
452         ber_int_options.lbo_valid = LBER_INITIALIZED;
453
454         if( bv == NULL ) {
455                 ber_errno = LBER_ERROR_PARAM;
456                 return NULL;
457         }
458
459         if(( new = LBER_MALLOC( sizeof(struct berval) )) == NULL ) {
460                 ber_errno = LBER_ERROR_MEMORY;
461                 return NULL;
462         }
463
464         if ( bv->bv_val == NULL ) {
465                 new->bv_val = NULL;
466                 new->bv_len = 0;
467                 return new;
468         }
469
470         if(( new->bv_val = LBER_MALLOC( bv->bv_len + 1 )) == NULL ) {
471                 ber_errno = LBER_ERROR_MEMORY;
472                 LBER_FREE( new );
473                 return NULL;
474         }
475
476         SAFEMEMCPY( new->bv_val, bv->bv_val, bv->bv_len );
477         new->bv_val[bv->bv_len] = '\0';
478         new->bv_len = bv->bv_len;
479
480         return( new );
481 }
482
483 struct berval *
484 ber_bvstr(
485         LDAP_CONST char *s )
486 {
487         struct berval *new;
488
489         ber_int_options.lbo_valid = LBER_INITIALIZED;
490
491         if( s == NULL ) {
492                 ber_errno = LBER_ERROR_PARAM;
493                 return NULL;
494         }
495
496         if(( new = LBER_MALLOC( sizeof(struct berval) )) == NULL ) {
497                 ber_errno = LBER_ERROR_MEMORY;
498                 return NULL;
499         }
500
501         if ( *s == '\0' ) {
502                 new->bv_val = NULL;
503                 new->bv_len = 0;
504                 return new;
505         }
506
507         new->bv_val = (char *) s;
508         new->bv_len = strlen( s );
509
510         return( new );
511 }
512
513 struct berval *
514 ber_bvstrdup(
515         LDAP_CONST char *s )
516 {
517         struct berval *new;
518         char *p;
519
520         ber_int_options.lbo_valid = LBER_INITIALIZED;
521
522         if( s == NULL ) {
523                 ber_errno = LBER_ERROR_PARAM;
524                 return NULL;
525         }
526
527         p = LBER_STRDUP( s );
528
529         if( p == NULL ) {
530                 ber_errno = LBER_ERROR_MEMORY;
531                 return NULL;
532         }
533
534         new = ber_bvstr( p );
535
536         if( new == NULL || *p == '\0' ) {
537                 LBER_FREE( p );
538         }
539
540         return( new );
541 }
542
543 char *
544 ber_strdup( LDAP_CONST char *s )
545 {
546         char    *p;
547         size_t  len;
548         
549         ber_int_options.lbo_valid = LBER_INITIALIZED;
550
551 #ifdef LDAP_MEMORY_DEBUG
552         assert(s != NULL);                      /* bv damn better point to something */
553 #endif
554
555         if( s == NULL ) {
556                 ber_errno = LBER_ERROR_PARAM;
557                 return( NULL );
558         }
559
560         len = strlen( s ) + 1;
561
562         if ( (p = LBER_MALLOC( len )) == NULL ) {
563                 ber_errno = LBER_ERROR_MEMORY;
564                 return( NULL );
565         }
566
567         SAFEMEMCPY( p, s, len );
568         return( p );
569 }