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