xref: /netbsd-src/external/bsd/openldap/dist/libraries/liblber/memory.c (revision 404fbe5fb94ca1e054339640cabb2801ce52dd30)
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/>.
3  *
4  * Copyright 1998-2008 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 
41 struct 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 0xdeaddadaU
66 
67 static const struct ber_mem_hdr ber_int_mem_hdr = { LBER_MEM_JUNK, 0, 0 };
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  */
76 long ber_int_meminuse = 0;
77 #ifdef LDAP_MEMORY_TRACE
78 static ber_int_t sequence = 0;
79 #endif
80 
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 };
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 
123 BerMemoryFunctions *ber_int_memory_fns = NULL;
124 
125 void
126 ber_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 
162 void
163 ber_memfree( void *p )
164 {
165 	ber_memfree_x(p, NULL);
166 }
167 
168 void
169 ber_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 
186 void
187 ber_memvfree( void **vec )
188 {
189 	ber_memvfree_x( vec, NULL );
190 }
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 		return NULL;
200 	}
201 
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;
206 
207 		mh->bm_top = LBER_MEM_JUNK;
208 		mh->bm_length = s;
209 		setdatatop( mh);
210 		setend( (char *)&mh[1] + mh->bm_length );
211 
212 		ber_int_meminuse += mh->bm_length;	/* Count mem inuse */
213 
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,
218 			ber_int_meminuse);
219 #endif
220 		/* poison new memory */
221 		memset( (char *)&mh[1], 0xff, s);
222 
223 		BER_MEM_VALID( &mh[1] );
224 		new = &mh[1];
225 #else
226 		new = malloc( s );
227 #endif
228 	} else {
229 		new = (*ber_int_memory_fns->bmf_malloc)( s, ctx );
230 	}
231 
232 	if( new == NULL ) {
233 		ber_errno = LBER_ERROR_MEMORY;
234 	}
235 
236 	return new;
237 }
238 
239 void *
240 ber_memalloc( ber_len_t s )
241 {
242 	return ber_memalloc_x( s, NULL );
243 }
244 
245 void *
246 ber_memcalloc_x( ber_len_t n, ber_len_t s, void *ctx )
247 {
248 	void *new;
249 
250 	if( n == 0 || s == 0 ) {
251 		LDAP_MEMORY_DEBUG_ASSERT( n != 0 && s != 0);
252 		return NULL;
253 	}
254 
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;
260 
261 		mh->bm_top = LBER_MEM_JUNK;
262 		mh->bm_length = n*s;
263 		setdatatop( mh);
264 		setend( (char *)&mh[1] + mh->bm_length );
265 
266 		ber_int_meminuse += mh->bm_length;
267 
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,
272 			ber_int_meminuse);
273 #endif
274 		BER_MEM_VALID( &mh[1] );
275 		new = &mh[1];
276 #else
277 		new = calloc( n, s );
278 #endif
279 
280 	} else {
281 		new = (*ber_int_memory_fns->bmf_calloc)( n, s, ctx );
282 	}
283 
284 	if( new == NULL ) {
285 		ber_errno = LBER_ERROR_MEMORY;
286 	}
287 
288 	return new;
289 }
290 
291 void *
292 ber_memcalloc( ber_len_t n, ber_len_t s )
293 {
294 	return ber_memcalloc_x( n, s, NULL );
295 }
296 
297 void *
298 ber_memrealloc_x( void* p, ber_len_t s, void *ctx )
299 {
300 	void *new = NULL;
301 
302 	/* realloc(NULL,s) -> malloc(s) */
303 	if( p == NULL ) {
304 		return ber_memalloc_x( s, ctx );
305 	}
306 
307 	/* realloc(p,0) -> free(p) */
308 	if( s == 0 ) {
309 		ber_memfree_x( p, ctx );
310 		return NULL;
311 	}
312 
313 	BER_MEM_VALID( p );
314 
315 	if( ber_int_memory_fns == NULL || ctx == NULL ) {
316 #ifdef LDAP_MEMORY_DEBUG
317 		ber_int_t oldlen;
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;
324 
325 		p = realloc( mh, s + sizeof(struct ber_mem_hdr) + sizeof(ber_int_t) );
326 		if( p == NULL ) {
327 			ber_errno = LBER_ERROR_MEMORY;
328 			return NULL;
329 		}
330 
331 			mh = p;
332 		mh->bm_length = s;
333 		setend( (char *)&mh[1] + mh->bm_length );
334 		if( s > oldlen ) {
335 			/* poison any new memory */
336 			memset( (char *)&mh[1] + oldlen, 0xff, s - oldlen);
337 		}
338 
339 		assert( mh->bm_top == LBER_MEM_JUNK);
340 		assert( testdatatop( mh));
341 
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,
346 			ber_int_meminuse);
347 #endif
348 			BER_MEM_VALID( &mh[1] );
349 		return &mh[1];
350 #else
351 		new = realloc( p, s );
352 #endif
353 	} else {
354 		new = (*ber_int_memory_fns->bmf_realloc)( p, s, ctx );
355 	}
356 
357 	if( new == NULL ) {
358 		ber_errno = LBER_ERROR_MEMORY;
359 	}
360 
361 	return new;
362 }
363 
364 void *
365 ber_memrealloc( void* p, ber_len_t s )
366 {
367 	return ber_memrealloc_x( p, s, NULL );
368 }
369 
370 void
371 ber_bvfree_x( struct berval *bv, void *ctx )
372 {
373 	if( bv == NULL ) {
374 		return;
375 	}
376 
377 	BER_MEM_VALID( bv );
378 
379 	if ( bv->bv_val != NULL ) {
380 		ber_memfree_x( bv->bv_val, ctx );
381 	}
382 
383 	ber_memfree_x( (char *) bv, ctx );
384 }
385 
386 void
387 ber_bvfree( struct berval *bv )
388 {
389 	ber_bvfree_x( bv, NULL );
390 }
391 
392 void
393 ber_bvecfree_x( struct berval **bv, void *ctx )
394 {
395 	int	i;
396 
397 	if( bv == NULL ) {
398 		return;
399 	}
400 
401 	BER_MEM_VALID( bv );
402 
403 	/* count elements */
404 	for ( i = 0; bv[i] != NULL; i++ ) ;
405 
406 	/* free in reverse order */
407 	for ( i--; i >= 0; i-- ) {
408 		ber_bvfree_x( bv[i], ctx );
409 	}
410 
411 	ber_memfree_x( (char *) bv, ctx );
412 }
413 
414 void
415 ber_bvecfree( struct berval **bv )
416 {
417 	ber_bvecfree_x( bv, NULL );
418 }
419 
420 int
421 ber_bvecadd_x( struct berval ***bvec, struct berval *bv, void *ctx )
422 {
423 	ber_len_t i;
424 	struct berval **new;
425 
426 	if( *bvec == NULL ) {
427 		if( bv == NULL ) {
428 			/* nothing to add */
429 			return 0;
430 		}
431 
432 		*bvec = ber_memalloc_x( 2 * sizeof(struct berval *), ctx );
433 
434 		if( *bvec == NULL ) {
435 			return -1;
436 		}
437 
438 		(*bvec)[0] = bv;
439 		(*bvec)[1] = NULL;
440 
441 		return 1;
442 	}
443 
444 	BER_MEM_VALID( bvec );
445 
446 	/* count entries */
447 	for ( i = 0; (*bvec)[i] != NULL; i++ ) {
448 		/* EMPTY */;
449 	}
450 
451 	if( bv == NULL ) {
452 		return i;
453 	}
454 
455 	new = ber_memrealloc_x( *bvec, (i+2) * sizeof(struct berval *), ctx);
456 
457 	if( new == NULL ) {
458 		return -1;
459 	}
460 
461 	*bvec = new;
462 
463 	(*bvec)[i++] = bv;
464 	(*bvec)[i] = NULL;
465 
466 	return i;
467 }
468 
469 int
470 ber_bvecadd( struct berval ***bvec, struct berval *bv )
471 {
472 	return ber_bvecadd_x( bvec, bv, NULL );
473 }
474 
475 struct berval *
476 ber_dupbv_x(
477 	struct berval *dst, struct berval *src, void *ctx )
478 {
479 	struct berval *new;
480 
481 	if( src == NULL ) {
482 		ber_errno = LBER_ERROR_PARAM;
483 		return NULL;
484 	}
485 
486 	if ( dst ) {
487 		new = dst;
488 	} else {
489 		if(( new = ber_memalloc_x( sizeof(struct berval), ctx )) == NULL ) {
490 			ber_errno = LBER_ERROR_MEMORY;
491 			return NULL;
492 		}
493 	}
494 
495 	if ( src->bv_val == NULL ) {
496 		new->bv_val = NULL;
497 		new->bv_len = 0;
498 		return new;
499 	}
500 
501 	if(( new->bv_val = ber_memalloc_x( src->bv_len + 1, ctx )) == NULL ) {
502 		ber_errno = LBER_ERROR_MEMORY;
503 		if ( !dst )
504 			ber_memfree_x( new, ctx );
505 		return NULL;
506 	}
507 
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;
511 
512 	return new;
513 }
514 
515 struct berval *
516 ber_dupbv(
517 	struct berval *dst, struct berval *src )
518 {
519 	return ber_dupbv_x( dst, src, NULL );
520 }
521 
522 struct berval *
523 ber_bvdup(
524 	struct berval *src )
525 {
526 	return ber_dupbv_x( NULL, src, NULL );
527 }
528 
529 struct berval *
530 ber_str2bv_x(
531 	LDAP_CONST char *s, ber_len_t len, int dup, struct berval *bv,
532 	void *ctx)
533 {
534 	struct berval *new;
535 
536 	if( s == NULL ) {
537 		ber_errno = LBER_ERROR_PARAM;
538 		return NULL;
539 	}
540 
541 	if( bv ) {
542 		new = bv;
543 	} else {
544 		if(( new = ber_memalloc_x( sizeof(struct berval), ctx )) == NULL ) {
545 			ber_errno = LBER_ERROR_MEMORY;
546 			return NULL;
547 		}
548 	}
549 
550 	new->bv_len = len ? len : strlen( s );
551 	if ( dup ) {
552 		if ( (new->bv_val = ber_memalloc_x( new->bv_len+1, ctx )) == NULL ) {
553 			ber_errno = LBER_ERROR_MEMORY;
554 			if ( !bv )
555 				ber_memfree_x( new, ctx );
556 			return NULL;
557 		}
558 
559 		AC_MEMCPY( new->bv_val, s, new->bv_len );
560 		new->bv_val[new->bv_len] = '\0';
561 	} else {
562 		new->bv_val = (char *) s;
563 	}
564 
565 	return( new );
566 }
567 
568 struct berval *
569 ber_str2bv(
570 	LDAP_CONST char *s, ber_len_t len, int dup, struct berval *bv)
571 {
572 	return ber_str2bv_x( s, len, dup, bv, NULL );
573 }
574 
575 struct berval *
576 ber_mem2bv_x(
577 	LDAP_CONST char *s, ber_len_t len, int dup, struct berval *bv,
578 	void *ctx)
579 {
580 	struct berval *new;
581 
582 	if( s == NULL ) {
583 		ber_errno = LBER_ERROR_PARAM;
584 		return NULL;
585 	}
586 
587 	if( bv ) {
588 		new = bv;
589 	} else {
590 		if(( new = ber_memalloc_x( sizeof(struct berval), ctx )) == NULL ) {
591 			ber_errno = LBER_ERROR_MEMORY;
592 			return NULL;
593 		}
594 	}
595 
596 	new->bv_len = len;
597 	if ( dup ) {
598 		if ( (new->bv_val = ber_memalloc_x( new->bv_len+1, ctx )) == NULL ) {
599 			ber_errno = LBER_ERROR_MEMORY;
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 
615 struct berval *
616 ber_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 
622 char *
623 ber_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 
639 	if ( (p = ber_memalloc_x( len, ctx )) == NULL ) {
640 		ber_errno = LBER_ERROR_MEMORY;
641 		return NULL;
642 	}
643 
644 	AC_MEMCPY( p, s, len );
645 	return p;
646 }
647 
648 char *
649 ber_strdup( LDAP_CONST char *s )
650 {
651 	return ber_strdup_x( s, NULL );
652 }
653 
654 char *
655 ber_strndup_x( LDAP_CONST char *s, ber_len_t l, void *ctx )
656 {
657 	char    *p;
658 	size_t	len;
659 
660 #ifdef LDAP_MEMORY_DEBUG
661 	assert(s != NULL);			/* bv damn better point to something */
662 #endif
663 
664 	if( s == NULL ) {
665 		ber_errno = LBER_ERROR_PARAM;
666 		return NULL;
667 	}
668 
669 	len = strlen( s );
670 
671 	if ( len > l ) {
672 		len = l;
673 	}
674 
675 	if ( (p = ber_memalloc_x( len + 1, ctx )) == NULL ) {
676 		ber_errno = LBER_ERROR_MEMORY;
677 		return NULL;
678 	}
679 
680 	AC_MEMCPY( p, s, len );
681 	p[len] = '\0';
682 	return p;
683 }
684 
685 char *
686 ber_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  */
696 struct berval *
697 ber_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 
712 struct berval *
713 ber_bvreplace( struct berval *dst, LDAP_CONST struct berval *src )
714 {
715 	return ber_bvreplace_x( dst, src, NULL );
716 }
717 
718 void
719 ber_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 
738 void
739 ber_bvarray_free( BerVarray a )
740 {
741 	ber_bvarray_free_x(a, NULL);
742 }
743 
744 int
745 ber_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 
771 int
772 ber_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 
816 int
817 ber_bvarray_add( BerVarray *a, BerValue *bv )
818 {
819 	return ber_bvarray_add_x( a, bv, NULL );
820 }
821