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