]> git.sur5r.net Git - openldap/blob - libraries/liblber/memory.c
remove meantion of ldap_unbind_ext_s(3)
[openldap] / libraries / liblber / memory.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1998-2005 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 # ifndef LDAP_MEMORY_DEBUG
25 #  define LDAP_MEMORY_DEBUG 1
26 # endif
27 #include <stdio.h>
28 #endif
29
30 #if LDAP_MEMORY_DEBUG
31 /*
32  * LDAP_MEMORY_DEBUG should only be enabled for the purposes of
33  * debugging memory management within OpenLDAP libraries and slapd.
34  * It should only be enabled by an experienced developer as it
35  * causes the inclusion of numerous assert()'s, many of which may
36  * be triggered by a prefectly valid program.
37  *
38  * The code behind this macro is subject to change as needed to
39  * support this testing.
40  */
41
42 struct ber_mem_hdr {
43         ber_int_t       bm_top; /* Pattern to detect buf overrun from prev buffer */
44         ber_int_t       bm_length; /* Length of user allocated area */
45 #ifdef LDAP_MEMORY_TRACE
46         ber_int_t       bm_sequence; /* Allocation sequence number */
47 #endif
48         union bmu_align_u {     /* Force alignment, pattern to detect back clobber */
49                 ber_len_t       bmu_len_t;
50                 ber_tag_t       bmu_tag_t;
51                 ber_int_t       bmu_int_t;
52
53                 size_t  bmu_size_t;
54                 void *  bmu_voidp;
55                 double  bmu_double;
56                 long    bmu_long;
57                 long    (*bmu_funcp)( double );
58                 unsigned char   bmu_char[4];
59         } ber_align;
60 #define bm_junk ber_align.bmu_len_t
61 #define bm_data ber_align.bmu_char[1]
62 #define bm_char ber_align.bmu_char
63 };
64
65 /* Pattern at top of allocated space */
66 #define LBER_MEM_JUNK 0xdeaddadaU
67
68 static const struct ber_mem_hdr ber_int_mem_hdr = { LBER_MEM_JUNK, 0, 0 };
69
70 /* Note sequence and ber_int_options.lbu_meminuse are counters, but are not
71  * thread safe.  If you want to use these values for multithreaded applications,
72  * you must put mutexes around them, otherwise they will have incorrect values.
73  * When debugging, if you sort the debug output, the sequence number will 
74  * put allocations/frees together.  It is then a simple matter to write a script
75  * to find any allocations that don't have a buffer free function.
76  */
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     ber_int_options.lbo_valid = LBER_INITIALIZED;
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_options.lbo_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_options.lbo_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         ber_int_options.lbo_valid = LBER_INITIALIZED;
176
177         if( vec == NULL ) {
178                 return;
179         }
180
181         BER_MEM_VALID( vec );
182
183         for ( i = 0; vec[i] != NULL; i++ ) {
184                 ber_memfree_x( vec[i], ctx );
185         }
186
187         ber_memfree_x( vec, ctx );
188 }
189
190 void
191 ber_memvfree( void **vec )
192 {
193         ber_memvfree_x( vec, NULL );
194 }
195
196 void *
197 ber_memalloc_x( ber_len_t s, void *ctx )
198 {
199         void *new;
200         ber_int_options.lbo_valid = LBER_INITIALIZED;
201
202 #ifdef LDAP_MEMORY_DEBUG
203         assert( s != 0 );
204 #endif
205
206         if( s == 0 ) {
207                 return NULL;
208         }
209
210         if( ber_int_memory_fns == NULL || ctx == NULL ) {
211 #ifdef LDAP_MEMORY_DEBUG
212                 struct ber_mem_hdr *mh = malloc(s + sizeof(struct ber_mem_hdr) + sizeof( ber_int_t));
213                 if( mh == NULL ) return NULL;
214
215                 mh->bm_top = LBER_MEM_JUNK;
216                 mh->bm_length = s;
217                 setdatatop( mh);
218                 setend( (char *)&mh[1] + mh->bm_length );
219
220                 ber_int_options.lbo_meminuse += mh->bm_length;  /* Count mem inuse */
221
222 #ifdef LDAP_MEMORY_TRACE
223                 mh->bm_sequence = sequence++;
224                 fprintf(stderr, "0x%08lx 0x%08lx -a- %ld ber_memalloc %ld\n",
225                         (long)mh->bm_sequence, (long)mh, (long)mh->bm_length,
226                         ber_int_options.lbo_meminuse);
227 #endif
228                 /* poison new memory */
229                 memset( (char *)&mh[1], 0xff, s);
230
231                 BER_MEM_VALID( &mh[1] );
232                 new = &mh[1];
233 #else
234                 new = malloc( s );
235 #endif
236         } else {
237                 new = (*ber_int_memory_fns->bmf_malloc)( s, ctx );
238         }
239
240         if( new == NULL ) {
241                 ber_errno = LBER_ERROR_MEMORY;
242         }
243
244         return new;
245 }
246
247 void *
248 ber_memalloc( ber_len_t s )
249 {
250         return ber_memalloc_x( s, NULL );
251 }
252
253 void *
254 ber_memcalloc_x( ber_len_t n, ber_len_t s, void *ctx )
255 {
256         void *new;
257         ber_int_options.lbo_valid = LBER_INITIALIZED;
258
259 #ifdef LDAP_MEMORY_DEBUG
260         assert( n != 0 && s != 0);
261 #endif
262
263         if( n == 0 || s == 0 ) {
264                 return NULL;
265         }
266
267         if( ber_int_memory_fns == NULL || ctx == NULL ) {
268 #ifdef LDAP_MEMORY_DEBUG
269                 struct ber_mem_hdr *mh = calloc(1,
270                         (n * s) + sizeof(struct ber_mem_hdr) + sizeof(ber_int_t) );
271                 if( mh == NULL ) return NULL;
272
273                 mh->bm_top = LBER_MEM_JUNK;
274                 mh->bm_length = n*s;
275                 setdatatop( mh);
276                 setend( (char *)&mh[1] + mh->bm_length );
277
278                 ber_int_options.lbo_meminuse += mh->bm_length;
279
280 #ifdef LDAP_MEMORY_TRACE
281                 mh->bm_sequence = sequence++;
282                 fprintf(stderr, "0x%08lx 0x%08lx -a- %ld ber_memcalloc %ld\n",
283                         (long)mh->bm_sequence, (long)mh, (long)mh->bm_length,
284                         ber_int_options.lbo_meminuse);
285 #endif
286                 BER_MEM_VALID( &mh[1] );
287                 new = &mh[1];
288 #else
289                 new = calloc( n, s );
290 #endif
291
292         } else {
293                 new = (*ber_int_memory_fns->bmf_calloc)( n, s, ctx );
294         }
295
296         if( new == NULL ) {
297                 ber_errno = LBER_ERROR_MEMORY;
298         }
299
300         return new;
301 }
302
303 void *
304 ber_memcalloc( ber_len_t n, ber_len_t s )
305 {
306         return ber_memcalloc_x( n, s, NULL );
307 }
308
309 void *
310 ber_memrealloc_x( void* p, ber_len_t s, void *ctx )
311 {
312         void *new = NULL;
313         ber_int_options.lbo_valid = LBER_INITIALIZED;
314
315         /* realloc(NULL,s) -> malloc(s) */
316         if( p == NULL ) {
317                 return ber_memalloc_x( s, ctx );
318         }
319         
320         /* realloc(p,0) -> free(p) */
321         if( s == 0 ) {
322                 ber_memfree_x( p, ctx );
323                 return NULL;
324         }
325
326         BER_MEM_VALID( p );
327
328         if( ber_int_memory_fns == NULL || ctx == NULL ) {
329 #ifdef LDAP_MEMORY_DEBUG
330                 ber_int_t oldlen;
331                 struct ber_mem_hdr *mh = (struct ber_mem_hdr *)
332                         ((char *)p - sizeof(struct ber_mem_hdr));
333                 assert( mh->bm_top == LBER_MEM_JUNK);
334                 assert( testdatatop( mh));
335                 assert( testend( (char *)&mh[1] + mh->bm_length) );
336                 oldlen = mh->bm_length;
337
338                 p = realloc( mh, s + sizeof(struct ber_mem_hdr) + sizeof(ber_int_t) );
339                 if( p == NULL ) {
340                         ber_errno = LBER_ERROR_MEMORY;
341                         return NULL;
342                 }
343
344                         mh = p;
345                 mh->bm_length = s;
346                 setend( (char *)&mh[1] + mh->bm_length );
347                 if( s > oldlen ) {
348                         /* poison any new memory */
349                         memset( (char *)&mh[1] + oldlen, 0xff, s - oldlen);
350                 }
351
352                 assert( mh->bm_top == LBER_MEM_JUNK);
353                 assert( testdatatop( mh));
354
355                 ber_int_options.lbo_meminuse += s - oldlen;
356 #ifdef LDAP_MEMORY_TRACE
357                 fprintf(stderr, "0x%08lx 0x%08lx -a- %ld ber_memrealloc %ld\n",
358                         (long)mh->bm_sequence, (long)mh, (long)mh->bm_length,
359                         ber_int_options.lbo_meminuse);
360 #endif
361                         BER_MEM_VALID( &mh[1] );
362                 return &mh[1];
363 #else
364                 new = realloc( p, s );
365 #endif
366         } else {
367                 new = (*ber_int_memory_fns->bmf_realloc)( p, s, ctx );
368         }
369
370         if( new == NULL ) {
371                 ber_errno = LBER_ERROR_MEMORY;
372         }
373
374         return new;
375 }
376
377 void *
378 ber_memrealloc( void* p, ber_len_t s )
379 {
380         return ber_memrealloc_x( p, s, NULL );
381 }
382
383 void
384 ber_bvfree_x( struct berval *bv, void *ctx )
385 {
386         ber_int_options.lbo_valid = LBER_INITIALIZED;
387
388         if( bv == NULL ) {
389                 return;
390         }
391
392         BER_MEM_VALID( bv );
393
394         if ( bv->bv_val != NULL ) {
395                 ber_memfree_x( bv->bv_val, ctx );
396         }
397
398         ber_memfree_x( (char *) bv, ctx );
399 }
400
401 void
402 ber_bvfree( struct berval *bv )
403 {
404         ber_bvfree_x( bv, NULL );
405 }
406
407 void
408 ber_bvecfree_x( struct berval **bv, void *ctx )
409 {
410         int     i;
411
412         ber_int_options.lbo_valid = LBER_INITIALIZED;
413
414         if( bv == NULL ) {
415                 return;
416         }
417
418         BER_MEM_VALID( bv );
419
420         /* count elements */
421         for ( i = 0; bv[i] != NULL; i++ ) ;
422
423         /* free in reverse order */
424         for ( i--; i >= 0; i-- ) {
425                 ber_bvfree_x( bv[i], ctx );
426         }
427
428         ber_memfree_x( (char *) bv, ctx );
429 }
430
431 void
432 ber_bvecfree( struct berval **bv )
433 {
434         ber_bvecfree_x( bv, NULL );
435 }
436
437 int
438 ber_bvecadd_x( struct berval ***bvec, struct berval *bv, void *ctx )
439 {
440         ber_len_t i;
441         struct berval **new;
442
443         ber_int_options.lbo_valid = LBER_INITIALIZED;
444
445         if( *bvec == NULL ) {
446                 if( bv == NULL ) {
447                         /* nothing to add */
448                         return 0;
449                 }
450
451                 *bvec = ber_memalloc_x( 2 * sizeof(struct berval *), ctx );
452
453                 if( *bvec == NULL ) {
454                         return -1;
455                 }
456
457                 (*bvec)[0] = bv;
458                 (*bvec)[1] = NULL;
459
460                 return 1;
461         }
462
463         BER_MEM_VALID( bvec );
464
465         /* count entries */
466         for ( i = 0; (*bvec)[i] != NULL; i++ ) {
467                 /* EMPTY */;
468         }
469
470         if( bv == NULL ) {
471                 return i;
472         }
473
474         new = ber_memrealloc_x( *bvec, (i+2) * sizeof(struct berval *), ctx);
475
476         if( new == NULL ) {
477                 return -1;
478         }
479
480         *bvec = new;
481
482         (*bvec)[i++] = bv;
483         (*bvec)[i] = NULL;
484
485         return i;
486 }
487
488 int
489 ber_bvecadd( struct berval ***bvec, struct berval *bv )
490 {
491         return ber_bvecadd_x( bvec, bv, NULL );
492 }
493
494 struct berval *
495 ber_dupbv_x(
496         struct berval *dst, struct berval *src, void *ctx )
497 {
498         struct berval *new;
499
500         ber_int_options.lbo_valid = LBER_INITIALIZED;
501
502         if( src == NULL ) {
503                 ber_errno = LBER_ERROR_PARAM;
504                 return NULL;
505         }
506
507         if ( dst ) {
508                 new = dst;
509         } else {
510                 if(( new = ber_memalloc_x( sizeof(struct berval), ctx )) == NULL ) {
511                         ber_errno = LBER_ERROR_MEMORY;
512                         return NULL;
513                 }
514         }
515
516         if ( src->bv_val == NULL ) {
517                 new->bv_val = NULL;
518                 new->bv_len = 0;
519                 return new;
520         }
521
522         if(( new->bv_val = ber_memalloc_x( src->bv_len + 1, ctx )) == NULL ) {
523                 ber_errno = LBER_ERROR_MEMORY;
524                 if ( !dst )
525                         ber_memfree_x( new, ctx );
526                 return NULL;
527         }
528
529         AC_MEMCPY( new->bv_val, src->bv_val, src->bv_len );
530         new->bv_val[src->bv_len] = '\0';
531         new->bv_len = src->bv_len;
532
533         return new;
534 }
535
536 struct berval *
537 ber_dupbv(
538         struct berval *dst, struct berval *src )
539 {
540         return ber_dupbv_x( dst, src, NULL );
541 }
542
543 struct berval *
544 ber_bvdup(
545         struct berval *src )
546 {
547         return ber_dupbv_x( NULL, src, NULL );
548 }
549
550 struct berval *
551 ber_str2bv_x(
552         LDAP_CONST char *s, ber_len_t len, int dup, struct berval *bv,
553         void *ctx)
554 {
555         struct berval *new;
556
557         ber_int_options.lbo_valid = LBER_INITIALIZED;
558
559         if( s == NULL ) {
560                 ber_errno = LBER_ERROR_PARAM;
561                 return NULL;
562         }
563
564         if( bv ) {
565                 new = bv;
566         } else {
567                 if(( new = ber_memalloc_x( sizeof(struct berval), ctx )) == NULL ) {
568                         ber_errno = LBER_ERROR_MEMORY;
569                         return NULL;
570                 }
571         }
572
573         new->bv_len = len ? len : strlen( s );
574         if ( dup ) {
575                 if ( (new->bv_val = ber_memalloc_x( new->bv_len+1, ctx )) == NULL ) {
576                         ber_errno = LBER_ERROR_MEMORY;
577                         if ( !bv )
578                                 ber_memfree_x( new, ctx );
579                         return NULL;
580                 }
581
582                 AC_MEMCPY( new->bv_val, s, new->bv_len );
583                 new->bv_val[new->bv_len] = '\0';
584         } else {
585                 new->bv_val = (char *) s;
586         }
587
588         return( new );
589 }
590
591 struct berval *
592 ber_str2bv(
593         LDAP_CONST char *s, ber_len_t len, int dup, struct berval *bv)
594 {
595         return ber_str2bv_x( s, len, dup, bv, NULL );
596 }
597
598 struct berval *
599 ber_mem2bv_x(
600         LDAP_CONST char *s, ber_len_t len, int dup, struct berval *bv,
601         void *ctx)
602 {
603         struct berval *new;
604
605         ber_int_options.lbo_valid = LBER_INITIALIZED;
606
607         if( s == NULL ) {
608                 ber_errno = LBER_ERROR_PARAM;
609                 return NULL;
610         }
611
612         if( bv ) {
613                 new = bv;
614         } else {
615                 if(( new = ber_memalloc_x( sizeof(struct berval), ctx )) == NULL ) {
616                         ber_errno = LBER_ERROR_MEMORY;
617                         return NULL;
618                 }
619         }
620
621         new->bv_len = len;
622         if ( dup ) {
623                 if ( (new->bv_val = ber_memalloc_x( new->bv_len+1, ctx )) == NULL ) {
624                         ber_errno = LBER_ERROR_MEMORY;
625                         if ( !bv ) {
626                                 ber_memfree_x( new, ctx );
627                         }
628                         return NULL;
629                 }
630
631                 AC_MEMCPY( new->bv_val, s, new->bv_len );
632                 new->bv_val[new->bv_len] = '\0';
633         } else {
634                 new->bv_val = (char *) s;
635         }
636
637         return( new );
638 }
639
640 struct berval *
641 ber_mem2bv(
642         LDAP_CONST char *s, ber_len_t len, int dup, struct berval *bv)
643 {
644         return ber_mem2bv_x( s, len, dup, bv, NULL );
645 }
646
647 char *
648 ber_strdup_x( LDAP_CONST char *s, void *ctx )
649 {
650         char    *p;
651         size_t  len;
652         
653         ber_int_options.lbo_valid = LBER_INITIALIZED;
654
655 #ifdef LDAP_MEMORY_DEBUG
656         assert(s != NULL);                      /* bv damn better point to something */
657 #endif
658
659         if( s == NULL ) {
660                 ber_errno = LBER_ERROR_PARAM;
661                 return NULL;
662         }
663
664         len = strlen( s ) + 1;
665
666         if ( (p = ber_memalloc_x( len, ctx )) == NULL ) {
667                 ber_errno = LBER_ERROR_MEMORY;
668                 return NULL;
669         }
670
671         AC_MEMCPY( p, s, len );
672         return p;
673 }
674
675 char *
676 ber_strdup( LDAP_CONST char *s )
677 {
678         return ber_strdup_x( s, NULL );
679 }
680
681 char *
682 ber_strndup_x( LDAP_CONST char *s, ber_len_t l, void *ctx )
683 {
684         char    *p;
685         size_t  len;
686         
687         ber_int_options.lbo_valid = LBER_INITIALIZED;
688
689 #ifdef LDAP_MEMORY_DEBUG
690         assert(s != NULL);                      /* bv damn better point to something */
691 #endif
692
693         if( s == NULL ) {
694                 ber_errno = LBER_ERROR_PARAM;
695                 return NULL;
696         }
697
698         len = strlen( s );
699
700         if ( len > l ) {
701                 len = l;
702         }
703
704         if ( (p = ber_memalloc_x( len + 1, ctx )) == NULL ) {
705                 ber_errno = LBER_ERROR_MEMORY;
706                 return NULL;
707         }
708
709         AC_MEMCPY( p, s, len );
710         p[len] = '\0';
711         return p;
712 }
713
714 char *
715 ber_strndup( LDAP_CONST char *s, ber_len_t l )
716 {
717         return ber_strndup_x( s, l, NULL );
718 }
719
720 /*
721  * dst is resized as required by src and the value of src is copied into dst
722  * dst->bv_val must be NULL (and dst->bv_len must be 0), or it must be
723  * alloc'ed with the context ctx
724  */
725 struct berval *
726 ber_bvreplace_x( struct berval *dst, LDAP_CONST struct berval *src, void *ctx )
727 {
728         assert( dst != NULL );
729
730         if ( dst->bv_len < src->bv_len ) {
731                 dst->bv_val = ber_memrealloc_x( dst->bv_val, src->bv_len + 1, ctx );
732         }
733
734         AC_MEMCPY( dst->bv_val, src->bv_val, src->bv_len + 1 );
735         dst->bv_len = src->bv_len;
736
737         return dst;
738 }
739
740 struct berval *
741 ber_bvreplace( struct berval *dst, LDAP_CONST struct berval *src )
742 {
743         return ber_bvreplace_x( dst, src, NULL );
744 }
745
746 void
747 ber_bvarray_free_x( BerVarray a, void *ctx )
748 {
749         int i;
750
751         ber_int_options.lbo_valid = LBER_INITIALIZED;
752
753         if (a) {
754                 BER_MEM_VALID( a );
755
756                 /* count elements */
757                 for (i=0; a[i].bv_val; i++) ;
758                 
759                 /* free in reverse order */
760                 for (i--; i>=0; i--) {
761                         ber_memfree_x(a[i].bv_val, ctx);
762                 }
763
764                 ber_memfree_x(a, ctx);
765         }
766 }
767
768 void
769 ber_bvarray_free( BerVarray a )
770 {
771         ber_bvarray_free_x(a, NULL);
772 }
773
774 int
775 ber_bvarray_add_x( BerVarray *a, BerValue *bv, void *ctx )
776 {
777         int     n;
778
779         ber_int_options.lbo_valid = LBER_INITIALIZED;
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
817         return n;
818 }
819
820 int
821 ber_bvarray_add( BerVarray *a, BerValue *bv )
822 {
823         return ber_bvarray_add_x( a, bv, NULL );
824 }