1/* $OpenLDAP$ */
2/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3 *
4 * Copyright 1998-2011 The OpenLDAP Foundation.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted only as authorized by the OpenLDAP
9 * Public License.
10 *
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>.
14 */
15
16#include "portable.h"
17
18#include <ac/stdlib.h>
19#include <ac/string.h>
20
21#include "lber-int.h"
22
23#ifdef LDAP_MEMORY_TRACE
24#include <stdio.h>
25#endif
26
27#ifdef LDAP_MEMORY_DEBUG
28/*
29 * LDAP_MEMORY_DEBUG should only be enabled for the purposes of
30 * debugging memory management within OpenLDAP libraries and slapd.
31 *
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.
36 *
37 * The code behind this macro is subject to change as needed to
38 * support this testing.
39 */
40
41struct ber_mem_hdr {
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 */
46#endif
47	union bmu_align_u {	/* Force alignment, pattern to detect back clobber */
48		ber_len_t	bmu_len_t;
49		ber_tag_t	bmu_tag_t;
50		ber_int_t	bmu_int_t;
51
52		size_t	bmu_size_t;
53		void *	bmu_voidp;
54		double	bmu_double;
55		long	bmu_long;
56		long	(*bmu_funcp)( double );
57		unsigned char	bmu_char[4];
58	} ber_align;
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
62};
63
64/* Pattern at top of allocated space */
65#define LBER_MEM_JUNK ((ber_int_t) 0xdeaddada)
66
67static const struct ber_mem_hdr ber_int_mem_hdr = { LBER_MEM_JUNK };
68
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.
75 */
76long ber_int_meminuse = 0;
77#ifdef LDAP_MEMORY_TRACE
78static ber_int_t sequence = 0;
79#endif
80
81/* Pattern placed just before user data */
82static unsigned char toppattern[4] = { 0xde, 0xad, 0xba, 0xde };
83/* Pattern placed just after user data */
84static unsigned char endpattern[4] = { 0xd1, 0xed, 0xde, 0xca };
85
86#define mbu_len sizeof(ber_int_mem_hdr.ber_align)
87
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] )
94
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];
100
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] )
106
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];
112
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 );	\
117	} while(0)
118
119#else
120#define BER_MEM_VALID(p)	/* no-op */
121#endif
122
123BerMemoryFunctions *ber_int_memory_fns = NULL;
124
125void
126ber_memfree_x( void *p, void *ctx )
127{
128	if( p == NULL ) {
129		return;
130	}
131
132	BER_MEM_VALID( p );
133
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;
142
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,
146			ber_int_meminuse);
147#endif
148		/* Fill the free space with poison */
149		memset( mh, 0xff, mh->bm_length + sizeof(struct ber_mem_hdr) + sizeof(ber_int_t));
150		free( mh );
151#else
152		free( p );
153#endif
154		return;
155	}
156
157	assert( ber_int_memory_fns->bmf_free != 0 );
158
159	(*ber_int_memory_fns->bmf_free)( p, ctx );
160}
161
162void
163ber_memfree( void *p )
164{
165	ber_memfree_x(p, NULL);
166}
167
168void
169ber_memvfree_x( void **vec, void *ctx )
170{
171	int	i;
172
173	if( vec == NULL ) {
174		return;
175	}
176
177	BER_MEM_VALID( vec );
178
179	for ( i = 0; vec[i] != NULL; i++ ) {
180		ber_memfree_x( vec[i], ctx );
181	}
182
183	ber_memfree_x( vec, ctx );
184}
185
186void
187ber_memvfree( void **vec )
188{
189	ber_memvfree_x( vec, NULL );
190}
191
192void *
193ber_memalloc_x( ber_len_t s, void *ctx )
194{
195	void *new;
196
197	if( s == 0 ) {
198		LDAP_MEMORY_DEBUG_ASSERT( s != 0 );
199		return NULL;
200	}
201
202	if( ber_int_memory_fns == NULL || ctx == NULL ) {
203#ifdef LDAP_MEMORY_DEBUG
204		new = malloc(s + sizeof(struct ber_mem_hdr) + sizeof( ber_int_t));
205		if( new )
206		{
207		struct ber_mem_hdr *mh = new;
208		mh->bm_top = LBER_MEM_JUNK;
209		mh->bm_length = s;
210		setdatatop( mh);
211		setend( (char *)&mh[1] + mh->bm_length );
212
213		ber_int_meminuse += mh->bm_length;	/* Count mem inuse */
214
215#ifdef LDAP_MEMORY_TRACE
216		mh->bm_sequence = sequence++;
217		fprintf(stderr, "0x%08lx 0x%08lx -a- %ld ber_memalloc %ld\n",
218			(long)mh->bm_sequence, (long)mh, (long)mh->bm_length,
219			ber_int_meminuse);
220#endif
221		/* poison new memory */
222		memset( (char *)&mh[1], 0xff, s);
223
224		BER_MEM_VALID( &mh[1] );
225		new = &mh[1];
226		}
227#else
228		new = malloc( s );
229#endif
230	} else {
231		new = (*ber_int_memory_fns->bmf_malloc)( s, ctx );
232	}
233
234	if( new == NULL ) {
235		ber_errno = LBER_ERROR_MEMORY;
236	}
237
238	return new;
239}
240
241void *
242ber_memalloc( ber_len_t s )
243{
244	return ber_memalloc_x( s, NULL );
245}
246
247void *
248ber_memcalloc_x( ber_len_t n, ber_len_t s, void *ctx )
249{
250	void *new;
251
252	if( n == 0 || s == 0 ) {
253		LDAP_MEMORY_DEBUG_ASSERT( n != 0 && s != 0);
254		return NULL;
255	}
256
257	if( ber_int_memory_fns == NULL || ctx == NULL ) {
258#ifdef LDAP_MEMORY_DEBUG
259		new = n < (-sizeof(struct ber_mem_hdr) - sizeof(ber_int_t)) / s
260			? calloc(1, n*s + sizeof(struct ber_mem_hdr) + sizeof(ber_int_t))
261			: NULL;
262		if( new )
263		{
264		struct ber_mem_hdr *mh = new;
265
266		mh->bm_top = LBER_MEM_JUNK;
267		mh->bm_length = n*s;
268		setdatatop( mh);
269		setend( (char *)&mh[1] + mh->bm_length );
270
271		ber_int_meminuse += mh->bm_length;
272
273#ifdef LDAP_MEMORY_TRACE
274		mh->bm_sequence = sequence++;
275		fprintf(stderr, "0x%08lx 0x%08lx -a- %ld ber_memcalloc %ld\n",
276			(long)mh->bm_sequence, (long)mh, (long)mh->bm_length,
277			ber_int_meminuse);
278#endif
279		BER_MEM_VALID( &mh[1] );
280		new = &mh[1];
281		}
282#else
283		new = calloc( n, s );
284#endif
285
286	} else {
287		new = (*ber_int_memory_fns->bmf_calloc)( n, s, ctx );
288	}
289
290	if( new == NULL ) {
291		ber_errno = LBER_ERROR_MEMORY;
292	}
293
294	return new;
295}
296
297void *
298ber_memcalloc( ber_len_t n, ber_len_t s )
299{
300	return ber_memcalloc_x( n, s, NULL );
301}
302
303void *
304ber_memrealloc_x( void* p, ber_len_t s, void *ctx )
305{
306	void *new = NULL;
307
308	/* realloc(NULL,s) -> malloc(s) */
309	if( p == NULL ) {
310		return ber_memalloc_x( s, ctx );
311	}
312
313	/* realloc(p,0) -> free(p) */
314	if( s == 0 ) {
315		ber_memfree_x( p, ctx );
316		return NULL;
317	}
318
319	BER_MEM_VALID( p );
320
321	if( ber_int_memory_fns == NULL || ctx == NULL ) {
322#ifdef LDAP_MEMORY_DEBUG
323		ber_int_t oldlen;
324		struct ber_mem_hdr *mh = (struct ber_mem_hdr *)
325			((char *)p - sizeof(struct ber_mem_hdr));
326		assert( mh->bm_top == LBER_MEM_JUNK);
327		assert( testdatatop( mh));
328		assert( testend( (char *)&mh[1] + mh->bm_length) );
329		oldlen = mh->bm_length;
330
331		p = realloc( mh, s + sizeof(struct ber_mem_hdr) + sizeof(ber_int_t) );
332		if( p == NULL ) {
333			ber_errno = LBER_ERROR_MEMORY;
334			return NULL;
335		}
336
337			mh = p;
338		mh->bm_length = s;
339		setend( (char *)&mh[1] + mh->bm_length );
340		if( s > oldlen ) {
341			/* poison any new memory */
342			memset( (char *)&mh[1] + oldlen, 0xff, s - oldlen);
343		}
344
345		assert( mh->bm_top == LBER_MEM_JUNK);
346		assert( testdatatop( mh));
347
348		ber_int_meminuse += s - oldlen;
349#ifdef LDAP_MEMORY_TRACE
350		fprintf(stderr, "0x%08lx 0x%08lx -a- %ld ber_memrealloc %ld\n",
351			(long)mh->bm_sequence, (long)mh, (long)mh->bm_length,
352			ber_int_meminuse);
353#endif
354			BER_MEM_VALID( &mh[1] );
355		return &mh[1];
356#else
357		new = realloc( p, s );
358#endif
359	} else {
360		new = (*ber_int_memory_fns->bmf_realloc)( p, s, ctx );
361	}
362
363	if( new == NULL ) {
364		ber_errno = LBER_ERROR_MEMORY;
365	}
366
367	return new;
368}
369
370void *
371ber_memrealloc( void* p, ber_len_t s )
372{
373	return ber_memrealloc_x( p, s, NULL );
374}
375
376void
377ber_bvfree_x( struct berval *bv, void *ctx )
378{
379	if( bv == NULL ) {
380		return;
381	}
382
383	BER_MEM_VALID( bv );
384
385	if ( bv->bv_val != NULL ) {
386		ber_memfree_x( bv->bv_val, ctx );
387	}
388
389	ber_memfree_x( (char *) bv, ctx );
390}
391
392void
393ber_bvfree( struct berval *bv )
394{
395	ber_bvfree_x( bv, NULL );
396}
397
398void
399ber_bvecfree_x( struct berval **bv, void *ctx )
400{
401	int	i;
402
403	if( bv == NULL ) {
404		return;
405	}
406
407	BER_MEM_VALID( bv );
408
409	/* count elements */
410	for ( i = 0; bv[i] != NULL; i++ ) ;
411
412	/* free in reverse order */
413	for ( i--; i >= 0; i-- ) {
414		ber_bvfree_x( bv[i], ctx );
415	}
416
417	ber_memfree_x( (char *) bv, ctx );
418}
419
420void
421ber_bvecfree( struct berval **bv )
422{
423	ber_bvecfree_x( bv, NULL );
424}
425
426int
427ber_bvecadd_x( struct berval ***bvec, struct berval *bv, void *ctx )
428{
429	ber_len_t i;
430	struct berval **new;
431
432	if( *bvec == NULL ) {
433		if( bv == NULL ) {
434			/* nothing to add */
435			return 0;
436		}
437
438		*bvec = ber_memalloc_x( 2 * sizeof(struct berval *), ctx );
439
440		if( *bvec == NULL ) {
441			return -1;
442		}
443
444		(*bvec)[0] = bv;
445		(*bvec)[1] = NULL;
446
447		return 1;
448	}
449
450	BER_MEM_VALID( bvec );
451
452	/* count entries */
453	for ( i = 0; (*bvec)[i] != NULL; i++ ) {
454		/* EMPTY */;
455	}
456
457	if( bv == NULL ) {
458		return i;
459	}
460
461	new = ber_memrealloc_x( *bvec, (i+2) * sizeof(struct berval *), ctx);
462
463	if( new == NULL ) {
464		return -1;
465	}
466
467	*bvec = new;
468
469	(*bvec)[i++] = bv;
470	(*bvec)[i] = NULL;
471
472	return i;
473}
474
475int
476ber_bvecadd( struct berval ***bvec, struct berval *bv )
477{
478	return ber_bvecadd_x( bvec, bv, NULL );
479}
480
481struct berval *
482ber_dupbv_x(
483	struct berval *dst, struct berval *src, void *ctx )
484{
485	struct berval *new;
486
487	if( src == NULL ) {
488		ber_errno = LBER_ERROR_PARAM;
489		return NULL;
490	}
491
492	if ( dst ) {
493		new = dst;
494	} else {
495		if(( new = ber_memalloc_x( sizeof(struct berval), ctx )) == NULL ) {
496			return NULL;
497		}
498	}
499
500	if ( src->bv_val == NULL ) {
501		new->bv_val = NULL;
502		new->bv_len = 0;
503		return new;
504	}
505
506	if(( new->bv_val = ber_memalloc_x( src->bv_len + 1, ctx )) == NULL ) {
507		if ( !dst )
508			ber_memfree_x( new, ctx );
509		return NULL;
510	}
511
512	AC_MEMCPY( new->bv_val, src->bv_val, src->bv_len );
513	new->bv_val[src->bv_len] = '\0';
514	new->bv_len = src->bv_len;
515
516	return new;
517}
518
519struct berval *
520ber_dupbv(
521	struct berval *dst, struct berval *src )
522{
523	return ber_dupbv_x( dst, src, NULL );
524}
525
526struct berval *
527ber_bvdup(
528	struct berval *src )
529{
530	return ber_dupbv_x( NULL, src, NULL );
531}
532
533struct berval *
534ber_str2bv_x(
535	LDAP_CONST char *s, ber_len_t len, int dup, struct berval *bv,
536	void *ctx)
537{
538	struct berval *new;
539
540	if( s == NULL ) {
541		ber_errno = LBER_ERROR_PARAM;
542		return NULL;
543	}
544
545	if( bv ) {
546		new = bv;
547	} else {
548		if(( new = ber_memalloc_x( sizeof(struct berval), ctx )) == NULL ) {
549			return NULL;
550		}
551	}
552
553	new->bv_len = len ? len : strlen( s );
554	if ( dup ) {
555		if ( (new->bv_val = ber_memalloc_x( new->bv_len+1, ctx )) == NULL ) {
556			if ( !bv )
557				ber_memfree_x( new, ctx );
558			return NULL;
559		}
560
561		AC_MEMCPY( new->bv_val, s, new->bv_len );
562		new->bv_val[new->bv_len] = '\0';
563	} else {
564		new->bv_val = (char *) s;
565	}
566
567	return( new );
568}
569
570struct berval *
571ber_str2bv(
572	LDAP_CONST char *s, ber_len_t len, int dup, struct berval *bv)
573{
574	return ber_str2bv_x( s, len, dup, bv, NULL );
575}
576
577struct berval *
578ber_mem2bv_x(
579	LDAP_CONST char *s, ber_len_t len, int dup, struct berval *bv,
580	void *ctx)
581{
582	struct berval *new;
583
584	if( s == NULL ) {
585		ber_errno = LBER_ERROR_PARAM;
586		return NULL;
587	}
588
589	if( bv ) {
590		new = bv;
591	} else {
592		if(( new = ber_memalloc_x( sizeof(struct berval), ctx )) == NULL ) {
593			return NULL;
594		}
595	}
596
597	new->bv_len = len;
598	if ( dup ) {
599		if ( (new->bv_val = ber_memalloc_x( new->bv_len+1, ctx )) == NULL ) {
600			if ( !bv ) {
601				ber_memfree_x( new, ctx );
602			}
603			return NULL;
604		}
605
606		AC_MEMCPY( new->bv_val, s, new->bv_len );
607		new->bv_val[new->bv_len] = '\0';
608	} else {
609		new->bv_val = (char *) s;
610	}
611
612	return( new );
613}
614
615struct berval *
616ber_mem2bv(
617	LDAP_CONST char *s, ber_len_t len, int dup, struct berval *bv)
618{
619	return ber_mem2bv_x( s, len, dup, bv, NULL );
620}
621
622char *
623ber_strdup_x( LDAP_CONST char *s, void *ctx )
624{
625	char    *p;
626	size_t	len;
627
628#ifdef LDAP_MEMORY_DEBUG
629	assert(s != NULL);			/* bv damn better point to something */
630#endif
631
632	if( s == NULL ) {
633		ber_errno = LBER_ERROR_PARAM;
634		return NULL;
635	}
636
637	len = strlen( s ) + 1;
638	if ( (p = ber_memalloc_x( len, ctx )) != NULL ) {
639		AC_MEMCPY( p, s, len );
640	}
641
642	return p;
643}
644
645char *
646ber_strdup( LDAP_CONST char *s )
647{
648	return ber_strdup_x( s, NULL );
649}
650
651ber_len_t
652ber_strnlen( LDAP_CONST char *s, ber_len_t len )
653{
654	ber_len_t l;
655
656	for ( l = 0; l < len && s[l] != '\0'; l++ ) ;
657
658	return l;
659}
660
661char *
662ber_strndup_x( LDAP_CONST char *s, ber_len_t l, void *ctx )
663{
664	char    *p;
665	size_t	len;
666
667#ifdef LDAP_MEMORY_DEBUG
668	assert(s != NULL);			/* bv damn better point to something */
669#endif
670
671	if( s == NULL ) {
672		ber_errno = LBER_ERROR_PARAM;
673		return NULL;
674	}
675
676	len = ber_strnlen( s, l );
677	if ( (p = ber_memalloc_x( len + 1, ctx )) != NULL ) {
678		AC_MEMCPY( p, s, len );
679		p[len] = '\0';
680	}
681
682	return p;
683}
684
685char *
686ber_strndup( LDAP_CONST char *s, ber_len_t l )
687{
688	return ber_strndup_x( s, l, NULL );
689}
690
691/*
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
695 */
696struct berval *
697ber_bvreplace_x( struct berval *dst, LDAP_CONST struct berval *src, void *ctx )
698{
699	assert( dst != NULL );
700	assert( !BER_BVISNULL( src ) );
701
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 );
704	}
705
706	AC_MEMCPY( dst->bv_val, src->bv_val, src->bv_len + 1 );
707	dst->bv_len = src->bv_len;
708
709	return dst;
710}
711
712struct berval *
713ber_bvreplace( struct berval *dst, LDAP_CONST struct berval *src )
714{
715	return ber_bvreplace_x( dst, src, NULL );
716}
717
718void
719ber_bvarray_free_x( BerVarray a, void *ctx )
720{
721	int i;
722
723	if (a) {
724		BER_MEM_VALID( a );
725
726		/* count elements */
727		for (i=0; a[i].bv_val; i++) ;
728
729		/* free in reverse order */
730		for (i--; i>=0; i--) {
731			ber_memfree_x(a[i].bv_val, ctx);
732		}
733
734		ber_memfree_x(a, ctx);
735	}
736}
737
738void
739ber_bvarray_free( BerVarray a )
740{
741	ber_bvarray_free_x(a, NULL);
742}
743
744int
745ber_bvarray_dup_x( BerVarray *dst, BerVarray src, void *ctx )
746{
747	int i, j;
748	BerVarray new;
749
750	if ( !src ) {
751		*dst = NULL;
752		return 0;
753	}
754
755	for (i=0; !BER_BVISNULL( &src[i] ); i++) ;
756	new = ber_memalloc_x(( i+1 ) * sizeof(BerValue), ctx );
757	if ( !new )
758		return -1;
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 );
763			return -1;
764		}
765	}
766	BER_BVZERO( &new[j] );
767	*dst = new;
768	return 0;
769}
770
771int
772ber_bvarray_add_x( BerVarray *a, BerValue *bv, void *ctx )
773{
774	int	n;
775
776	if ( *a == NULL ) {
777		if (bv == NULL) {
778			return 0;
779		}
780		n = 0;
781
782		*a = (BerValue *) ber_memalloc_x( 2 * sizeof(BerValue), ctx );
783		if ( *a == NULL ) {
784			return -1;
785		}
786
787	} else {
788		BerVarray atmp;
789		BER_MEM_VALID( a );
790
791		for ( n = 0; *a != NULL && (*a)[n].bv_val != NULL; n++ ) {
792			;	/* just count them */
793		}
794
795		if (bv == NULL) {
796			return n;
797		}
798
799		atmp = (BerValue *) ber_memrealloc_x( (char *) *a,
800		    (n + 2) * sizeof(BerValue), ctx );
801
802		if( atmp == NULL ) {
803			return -1;
804		}
805
806		*a = atmp;
807	}
808
809	(*a)[n++] = *bv;
810	(*a)[n].bv_val = NULL;
811	(*a)[n].bv_len = 0;
812
813	return n;
814}
815
816int
817ber_bvarray_add( BerVarray *a, BerValue *bv )
818{
819	return ber_bvarray_add_x( a, bv, NULL );
820}
821