xref: /netbsd-src/external/bsd/openldap/dist/libraries/liblber/memory.c (revision 946379e7b37692fc43f68eb0d1c10daa0a7f3b6c)
1 /*	$NetBSD: memory.c,v 1.1.1.4 2014/05/28 09:58:41 tron Exp $	*/
2 
3 /* $OpenLDAP$ */
4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5  *
6  * Copyright 1998-2014 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 ((ber_int_t) 0xdeaddada)
68 
69 static const struct ber_mem_hdr ber_int_mem_hdr = { LBER_MEM_JUNK };
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 		new = malloc(s + sizeof(struct ber_mem_hdr) + sizeof( ber_int_t));
207 		if( new )
208 		{
209 		struct ber_mem_hdr *mh = new;
210 		mh->bm_top = LBER_MEM_JUNK;
211 		mh->bm_length = s;
212 		setdatatop( mh);
213 		setend( (char *)&mh[1] + mh->bm_length );
214 
215 		ber_int_meminuse += mh->bm_length;	/* Count mem inuse */
216 
217 #ifdef LDAP_MEMORY_TRACE
218 		mh->bm_sequence = sequence++;
219 		fprintf(stderr, "0x%08lx 0x%08lx -a- %ld ber_memalloc %ld\n",
220 			(long)mh->bm_sequence, (long)mh, (long)mh->bm_length,
221 			ber_int_meminuse);
222 #endif
223 		/* poison new memory */
224 		memset( (char *)&mh[1], 0xff, s);
225 
226 		BER_MEM_VALID( &mh[1] );
227 		new = &mh[1];
228 		}
229 #else
230 		new = malloc( s );
231 #endif
232 	} else {
233 		new = (*ber_int_memory_fns->bmf_malloc)( s, ctx );
234 	}
235 
236 	if( new == NULL ) {
237 		ber_errno = LBER_ERROR_MEMORY;
238 	}
239 
240 	return new;
241 }
242 
243 void *
244 ber_memalloc( ber_len_t s )
245 {
246 	return ber_memalloc_x( s, NULL );
247 }
248 
249 void *
250 ber_memcalloc_x( ber_len_t n, ber_len_t s, void *ctx )
251 {
252 	void *new;
253 
254 	if( n == 0 || s == 0 ) {
255 		LDAP_MEMORY_DEBUG_ASSERT( n != 0 && s != 0);
256 		return NULL;
257 	}
258 
259 	if( ber_int_memory_fns == NULL || ctx == NULL ) {
260 #ifdef LDAP_MEMORY_DEBUG
261 		new = n < (-sizeof(struct ber_mem_hdr) - sizeof(ber_int_t)) / s
262 			? calloc(1, n*s + sizeof(struct ber_mem_hdr) + sizeof(ber_int_t))
263 			: NULL;
264 		if( new )
265 		{
266 		struct ber_mem_hdr *mh = new;
267 
268 		mh->bm_top = LBER_MEM_JUNK;
269 		mh->bm_length = n*s;
270 		setdatatop( mh);
271 		setend( (char *)&mh[1] + mh->bm_length );
272 
273 		ber_int_meminuse += mh->bm_length;
274 
275 #ifdef LDAP_MEMORY_TRACE
276 		mh->bm_sequence = sequence++;
277 		fprintf(stderr, "0x%08lx 0x%08lx -a- %ld ber_memcalloc %ld\n",
278 			(long)mh->bm_sequence, (long)mh, (long)mh->bm_length,
279 			ber_int_meminuse);
280 #endif
281 		BER_MEM_VALID( &mh[1] );
282 		new = &mh[1];
283 		}
284 #else
285 		new = calloc( n, s );
286 #endif
287 
288 	} else {
289 		new = (*ber_int_memory_fns->bmf_calloc)( n, s, ctx );
290 	}
291 
292 	if( new == NULL ) {
293 		ber_errno = LBER_ERROR_MEMORY;
294 	}
295 
296 	return new;
297 }
298 
299 void *
300 ber_memcalloc( ber_len_t n, ber_len_t s )
301 {
302 	return ber_memcalloc_x( n, s, NULL );
303 }
304 
305 void *
306 ber_memrealloc_x( void* p, ber_len_t s, void *ctx )
307 {
308 	void *new = NULL;
309 
310 	/* realloc(NULL,s) -> malloc(s) */
311 	if( p == NULL ) {
312 		return ber_memalloc_x( s, ctx );
313 	}
314 
315 	/* realloc(p,0) -> free(p) */
316 	if( s == 0 ) {
317 		ber_memfree_x( p, ctx );
318 		return NULL;
319 	}
320 
321 	BER_MEM_VALID( p );
322 
323 	if( ber_int_memory_fns == NULL || ctx == NULL ) {
324 #ifdef LDAP_MEMORY_DEBUG
325 		ber_int_t oldlen;
326 		struct ber_mem_hdr *mh = (struct ber_mem_hdr *)
327 			((char *)p - sizeof(struct ber_mem_hdr));
328 		assert( mh->bm_top == LBER_MEM_JUNK);
329 		assert( testdatatop( mh));
330 		assert( testend( (char *)&mh[1] + mh->bm_length) );
331 		oldlen = mh->bm_length;
332 
333 		p = realloc( mh, s + sizeof(struct ber_mem_hdr) + sizeof(ber_int_t) );
334 		if( p == NULL ) {
335 			ber_errno = LBER_ERROR_MEMORY;
336 			return NULL;
337 		}
338 
339 			mh = p;
340 		mh->bm_length = s;
341 		setend( (char *)&mh[1] + mh->bm_length );
342 		if( s > oldlen ) {
343 			/* poison any new memory */
344 			memset( (char *)&mh[1] + oldlen, 0xff, s - oldlen);
345 		}
346 
347 		assert( mh->bm_top == LBER_MEM_JUNK);
348 		assert( testdatatop( mh));
349 
350 		ber_int_meminuse += s - oldlen;
351 #ifdef LDAP_MEMORY_TRACE
352 		fprintf(stderr, "0x%08lx 0x%08lx -a- %ld ber_memrealloc %ld\n",
353 			(long)mh->bm_sequence, (long)mh, (long)mh->bm_length,
354 			ber_int_meminuse);
355 #endif
356 			BER_MEM_VALID( &mh[1] );
357 		return &mh[1];
358 #else
359 		new = realloc( p, s );
360 #endif
361 	} else {
362 		new = (*ber_int_memory_fns->bmf_realloc)( p, s, ctx );
363 	}
364 
365 	if( new == NULL ) {
366 		ber_errno = LBER_ERROR_MEMORY;
367 	}
368 
369 	return new;
370 }
371 
372 void *
373 ber_memrealloc( void* p, ber_len_t s )
374 {
375 	return ber_memrealloc_x( p, s, NULL );
376 }
377 
378 void
379 ber_bvfree_x( struct berval *bv, void *ctx )
380 {
381 	if( bv == NULL ) {
382 		return;
383 	}
384 
385 	BER_MEM_VALID( bv );
386 
387 	if ( bv->bv_val != NULL ) {
388 		ber_memfree_x( bv->bv_val, ctx );
389 	}
390 
391 	ber_memfree_x( (char *) bv, ctx );
392 }
393 
394 void
395 ber_bvfree( struct berval *bv )
396 {
397 	ber_bvfree_x( bv, NULL );
398 }
399 
400 void
401 ber_bvecfree_x( struct berval **bv, void *ctx )
402 {
403 	int	i;
404 
405 	if( bv == NULL ) {
406 		return;
407 	}
408 
409 	BER_MEM_VALID( bv );
410 
411 	/* count elements */
412 	for ( i = 0; bv[i] != NULL; i++ ) ;
413 
414 	/* free in reverse order */
415 	for ( i--; i >= 0; i-- ) {
416 		ber_bvfree_x( bv[i], ctx );
417 	}
418 
419 	ber_memfree_x( (char *) bv, ctx );
420 }
421 
422 void
423 ber_bvecfree( struct berval **bv )
424 {
425 	ber_bvecfree_x( bv, NULL );
426 }
427 
428 int
429 ber_bvecadd_x( struct berval ***bvec, struct berval *bv, void *ctx )
430 {
431 	ber_len_t i;
432 	struct berval **new;
433 
434 	if( *bvec == NULL ) {
435 		if( bv == NULL ) {
436 			/* nothing to add */
437 			return 0;
438 		}
439 
440 		*bvec = ber_memalloc_x( 2 * sizeof(struct berval *), ctx );
441 
442 		if( *bvec == NULL ) {
443 			return -1;
444 		}
445 
446 		(*bvec)[0] = bv;
447 		(*bvec)[1] = NULL;
448 
449 		return 1;
450 	}
451 
452 	BER_MEM_VALID( bvec );
453 
454 	/* count entries */
455 	for ( i = 0; (*bvec)[i] != NULL; i++ ) {
456 		/* EMPTY */;
457 	}
458 
459 	if( bv == NULL ) {
460 		return i;
461 	}
462 
463 	new = ber_memrealloc_x( *bvec, (i+2) * sizeof(struct berval *), ctx);
464 
465 	if( new == NULL ) {
466 		return -1;
467 	}
468 
469 	*bvec = new;
470 
471 	(*bvec)[i++] = bv;
472 	(*bvec)[i] = NULL;
473 
474 	return i;
475 }
476 
477 int
478 ber_bvecadd( struct berval ***bvec, struct berval *bv )
479 {
480 	return ber_bvecadd_x( bvec, bv, NULL );
481 }
482 
483 struct berval *
484 ber_dupbv_x(
485 	struct berval *dst, struct berval *src, void *ctx )
486 {
487 	struct berval *new;
488 
489 	if( src == NULL ) {
490 		ber_errno = LBER_ERROR_PARAM;
491 		return NULL;
492 	}
493 
494 	if ( dst ) {
495 		new = dst;
496 	} else {
497 		if(( new = ber_memalloc_x( sizeof(struct berval), ctx )) == NULL ) {
498 			return NULL;
499 		}
500 	}
501 
502 	if ( src->bv_val == NULL ) {
503 		new->bv_val = NULL;
504 		new->bv_len = 0;
505 		return new;
506 	}
507 
508 	if(( new->bv_val = ber_memalloc_x( src->bv_len + 1, ctx )) == NULL ) {
509 		if ( !dst )
510 			ber_memfree_x( new, ctx );
511 		return NULL;
512 	}
513 
514 	AC_MEMCPY( new->bv_val, src->bv_val, src->bv_len );
515 	new->bv_val[src->bv_len] = '\0';
516 	new->bv_len = src->bv_len;
517 
518 	return new;
519 }
520 
521 struct berval *
522 ber_dupbv(
523 	struct berval *dst, struct berval *src )
524 {
525 	return ber_dupbv_x( dst, src, NULL );
526 }
527 
528 struct berval *
529 ber_bvdup(
530 	struct berval *src )
531 {
532 	return ber_dupbv_x( NULL, src, NULL );
533 }
534 
535 struct berval *
536 ber_str2bv_x(
537 	LDAP_CONST char *s, ber_len_t len, int dup, struct berval *bv,
538 	void *ctx)
539 {
540 	struct berval *new;
541 
542 	if( s == NULL ) {
543 		ber_errno = LBER_ERROR_PARAM;
544 		return NULL;
545 	}
546 
547 	if( bv ) {
548 		new = bv;
549 	} else {
550 		if(( new = ber_memalloc_x( sizeof(struct berval), ctx )) == NULL ) {
551 			return NULL;
552 		}
553 	}
554 
555 	new->bv_len = len ? len : strlen( s );
556 	if ( dup ) {
557 		if ( (new->bv_val = ber_memalloc_x( new->bv_len+1, ctx )) == NULL ) {
558 			if ( !bv )
559 				ber_memfree_x( new, ctx );
560 			return NULL;
561 		}
562 
563 		AC_MEMCPY( new->bv_val, s, new->bv_len );
564 		new->bv_val[new->bv_len] = '\0';
565 	} else {
566 		new->bv_val = (char *) s;
567 	}
568 
569 	return( new );
570 }
571 
572 struct berval *
573 ber_str2bv(
574 	LDAP_CONST char *s, ber_len_t len, int dup, struct berval *bv)
575 {
576 	return ber_str2bv_x( s, len, dup, bv, NULL );
577 }
578 
579 struct berval *
580 ber_mem2bv_x(
581 	LDAP_CONST char *s, ber_len_t len, int dup, struct berval *bv,
582 	void *ctx)
583 {
584 	struct berval *new;
585 
586 	if( s == NULL ) {
587 		ber_errno = LBER_ERROR_PARAM;
588 		return NULL;
589 	}
590 
591 	if( bv ) {
592 		new = bv;
593 	} else {
594 		if(( new = ber_memalloc_x( sizeof(struct berval), ctx )) == NULL ) {
595 			return NULL;
596 		}
597 	}
598 
599 	new->bv_len = len;
600 	if ( dup ) {
601 		if ( (new->bv_val = ber_memalloc_x( new->bv_len+1, ctx )) == NULL ) {
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 	if ( (p = ber_memalloc_x( len, ctx )) != NULL ) {
641 		AC_MEMCPY( p, s, len );
642 	}
643 
644 	return p;
645 }
646 
647 char *
648 ber_strdup( LDAP_CONST char *s )
649 {
650 	return ber_strdup_x( s, NULL );
651 }
652 
653 ber_len_t
654 ber_strnlen( LDAP_CONST char *s, ber_len_t len )
655 {
656 	ber_len_t l;
657 
658 	for ( l = 0; l < len && s[l] != '\0'; l++ ) ;
659 
660 	return l;
661 }
662 
663 char *
664 ber_strndup_x( LDAP_CONST char *s, ber_len_t l, void *ctx )
665 {
666 	char    *p;
667 	size_t	len;
668 
669 #ifdef LDAP_MEMORY_DEBUG
670 	assert(s != NULL);			/* bv damn better point to something */
671 #endif
672 
673 	if( s == NULL ) {
674 		ber_errno = LBER_ERROR_PARAM;
675 		return NULL;
676 	}
677 
678 	len = ber_strnlen( s, l );
679 	if ( (p = ber_memalloc_x( len + 1, ctx )) != NULL ) {
680 		AC_MEMCPY( p, s, len );
681 		p[len] = '\0';
682 	}
683 
684 	return p;
685 }
686 
687 char *
688 ber_strndup( LDAP_CONST char *s, ber_len_t l )
689 {
690 	return ber_strndup_x( s, l, NULL );
691 }
692 
693 /*
694  * dst is resized as required by src and the value of src is copied into dst
695  * dst->bv_val must be NULL (and dst->bv_len must be 0), or it must be
696  * alloc'ed with the context ctx
697  */
698 struct berval *
699 ber_bvreplace_x( struct berval *dst, LDAP_CONST struct berval *src, void *ctx )
700 {
701 	assert( dst != NULL );
702 	assert( !BER_BVISNULL( src ) );
703 
704 	if ( BER_BVISNULL( dst ) || dst->bv_len < src->bv_len ) {
705 		dst->bv_val = ber_memrealloc_x( dst->bv_val, src->bv_len + 1, ctx );
706 	}
707 
708 	AC_MEMCPY( dst->bv_val, src->bv_val, src->bv_len + 1 );
709 	dst->bv_len = src->bv_len;
710 
711 	return dst;
712 }
713 
714 struct berval *
715 ber_bvreplace( struct berval *dst, LDAP_CONST struct berval *src )
716 {
717 	return ber_bvreplace_x( dst, src, NULL );
718 }
719 
720 void
721 ber_bvarray_free_x( BerVarray a, void *ctx )
722 {
723 	int i;
724 
725 	if (a) {
726 		BER_MEM_VALID( a );
727 
728 		/* count elements */
729 		for (i=0; a[i].bv_val; i++) ;
730 
731 		/* free in reverse order */
732 		for (i--; i>=0; i--) {
733 			ber_memfree_x(a[i].bv_val, ctx);
734 		}
735 
736 		ber_memfree_x(a, ctx);
737 	}
738 }
739 
740 void
741 ber_bvarray_free( BerVarray a )
742 {
743 	ber_bvarray_free_x(a, NULL);
744 }
745 
746 int
747 ber_bvarray_dup_x( BerVarray *dst, BerVarray src, void *ctx )
748 {
749 	int i, j;
750 	BerVarray new;
751 
752 	if ( !src ) {
753 		*dst = NULL;
754 		return 0;
755 	}
756 
757 	for (i=0; !BER_BVISNULL( &src[i] ); i++) ;
758 	new = ber_memalloc_x(( i+1 ) * sizeof(BerValue), ctx );
759 	if ( !new )
760 		return -1;
761 	for (j=0; j<i; j++) {
762 		ber_dupbv_x( &new[j], &src[j], ctx );
763 		if ( BER_BVISNULL( &new[j] )) {
764 			ber_bvarray_free_x( new, ctx );
765 			return -1;
766 		}
767 	}
768 	BER_BVZERO( &new[j] );
769 	*dst = new;
770 	return 0;
771 }
772 
773 int
774 ber_bvarray_add_x( BerVarray *a, BerValue *bv, void *ctx )
775 {
776 	int	n;
777 
778 	if ( *a == NULL ) {
779 		if (bv == NULL) {
780 			return 0;
781 		}
782 		n = 0;
783 
784 		*a = (BerValue *) ber_memalloc_x( 2 * sizeof(BerValue), ctx );
785 		if ( *a == NULL ) {
786 			return -1;
787 		}
788 
789 	} else {
790 		BerVarray atmp;
791 		BER_MEM_VALID( a );
792 
793 		for ( n = 0; *a != NULL && (*a)[n].bv_val != NULL; n++ ) {
794 			;	/* just count them */
795 		}
796 
797 		if (bv == NULL) {
798 			return n;
799 		}
800 
801 		atmp = (BerValue *) ber_memrealloc_x( (char *) *a,
802 		    (n + 2) * sizeof(BerValue), ctx );
803 
804 		if( atmp == NULL ) {
805 			return -1;
806 		}
807 
808 		*a = atmp;
809 	}
810 
811 	(*a)[n++] = *bv;
812 	(*a)[n].bv_val = NULL;
813 	(*a)[n].bv_len = 0;
814 
815 	return n;
816 }
817 
818 int
819 ber_bvarray_add( BerVarray *a, BerValue *bv )
820 {
821 	return ber_bvarray_add_x( a, bv, NULL );
822 }
823