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