]> git.sur5r.net Git - openldap/blob - libraries/liblber/memory.c
94ef772d97dbe169807c261b6840bcd9dcf23216
[openldap] / libraries / liblber / memory.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1998-2007 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 }