1 /* $OpenLDAP: pkg/ldap/libraries/liblber/memory.c,v 1.64.2.4 2008/02/11 23:26:41 kurt Exp $ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 1998-2008 The OpenLDAP Foundation.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted only as authorized by the OpenLDAP
11 * A copy of this license is available in the file LICENSE in the
12 * top-level directory of the distribution or, alternatively, at
13 * <http://www.OpenLDAP.org/license.html>.
18 #include <ac/stdlib.h>
19 #include <ac/string.h>
23 #ifdef LDAP_MEMORY_TRACE
27 #ifdef LDAP_MEMORY_DEBUG
29 * LDAP_MEMORY_DEBUG should only be enabled for the purposes of
30 * debugging memory management within OpenLDAP libraries and slapd.
32 * It should only be enabled by an experienced developer as it causes
33 * the inclusion of numerous assert()'s, many of which may be triggered
34 * by a prefectly valid program. If LDAP_MEMORY_DEBUG & 2 is true,
35 * that includes asserts known to break both slapd and current clients.
37 * The code behind this macro is subject to change as needed to
38 * support this testing.
42 ber_int_t bm_top
; /* Pattern to detect buf overrun from prev buffer */
43 ber_int_t bm_length
; /* Length of user allocated area */
44 #ifdef LDAP_MEMORY_TRACE
45 ber_int_t bm_sequence
; /* Allocation sequence number */
47 union bmu_align_u
{ /* Force alignment, pattern to detect back clobber */
56 long (*bmu_funcp
)( double );
57 unsigned char bmu_char
[4];
59 #define bm_junk ber_align.bmu_len_t
60 #define bm_data ber_align.bmu_char[1]
61 #define bm_char ber_align.bmu_char
64 /* Pattern at top of allocated space */
65 #define LBER_MEM_JUNK 0xdeaddadaU
67 static const struct ber_mem_hdr ber_int_mem_hdr
= { LBER_MEM_JUNK
, 0, 0 };
69 /* Note sequence and ber_int_meminuse are counters, but are not
70 * thread safe. If you want to use these values for multithreaded applications,
71 * you must put mutexes around them, otherwise they will have incorrect values.
72 * When debugging, if you sort the debug output, the sequence number will
73 * put allocations/frees together. It is then a simple matter to write a script
74 * to find any allocations that don't have a buffer free function.
76 long ber_int_meminuse
= 0;
77 #ifdef LDAP_MEMORY_TRACE
78 static ber_int_t sequence
= 0;
81 /* Pattern placed just before user data */
82 static unsigned char toppattern
[4] = { 0xde, 0xad, 0xba, 0xde };
83 /* Pattern placed just after user data */
84 static unsigned char endpattern
[4] = { 0xd1, 0xed, 0xde, 0xca };
86 #define mbu_len sizeof(ber_int_mem_hdr.ber_align)
88 /* Test if pattern placed just before user data is good */
89 #define testdatatop(val) ( \
90 *(val->bm_char+mbu_len-4)==toppattern[0] && \
91 *(val->bm_char+mbu_len-3)==toppattern[1] && \
92 *(val->bm_char+mbu_len-2)==toppattern[2] && \
93 *(val->bm_char+mbu_len-1)==toppattern[3] )
95 /* Place pattern just before user data */
96 #define setdatatop(val) *(val->bm_char+mbu_len-4)=toppattern[0]; \
97 *(val->bm_char+mbu_len-3)=toppattern[1]; \
98 *(val->bm_char+mbu_len-2)=toppattern[2]; \
99 *(val->bm_char+mbu_len-1)=toppattern[3];
101 /* Test if pattern placed just after user data is good */
102 #define testend(val) ( *((unsigned char *)val+0)==endpattern[0] && \
103 *((unsigned char *)val+1)==endpattern[1] && \
104 *((unsigned char *)val+2)==endpattern[2] && \
105 *((unsigned char *)val+3)==endpattern[3] )
107 /* Place pattern just after user data */
108 #define setend(val) *((unsigned char *)val+0)=endpattern[0]; \
109 *((unsigned char *)val+1)=endpattern[1]; \
110 *((unsigned char *)val+2)=endpattern[2]; \
111 *((unsigned char *)val+3)=endpattern[3];
113 #define BER_MEM_BADADDR ((void *) &ber_int_mem_hdr.bm_data)
114 #define BER_MEM_VALID(p) do { \
115 assert( (p) != BER_MEM_BADADDR ); \
116 assert( (p) != (void *) &ber_int_mem_hdr ); \
120 #define BER_MEM_VALID(p) /* no-op */
123 BerMemoryFunctions
*ber_int_memory_fns
= NULL
;
126 ber_memfree_x( void *p
, void *ctx
)
134 if( ber_int_memory_fns
== NULL
|| ctx
== NULL
) {
135 #ifdef LDAP_MEMORY_DEBUG
136 struct ber_mem_hdr
*mh
= (struct ber_mem_hdr
*)
137 ((char *)p
- sizeof(struct ber_mem_hdr
));
138 assert( mh
->bm_top
== LBER_MEM_JUNK
);
139 assert( testdatatop( mh
));
140 assert( testend( (char *)&mh
[1] + mh
->bm_length
) );
141 ber_int_meminuse
-= mh
->bm_length
;
143 #ifdef LDAP_MEMORY_TRACE
144 fprintf(stderr
, "0x%08lx 0x%08lx -f- %ld ber_memfree %ld\n",
145 (long)mh
->bm_sequence
, (long)mh
, (long)mh
->bm_length
,
148 /* Fill the free space with poison */
149 memset( mh
, 0xff, mh
->bm_length
+ sizeof(struct ber_mem_hdr
) + sizeof(ber_int_t
));
157 assert( ber_int_memory_fns
->bmf_free
!= 0 );
159 (*ber_int_memory_fns
->bmf_free
)( p
, ctx
);
163 ber_memfree( void *p
)
165 ber_memfree_x(p
, NULL
);
169 ber_memvfree_x( void **vec
, void *ctx
)
177 BER_MEM_VALID( vec
);
179 for ( i
= 0; vec
[i
] != NULL
; i
++ ) {
180 ber_memfree_x( vec
[i
], ctx
);
183 ber_memfree_x( vec
, ctx
);
187 ber_memvfree( void **vec
)
189 ber_memvfree_x( vec
, NULL
);
193 ber_memalloc_x( ber_len_t s
, void *ctx
)
198 LDAP_MEMORY_DEBUG_ASSERT( s
!= 0 );
202 if( ber_int_memory_fns
== NULL
|| ctx
== 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
;
207 mh
->bm_top
= LBER_MEM_JUNK
;
210 setend( (char *)&mh
[1] + mh
->bm_length
);
212 ber_int_meminuse
+= mh
->bm_length
; /* Count mem inuse */
214 #ifdef LDAP_MEMORY_TRACE
215 mh
->bm_sequence
= sequence
++;
216 fprintf(stderr
, "0x%08lx 0x%08lx -a- %ld ber_memalloc %ld\n",
217 (long)mh
->bm_sequence
, (long)mh
, (long)mh
->bm_length
,
220 /* poison new memory */
221 memset( (char *)&mh
[1], 0xff, s
);
223 BER_MEM_VALID( &mh
[1] );
229 new = (*ber_int_memory_fns
->bmf_malloc
)( s
, ctx
);
233 ber_errno
= LBER_ERROR_MEMORY
;
240 ber_memalloc( ber_len_t s
)
242 return ber_memalloc_x( s
, NULL
);
246 ber_memcalloc_x( ber_len_t n
, ber_len_t s
, void *ctx
)
250 if( n
== 0 || s
== 0 ) {
251 LDAP_MEMORY_DEBUG_ASSERT( n
!= 0 && s
!= 0);
255 if( ber_int_memory_fns
== NULL
|| ctx
== NULL
) {
256 #ifdef LDAP_MEMORY_DEBUG
257 struct ber_mem_hdr
*mh
= calloc(1,
258 (n
* s
) + sizeof(struct ber_mem_hdr
) + sizeof(ber_int_t
) );
259 if( mh
== NULL
) return NULL
;
261 mh
->bm_top
= LBER_MEM_JUNK
;
264 setend( (char *)&mh
[1] + mh
->bm_length
);
266 ber_int_meminuse
+= mh
->bm_length
;
268 #ifdef LDAP_MEMORY_TRACE
269 mh
->bm_sequence
= sequence
++;
270 fprintf(stderr
, "0x%08lx 0x%08lx -a- %ld ber_memcalloc %ld\n",
271 (long)mh
->bm_sequence
, (long)mh
, (long)mh
->bm_length
,
274 BER_MEM_VALID( &mh
[1] );
277 new = calloc( n
, s
);
281 new = (*ber_int_memory_fns
->bmf_calloc
)( n
, s
, ctx
);
285 ber_errno
= LBER_ERROR_MEMORY
;
292 ber_memcalloc( ber_len_t n
, ber_len_t s
)
294 return ber_memcalloc_x( n
, s
, NULL
);
298 ber_memrealloc_x( void* p
, ber_len_t s
, void *ctx
)
302 /* realloc(NULL,s) -> malloc(s) */
304 return ber_memalloc_x( s
, ctx
);
307 /* realloc(p,0) -> free(p) */
309 ber_memfree_x( p
, ctx
);
315 if( ber_int_memory_fns
== NULL
|| ctx
== NULL
) {
316 #ifdef LDAP_MEMORY_DEBUG
318 struct ber_mem_hdr
*mh
= (struct ber_mem_hdr
*)
319 ((char *)p
- sizeof(struct ber_mem_hdr
));
320 assert( mh
->bm_top
== LBER_MEM_JUNK
);
321 assert( testdatatop( mh
));
322 assert( testend( (char *)&mh
[1] + mh
->bm_length
) );
323 oldlen
= mh
->bm_length
;
325 p
= realloc( mh
, s
+ sizeof(struct ber_mem_hdr
) + sizeof(ber_int_t
) );
327 ber_errno
= LBER_ERROR_MEMORY
;
333 setend( (char *)&mh
[1] + mh
->bm_length
);
335 /* poison any new memory */
336 memset( (char *)&mh
[1] + oldlen
, 0xff, s
- oldlen
);
339 assert( mh
->bm_top
== LBER_MEM_JUNK
);
340 assert( testdatatop( mh
));
342 ber_int_meminuse
+= s
- oldlen
;
343 #ifdef LDAP_MEMORY_TRACE
344 fprintf(stderr
, "0x%08lx 0x%08lx -a- %ld ber_memrealloc %ld\n",
345 (long)mh
->bm_sequence
, (long)mh
, (long)mh
->bm_length
,
348 BER_MEM_VALID( &mh
[1] );
351 new = realloc( p
, s
);
354 new = (*ber_int_memory_fns
->bmf_realloc
)( p
, s
, ctx
);
358 ber_errno
= LBER_ERROR_MEMORY
;
365 ber_memrealloc( void* p
, ber_len_t s
)
367 return ber_memrealloc_x( p
, s
, NULL
);
371 ber_bvfree_x( struct berval
*bv
, void *ctx
)
379 if ( bv
->bv_val
!= NULL
) {
380 ber_memfree_x( bv
->bv_val
, ctx
);
383 ber_memfree_x( (char *) bv
, ctx
);
387 ber_bvfree( struct berval
*bv
)
389 ber_bvfree_x( bv
, NULL
);
393 ber_bvecfree_x( struct berval
**bv
, void *ctx
)
404 for ( i
= 0; bv
[i
] != NULL
; i
++ ) ;
406 /* free in reverse order */
407 for ( i
--; i
>= 0; i
-- ) {
408 ber_bvfree_x( bv
[i
], ctx
);
411 ber_memfree_x( (char *) bv
, ctx
);
415 ber_bvecfree( struct berval
**bv
)
417 ber_bvecfree_x( bv
, NULL
);
421 ber_bvecadd_x( struct berval
***bvec
, struct berval
*bv
, void *ctx
)
426 if( *bvec
== NULL
) {
432 *bvec
= ber_memalloc_x( 2 * sizeof(struct berval
*), ctx
);
434 if( *bvec
== NULL
) {
444 BER_MEM_VALID( bvec
);
447 for ( i
= 0; (*bvec
)[i
] != NULL
; i
++ ) {
455 new = ber_memrealloc_x( *bvec
, (i
+2) * sizeof(struct berval
*), ctx
);
470 ber_bvecadd( struct berval
***bvec
, struct berval
*bv
)
472 return ber_bvecadd_x( bvec
, bv
, NULL
);
477 struct berval
*dst
, struct berval
*src
, void *ctx
)
482 ber_errno
= LBER_ERROR_PARAM
;
489 if(( new = ber_memalloc_x( sizeof(struct berval
), ctx
)) == NULL
) {
490 ber_errno
= LBER_ERROR_MEMORY
;
495 if ( src
->bv_val
== NULL
) {
501 if(( new->bv_val
= ber_memalloc_x( src
->bv_len
+ 1, ctx
)) == NULL
) {
502 ber_errno
= LBER_ERROR_MEMORY
;
504 ber_memfree_x( new, ctx
);
508 AC_MEMCPY( new->bv_val
, src
->bv_val
, src
->bv_len
);
509 new->bv_val
[src
->bv_len
] = '\0';
510 new->bv_len
= src
->bv_len
;
517 struct berval
*dst
, struct berval
*src
)
519 return ber_dupbv_x( dst
, src
, NULL
);
526 return ber_dupbv_x( NULL
, src
, NULL
);
531 LDAP_CONST
char *s
, ber_len_t len
, int dup
, struct berval
*bv
,
537 ber_errno
= LBER_ERROR_PARAM
;
544 if(( new = ber_memalloc_x( sizeof(struct berval
), ctx
)) == NULL
) {
545 ber_errno
= LBER_ERROR_MEMORY
;
550 new->bv_len
= len
? len
: strlen( s
);
552 if ( (new->bv_val
= ber_memalloc_x( new->bv_len
+1, ctx
)) == NULL
) {
553 ber_errno
= LBER_ERROR_MEMORY
;
555 ber_memfree_x( new, ctx
);
559 AC_MEMCPY( new->bv_val
, s
, new->bv_len
);
560 new->bv_val
[new->bv_len
] = '\0';
562 new->bv_val
= (char *) s
;
570 LDAP_CONST
char *s
, ber_len_t len
, int dup
, struct berval
*bv
)
572 return ber_str2bv_x( s
, len
, dup
, bv
, NULL
);
577 LDAP_CONST
char *s
, ber_len_t len
, int dup
, struct berval
*bv
,
583 ber_errno
= LBER_ERROR_PARAM
;
590 if(( new = ber_memalloc_x( sizeof(struct berval
), ctx
)) == NULL
) {
591 ber_errno
= LBER_ERROR_MEMORY
;
598 if ( (new->bv_val
= ber_memalloc_x( new->bv_len
+1, ctx
)) == NULL
) {
599 ber_errno
= LBER_ERROR_MEMORY
;
601 ber_memfree_x( new, ctx
);
606 AC_MEMCPY( new->bv_val
, s
, new->bv_len
);
607 new->bv_val
[new->bv_len
] = '\0';
609 new->bv_val
= (char *) s
;
617 LDAP_CONST
char *s
, ber_len_t len
, int dup
, struct berval
*bv
)
619 return ber_mem2bv_x( s
, len
, dup
, bv
, NULL
);
623 ber_strdup_x( LDAP_CONST
char *s
, void *ctx
)
628 #ifdef LDAP_MEMORY_DEBUG
629 assert(s
!= NULL
); /* bv damn better point to something */
633 ber_errno
= LBER_ERROR_PARAM
;
637 len
= strlen( s
) + 1;
639 if ( (p
= ber_memalloc_x( len
, ctx
)) == NULL
) {
640 ber_errno
= LBER_ERROR_MEMORY
;
644 AC_MEMCPY( p
, s
, len
);
649 ber_strdup( LDAP_CONST
char *s
)
651 return ber_strdup_x( s
, NULL
);
655 ber_strndup_x( LDAP_CONST
char *s
, ber_len_t l
, void *ctx
)
660 #ifdef LDAP_MEMORY_DEBUG
661 assert(s
!= NULL
); /* bv damn better point to something */
665 ber_errno
= LBER_ERROR_PARAM
;
675 if ( (p
= ber_memalloc_x( len
+ 1, ctx
)) == NULL
) {
676 ber_errno
= LBER_ERROR_MEMORY
;
680 AC_MEMCPY( p
, s
, len
);
686 ber_strndup( LDAP_CONST
char *s
, ber_len_t l
)
688 return ber_strndup_x( s
, l
, NULL
);
692 * dst is resized as required by src and the value of src is copied into dst
693 * dst->bv_val must be NULL (and dst->bv_len must be 0), or it must be
694 * alloc'ed with the context ctx
697 ber_bvreplace_x( struct berval
*dst
, LDAP_CONST
struct berval
*src
, void *ctx
)
699 assert( dst
!= NULL
);
700 assert( !BER_BVISNULL( src
) );
702 if ( BER_BVISNULL( dst
) || dst
->bv_len
< src
->bv_len
) {
703 dst
->bv_val
= ber_memrealloc_x( dst
->bv_val
, src
->bv_len
+ 1, ctx
);
706 AC_MEMCPY( dst
->bv_val
, src
->bv_val
, src
->bv_len
+ 1 );
707 dst
->bv_len
= src
->bv_len
;
713 ber_bvreplace( struct berval
*dst
, LDAP_CONST
struct berval
*src
)
715 return ber_bvreplace_x( dst
, src
, NULL
);
719 ber_bvarray_free_x( BerVarray a
, void *ctx
)
727 for (i
=0; a
[i
].bv_val
; i
++) ;
729 /* free in reverse order */
730 for (i
--; i
>=0; i
--) {
731 ber_memfree_x(a
[i
].bv_val
, ctx
);
734 ber_memfree_x(a
, ctx
);
739 ber_bvarray_free( BerVarray a
)
741 ber_bvarray_free_x(a
, NULL
);
745 ber_bvarray_dup_x( BerVarray
*dst
, BerVarray src
, void *ctx
)
755 for (i
=0; !BER_BVISNULL( &src
[i
] ); i
++) ;
756 new = ber_memalloc_x(( i
+1 ) * sizeof(BerValue
), ctx
);
759 for (j
=0; j
<i
; j
++) {
760 ber_dupbv_x( &new[j
], &src
[j
], ctx
);
761 if ( BER_BVISNULL( &new[j
] )) {
762 ber_bvarray_free_x( new, ctx
);
766 BER_BVZERO( &new[j
] );
772 ber_bvarray_add_x( BerVarray
*a
, BerValue
*bv
, void *ctx
)
782 *a
= (BerValue
*) ber_memalloc_x( 2 * sizeof(BerValue
), ctx
);
791 for ( n
= 0; *a
!= NULL
&& (*a
)[n
].bv_val
!= NULL
; n
++ ) {
792 ; /* just count them */
799 atmp
= (BerValue
*) ber_memrealloc_x( (char *) *a
,
800 (n
+ 2) * sizeof(BerValue
), ctx
);
810 (*a
)[n
].bv_val
= NULL
;
817 ber_bvarray_add( BerVarray
*a
, BerValue
*bv
)
819 return ber_bvarray_add_x( a
, bv
, NULL
);