]> git.sur5r.net Git - openldap/blob - libraries/liblber/memory.c
Notice updates
[openldap] / libraries / liblber / memory.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1998-2003 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%08x 0x%08x -f- %d ber_memfree %d\n",
147                         mh->bm_sequence, mh, mh->bm_length, ber_int_options.lbo_meminuse);
148 #endif
149                 /* Fill the free space with poison */
150                 memset( mh, 0xff, mh->bm_length + sizeof(struct ber_mem_hdr) + sizeof(ber_int_t));
151                 free( mh );
152 #else
153                 free( p );
154 #endif
155                 return;
156         }
157
158         assert( ber_int_memory_fns->bmf_free );
159
160         (*ber_int_memory_fns->bmf_free)( p, ctx );
161 }
162
163 void
164 ber_memfree( void *p )
165 {
166         ber_memfree_x(p, NULL);
167 }
168
169 void
170 ber_memvfree_x( void **vec, void *ctx )
171 {
172         int     i;
173
174         ber_int_options.lbo_valid = LBER_INITIALIZED;
175
176         if( vec == NULL ) {
177                 return;
178         }
179
180         BER_MEM_VALID( vec );
181
182         for ( i = 0; vec[i] != NULL; i++ ) {
183                 ber_memfree_x( vec[i], ctx );
184         }
185
186         ber_memfree_x( vec, ctx );
187 }
188
189 void
190 ber_memvfree( void **vec )
191 {
192         ber_memvfree_x( vec, NULL );
193 }
194
195 void *
196 ber_memalloc_x( ber_len_t s, void *ctx )
197 {
198         void *new;
199         ber_int_options.lbo_valid = LBER_INITIALIZED;
200
201 #ifdef LDAP_MEMORY_DEBUG
202         assert( s != 0 );
203 #endif
204
205         if( s == 0 ) {
206                 return NULL;
207         }
208
209         if( ber_int_memory_fns == NULL || ctx == NULL ) {
210 #ifdef LDAP_MEMORY_DEBUG
211                 struct ber_mem_hdr *mh = malloc(s + sizeof(struct ber_mem_hdr) + sizeof( ber_int_t));
212                 if( mh == NULL ) return NULL;
213
214                 mh->bm_top = LBER_MEM_JUNK;
215                 mh->bm_length = s;
216                 setdatatop( mh);
217                 setend( (char *)&mh[1] + mh->bm_length );
218
219                 ber_int_options.lbo_meminuse += mh->bm_length;  /* Count mem inuse */
220
221 #ifdef LDAP_MEMORY_TRACE
222                 mh->bm_sequence = sequence++;
223                 fprintf(stderr, "0x%08x 0x%08x -a- %d ber_memalloc %d\n",
224                         mh->bm_sequence, mh, mh->bm_length, ber_int_options.lbo_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 #else
232                 new = malloc( s );
233 #endif
234         } else {
235                 new = (*ber_int_memory_fns->bmf_malloc)( s, ctx );
236         }
237
238         if( new == NULL ) {
239                 ber_errno = LBER_ERROR_MEMORY;
240         }
241
242         return new;
243 }
244
245 void *
246 ber_memalloc( ber_len_t s )
247 {
248         return ber_memalloc_x( s, NULL );
249 }
250
251 void *
252 ber_memcalloc_x( ber_len_t n, ber_len_t s, void *ctx )
253 {
254         void *new;
255         ber_int_options.lbo_valid = LBER_INITIALIZED;
256
257 #ifdef LDAP_MEMORY_DEBUG
258         assert( n != 0 && s != 0);
259 #endif
260
261         if( n == 0 || s == 0 ) {
262                 return NULL;
263         }
264
265         if( ber_int_memory_fns == NULL || ctx == NULL ) {
266 #ifdef LDAP_MEMORY_DEBUG
267                 struct ber_mem_hdr *mh = calloc(1,
268                         (n * s) + sizeof(struct ber_mem_hdr) + sizeof(ber_int_t) );
269                 if( mh == NULL ) return NULL;
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_options.lbo_meminuse += mh->bm_length;
277
278 #ifdef LDAP_MEMORY_TRACE
279                 mh->bm_sequence = sequence++;
280                 fprintf(stderr, "0x%08x 0x%08x -a- %d ber_memcalloc %d\n",
281                         mh->bm_sequence, mh, mh->bm_length, ber_int_options.lbo_meminuse);
282 #endif
283                 BER_MEM_VALID( &mh[1] );
284                 new = &mh[1];
285 #else
286                 new = calloc( n, s );
287 #endif
288
289         } else {
290                 new = (*ber_int_memory_fns->bmf_calloc)( n, s, ctx );
291         }
292
293         if( new == NULL ) {
294                 ber_errno = LBER_ERROR_MEMORY;
295         }
296
297         return new;
298 }
299
300 void *
301 ber_memcalloc( ber_len_t n, ber_len_t s )
302 {
303         return ber_memcalloc_x( n, s, NULL );
304 }
305
306 void *
307 ber_memrealloc_x( void* p, ber_len_t s, void *ctx )
308 {
309         void *new = NULL;
310         ber_int_options.lbo_valid = LBER_INITIALIZED;
311
312         /* realloc(NULL,s) -> malloc(s) */
313         if( p == NULL ) {
314                 return ber_memalloc_x( s, ctx );
315         }
316         
317         /* realloc(p,0) -> free(p) */
318         if( s == 0 ) {
319                 ber_memfree_x( p, ctx );
320                 return NULL;
321         }
322
323         BER_MEM_VALID( p );
324
325         if( ber_int_memory_fns == NULL || ctx == NULL ) {
326 #ifdef LDAP_MEMORY_DEBUG
327                 ber_int_t oldlen;
328                 struct ber_mem_hdr *mh = (struct ber_mem_hdr *)
329                         ((char *)p - sizeof(struct ber_mem_hdr));
330                 assert( mh->bm_top == LBER_MEM_JUNK);
331                 assert( testdatatop( mh));
332                 assert( testend( (char *)&mh[1] + mh->bm_length) );
333                 oldlen = mh->bm_length;
334
335                 p = realloc( mh, s + sizeof(struct ber_mem_hdr) + sizeof(ber_int_t) );
336                 if( p == NULL ) {
337                         ber_errno = LBER_ERROR_MEMORY;
338                         return NULL;
339                 }
340
341                         mh = p;
342                 mh->bm_length = s;
343                 setend( (char *)&mh[1] + mh->bm_length );
344                 if( (s - oldlen) > 0 ) {
345                         /* poison any new memory */
346                         memset( (char *)&mh[1] + oldlen, 0xff, s - oldlen);
347                 }
348
349                 assert( mh->bm_top == LBER_MEM_JUNK);
350                 assert( testdatatop( mh));
351
352                 ber_int_options.lbo_meminuse += s - oldlen;
353 #ifdef LDAP_MEMORY_TRACE
354                 fprintf(stderr, "0x%08x 0x%08x -a- %d ber_memrealloc %d\n",
355                         mh->bm_sequence, mh, mh->bm_length, ber_int_options.lbo_meminuse);
356 #endif
357                         BER_MEM_VALID( &mh[1] );
358                 return &mh[1];
359 #else
360                 new = realloc( p, s );
361 #endif
362         } else {
363                 new = (*ber_int_memory_fns->bmf_realloc)( p, s, ctx );
364         }
365
366         if( new == NULL ) {
367                 ber_errno = LBER_ERROR_MEMORY;
368         }
369
370         return new;
371 }
372
373 void *
374 ber_memrealloc( void* p, ber_len_t s )
375 {
376         return ber_memrealloc_x( p, s, NULL );
377 }
378
379 void
380 ber_bvfree_x( struct berval *bv, void *ctx )
381 {
382         ber_int_options.lbo_valid = LBER_INITIALIZED;
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         ber_int_options.lbo_valid = LBER_INITIALIZED;
409
410         if( bv == NULL ) {
411                 return;
412         }
413
414         BER_MEM_VALID( bv );
415
416         /* count elements */
417         for ( i = 0; bv[i] != NULL; i++ ) ;
418
419         /* free in reverse order */
420         for ( i--; i >= 0; i-- ) {
421                 ber_bvfree_x( bv[i], ctx );
422         }
423
424         ber_memfree_x( (char *) bv, ctx );
425 }
426
427 void
428 ber_bvecfree( struct berval **bv )
429 {
430         ber_bvecfree_x( bv, NULL );
431 }
432
433 int
434 ber_bvecadd_x( struct berval ***bvec, struct berval *bv, void *ctx )
435 {
436         ber_len_t i;
437         struct berval **new;
438
439         ber_int_options.lbo_valid = LBER_INITIALIZED;
440
441         if( *bvec == NULL ) {
442                 if( bv == NULL ) {
443                         /* nothing to add */
444                         return 0;
445                 }
446
447                 *bvec = ber_memalloc_x( 2 * sizeof(struct berval *), ctx );
448
449                 if( *bvec == NULL ) {
450                         return -1;
451                 }
452
453                 (*bvec)[0] = bv;
454                 (*bvec)[1] = NULL;
455
456                 return 1;
457         }
458
459         BER_MEM_VALID( bvec );
460
461         /* count entries */
462         for ( i = 0; (*bvec)[i] != NULL; i++ ) {
463                 /* EMPTY */;
464         }
465
466         if( bv == NULL ) {
467                 return i;
468         }
469
470         new = ber_memrealloc_x( *bvec, (i+2) * sizeof(struct berval *), ctx);
471
472         if( new == NULL ) {
473                 return -1;
474         }
475
476         *bvec = new;
477
478         (*bvec)[i++] = bv;
479         (*bvec)[i] = NULL;
480
481         return i;
482 }
483
484 int
485 ber_bvecadd( struct berval ***bvec, struct berval *bv )
486 {
487         return ber_bvecadd_x( bvec, bv, NULL );
488 }
489
490 struct berval *
491 ber_dupbv_x(
492         struct berval *dst, struct berval *src, void *ctx )
493 {
494         struct berval *new;
495
496         ber_int_options.lbo_valid = LBER_INITIALIZED;
497
498         if( src == NULL ) {
499                 ber_errno = LBER_ERROR_PARAM;
500                 return NULL;
501         }
502
503         if ( dst ) {
504                 new = dst;
505         } else {
506                 if(( new = ber_memalloc_x( sizeof(struct berval), ctx )) == NULL ) {
507                         ber_errno = LBER_ERROR_MEMORY;
508                         return NULL;
509                 }
510         }
511
512         if ( src->bv_val == NULL ) {
513                 new->bv_val = NULL;
514                 new->bv_len = 0;
515                 return new;
516         }
517
518         if(( new->bv_val = ber_memalloc_x( src->bv_len + 1, ctx )) == NULL ) {
519                 ber_errno = LBER_ERROR_MEMORY;
520                 if ( !dst )
521                         ber_memfree_x( new, ctx );
522                 return NULL;
523         }
524
525         AC_MEMCPY( new->bv_val, src->bv_val, src->bv_len );
526         new->bv_val[src->bv_len] = '\0';
527         new->bv_len = src->bv_len;
528
529         return new;
530 }
531
532 struct berval *
533 ber_dupbv(
534         struct berval *dst, struct berval *src )
535 {
536         return ber_dupbv_x( dst, src, NULL );
537 }
538
539 struct berval *
540 ber_bvdup(
541         struct berval *src )
542 {
543         return ber_dupbv_x( NULL, src, NULL );
544 }
545
546 struct berval *
547 ber_str2bv_x(
548         LDAP_CONST char *s, ber_len_t len, int dup, struct berval *bv,
549         void *ctx)
550 {
551         struct berval *new;
552
553         ber_int_options.lbo_valid = LBER_INITIALIZED;
554
555         if( s == NULL ) {
556                 ber_errno = LBER_ERROR_PARAM;
557                 return NULL;
558         }
559
560         if( bv ) {
561                 new = bv;
562         } else {
563                 if(( new = ber_memalloc_x( sizeof(struct berval), ctx )) == NULL ) {
564                         ber_errno = LBER_ERROR_MEMORY;
565                         return NULL;
566                 }
567         }
568
569         new->bv_len = len ? len : strlen( s );
570         if ( dup ) {
571                 if ( (new->bv_val = ber_memalloc_x( new->bv_len+1, ctx )) == NULL ) {
572                         ber_errno = LBER_ERROR_MEMORY;
573                         if ( !bv )
574                                 ber_memfree_x( new, ctx );
575                         return NULL;
576                 }
577
578                 AC_MEMCPY( new->bv_val, s, new->bv_len );
579                 new->bv_val[new->bv_len] = '\0';
580         } else {
581                 new->bv_val = (char *) s;
582         }
583
584         return( new );
585 }
586
587 struct berval *
588 ber_str2bv(
589         LDAP_CONST char *s, ber_len_t len, int dup, struct berval *bv)
590 {
591         return ber_str2bv_x( s, len, dup, bv, NULL );
592 }
593
594 struct berval *
595 ber_mem2bv_x(
596         LDAP_CONST char *s, ber_len_t len, int dup, struct berval *bv,
597         void *ctx)
598 {
599         struct berval *new;
600
601         ber_int_options.lbo_valid = LBER_INITIALIZED;
602
603         if( s == NULL ) {
604                 ber_errno = LBER_ERROR_PARAM;
605                 return NULL;
606         }
607
608         if( bv ) {
609                 new = bv;
610         } else {
611                 if(( new = ber_memalloc_x( sizeof(struct berval), ctx )) == NULL ) {
612                         ber_errno = LBER_ERROR_MEMORY;
613                         return NULL;
614                 }
615         }
616
617         new->bv_len = len;
618         if ( dup ) {
619                 if ( (new->bv_val = ber_memalloc_x( new->bv_len+1, ctx )) == NULL ) {
620                         ber_errno = LBER_ERROR_MEMORY;
621                         if ( !bv ) {
622                                 ber_memfree_x( new, ctx );
623                         }
624                         return NULL;
625                 }
626
627                 AC_MEMCPY( new->bv_val, s, new->bv_len );
628                 new->bv_val[new->bv_len] = '\0';
629         } else {
630                 new->bv_val = (char *) s;
631         }
632
633         return( new );
634 }
635
636 struct berval *
637 ber_mem2bv(
638         LDAP_CONST char *s, ber_len_t len, int dup, struct berval *bv)
639 {
640         return ber_mem2bv_x( s, len, dup, bv, NULL );
641 }
642
643 char *
644 ber_strdup_x( LDAP_CONST char *s, void *ctx )
645 {
646         char    *p;
647         size_t  len;
648         
649         ber_int_options.lbo_valid = LBER_INITIALIZED;
650
651 #ifdef LDAP_MEMORY_DEBUG
652         assert(s != NULL);                      /* bv damn better point to something */
653 #endif
654
655         if( s == NULL ) {
656                 ber_errno = LBER_ERROR_PARAM;
657                 return NULL;
658         }
659
660         len = strlen( s ) + 1;
661
662         if ( (p = ber_memalloc_x( len, ctx )) == NULL ) {
663                 ber_errno = LBER_ERROR_MEMORY;
664                 return NULL;
665         }
666
667         AC_MEMCPY( p, s, len );
668         return p;
669 }
670
671 char *
672 ber_strdup( LDAP_CONST char *s )
673 {
674         return ber_strdup_x( s, NULL );
675 }
676
677 char *
678 ber_strndup_x( LDAP_CONST char *s, ber_len_t l, void *ctx )
679 {
680         char    *p;
681         size_t  len;
682         
683         ber_int_options.lbo_valid = LBER_INITIALIZED;
684
685 #ifdef LDAP_MEMORY_DEBUG
686         assert(s != NULL);                      /* bv damn better point to something */
687 #endif
688
689         if( s == NULL ) {
690                 ber_errno = LBER_ERROR_PARAM;
691                 return NULL;
692         }
693
694         len = strlen( s );
695
696         if ( len > l ) {
697                 len = l;
698         }
699
700         if ( (p = ber_memalloc_x( len + 1, ctx )) == NULL ) {
701                 ber_errno = LBER_ERROR_MEMORY;
702                 return NULL;
703         }
704
705         AC_MEMCPY( p, s, len );
706         p[len] = '\0';
707         return p;
708 }
709
710 char *
711 ber_strndup( LDAP_CONST char *s, ber_len_t l )
712 {
713         return ber_strndup_x( s, l, NULL );
714 }
715
716 void
717 ber_bvarray_free_x( BerVarray a, void *ctx )
718 {
719         int i;
720
721         ber_int_options.lbo_valid = LBER_INITIALIZED;
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_add_x( BerVarray *a, BerValue *bv, void *ctx )
746 {
747         int     n;
748
749         ber_int_options.lbo_valid = LBER_INITIALIZED;
750
751         if ( *a == NULL ) {
752                 if (bv == NULL) {
753                         return 0;
754                 }
755                 n = 0;
756
757                 *a = (BerValue *) ber_memalloc_x( 2 * sizeof(BerValue), ctx );
758                 if ( *a == NULL ) {
759                         return -1;
760                 }
761
762         } else {
763                 BerVarray atmp;
764                 BER_MEM_VALID( a );
765
766                 for ( n = 0; *a != NULL && (*a)[n].bv_val != NULL; n++ ) {
767                         ;       /* just count them */
768                 }
769
770                 if (bv == NULL) {
771                         return n;
772                 }
773
774                 atmp = (BerValue *) ber_memrealloc_x( (char *) *a,
775                     (n + 2) * sizeof(BerValue), ctx );
776
777                 if( atmp == NULL ) {
778                         return -1;
779                 }
780
781                 *a = atmp;
782         }
783
784         (*a)[n++] = *bv;
785         (*a)[n].bv_val = NULL;
786
787         return n;
788 }
789
790 int
791 ber_bvarray_add( BerVarray *a, BerValue *bv )
792 {
793         return ber_bvarray_add_x( a, bv, NULL );
794 }