memory.c 16.1 KB
Newer Older
1
/* $OpenLDAP$ */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
2
3
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
 *
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
4
 * Copyright 1998-2018 The OpenLDAP Foundation.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
5
6
7
8
9
10
11
12
13
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted only as authorized by the OpenLDAP
 * Public License.
 *
 * A copy of this license is available in the file LICENSE in the
 * top-level directory of the distribution or, alternatively, at
 * <http://www.OpenLDAP.org/license.html>.
14
 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
15

16
17
#include "portable.h"

Kurt Zeilenga's avatar
Kurt Zeilenga committed
18
#include <ac/stdlib.h>
19
#include <ac/string.h>
20
21
22

#include "lber-int.h"

23
24
25
26
#ifdef LDAP_MEMORY_TRACE
#include <stdio.h>
#endif

27
#ifdef LDAP_MEMORY_DEBUG
28
29
30
/*
 * LDAP_MEMORY_DEBUG should only be enabled for the purposes of
 * debugging memory management within OpenLDAP libraries and slapd.
31
32
33
34
35
 *
 * It should only be enabled by an experienced developer as it causes
 * the inclusion of numerous assert()'s, many of which may be triggered
 * by a prefectly valid program.  If LDAP_MEMORY_DEBUG & 2 is true,
 * that includes asserts known to break both slapd and current clients.
36
37
38
39
40
 *
 * The code behind this macro is subject to change as needed to
 * support this testing.
 */

41
struct ber_mem_hdr {
42
43
44
45
46
47
	ber_int_t	bm_top;	/* Pattern to detect buf overrun from prev buffer */
	ber_int_t	bm_length; /* Length of user allocated area */
#ifdef LDAP_MEMORY_TRACE
	ber_int_t	bm_sequence; /* Allocation sequence number */
#endif
	union bmu_align_u {	/* Force alignment, pattern to detect back clobber */
48
49
50
51
		ber_len_t	bmu_len_t;
		ber_tag_t	bmu_tag_t;
		ber_int_t	bmu_int_t;

52
53
54
55
		size_t	bmu_size_t;
		void *	bmu_voidp;
		double	bmu_double;
		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 */
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
65
#define LBER_MEM_JUNK ((ber_int_t) 0xdeaddada)
66

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
67
static 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
71
72
73
74
75
 * thread safe.  If you want to use these values for multithreaded applications,
 * you must put mutexes around them, otherwise they will have incorrect values.
 * When debugging, if you sort the debug output, the sequence number will 
 * put allocations/frees together.  It is then a simple matter to write a script
 * to find any allocations that don't have a buffer free function.
 */
76
long ber_int_meminuse = 0;
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#ifdef LDAP_MEMORY_TRACE
static ber_int_t sequence = 0;
#endif

/* Pattern placed just before user data */
static unsigned char toppattern[4] = { 0xde, 0xad, 0xba, 0xde };
/* Pattern placed just after user data */
static unsigned char endpattern[4] = { 0xd1, 0xed, 0xde, 0xca };

#define mbu_len sizeof(ber_int_mem_hdr.ber_align)

/* Test if pattern placed just before user data is good */
#define testdatatop(val) ( \
	*(val->bm_char+mbu_len-4)==toppattern[0] && \
	*(val->bm_char+mbu_len-3)==toppattern[1] && \
	*(val->bm_char+mbu_len-2)==toppattern[2] && \
	*(val->bm_char+mbu_len-1)==toppattern[3] )

/* Place pattern just before user data */
#define setdatatop(val)	*(val->bm_char+mbu_len-4)=toppattern[0]; \
	*(val->bm_char+mbu_len-3)=toppattern[1]; \
	*(val->bm_char+mbu_len-2)=toppattern[2]; \
	*(val->bm_char+mbu_len-1)=toppattern[3];

/* Test if pattern placed just after user data is good */
#define testend(val) ( 	*((unsigned char *)val+0)==endpattern[0] && \
	*((unsigned char *)val+1)==endpattern[1] && \
	*((unsigned char *)val+2)==endpattern[2] && \
	*((unsigned char *)val+3)==endpattern[3] )

/* Place pattern just after user data */
#define setend(val)  	*((unsigned char *)val+0)=endpattern[0]; \
	*((unsigned char *)val+1)=endpattern[1]; \
	*((unsigned char *)val+2)=endpattern[2]; \
	*((unsigned char *)val+3)=endpattern[3];

113
#define BER_MEM_BADADDR	((void *) &ber_int_mem_hdr.bm_data)
114
115
116
#define BER_MEM_VALID(p)	do { \
		assert( (p) != BER_MEM_BADADDR );	\
		assert( (p) != (void *) &ber_int_mem_hdr );	\
117
	} while(0)
118

119
120
#else
#define BER_MEM_VALID(p)	/* no-op */
121
#endif
122

123
BerMemoryFunctions *ber_int_memory_fns = NULL;
124

125
void
126
ber_memfree_x( void *p, void *ctx )
127
{
128
129
130
131
	if( p == NULL ) {
		return;
	}

132
	BER_MEM_VALID( p );
133

134
	if( ber_int_memory_fns == NULL || ctx == NULL ) {
135
136
137
#ifdef LDAP_MEMORY_DEBUG
		struct ber_mem_hdr *mh = (struct ber_mem_hdr *)
			((char *)p - sizeof(struct ber_mem_hdr));
138
		assert( mh->bm_top == LBER_MEM_JUNK);
139
140
		assert( testdatatop( mh));
		assert( testend( (char *)&mh[1] + mh->bm_length) );
141
		ber_int_meminuse -= mh->bm_length;
142
143

#ifdef LDAP_MEMORY_TRACE
144
145
		fprintf(stderr, "0x%08lx 0x%08lx -f- %ld ber_memfree %ld\n",
			(long)mh->bm_sequence, (long)mh, (long)mh->bm_length,
146
			ber_int_meminuse);
147
148
#endif
		/* Fill the free space with poison */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
149
		memset( mh, 0xff, mh->bm_length + sizeof(struct ber_mem_hdr) + sizeof(ber_int_t));
150
151
		free( mh );
#else
152
		free( p );
153
#endif
154
155
156
		return;
	}

157
	assert( ber_int_memory_fns->bmf_free != 0 );
158

159
	(*ber_int_memory_fns->bmf_free)( p, ctx );
160
161
}

162
163
164
165
166
void
ber_memfree( void *p )
{
	ber_memfree_x(p, NULL);
}
167
168

void
169
ber_memvfree_x( void **vec, void *ctx )
170
171
172
{
	int	i;

173
174
175
	if( vec == NULL ) {
		return;
	}
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
}

186
187
188
189
190
void
ber_memvfree( void **vec )
{
	ber_memvfree_x( vec, NULL );
}
191

192
void *
193
ber_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
200
201
		return NULL;
	}

202
	if( ber_int_memory_fns == NULL || ctx == NULL ) {
203
#ifdef LDAP_MEMORY_DEBUG
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
204
205
206
207
		new = malloc(s + sizeof(struct ber_mem_hdr) + sizeof( ber_int_t));
		if( new )
		{
		struct ber_mem_hdr *mh = new;
208
		mh->bm_top = LBER_MEM_JUNK;
209
210
211
212
		mh->bm_length = s;
		setdatatop( mh);
		setend( (char *)&mh[1] + mh->bm_length );

213
		ber_int_meminuse += mh->bm_length;	/* Count mem inuse */
214
215
216

#ifdef LDAP_MEMORY_TRACE
		mh->bm_sequence = sequence++;
217
218
		fprintf(stderr, "0x%08lx 0x%08lx -a- %ld ber_memalloc %ld\n",
			(long)mh->bm_sequence, (long)mh, (long)mh->bm_length,
219
			ber_int_meminuse);
220
221
222
#endif
		/* poison new memory */
		memset( (char *)&mh[1], 0xff, s);
223

224
		BER_MEM_VALID( &mh[1] );
225
		new = &mh[1];
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
226
		}
227
#else
228
		new = malloc( s );
229
#endif
230
	} else {
231
		new = (*ber_int_memory_fns->bmf_malloc)( s, ctx );
232
233
	}

234
235
236
	if( new == NULL ) {
		ber_errno = LBER_ERROR_MEMORY;
	}
237

238
	return new;
239
240
}

241
242
243
244
245
void *
ber_memalloc( ber_len_t s )
{
	return ber_memalloc_x( s, NULL );
}
246

247
void *
248
ber_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
255
256
		return NULL;
	}

257
	if( ber_int_memory_fns == NULL || ctx == NULL ) {
258
#ifdef LDAP_MEMORY_DEBUG
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
259
260
261
		new = n < (-sizeof(struct ber_mem_hdr) - sizeof(ber_int_t)) / s
			? calloc(1, n*s + sizeof(struct ber_mem_hdr) + sizeof(ber_int_t))
			: NULL;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
262
263
264
		if( new )
		{
		struct ber_mem_hdr *mh = new;
265

266
		mh->bm_top = LBER_MEM_JUNK;
267
268
269
		mh->bm_length = n*s;
		setdatatop( mh);
		setend( (char *)&mh[1] + mh->bm_length );
270

271
		ber_int_meminuse += mh->bm_length;
272

273
274
#ifdef LDAP_MEMORY_TRACE
		mh->bm_sequence = sequence++;
275
276
		fprintf(stderr, "0x%08lx 0x%08lx -a- %ld ber_memcalloc %ld\n",
			(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];
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
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
291
292
	if( new == NULL ) {
		ber_errno = LBER_ERROR_MEMORY;
	}
293

294
	return new;
295
296
}

297
298
299
300
301
void *
ber_memcalloc( ber_len_t n, ber_len_t s )
{
	return ber_memcalloc_x( n, s, NULL );
}
302

303
void *
304
ber_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
317
		return NULL;
	}
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
325
		struct ber_mem_hdr *mh = (struct ber_mem_hdr *)
			((char *)p - sizeof(struct ber_mem_hdr));
326
		assert( mh->bm_top == LBER_MEM_JUNK);
327
328
329
330
331
332
333
334
335
		assert( testdatatop( mh));
		assert( testend( (char *)&mh[1] + mh->bm_length) );
		oldlen = mh->bm_length;

		p = realloc( mh, s + sizeof(struct ber_mem_hdr) + sizeof(ber_int_t) );
		if( p == NULL ) {
			ber_errno = LBER_ERROR_MEMORY;
			return NULL;
		}
336

337
			mh = p;
338
339
		mh->bm_length = s;
		setend( (char *)&mh[1] + mh->bm_length );
340
		if( s > oldlen ) {
341
342
343
			/* poison any new memory */
			memset( (char *)&mh[1] + oldlen, 0xff, s - oldlen);
		}
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
351
		fprintf(stderr, "0x%08lx 0x%08lx -a- %ld ber_memrealloc %ld\n",
			(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
364
365
	if( new == NULL ) {
		ber_errno = LBER_ERROR_MEMORY;
	}
366

367
	return new;
368
369
}

370
371
372
373
374
void *
ber_memrealloc( void* p, ber_len_t s )
{
	return ber_memrealloc_x( p, s, NULL );
}
375
376

void
377
ber_bvfree_x( struct berval *bv, void *ctx )
378
{
379
380
381
	if( bv == NULL ) {
		return;
	}
382

383
	BER_MEM_VALID( bv );
384

Kurt Zeilenga's avatar
Kurt Zeilenga committed
385
	if ( bv->bv_val != NULL ) {
386
		ber_memfree_x( bv->bv_val, ctx );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
387
	}
388

389
	ber_memfree_x( (char *) bv, ctx );
390
391
}

392
393
394
395
396
void
ber_bvfree( struct berval *bv )
{
	ber_bvfree_x( bv, NULL );
}
397
398

void
399
ber_bvecfree_x( struct berval **bv, void *ctx )
400
401
402
{
	int	i;

403
404
405
	if( bv == NULL ) {
		return;
	}
406

407
	BER_MEM_VALID( bv );
408

409
410
411
412
413
	/* count elements */
	for ( i = 0; bv[i] != NULL; i++ ) ;

	/* free in reverse order */
	for ( i--; i >= 0; i-- ) {
414
		ber_bvfree_x( bv[i], ctx );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
415
	}
416

417
418
419
420
421
422
423
	ber_memfree_x( (char *) bv, ctx );
}

void
ber_bvecfree( struct berval **bv )
{
	ber_bvecfree_x( bv, NULL );
424
425
}

426
int
427
ber_bvecadd_x( struct berval ***bvec, struct berval *bv, void *ctx )
428
429
430
431
{
	ber_len_t i;
	struct berval **new;

Pierangelo Masarati's avatar
Pierangelo Masarati committed
432
	if( *bvec == NULL ) {
433
434
435
436
437
		if( bv == NULL ) {
			/* nothing to add */
			return 0;
		}

438
		*bvec = ber_memalloc_x( 2 * sizeof(struct berval *), ctx );
439
440
441
442
443
444
445
446
447
448
449
450
451
452

		if( *bvec == NULL ) {
			return -1;
		}

		(*bvec)[0] = bv;
		(*bvec)[1] = NULL;

		return 1;
	}

	BER_MEM_VALID( bvec );

	/* count entries */
Pierangelo Masarati's avatar
Pierangelo Masarati committed
453
	for ( i = 0; (*bvec)[i] != NULL; i++ ) {
454
455
456
457
458
459
460
		/* EMPTY */;
	}

	if( bv == NULL ) {
		return i;
	}

461
	new = ber_memrealloc_x( *bvec, (i+2) * sizeof(struct berval *), ctx);
462
463
464
465
466
467
468
469
470
471
472
473
474

	if( new == NULL ) {
		return -1;
	}

	*bvec = new;

	(*bvec)[i++] = bv;
	(*bvec)[i] = NULL;

	return i;
}

475
476
477
478
479
int
ber_bvecadd( struct berval ***bvec, struct berval *bv )
{
	return ber_bvecadd_x( bvec, bv, NULL );
}
480
481

struct berval *
482
483
ber_dupbv_x(
	struct berval *dst, struct berval *src, void *ctx )
484
{
Howard Chu's avatar
Howard Chu committed
485
	struct berval *new, tmp;
486

487
	if( src == NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
488
		ber_errno = LBER_ERROR_PARAM;
489
490
491
		return NULL;
	}

492
	if ( dst ) {
Howard Chu's avatar
Howard Chu committed
493
		new = &tmp;
494
	} else {
495
		if(( new = ber_memalloc_x( sizeof(struct berval), ctx )) == NULL ) {
496
497
			return NULL;
		}
498
499
	}

500
	if ( src->bv_val == NULL ) {
501
502
		new->bv_val = NULL;
		new->bv_len = 0;
Howard Chu's avatar
Howard Chu committed
503
	} else {
504

Howard Chu's avatar
Howard Chu committed
505
506
507
508
509
510
511
512
513
		if(( new->bv_val = ber_memalloc_x( src->bv_len + 1, ctx )) == NULL ) {
			if ( !dst )
				ber_memfree_x( new, ctx );
			return NULL;
		}

		AC_MEMCPY( new->bv_val, src->bv_val, src->bv_len );
		new->bv_val[src->bv_len] = '\0';
		new->bv_len = src->bv_len;
514
515
	}

Howard Chu's avatar
Howard Chu committed
516
517
518
519
	if ( dst ) {
		*dst = *new;
		new = dst;
	}
520

Kurt Zeilenga's avatar
Kurt Zeilenga committed
521
	return new;
522
}
523

524
525
526
527
528
529
struct berval *
ber_dupbv(
	struct berval *dst, struct berval *src )
{
	return ber_dupbv_x( dst, src, NULL );
}
530
531
532

struct berval *
ber_bvdup(
533
	struct berval *src )
534
{
535
	return ber_dupbv_x( NULL, src, NULL );
536
537
}

538
struct berval *
539
540
541
ber_str2bv_x(
	LDAP_CONST char *s, ber_len_t len, int dup, struct berval *bv,
	void *ctx)
542
543
544
545
546
547
548
549
{
	struct berval *new;

	if( s == NULL ) {
		ber_errno = LBER_ERROR_PARAM;
		return NULL;
	}

550
551
552
	if( bv ) {
		new = bv;
	} else {
553
		if(( new = ber_memalloc_x( sizeof(struct berval), ctx )) == NULL ) {
554
555
			return NULL;
		}
556
557
	}

Howard Chu's avatar
Howard Chu committed
558
	new->bv_len = len ? len : strlen( s );
559
	if ( dup ) {
560
		if ( (new->bv_val = ber_memalloc_x( new->bv_len+1, ctx )) == NULL ) {
561
			if ( !bv )
562
				ber_memfree_x( new, ctx );
563
564
			return NULL;
		}
565

566
567
568
		AC_MEMCPY( new->bv_val, s, new->bv_len );
		new->bv_val[new->bv_len] = '\0';
	} else {
569
570
571
572
573
574
575
		new->bv_val = (char *) s;
	}

	return( new );
}

struct berval *
576
ber_str2bv(
577
	LDAP_CONST char *s, ber_len_t len, int dup, struct berval *bv)
578
579
580
581
582
583
584
585
{
	return ber_str2bv_x( s, len, dup, bv, NULL );
}

struct berval *
ber_mem2bv_x(
	LDAP_CONST char *s, ber_len_t len, int dup, struct berval *bv,
	void *ctx)
586
587
588
{
	struct berval *new;

589
	if( s == NULL ) {
590
591
592
593
594
595
596
		ber_errno = LBER_ERROR_PARAM;
		return NULL;
	}

	if( bv ) {
		new = bv;
	} else {
597
		if(( new = ber_memalloc_x( sizeof(struct berval), ctx )) == NULL ) {
598
599
600
601
602
603
			return NULL;
		}
	}

	new->bv_len = len;
	if ( dup ) {
604
		if ( (new->bv_val = ber_memalloc_x( new->bv_len+1, ctx )) == NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
605
			if ( !bv ) {
606
				ber_memfree_x( new, ctx );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
607
			}
608
609
610
611
612
613
			return NULL;
		}

		AC_MEMCPY( new->bv_val, s, new->bv_len );
		new->bv_val[new->bv_len] = '\0';
	} else {
614
		new->bv_val = (char *) s;
615
616
	}

617
	return( new );
618
619
}

620
621
622
623
624
625
626
struct berval *
ber_mem2bv(
	LDAP_CONST char *s, ber_len_t len, int dup, struct berval *bv)
{
	return ber_mem2bv_x( s, len, dup, bv, NULL );
}

627
char *
628
ber_strdup_x( LDAP_CONST char *s, void *ctx )
629
630
{
	char    *p;
631
632
633
634
635
636
637
	size_t	len;
	
#ifdef LDAP_MEMORY_DEBUG
	assert(s != NULL);			/* bv damn better point to something */
#endif

	if( s == NULL ) {
638
		ber_errno = LBER_ERROR_PARAM;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
639
		return NULL;
640
641
642
	}

	len = strlen( s ) + 1;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
643
644
	if ( (p = ber_memalloc_x( len, ctx )) != NULL ) {
		AC_MEMCPY( p, s, len );
645
646
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
647
	return p;
648
}
649
650

char *
651
652
653
654
655
ber_strdup( LDAP_CONST char *s )
{
	return ber_strdup_x( s, NULL );
}

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
656
657
658
659
660
661
662
663
664
665
ber_len_t
ber_strnlen( LDAP_CONST char *s, ber_len_t len )
{
	ber_len_t l;

	for ( l = 0; l < len && s[l] != '\0'; l++ ) ;

	return l;
}

666
667
char *
ber_strndup_x( LDAP_CONST char *s, ber_len_t l, void *ctx )
668
669
670
671
672
673
674
675
676
677
678
679
680
{
	char    *p;
	size_t	len;
	
#ifdef LDAP_MEMORY_DEBUG
	assert(s != NULL);			/* bv damn better point to something */
#endif

	if( s == NULL ) {
		ber_errno = LBER_ERROR_PARAM;
		return NULL;
	}

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
681
	len = ber_strnlen( s, l );
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
682
683
684
	if ( (p = ber_memalloc_x( len + 1, ctx )) != NULL ) {
		AC_MEMCPY( p, s, len );
		p[len] = '\0';
685
686
687
688
689
690
	}

	return p;
}

char *
691
ber_strndup( LDAP_CONST char *s, ber_len_t l )
692
{
693
	return ber_strndup_x( s, l, NULL );
694
}
695

696
697
698
699
700
701
702
703
704
/*
 * dst is resized as required by src and the value of src is copied into dst
 * dst->bv_val must be NULL (and dst->bv_len must be 0), or it must be
 * alloc'ed with the context ctx
 */
struct berval *
ber_bvreplace_x( struct berval *dst, LDAP_CONST struct berval *src, void *ctx )
{
	assert( dst != NULL );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
705
	assert( !BER_BVISNULL( src ) );
706

Pierangelo Masarati's avatar
Pierangelo Masarati committed
707
	if ( BER_BVISNULL( dst ) || dst->bv_len < src->bv_len ) {
708
709
710
711
		dst->bv_val = ber_memrealloc_x( dst->bv_val, src->bv_len + 1, ctx );
	}

	AC_MEMCPY( dst->bv_val, src->bv_val, src->bv_len + 1 );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
712
	dst->bv_len = src->bv_len;
713
714
715
716
717
718
719
720
721
722

	return dst;
}

struct berval *
ber_bvreplace( struct berval *dst, LDAP_CONST struct berval *src )
{
	return ber_bvreplace_x( dst, src, NULL );
}

723
void
724
ber_bvarray_free_x( BerVarray a, void *ctx )
725
726
727
728
729
730
{
	int i;

	if (a) {
		BER_MEM_VALID( a );

731
732
733
734
735
		/* count elements */
		for (i=0; a[i].bv_val; i++) ;
		
		/* free in reverse order */
		for (i--; i>=0; i--) {
736
			ber_memfree_x(a[i].bv_val, ctx);
737
738
		}

739
		ber_memfree_x(a, ctx);
740
741
742
	}
}

743
744
745
746
747
748
void
ber_bvarray_free( BerVarray a )
{
	ber_bvarray_free_x(a, NULL);
}

Howard Chu's avatar
Howard Chu committed
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
int
ber_bvarray_dup_x( BerVarray *dst, BerVarray src, void *ctx )
{
	int i, j;
	BerVarray new;

	if ( !src ) {
		*dst = NULL;
		return 0;
	}

	for (i=0; !BER_BVISNULL( &src[i] ); i++) ;
	new = ber_memalloc_x(( i+1 ) * sizeof(BerValue), ctx );
	if ( !new )
		return -1;
	for (j=0; j<i; j++) {
		ber_dupbv_x( &new[j], &src[j], ctx );
		if ( BER_BVISNULL( &new[j] )) {
			ber_bvarray_free_x( new, ctx );
			return -1;
		}
	}
	BER_BVZERO( &new[j] );
	*dst = new;
	return 0;
}

776
int
777
ber_bvarray_add_x( BerVarray *a, BerValue *bv, void *ctx )
778
779
780
781
782
783
784
785
{
	int	n;

	if ( *a == NULL ) {
		if (bv == NULL) {
			return 0;
		}
		n = 0;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
786

787
		*a = (BerValue *) ber_memalloc_x( 2 * sizeof(BerValue), ctx );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
788
789
790
791
		if ( *a == NULL ) {
			return -1;
		}

792
	} else {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
793
		BerVarray atmp;
794
795
796
		BER_MEM_VALID( a );

		for ( n = 0; *a != NULL && (*a)[n].bv_val != NULL; n++ ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
797
			;	/* just count them */
798
799
800
801
802
		}

		if (bv == NULL) {
			return n;
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
803

804
805
		atmp = (BerValue *) ber_memrealloc_x( (char *) *a,
		    (n + 2) * sizeof(BerValue), ctx );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
806

Kurt Zeilenga's avatar
Kurt Zeilenga committed
807
		if( atmp == NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
808
809
810
			return -1;
		}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
811
		*a = atmp;
812
813
814
815
	}

	(*a)[n++] = *bv;
	(*a)[n].bv_val = NULL;
Howard Chu's avatar
Howard Chu committed
816
	(*a)[n].bv_len = 0;
817
818
819

	return n;
}
820

821
822
823
824
825
int
ber_bvarray_add( BerVarray *a, BerValue *bv )
{
	return ber_bvarray_add_x( a, bv, NULL );
}