1 /*	$NetBSD: memory.c,v 1.1.1.3 2010/12/12 15:21:28 adam Exp $	*/
2 
3 /* OpenLDAP: pkg/ldap/libraries/liblber/memory.c,v 1.64.2.7 2010/04/13 20:22:54 kurt Exp */
4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5  *
6  * Copyright 1998-2010 The OpenLDAP Foundation.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted only as authorized by the OpenLDAP
11  * Public License.
12  *
13  * A copy of this license is available in the file LICENSE in the
14  * top-level directory of the distribution or, alternatively, at
15  * <http://www.OpenLDAP.org/license.html>.
16  */
17 
18 #include "portable.h"
19 
20 #include <ac/stdlib.h>
21 #include <ac/string.h>
22 
23 #include "lber-int.h"
24 
25 #ifdef LDAP_MEMORY_TRACE
26 #include <stdio.h>
27 #endif
28 
29 #ifdef LDAP_MEMORY_DEBUG
30 /*
31  * LDAP_MEMORY_DEBUG should only be enabled for the purposes of
32  * debugging memory management within OpenLDAP libraries and slapd.
33  *
34  * It should only be enabled by an experienced developer as it causes
35  * the inclusion of numerous assert()'s, many of which may be triggered
36  * by a prefectly valid program.  If LDAP_MEMORY_DEBUG & 2 is true,
37  * that includes asserts known to break both slapd and current clients.
38  *
39  * The code behind this macro is subject to change as needed to
40  * support this testing.
41  */
42 
43 struct ber_mem_hdr {
44 	ber_int_t	bm_top;	/* Pattern to detect buf overrun from prev buffer */
45 	ber_int_t	bm_length; /* Length of user allocated area */
46 #ifdef LDAP_MEMORY_TRACE
47 	ber_int_t	bm_sequence; /* Allocation sequence number */
48 #endif
49 	union bmu_align_u {	/* Force alignment, pattern to detect back clobber */
50 		ber_len_t	bmu_len_t;
51 		ber_tag_t	bmu_tag_t;
52 		ber_int_t	bmu_int_t;
53 
54 		size_t	bmu_size_t;
55 		void *	bmu_voidp;
56 		double	bmu_double;
57 		long	bmu_long;
58 		long	(*bmu_funcp)( double );
59 		unsigned char	bmu_char[4];
60 	} ber_align;
61 #define bm_junk	ber_align.bmu_len_t
62 #define bm_data	ber_align.bmu_char[1]
63 #define bm_char	ber_align.bmu_char
64 };
65 
66 /* Pattern at top of allocated space */
67 #define LBER_MEM_JUNK 0xdeaddadaU
68 
69 static const struct ber_mem_hdr ber_int_mem_hdr = { LBER_MEM_JUNK, 0, 0 };
70 
71 /* Note sequence and ber_int_meminuse are counters, but are not
72  * thread safe.  If you want to use these values for multithreaded applications,
73  * you must put mutexes around them, otherwise they will have incorrect values.
74  * When debugging, if you sort the debug output, the sequence number will
75  * put allocations/frees together.  It is then a simple matter to write a script
76  * to find any allocations that don't have a buffer free function.
77  */
78 long ber_int_meminuse = 0;
79 #ifdef LDAP_MEMORY_TRACE
80 static ber_int_t sequence = 0;
81 #endif
82 
83 /* Pattern placed just before user data */
84 static unsigned char toppattern[4] = { 0xde, 0xad, 0xba, 0xde };
85 /* Pattern placed just after user data */
86 static unsigned char endpattern[4] = { 0xd1, 0xed, 0xde, 0xca };
87 
88 #define mbu_len sizeof(ber_int_mem_hdr.ber_align)
89 
90 /* Test if pattern placed just before user data is good */
91 #define testdatatop(val) ( \
92 	*(val->bm_char+mbu_len-4)==toppattern[0] && \
93 	*(val->bm_char+mbu_len-3)==toppattern[1] && \
94 	*(val->bm_char+mbu_len-2)==toppattern[2] && \
95 	*(val->bm_char+mbu_len-1)==toppattern[3] )
96 
97 /* Place pattern just before user data */
98 #define setdatatop(val)	*(val->bm_char+mbu_len-4)=toppattern[0]; \
99 	*(val->bm_char+mbu_len-3)=toppattern[1]; \
100 	*(val->bm_char+mbu_len-2)=toppattern[2]; \
101 	*(val->bm_char+mbu_len-1)=toppattern[3];
102 
103 /* Test if pattern placed just after user data is good */
104 #define testend(val) ( 	*((unsigned char *)val+0)==endpattern[0] && \
105 	*((unsigned char *)val+1)==endpattern[1] && \
106 	*((unsigned char *)val+2)==endpattern[2] && \
107 	*((unsigned char *)val+3)==endpattern[3] )
108 
109 /* Place pattern just after user data */
110 #define setend(val)  	*((unsigned char *)val+0)=endpattern[0]; \
111 	*((unsigned char *)val+1)=endpattern[1]; \
112 	*((unsigned char *)val+2)=endpattern[2]; \
113 	*((unsigned char *)val+3)=endpattern[3];
114 
115 #define BER_MEM_BADADDR	((void *) &ber_int_mem_hdr.bm_data)
116 #define BER_MEM_VALID(p)	do { \
117 		assert( (p) != BER_MEM_BADADDR );	\
118 		assert( (p) != (void *) &ber_int_mem_hdr );	\
119 	} while(0)
120 
121 #else
122 #define BER_MEM_VALID(p)	/* no-op */
123 #endif
124 
125 BerMemoryFunctions *ber_int_memory_fns = NULL;
126 
127 void
128 ber_memfree_x( void *p, void *ctx )
129 {
130 	if( p == NULL ) {
131 		return;
132 	}
133 
134 	BER_MEM_VALID( p );
135 
136 	if( ber_int_memory_fns == NULL || ctx == NULL ) {
137 #ifdef LDAP_MEMORY_DEBUG
138 		struct ber_mem_hdr *mh = (struct ber_mem_hdr *)
139 			((char *)p - sizeof(struct ber_mem_hdr));
140 		assert( mh->bm_top == LBER_MEM_JUNK);
141 		assert( testdatatop( mh));
142 		assert( testend( (char *)&mh[1] + mh->bm_length) );
143 		ber_int_meminuse -= mh->bm_length;
144 
145 #ifdef LDAP_MEMORY_TRACE
146 		fprintf(stderr, "0x%08lx 0x%08lx -f- %ld ber_memfree %ld\n",
147 			(long)mh->bm_sequence, (long)mh, (long)mh->bm_length,
148 			ber_int_meminuse);
149 #endif
150 		/* Fill the free space with poison */
151 		memset( mh, 0xff, mh->bm_length + sizeof(struct ber_mem_hdr) + sizeof(ber_int_t));
152 		free( mh );
153 #else
154 		free( p );
155 #endif
156 		return;
157 	}
158 
159 	assert( ber_int_memory_fns->bmf_free != 0 );
160 
161 	(*ber_int_memory_fns->bmf_free)( p, ctx );
162 }
163 
164 void
165 ber_memfree( void *p )
166 {
167 	ber_memfree_x(p, NULL);
168 }
169 
170 void
171 ber_memvfree_x( void **vec, void *ctx )
172 {
173 	int	i;
174 
175 	if( vec == NULL ) {
176 		return;
177 	}
178 
179 	BER_MEM_VALID( vec );
180 
181 	for ( i = 0; vec[i] != NULL; i++ ) {
182 		ber_memfree_x( vec[i], ctx );
183 	}
184 
185 	ber_memfree_x( vec, ctx );
186 }
187 
188 void
189 ber_memvfree( void **vec )
190 {
191 	ber_memvfree_x( vec, NULL );
192 }
193 
194 void *
195 ber_memalloc_x( ber_len_t s, void *ctx )
196 {
197 	void *new;
198 
199 	if( s == 0 ) {
200 		LDAP_MEMORY_DEBUG_ASSERT( s != 0 );
201 		return NULL;
202 	}
203 
204 	if( ber_int_memory_fns == NULL || ctx == NULL ) {
205 #ifdef LDAP_MEMORY_DEBUG
206 		struct ber_mem_hdr *mh = malloc(s + sizeof(struct ber_mem_hdr) + sizeof( ber_int_t));
207 		if( mh == NULL ) return NULL;
208 
209 		mh->bm_top = LBER_MEM_JUNK;
210 		mh->bm_length = s;
211 		setdatatop( mh);
212 		setend( (char *)&mh[1] + mh->bm_length );
213 
214 		ber_int_meminuse += mh->bm_length;	/* Count mem inuse */
215 
216 #ifdef LDAP_MEMORY_TRACE
217 		mh->bm_sequence = sequence++;
218 		fprintf(stderr, "0x%08lx 0x%08lx -a- %ld ber_memalloc %ld\n",
219 			(long)mh->bm_sequence, (long)mh, (long)mh->bm_length,
220 			ber_int_meminuse);
221 #endif
222 		/* poison new memory */
223 		memset( (char *)&mh[1], 0xff, s);
224 
225 		BER_MEM_VALID( &mh[1] );
226 		new = &mh[1];
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 
241 void *
242 ber_memalloc( ber_len_t s )
243 {
244 	return ber_memalloc_x( s, NULL );
245 }
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 		return NULL;
255 	}
256 
257 	if( ber_int_memory_fns == NULL || ctx == NULL ) {
258 #ifdef LDAP_MEMORY_DEBUG
259 		struct ber_mem_hdr *mh = calloc(1,
260 			(n * s) + sizeof(struct ber_mem_hdr) + sizeof(ber_int_t) );
261 		if( mh == NULL ) return NULL;
262 
263 		mh->bm_top = LBER_MEM_JUNK;
264 		mh->bm_length = n*s;
265 		setdatatop( mh);
266 		setend( (char *)&mh[1] + mh->bm_length );
267 
268 		ber_int_meminuse += mh->bm_length;
269 
270 #ifdef LDAP_MEMORY_TRACE
271 		mh->bm_sequence = sequence++;
272 		fprintf(stderr, "0x%08lx 0x%08lx -a- %ld ber_memcalloc %ld\n",
273 			(long)mh->bm_sequence, (long)mh, (long)mh->bm_length,
274 			ber_int_meminuse);
275 #endif
276 		BER_MEM_VALID( &mh[1] );
277 		new = &mh[1];
278 #else
279 		new = calloc( n, s );
280 #endif
281 
282 	} else {
283 		new = (*ber_int_memory_fns->bmf_calloc)( n, s, ctx );
284 	}
285 
286 	if( new == NULL ) {
287 		ber_errno = LBER_ERROR_MEMORY;
288 	}
289 
290 	return new;
291 }
292 
293 void *
294 ber_memcalloc( ber_len_t n, ber_len_t s )
295 {
296 	return ber_memcalloc_x( n, s, NULL );
297 }
298 
299 void *
300 ber_memrealloc_x( void* p, ber_len_t s, void *ctx )
301 {
302 	void *new = NULL;
303 
304 	/* realloc(NULL,s) -> malloc(s) */
305 	if( p == NULL ) {
306 		return ber_memalloc_x( s, ctx );
307 	}
308 
309 	/* realloc(p,0) -> free(p) */
310 	if( s == 0 ) {
311 		ber_memfree_x( p, ctx );
312 		return NULL;
313 	}
314 
315 	BER_MEM_VALID( p );
316 
317 	if( ber_int_memory_fns == NULL || ctx == NULL ) {
318 #ifdef LDAP_MEMORY_DEBUG
319 		ber_int_t oldlen;
320 		struct ber_mem_hdr *mh = (struct ber_mem_hdr *)
321 			((char *)p - sizeof(struct ber_mem_hdr));
322 		assert( mh->bm_top == LBER_MEM_JUNK);
323 		assert( testdatatop( mh));
324 		assert( testend( (char *)&mh[1] + mh->bm_length) );
325 		oldlen = mh->bm_length;
326 
327 		p = realloc( mh, s + sizeof(struct ber_mem_hdr) + sizeof(ber_int_t) );
328 		if( p == NULL ) {
329 			ber_errno = LBER_ERROR_MEMORY;
330 			return NULL;
331 		}
332 
333 			mh = p;
334 		mh->bm_length = s;
335 		setend( (char *)&mh[1] + mh->bm_length );
336 		if( s > oldlen ) {
337 			/* poison any new memory */
338 			memset( (char *)&mh[1] + oldlen, 0xff, s - oldlen);
339 		}
340 
341 		assert( mh->bm_top == LBER_MEM_JUNK);
342 		assert( testdatatop( mh));
343 
344 		ber_int_meminuse += s - oldlen;
345 #ifdef LDAP_MEMORY_TRACE
346 		fprintf(stderr, "0x%08lx 0x%08lx -a- %ld ber_memrealloc %ld\n",
347 			(long)mh->bm_sequence, (long)mh, (long)mh->bm_length,
348 			ber_int_meminuse);
349 #endif
350 			BER_MEM_VALID( &mh[1] );
351 		return &mh[1];
352 #else
353 		new = realloc( p, s );
354 #endif
355 	} else {
356 		new = (*ber_int_memory_fns->bmf_realloc)( p, s, ctx );
357 	}
358 
359 	if( new == NULL ) {
360 		ber_errno = LBER_ERROR_MEMORY;
361 	}
362 
363 	return new;
364 }
365 
366 void *
367 ber_memrealloc( void* p, ber_len_t s )
368 {
369 	return ber_memrealloc_x( p, s, NULL );
370 }
371 
372 void
373 ber_bvfree_x( struct berval *bv, void *ctx )
374 {
375 	if( bv == NULL ) {
376 		return;
377 	}
378 
379 	BER_MEM_VALID( bv );
380 
381 	if ( bv->bv_val != NULL ) {
382 		ber_memfree_x( bv->bv_val, ctx );
383 	}
384 
385 	ber_memfree_x( (char *) bv, ctx );
386 }
387 
388 void
389 ber_bvfree( struct berval *bv )
390 {
391 	ber_bvfree_x( bv, NULL );
392 }
393 
394 void
395 ber_bvecfree_x( struct berval **bv, void *ctx )
396 {
397 	int	i;
398 
399 	if( bv == NULL ) {
400 		return;
401 	}
402 
403 	BER_MEM_VALID( bv );
404 
405 	/* count elements */
406 	for ( i = 0; bv[i] != NULL; i++ ) ;
407 
408 	/* free in reverse order */
409 	for ( i--; i >= 0; i-- ) {
410 		ber_bvfree_x( bv[i], ctx );
411 	}
412 
413 	ber_memfree_x( (char *) bv, ctx );
414 }
415 
416 void
417 ber_bvecfree( struct berval **bv )
418 {
419 	ber_bvecfree_x( bv, NULL );
420 }
421 
422 int
423 ber_bvecadd_x( struct berval ***bvec, struct berval *bv, void *ctx )
424 {
425 	ber_len_t i;
426 	struct berval **new;
427 
428 	if( *bvec == NULL ) {
429 		if( bv == NULL ) {
430 			/* nothing to add */
431 			return 0;
432 		}
433 
434 		*bvec = ber_memalloc_x( 2 * sizeof(struct berval *), ctx );
435 
436 		if( *bvec == NULL ) {
437 			return -1;
438 		}
439 
440 		(*bvec)[0] = bv;
441 		(*bvec)[1] = NULL;
442 
443 		return 1;
444 	}
445 
446 	BER_MEM_VALID( bvec );
447 
448 	/* count entries */
449 	for ( i = 0; (*bvec)[i] != NULL; i++ ) {
450 		/* EMPTY */;
451 	}
452 
453 	if( bv == NULL ) {
454 		return i;
455 	}
456 
457 	new = ber_memrealloc_x( *bvec, (i+2) * sizeof(struct berval *), ctx);
458 
459 	if( new == NULL ) {
460 		return -1;
461 	}
462 
463 	*bvec = new;
464 
465 	(*bvec)[i++] = bv;
466 	(*bvec)[i] = NULL;
467 
468 	return i;
469 }
470 
471 int
472 ber_bvecadd( struct berval ***bvec, struct berval *bv )
473 {
474 	return ber_bvecadd_x( bvec, bv, NULL );
475 }
476 
477 struct berval *
478 ber_dupbv_x(
479 	struct berval *dst, struct berval *src, void *ctx )
480 {
481 	struct berval *new;
482 
483 	if( src == NULL ) {
484 		ber_errno = LBER_ERROR_PARAM;
485 		return NULL;
486 	}
487 
488 	if ( dst ) {
489 		new = dst;
490 	} else {
491 		if(( new = ber_memalloc_x( sizeof(struct berval), ctx )) == NULL ) {
492 			ber_errno = LBER_ERROR_MEMORY;
493 			return NULL;
494 		}
495 	}
496 
497 	if ( src->bv_val == NULL ) {
498 		new->bv_val = NULL;
499 		new->bv_len = 0;
500 		return new;
501 	}
502 
503 	if(( new->bv_val = ber_memalloc_x( src->bv_len + 1, ctx )) == NULL ) {
504 		ber_errno = LBER_ERROR_MEMORY;
505 		if ( !dst )
506 			ber_memfree_x( new, ctx );
507 		return NULL;
508 	}
509 
510 	AC_MEMCPY( new->bv_val, src->bv_val, src->bv_len );
511 	new->bv_val[src->bv_len] = '\0';
512 	new->bv_len = src->bv_len;
513 
514 	return new;
515 }
516 
517 struct berval *
518 ber_dupbv(
519 	struct berval *dst, struct berval *src )
520 {
521 	return ber_dupbv_x( dst, src, NULL );
522 }
523 
524 struct berval *
525 ber_bvdup(
526 	struct berval *src )
527 {
528 	return ber_dupbv_x( NULL, src, NULL );
529 }
530 
531 struct berval *
532 ber_str2bv_x(
533 	LDAP_CONST char *s, ber_len_t len, int dup, struct berval *bv,
534 	void *ctx)
535 {
536 	struct berval *new;
537 
538 	if( s == NULL ) {
539 		ber_errno = LBER_ERROR_PARAM;
540 		return NULL;
541 	}
542 
543 	if( bv ) {
544 		new = bv;
545 	} else {
546 		if(( new = ber_memalloc_x( sizeof(struct berval), ctx )) == NULL ) {
547 			ber_errno = LBER_ERROR_MEMORY;
548 			return NULL;
549 		}
550 	}
551 
552 	new->bv_len = len ? len : strlen( s );
553 	if ( dup ) {
554 		if ( (new->bv_val = ber_memalloc_x( new->bv_len+1, ctx )) == NULL ) {
555 			ber_errno = LBER_ERROR_MEMORY;
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 
570 struct berval *
571 ber_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 
577 struct berval *
578 ber_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 			ber_errno = LBER_ERROR_MEMORY;
594 			return NULL;
595 		}
596 	}
597 
598 	new->bv_len = len;
599 	if ( dup ) {
600 		if ( (new->bv_val = ber_memalloc_x( new->bv_len+1, ctx )) == NULL ) {
601 			ber_errno = LBER_ERROR_MEMORY;
602 			if ( !bv ) {
603 				ber_memfree_x( new, ctx );
604 			}
605 			return NULL;
606 		}
607 
608 		AC_MEMCPY( new->bv_val, s, new->bv_len );
609 		new->bv_val[new->bv_len] = '\0';
610 	} else {
611 		new->bv_val = (char *) s;
612 	}
613 
614 	return( new );
615 }
616 
617 struct berval *
618 ber_mem2bv(
619 	LDAP_CONST char *s, ber_len_t len, int dup, struct berval *bv)
620 {
621 	return ber_mem2bv_x( s, len, dup, bv, NULL );
622 }
623 
624 char *
625 ber_strdup_x( LDAP_CONST char *s, void *ctx )
626 {
627 	char    *p;
628 	size_t	len;
629 
630 #ifdef LDAP_MEMORY_DEBUG
631 	assert(s != NULL);			/* bv damn better point to something */
632 #endif
633 
634 	if( s == NULL ) {
635 		ber_errno = LBER_ERROR_PARAM;
636 		return NULL;
637 	}
638 
639 	len = strlen( s ) + 1;
640 
641 	if ( (p = ber_memalloc_x( len, ctx )) == NULL ) {
642 		ber_errno = LBER_ERROR_MEMORY;
643 		return NULL;
644 	}
645 
646 	AC_MEMCPY( p, s, len );
647 	return p;
648 }
649 
650 char *
651 ber_strdup( LDAP_CONST char *s )
652 {
653 	return ber_strdup_x( s, NULL );
654 }
655 
656 ber_len_t
657 ber_strnlen( LDAP_CONST char *s, ber_len_t len )
658 {
659 	ber_len_t l;
660 
661 	for ( l = 0; l < len && s[l] != '\0'; l++ ) ;
662 
663 	return l;
664 }
665 
666 char *
667 ber_strndup_x( LDAP_CONST char *s, ber_len_t l, void *ctx )
668 {
669 	char    *p;
670 	size_t	len;
671 
672 #ifdef LDAP_MEMORY_DEBUG
673 	assert(s != NULL);			/* bv damn better point to something */
674 #endif
675 
676 	if( s == NULL ) {
677 		ber_errno = LBER_ERROR_PARAM;
678 		return NULL;
679 	}
680 
681 	len = ber_strnlen( s, l );
682 
683 	if ( (p = ber_memalloc_x( len + 1, ctx )) == NULL ) {
684 		ber_errno = LBER_ERROR_MEMORY;
685 		return NULL;
686 	}
687 
688 	AC_MEMCPY( p, s, len );
689 	p[len] = '\0';
690 	return p;
691 }
692 
693 char *
694 ber_strndup( LDAP_CONST char *s, ber_len_t l )
695 {
696 	return ber_strndup_x( s, l, NULL );
697 }
698 
699 /*
700  * dst is resized as required by src and the value of src is copied into dst
701  * dst->bv_val must be NULL (and dst->bv_len must be 0), or it must be
702  * alloc'ed with the context ctx
703  */
704 struct berval *
705 ber_bvreplace_x( struct berval *dst, LDAP_CONST struct berval *src, void *ctx )
706 {
707 	assert( dst != NULL );
708 	assert( !BER_BVISNULL( src ) );
709 
710 	if ( BER_BVISNULL( dst ) || dst->bv_len < src->bv_len ) {
711 		dst->bv_val = ber_memrealloc_x( dst->bv_val, src->bv_len + 1, ctx );
712 	}
713 
714 	AC_MEMCPY( dst->bv_val, src->bv_val, src->bv_len + 1 );
715 	dst->bv_len = src->bv_len;
716 
717 	return dst;
718 }
719 
720 struct berval *
721 ber_bvreplace( struct berval *dst, LDAP_CONST struct berval *src )
722 {
723 	return ber_bvreplace_x( dst, src, NULL );
724 }
725 
726 void
727 ber_bvarray_free_x( BerVarray a, void *ctx )
728 {
729 	int i;
730 
731 	if (a) {
732 		BER_MEM_VALID( a );
733 
734 		/* count elements */
735 		for (i=0; a[i].bv_val; i++) ;
736 
737 		/* free in reverse order */
738 		for (i--; i>=0; i--) {
739 			ber_memfree_x(a[i].bv_val, ctx);
740 		}
741 
742 		ber_memfree_x(a, ctx);
743 	}
744 }
745 
746 void
747 ber_bvarray_free( BerVarray a )
748 {
749 	ber_bvarray_free_x(a, NULL);
750 }
751 
752 int
753 ber_bvarray_dup_x( BerVarray *dst, BerVarray src, void *ctx )
754 {
755 	int i, j;
756 	BerVarray new;
757 
758 	if ( !src ) {
759 		*dst = NULL;
760 		return 0;
761 	}
762 
763 	for (i=0; !BER_BVISNULL( &src[i] ); i++) ;
764 	new = ber_memalloc_x(( i+1 ) * sizeof(BerValue), ctx );
765 	if ( !new )
766 		return -1;
767 	for (j=0; j<i; j++) {
768 		ber_dupbv_x( &new[j], &src[j], ctx );
769 		if ( BER_BVISNULL( &new[j] )) {
770 			ber_bvarray_free_x( new, ctx );
771 			return -1;
772 		}
773 	}
774 	BER_BVZERO( &new[j] );
775 	*dst = new;
776 	return 0;
777 }
778 
779 int
780 ber_bvarray_add_x( BerVarray *a, BerValue *bv, void *ctx )
781 {
782 	int	n;
783 
784 	if ( *a == NULL ) {
785 		if (bv == NULL) {
786 			return 0;
787 		}
788 		n = 0;
789 
790 		*a = (BerValue *) ber_memalloc_x( 2 * sizeof(BerValue), ctx );
791 		if ( *a == NULL ) {
792 			return -1;
793 		}
794 
795 	} else {
796 		BerVarray atmp;
797 		BER_MEM_VALID( a );
798 
799 		for ( n = 0; *a != NULL && (*a)[n].bv_val != NULL; n++ ) {
800 			;	/* just count them */
801 		}
802 
803 		if (bv == NULL) {
804 			return n;
805 		}
806 
807 		atmp = (BerValue *) ber_memrealloc_x( (char *) *a,
808 		    (n + 2) * sizeof(BerValue), ctx );
809 
810 		if( atmp == NULL ) {
811 			return -1;
812 		}
813 
814 		*a = atmp;
815 	}
816 
817 	(*a)[n++] = *bv;
818 	(*a)[n].bv_val = NULL;
819 	(*a)[n].bv_len = 0;
820 
821 	return n;
822 }
823 
824 int
825 ber_bvarray_add( BerVarray *a, BerValue *bv )
826 {
827 	return ber_bvarray_add_x( a, bv, NULL );
828 }
829