Home | History | Annotate | Line # | Download | only in liblber
      1 /*	$NetBSD: memory.c,v 1.4 2025/09/05 21:16:20 christos Exp $	*/
      2 
      3 /* $OpenLDAP$ */
      4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
      5  *
      6  * Copyright 1998-2024 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.4 2025/09/05 21:16:20 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 perfectly 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, tmp;
    491 
    492 	if( src == NULL ) {
    493 		ber_errno = LBER_ERROR_PARAM;
    494 		return NULL;
    495 	}
    496 
    497 	if ( dst ) {
    498 		new = &tmp;
    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 	} else {
    509 
    510 		if(( new->bv_val = ber_memalloc_x( src->bv_len + 1, ctx )) == NULL ) {
    511 			if ( !dst )
    512 				ber_memfree_x( new, ctx );
    513 			return NULL;
    514 		}
    515 
    516 		AC_MEMCPY( new->bv_val, src->bv_val, src->bv_len );
    517 		new->bv_val[src->bv_len] = '\0';
    518 		new->bv_len = src->bv_len;
    519 	}
    520 
    521 	if ( dst ) {
    522 		*dst = *new;
    523 		new = dst;
    524 	}
    525 
    526 	return new;
    527 }
    528 
    529 struct berval *
    530 ber_dupbv(
    531 	struct berval *dst, struct berval *src )
    532 {
    533 	return ber_dupbv_x( dst, src, NULL );
    534 }
    535 
    536 struct berval *
    537 ber_bvdup(
    538 	struct berval *src )
    539 {
    540 	return ber_dupbv_x( NULL, src, NULL );
    541 }
    542 
    543 struct berval *
    544 ber_str2bv_x(
    545 	LDAP_CONST char *s, ber_len_t len, int dup, struct berval *bv,
    546 	void *ctx)
    547 {
    548 	struct berval *new;
    549 
    550 	if( s == NULL ) {
    551 		ber_errno = LBER_ERROR_PARAM;
    552 		return NULL;
    553 	}
    554 
    555 	if( bv ) {
    556 		new = bv;
    557 	} else {
    558 		if(( new = ber_memalloc_x( sizeof(struct berval), ctx )) == NULL ) {
    559 			return NULL;
    560 		}
    561 	}
    562 
    563 	new->bv_len = len ? len : strlen( s );
    564 	if ( dup ) {
    565 		if ( (new->bv_val = ber_memalloc_x( new->bv_len+1, ctx )) == NULL ) {
    566 			if ( !bv )
    567 				ber_memfree_x( new, ctx );
    568 			return NULL;
    569 		}
    570 
    571 		AC_MEMCPY( new->bv_val, s, new->bv_len );
    572 		new->bv_val[new->bv_len] = '\0';
    573 	} else {
    574 		new->bv_val = (char *) s;
    575 	}
    576 
    577 	return( new );
    578 }
    579 
    580 struct berval *
    581 ber_str2bv(
    582 	LDAP_CONST char *s, ber_len_t len, int dup, struct berval *bv)
    583 {
    584 	return ber_str2bv_x( s, len, dup, bv, NULL );
    585 }
    586 
    587 struct berval *
    588 ber_mem2bv_x(
    589 	LDAP_CONST char *s, ber_len_t len, int dup, struct berval *bv,
    590 	void *ctx)
    591 {
    592 	struct berval *new;
    593 
    594 	if( s == NULL ) {
    595 		ber_errno = LBER_ERROR_PARAM;
    596 		return NULL;
    597 	}
    598 
    599 	if( bv ) {
    600 		new = bv;
    601 	} else {
    602 		if(( new = ber_memalloc_x( sizeof(struct berval), ctx )) == NULL ) {
    603 			return NULL;
    604 		}
    605 	}
    606 
    607 	new->bv_len = len;
    608 	if ( dup ) {
    609 		if ( (new->bv_val = ber_memalloc_x( new->bv_len+1, ctx )) == NULL ) {
    610 			if ( !bv ) {
    611 				ber_memfree_x( new, ctx );
    612 			}
    613 			return NULL;
    614 		}
    615 
    616 		AC_MEMCPY( new->bv_val, s, new->bv_len );
    617 		new->bv_val[new->bv_len] = '\0';
    618 	} else {
    619 		new->bv_val = (char *) s;
    620 	}
    621 
    622 	return( new );
    623 }
    624 
    625 struct berval *
    626 ber_mem2bv(
    627 	LDAP_CONST char *s, ber_len_t len, int dup, struct berval *bv)
    628 {
    629 	return ber_mem2bv_x( s, len, dup, bv, NULL );
    630 }
    631 
    632 char *
    633 ber_strdup_x( LDAP_CONST char *s, void *ctx )
    634 {
    635 	char    *p;
    636 	size_t	len;
    637 
    638 #ifdef LDAP_MEMORY_DEBUG
    639 	assert(s != NULL);			/* bv damn better point to something */
    640 #endif
    641 
    642 	if( s == NULL ) {
    643 		ber_errno = LBER_ERROR_PARAM;
    644 		return NULL;
    645 	}
    646 
    647 	len = strlen( s ) + 1;
    648 	if ( (p = ber_memalloc_x( len, ctx )) != NULL ) {
    649 		AC_MEMCPY( p, s, len );
    650 	}
    651 
    652 	return p;
    653 }
    654 
    655 char *
    656 ber_strdup( LDAP_CONST char *s )
    657 {
    658 	return ber_strdup_x( s, NULL );
    659 }
    660 
    661 ber_len_t
    662 ber_strnlen( LDAP_CONST char *s, ber_len_t len )
    663 {
    664 	ber_len_t l;
    665 
    666 	for ( l = 0; l < len && s[l] != '\0'; l++ ) ;
    667 
    668 	return l;
    669 }
    670 
    671 char *
    672 ber_strndup_x( LDAP_CONST char *s, ber_len_t l, void *ctx )
    673 {
    674 	char    *p;
    675 	size_t	len;
    676 
    677 #ifdef LDAP_MEMORY_DEBUG
    678 	assert(s != NULL);			/* bv damn better point to something */
    679 #endif
    680 
    681 	if( s == NULL ) {
    682 		ber_errno = LBER_ERROR_PARAM;
    683 		return NULL;
    684 	}
    685 
    686 	len = ber_strnlen( s, l );
    687 	if ( (p = ber_memalloc_x( len + 1, ctx )) != NULL ) {
    688 		AC_MEMCPY( p, s, len );
    689 		p[len] = '\0';
    690 	}
    691 
    692 	return p;
    693 }
    694 
    695 char *
    696 ber_strndup( LDAP_CONST char *s, ber_len_t l )
    697 {
    698 	return ber_strndup_x( s, l, NULL );
    699 }
    700 
    701 /*
    702  * dst is resized as required by src and the value of src is copied into dst
    703  * dst->bv_val must be NULL (and dst->bv_len must be 0), or it must be
    704  * alloc'ed with the context ctx
    705  */
    706 struct berval *
    707 ber_bvreplace_x( struct berval *dst, LDAP_CONST struct berval *src, void *ctx )
    708 {
    709 	assert( dst != NULL );
    710 	assert( !BER_BVISNULL( src ) );
    711 
    712 	if ( BER_BVISNULL( dst ) || dst->bv_len < src->bv_len ) {
    713 		dst->bv_val = ber_memrealloc_x( dst->bv_val, src->bv_len + 1, ctx );
    714 	}
    715 
    716 	AC_MEMCPY( dst->bv_val, src->bv_val, src->bv_len + 1 );
    717 	dst->bv_len = src->bv_len;
    718 
    719 	return dst;
    720 }
    721 
    722 struct berval *
    723 ber_bvreplace( struct berval *dst, LDAP_CONST struct berval *src )
    724 {
    725 	return ber_bvreplace_x( dst, src, NULL );
    726 }
    727 
    728 void
    729 ber_bvarray_free_x( BerVarray a, void *ctx )
    730 {
    731 	int i;
    732 
    733 	if (a) {
    734 		BER_MEM_VALID( a );
    735 
    736 		/* count elements */
    737 		for (i=0; a[i].bv_val; i++) ;
    738 
    739 		/* free in reverse order */
    740 		for (i--; i>=0; i--) {
    741 			ber_memfree_x(a[i].bv_val, ctx);
    742 		}
    743 
    744 		ber_memfree_x(a, ctx);
    745 	}
    746 }
    747 
    748 void
    749 ber_bvarray_free( BerVarray a )
    750 {
    751 	ber_bvarray_free_x(a, NULL);
    752 }
    753 
    754 int
    755 ber_bvarray_dup_x( BerVarray *dst, BerVarray src, void *ctx )
    756 {
    757 	int i, j;
    758 	BerVarray new;
    759 
    760 	if ( !src ) {
    761 		*dst = NULL;
    762 		return 0;
    763 	}
    764 
    765 	for (i=0; !BER_BVISNULL( &src[i] ); i++) ;
    766 	new = ber_memalloc_x(( i+1 ) * sizeof(BerValue), ctx );
    767 	if ( !new )
    768 		return -1;
    769 	for (j=0; j<i; j++) {
    770 		ber_dupbv_x( &new[j], &src[j], ctx );
    771 		if ( BER_BVISNULL( &new[j] )) {
    772 			ber_bvarray_free_x( new, ctx );
    773 			return -1;
    774 		}
    775 	}
    776 	BER_BVZERO( &new[j] );
    777 	*dst = new;
    778 	return 0;
    779 }
    780 
    781 int
    782 ber_bvarray_add_x( BerVarray *a, BerValue *bv, void *ctx )
    783 {
    784 	int	n;
    785 
    786 	if ( *a == NULL ) {
    787 		if (bv == NULL) {
    788 			return 0;
    789 		}
    790 		n = 0;
    791 
    792 		*a = (BerValue *) ber_memalloc_x( 2 * sizeof(BerValue), ctx );
    793 		if ( *a == NULL ) {
    794 			return -1;
    795 		}
    796 
    797 	} else {
    798 		BerVarray atmp;
    799 		BER_MEM_VALID( a );
    800 
    801 		for ( n = 0; *a != NULL && (*a)[n].bv_val != NULL; n++ ) {
    802 			;	/* just count them */
    803 		}
    804 
    805 		if (bv == NULL) {
    806 			return n;
    807 		}
    808 
    809 		atmp = (BerValue *) ber_memrealloc_x( (char *) *a,
    810 		    (n + 2) * sizeof(BerValue), ctx );
    811 
    812 		if( atmp == NULL ) {
    813 			return -1;
    814 		}
    815 
    816 		*a = atmp;
    817 	}
    818 
    819 	(*a)[n++] = *bv;
    820 	(*a)[n].bv_val = NULL;
    821 	(*a)[n].bv_len = 0;
    822 
    823 	return n;
    824 }
    825 
    826 int
    827 ber_bvarray_add( BerVarray *a, BerValue *bv )
    828 {
    829 	return ber_bvarray_add_x( a, bv, NULL );
    830 }
    831