1 /*
2  *  Buffer-based memory allocator
3  *
4  *  Copyright The Mbed TLS Contributors
5  *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
6  *
7  *  This file is provided under the Apache License 2.0, or the
8  *  GNU General Public License v2.0 or later.
9  *
10  *  **********
11  *  Apache License 2.0:
12  *
13  *  Licensed under the Apache License, Version 2.0 (the "License"); you may
14  *  not use this file except in compliance with the License.
15  *  You may obtain a copy of the License at
16  *
17  *  http://www.apache.org/licenses/LICENSE-2.0
18  *
19  *  Unless required by applicable law or agreed to in writing, software
20  *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
21  *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22  *  See the License for the specific language governing permissions and
23  *  limitations under the License.
24  *
25  *  **********
26  *
27  *  **********
28  *  GNU General Public License v2.0 or later:
29  *
30  *  This program is free software; you can redistribute it and/or modify
31  *  it under the terms of the GNU General Public License as published by
32  *  the Free Software Foundation; either version 2 of the License, or
33  *  (at your option) any later version.
34  *
35  *  This program is distributed in the hope that it will be useful,
36  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
37  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
38  *  GNU General Public License for more details.
39  *
40  *  You should have received a copy of the GNU General Public License along
41  *  with this program; if not, write to the Free Software Foundation, Inc.,
42  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
43  *
44  *  **********
45  */
46 
47 #if !defined(MBEDTLS_CONFIG_FILE)
48 #include "mbedtls/config.h"
49 #else
50 #include MBEDTLS_CONFIG_FILE
51 #endif
52 
53 #if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C)
54 #include "mbedtls/memory_buffer_alloc.h"
55 
56 /* No need for the header guard as MBEDTLS_MEMORY_BUFFER_ALLOC_C
57    is dependent upon MBEDTLS_PLATFORM_C */
58 #include "mbedtls/platform.h"
59 #include "mbedtls/platform_util.h"
60 
61 #include <string.h>
62 
63 #if defined(MBEDTLS_MEMORY_BACKTRACE)
64 #include <execinfo.h>
65 #endif
66 
67 #if defined(MBEDTLS_THREADING_C)
68 #include "mbedtls/threading.h"
69 #endif
70 
71 #define MAGIC1       0xFF00AA55
72 #define MAGIC2       0xEE119966
73 #define MAX_BT 20
74 
75 typedef struct _memory_header memory_header;
76 struct _memory_header
77 {
78     size_t          magic1;
79     size_t          size;
80     size_t          alloc;
81     memory_header   *prev;
82     memory_header   *next;
83     memory_header   *prev_free;
84     memory_header   *next_free;
85 #if defined(MBEDTLS_MEMORY_BACKTRACE)
86     char            **trace;
87     size_t          trace_count;
88 #endif
89     size_t          magic2;
90 };
91 
92 typedef struct
93 {
94     unsigned char   *buf;
95     size_t          len;
96     memory_header   *first;
97     memory_header   *first_free;
98     int             verify;
99 #if defined(MBEDTLS_MEMORY_DEBUG)
100     size_t          alloc_count;
101     size_t          free_count;
102     size_t          total_used;
103     size_t          maximum_used;
104     size_t          header_count;
105     size_t          maximum_header_count;
106 #endif
107 #if defined(MBEDTLS_THREADING_C)
108     mbedtls_threading_mutex_t   mutex;
109 #endif
110 }
111 buffer_alloc_ctx;
112 
113 static buffer_alloc_ctx heap;
114 
115 #if defined(MBEDTLS_MEMORY_DEBUG)
116 static void debug_header( memory_header *hdr )
117 {
118 #if defined(MBEDTLS_MEMORY_BACKTRACE)
119     size_t i;
120 #endif
121 
122     mbedtls_fprintf( stderr, "HDR:  PTR(%10zu), PREV(%10zu), NEXT(%10zu), "
123                               "ALLOC(%zu), SIZE(%10zu)\n",
124                       (size_t) hdr, (size_t) hdr->prev, (size_t) hdr->next,
125                       hdr->alloc, hdr->size );
126     mbedtls_fprintf( stderr, "      FPREV(%10zu), FNEXT(%10zu)\n",
127                       (size_t) hdr->prev_free, (size_t) hdr->next_free );
128 
129 #if defined(MBEDTLS_MEMORY_BACKTRACE)
130     mbedtls_fprintf( stderr, "TRACE: \n" );
131     for( i = 0; i < hdr->trace_count; i++ )
132         mbedtls_fprintf( stderr, "%s\n", hdr->trace[i] );
133     mbedtls_fprintf( stderr, "\n" );
134 #endif
135 }
136 
137 static void debug_chain( void )
138 {
139     memory_header *cur = heap.first;
140 
141     mbedtls_fprintf( stderr, "\nBlock list\n" );
142     while( cur != NULL )
143     {
144         debug_header( cur );
145         cur = cur->next;
146     }
147 
148     mbedtls_fprintf( stderr, "Free list\n" );
149     cur = heap.first_free;
150 
151     while( cur != NULL )
152     {
153         debug_header( cur );
154         cur = cur->next_free;
155     }
156 }
157 #endif /* MBEDTLS_MEMORY_DEBUG */
158 
159 static int verify_header( memory_header *hdr )
160 {
161     if( hdr->magic1 != MAGIC1 )
162     {
163 #if defined(MBEDTLS_MEMORY_DEBUG)
164         mbedtls_fprintf( stderr, "FATAL: MAGIC1 mismatch\n" );
165 #endif
166         return( 1 );
167     }
168 
169     if( hdr->magic2 != MAGIC2 )
170     {
171 #if defined(MBEDTLS_MEMORY_DEBUG)
172         mbedtls_fprintf( stderr, "FATAL: MAGIC2 mismatch\n" );
173 #endif
174         return( 1 );
175     }
176 
177     if( hdr->alloc > 1 )
178     {
179 #if defined(MBEDTLS_MEMORY_DEBUG)
180         mbedtls_fprintf( stderr, "FATAL: alloc has illegal value\n" );
181 #endif
182         return( 1 );
183     }
184 
185     if( hdr->prev != NULL && hdr->prev == hdr->next )
186     {
187 #if defined(MBEDTLS_MEMORY_DEBUG)
188         mbedtls_fprintf( stderr, "FATAL: prev == next\n" );
189 #endif
190         return( 1 );
191     }
192 
193     if( hdr->prev_free != NULL && hdr->prev_free == hdr->next_free )
194     {
195 #if defined(MBEDTLS_MEMORY_DEBUG)
196         mbedtls_fprintf( stderr, "FATAL: prev_free == next_free\n" );
197 #endif
198         return( 1 );
199     }
200 
201     return( 0 );
202 }
203 
204 static int verify_chain( void )
205 {
206     memory_header *prv = heap.first, *cur;
207 
208     if( prv == NULL || verify_header( prv ) != 0 )
209     {
210 #if defined(MBEDTLS_MEMORY_DEBUG)
211         mbedtls_fprintf( stderr, "FATAL: verification of first header "
212                                   "failed\n" );
213 #endif
214         return( 1 );
215     }
216 
217     if( heap.first->prev != NULL )
218     {
219 #if defined(MBEDTLS_MEMORY_DEBUG)
220         mbedtls_fprintf( stderr, "FATAL: verification failed: "
221                                   "first->prev != NULL\n" );
222 #endif
223         return( 1 );
224     }
225 
226     cur = heap.first->next;
227 
228     while( cur != NULL )
229     {
230         if( verify_header( cur ) != 0 )
231         {
232 #if defined(MBEDTLS_MEMORY_DEBUG)
233             mbedtls_fprintf( stderr, "FATAL: verification of header "
234                                       "failed\n" );
235 #endif
236             return( 1 );
237         }
238 
239         if( cur->prev != prv )
240         {
241 #if defined(MBEDTLS_MEMORY_DEBUG)
242             mbedtls_fprintf( stderr, "FATAL: verification failed: "
243                                       "cur->prev != prv\n" );
244 #endif
245             return( 1 );
246         }
247 
248         prv = cur;
249         cur = cur->next;
250     }
251 
252     return( 0 );
253 }
254 
255 static void *buffer_alloc_calloc( size_t n, size_t size )
256 {
257     memory_header *new, *cur = heap.first_free;
258     unsigned char *p;
259     void *ret;
260     size_t original_len, len;
261 #if defined(MBEDTLS_MEMORY_BACKTRACE)
262     void *trace_buffer[MAX_BT];
263     size_t trace_cnt;
264 #endif
265 
266     if( heap.buf == NULL || heap.first == NULL )
267         return( NULL );
268 
269     original_len = len = n * size;
270 
271     if( n == 0 || size == 0 || len / n != size )
272         return( NULL );
273     else if( len > (size_t)-MBEDTLS_MEMORY_ALIGN_MULTIPLE )
274         return( NULL );
275 
276     if( len % MBEDTLS_MEMORY_ALIGN_MULTIPLE )
277     {
278         len -= len % MBEDTLS_MEMORY_ALIGN_MULTIPLE;
279         len += MBEDTLS_MEMORY_ALIGN_MULTIPLE;
280     }
281 
282     // Find block that fits
283     //
284     while( cur != NULL )
285     {
286         if( cur->size >= len )
287             break;
288 
289         cur = cur->next_free;
290     }
291 
292     if( cur == NULL )
293         return( NULL );
294 
295     if( cur->alloc != 0 )
296     {
297 #if defined(MBEDTLS_MEMORY_DEBUG)
298         mbedtls_fprintf( stderr, "FATAL: block in free_list but allocated "
299                                   "data\n" );
300 #endif
301         mbedtls_exit( 1 );
302     }
303 
304 #if defined(MBEDTLS_MEMORY_DEBUG)
305     heap.alloc_count++;
306 #endif
307 
308     // Found location, split block if > memory_header + 4 room left
309     //
310     if( cur->size - len < sizeof(memory_header) +
311                           MBEDTLS_MEMORY_ALIGN_MULTIPLE )
312     {
313         cur->alloc = 1;
314 
315         // Remove from free_list
316         //
317         if( cur->prev_free != NULL )
318             cur->prev_free->next_free = cur->next_free;
319         else
320             heap.first_free = cur->next_free;
321 
322         if( cur->next_free != NULL )
323             cur->next_free->prev_free = cur->prev_free;
324 
325         cur->prev_free = NULL;
326         cur->next_free = NULL;
327 
328 #if defined(MBEDTLS_MEMORY_DEBUG)
329         heap.total_used += cur->size;
330         if( heap.total_used > heap.maximum_used )
331             heap.maximum_used = heap.total_used;
332 #endif
333 #if defined(MBEDTLS_MEMORY_BACKTRACE)
334         trace_cnt = backtrace( trace_buffer, MAX_BT );
335         cur->trace = backtrace_symbols( trace_buffer, trace_cnt );
336         cur->trace_count = trace_cnt;
337 #endif
338 
339         if( ( heap.verify & MBEDTLS_MEMORY_VERIFY_ALLOC ) && verify_chain() != 0 )
340             mbedtls_exit( 1 );
341 
342         ret = (unsigned char *) cur + sizeof( memory_header );
343         memset( ret, 0, original_len );
344 
345         return( ret );
346     }
347 
348     p = ( (unsigned char *) cur ) + sizeof(memory_header) + len;
349     new = (memory_header *) p;
350 
351     new->size = cur->size - len - sizeof(memory_header);
352     new->alloc = 0;
353     new->prev = cur;
354     new->next = cur->next;
355 #if defined(MBEDTLS_MEMORY_BACKTRACE)
356     new->trace = NULL;
357     new->trace_count = 0;
358 #endif
359     new->magic1 = MAGIC1;
360     new->magic2 = MAGIC2;
361 
362     if( new->next != NULL )
363         new->next->prev = new;
364 
365     // Replace cur with new in free_list
366     //
367     new->prev_free = cur->prev_free;
368     new->next_free = cur->next_free;
369     if( new->prev_free != NULL )
370         new->prev_free->next_free = new;
371     else
372         heap.first_free = new;
373 
374     if( new->next_free != NULL )
375         new->next_free->prev_free = new;
376 
377     cur->alloc = 1;
378     cur->size = len;
379     cur->next = new;
380     cur->prev_free = NULL;
381     cur->next_free = NULL;
382 
383 #if defined(MBEDTLS_MEMORY_DEBUG)
384     heap.header_count++;
385     if( heap.header_count > heap.maximum_header_count )
386         heap.maximum_header_count = heap.header_count;
387     heap.total_used += cur->size;
388     if( heap.total_used > heap.maximum_used )
389         heap.maximum_used = heap.total_used;
390 #endif
391 #if defined(MBEDTLS_MEMORY_BACKTRACE)
392     trace_cnt = backtrace( trace_buffer, MAX_BT );
393     cur->trace = backtrace_symbols( trace_buffer, trace_cnt );
394     cur->trace_count = trace_cnt;
395 #endif
396 
397     if( ( heap.verify & MBEDTLS_MEMORY_VERIFY_ALLOC ) && verify_chain() != 0 )
398         mbedtls_exit( 1 );
399 
400     ret = (unsigned char *) cur + sizeof( memory_header );
401     memset( ret, 0, original_len );
402 
403     return( ret );
404 }
405 
406 static void buffer_alloc_free( void *ptr )
407 {
408     memory_header *hdr, *old = NULL;
409     unsigned char *p = (unsigned char *) ptr;
410 
411     if( ptr == NULL || heap.buf == NULL || heap.first == NULL )
412         return;
413 
414     if( p < heap.buf || p >= heap.buf + heap.len )
415     {
416 #if defined(MBEDTLS_MEMORY_DEBUG)
417         mbedtls_fprintf( stderr, "FATAL: mbedtls_free() outside of managed "
418                                   "space\n" );
419 #endif
420         mbedtls_exit( 1 );
421     }
422 
423     p -= sizeof(memory_header);
424     hdr = (memory_header *) p;
425 
426     if( verify_header( hdr ) != 0 )
427         mbedtls_exit( 1 );
428 
429     if( hdr->alloc != 1 )
430     {
431 #if defined(MBEDTLS_MEMORY_DEBUG)
432         mbedtls_fprintf( stderr, "FATAL: mbedtls_free() on unallocated "
433                                   "data\n" );
434 #endif
435         mbedtls_exit( 1 );
436     }
437 
438     hdr->alloc = 0;
439 
440 #if defined(MBEDTLS_MEMORY_DEBUG)
441     heap.free_count++;
442     heap.total_used -= hdr->size;
443 #endif
444 
445 #if defined(MBEDTLS_MEMORY_BACKTRACE)
446     free( hdr->trace );
447     hdr->trace = NULL;
448     hdr->trace_count = 0;
449 #endif
450 
451     // Regroup with block before
452     //
453     if( hdr->prev != NULL && hdr->prev->alloc == 0 )
454     {
455 #if defined(MBEDTLS_MEMORY_DEBUG)
456         heap.header_count--;
457 #endif
458         hdr->prev->size += sizeof(memory_header) + hdr->size;
459         hdr->prev->next = hdr->next;
460         old = hdr;
461         hdr = hdr->prev;
462 
463         if( hdr->next != NULL )
464             hdr->next->prev = hdr;
465 
466         memset( old, 0, sizeof(memory_header) );
467     }
468 
469     // Regroup with block after
470     //
471     if( hdr->next != NULL && hdr->next->alloc == 0 )
472     {
473 #if defined(MBEDTLS_MEMORY_DEBUG)
474         heap.header_count--;
475 #endif
476         hdr->size += sizeof(memory_header) + hdr->next->size;
477         old = hdr->next;
478         hdr->next = hdr->next->next;
479 
480         if( hdr->prev_free != NULL || hdr->next_free != NULL )
481         {
482             if( hdr->prev_free != NULL )
483                 hdr->prev_free->next_free = hdr->next_free;
484             else
485                 heap.first_free = hdr->next_free;
486 
487             if( hdr->next_free != NULL )
488                 hdr->next_free->prev_free = hdr->prev_free;
489         }
490 
491         hdr->prev_free = old->prev_free;
492         hdr->next_free = old->next_free;
493 
494         if( hdr->prev_free != NULL )
495             hdr->prev_free->next_free = hdr;
496         else
497             heap.first_free = hdr;
498 
499         if( hdr->next_free != NULL )
500             hdr->next_free->prev_free = hdr;
501 
502         if( hdr->next != NULL )
503             hdr->next->prev = hdr;
504 
505         memset( old, 0, sizeof(memory_header) );
506     }
507 
508     // Prepend to free_list if we have not merged
509     // (Does not have to stay in same order as prev / next list)
510     //
511     if( old == NULL )
512     {
513         hdr->next_free = heap.first_free;
514         if( heap.first_free != NULL )
515             heap.first_free->prev_free = hdr;
516         heap.first_free = hdr;
517     }
518 
519     if( ( heap.verify & MBEDTLS_MEMORY_VERIFY_FREE ) && verify_chain() != 0 )
520         mbedtls_exit( 1 );
521 }
522 
523 void mbedtls_memory_buffer_set_verify( int verify )
524 {
525     heap.verify = verify;
526 }
527 
528 int mbedtls_memory_buffer_alloc_verify( void )
529 {
530     return verify_chain();
531 }
532 
533 #if defined(MBEDTLS_MEMORY_DEBUG)
534 void mbedtls_memory_buffer_alloc_status( void )
535 {
536     mbedtls_fprintf( stderr,
537                       "Current use: %zu blocks / %zu bytes, max: %zu blocks / "
538                       "%zu bytes (total %zu bytes), alloc / free: %zu / %zu\n",
539                       heap.header_count, heap.total_used,
540                       heap.maximum_header_count, heap.maximum_used,
541                       heap.maximum_header_count * sizeof( memory_header )
542                       + heap.maximum_used,
543                       heap.alloc_count, heap.free_count );
544 
545     if( heap.first->next == NULL )
546     {
547         mbedtls_fprintf( stderr, "All memory de-allocated in stack buffer\n" );
548     }
549     else
550     {
551         mbedtls_fprintf( stderr, "Memory currently allocated:\n" );
552         debug_chain();
553     }
554 }
555 
556 void mbedtls_memory_buffer_alloc_max_get( size_t *max_used, size_t *max_blocks )
557 {
558     *max_used   = heap.maximum_used;
559     *max_blocks = heap.maximum_header_count;
560 }
561 
562 void mbedtls_memory_buffer_alloc_max_reset( void )
563 {
564     heap.maximum_used = 0;
565     heap.maximum_header_count = 0;
566 }
567 
568 void mbedtls_memory_buffer_alloc_cur_get( size_t *cur_used, size_t *cur_blocks )
569 {
570     *cur_used   = heap.total_used;
571     *cur_blocks = heap.header_count;
572 }
573 #endif /* MBEDTLS_MEMORY_DEBUG */
574 
575 #if defined(MBEDTLS_THREADING_C)
576 static void *buffer_alloc_calloc_mutexed( size_t n, size_t size )
577 {
578     void *buf;
579     if( mbedtls_mutex_lock( &heap.mutex ) != 0 )
580         return( NULL );
581     buf = buffer_alloc_calloc( n, size );
582     if( mbedtls_mutex_unlock( &heap.mutex ) )
583         return( NULL );
584     return( buf );
585 }
586 
587 static void buffer_alloc_free_mutexed( void *ptr )
588 {
589     /* We have to good option here, but corrupting the heap seems
590      * worse than loosing memory. */
591     if( mbedtls_mutex_lock( &heap.mutex ) )
592         return;
593     buffer_alloc_free( ptr );
594     (void) mbedtls_mutex_unlock( &heap.mutex );
595 }
596 #endif /* MBEDTLS_THREADING_C */
597 
598 void mbedtls_memory_buffer_alloc_init( unsigned char *buf, size_t len )
599 {
600     memset( &heap, 0, sizeof( buffer_alloc_ctx ) );
601 
602 #if defined(MBEDTLS_THREADING_C)
603     mbedtls_mutex_init( &heap.mutex );
604     mbedtls_platform_set_calloc_free( buffer_alloc_calloc_mutexed,
605                               buffer_alloc_free_mutexed );
606 #else
607     mbedtls_platform_set_calloc_free( buffer_alloc_calloc, buffer_alloc_free );
608 #endif
609 
610     if( len < sizeof( memory_header ) + MBEDTLS_MEMORY_ALIGN_MULTIPLE )
611         return;
612     else if( (size_t)buf % MBEDTLS_MEMORY_ALIGN_MULTIPLE )
613     {
614         /* Adjust len first since buf is used in the computation */
615         len -= MBEDTLS_MEMORY_ALIGN_MULTIPLE
616              - (size_t)buf % MBEDTLS_MEMORY_ALIGN_MULTIPLE;
617         buf += MBEDTLS_MEMORY_ALIGN_MULTIPLE
618              - (size_t)buf % MBEDTLS_MEMORY_ALIGN_MULTIPLE;
619     }
620 
621     memset( buf, 0, len );
622 
623     heap.buf = buf;
624     heap.len = len;
625 
626     heap.first = (memory_header *)buf;
627     heap.first->size = len - sizeof( memory_header );
628     heap.first->magic1 = MAGIC1;
629     heap.first->magic2 = MAGIC2;
630     heap.first_free = heap.first;
631 }
632 
633 void mbedtls_memory_buffer_alloc_free( void )
634 {
635 #if defined(MBEDTLS_THREADING_C)
636     mbedtls_mutex_free( &heap.mutex );
637 #endif
638     mbedtls_platform_zeroize( &heap, sizeof(buffer_alloc_ctx) );
639 }
640 
641 #if defined(MBEDTLS_SELF_TEST)
642 static int check_pointer( void *p )
643 {
644     if( p == NULL )
645         return( -1 );
646 
647     if( (size_t) p % MBEDTLS_MEMORY_ALIGN_MULTIPLE != 0 )
648         return( -1 );
649 
650     return( 0 );
651 }
652 
653 static int check_all_free( void )
654 {
655     if(
656 #if defined(MBEDTLS_MEMORY_DEBUG)
657         heap.total_used != 0 ||
658 #endif
659         heap.first != heap.first_free ||
660         (void *) heap.first != (void *) heap.buf )
661     {
662         return( -1 );
663     }
664 
665     return( 0 );
666 }
667 
668 #define TEST_ASSERT( condition )            \
669     if( ! (condition) )                     \
670     {                                       \
671         if( verbose != 0 )                  \
672             mbedtls_printf( "failed\n" );  \
673                                             \
674         ret = 1;                            \
675         goto cleanup;                       \
676     }
677 
678 int mbedtls_memory_buffer_alloc_self_test( int verbose )
679 {
680     unsigned char buf[1024];
681     unsigned char *p, *q, *r, *end;
682     int ret = 0;
683 
684     if( verbose != 0 )
685         mbedtls_printf( "  MBA test #1 (basic alloc-free cycle): " );
686 
687     mbedtls_memory_buffer_alloc_init( buf, sizeof( buf ) );
688 
689     p = mbedtls_calloc( 1, 1 );
690     q = mbedtls_calloc( 1, 128 );
691     r = mbedtls_calloc( 1, 16 );
692 
693     TEST_ASSERT( check_pointer( p ) == 0 &&
694                  check_pointer( q ) == 0 &&
695                  check_pointer( r ) == 0 );
696 
697     mbedtls_free( r );
698     mbedtls_free( q );
699     mbedtls_free( p );
700 
701     TEST_ASSERT( check_all_free( ) == 0 );
702 
703     /* Memorize end to compare with the next test */
704     end = heap.buf + heap.len;
705 
706     mbedtls_memory_buffer_alloc_free( );
707 
708     if( verbose != 0 )
709         mbedtls_printf( "passed\n" );
710 
711     if( verbose != 0 )
712         mbedtls_printf( "  MBA test #2 (buf not aligned): " );
713 
714     mbedtls_memory_buffer_alloc_init( buf + 1, sizeof( buf ) - 1 );
715 
716     TEST_ASSERT( heap.buf + heap.len == end );
717 
718     p = mbedtls_calloc( 1, 1 );
719     q = mbedtls_calloc( 1, 128 );
720     r = mbedtls_calloc( 1, 16 );
721 
722     TEST_ASSERT( check_pointer( p ) == 0 &&
723                  check_pointer( q ) == 0 &&
724                  check_pointer( r ) == 0 );
725 
726     mbedtls_free( r );
727     mbedtls_free( q );
728     mbedtls_free( p );
729 
730     TEST_ASSERT( check_all_free( ) == 0 );
731 
732     mbedtls_memory_buffer_alloc_free( );
733 
734     if( verbose != 0 )
735         mbedtls_printf( "passed\n" );
736 
737     if( verbose != 0 )
738         mbedtls_printf( "  MBA test #3 (full): " );
739 
740     mbedtls_memory_buffer_alloc_init( buf, sizeof( buf ) );
741 
742     p = mbedtls_calloc( 1, sizeof( buf ) - sizeof( memory_header ) );
743 
744     TEST_ASSERT( check_pointer( p ) == 0 );
745     TEST_ASSERT( mbedtls_calloc( 1, 1 ) == NULL );
746 
747     mbedtls_free( p );
748 
749     p = mbedtls_calloc( 1, sizeof( buf ) - 2 * sizeof( memory_header ) - 16 );
750     q = mbedtls_calloc( 1, 16 );
751 
752     TEST_ASSERT( check_pointer( p ) == 0 && check_pointer( q ) == 0 );
753     TEST_ASSERT( mbedtls_calloc( 1, 1 ) == NULL );
754 
755     mbedtls_free( q );
756 
757     TEST_ASSERT( mbedtls_calloc( 1, 17 ) == NULL );
758 
759     mbedtls_free( p );
760 
761     TEST_ASSERT( check_all_free( ) == 0 );
762 
763     mbedtls_memory_buffer_alloc_free( );
764 
765     if( verbose != 0 )
766         mbedtls_printf( "passed\n" );
767 
768 cleanup:
769     mbedtls_memory_buffer_alloc_free( );
770 
771     return( ret );
772 }
773 #endif /* MBEDTLS_SELF_TEST */
774 
775 #endif /* MBEDTLS_MEMORY_BUFFER_ALLOC_C */
776