Ignore:
Timestamp:
Aug 11, 2020, 4:40:15 PM (5 years ago)
Author:
Thierry Delisle <tdelisle@…>
Branches:
ADT, arm-eh, ast-experimental, enum, forall-pointer-decay, jacob/cs343-translation, master, new-ast, new-ast-unique-expr, pthread-emulation, qualifiedEnum
Children:
0d070ca
Parents:
07d867b (diff), 129674b (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge branch 'master' into new-ast

File:
1 edited

Legend:

Unmodified
Added
Removed
  • libcfa/src/heap.cfa

    r07d867b r22f94a4  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // heap.c --
     7// heap.cfa --
    88//
    99// Author           : Peter A. Buhr
    1010// Created On       : Tue Dec 19 21:58:35 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed May  6 17:29:26 2020
    13 // Update Count     : 727
     12// Last Modified On : Sun Aug  9 12:23:20 2020
     13// Update Count     : 894
    1414//
    1515
     
    2020#include <string.h>                                                                             // memset, memcpy
    2121#include <limits.h>                                                                             // ULONG_MAX
    22 extern "C" {
     22#include <malloc.h>                                                                             // memalign, malloc_usable_size
    2323#include <sys/mman.h>                                                                   // mmap, munmap
    24 } // extern "C"
    25 
    26 #include "bits/align.hfa"                                                               // libPow2
     24
     25#include "bits/align.hfa"                                                               // libAlign
    2726#include "bits/defs.hfa"                                                                // likely, unlikely
    2827#include "bits/locks.hfa"                                                               // __spinlock_t
    2928#include "startup.hfa"                                                                  // STARTUP_PRIORITY_MEMORY
    3029//#include "stdlib.hfa"                                                                 // bsearchl
    31 #include "malloc.h"
    3230#include "bitmanip.hfa"                                                                 // ceiling
    3331
     
    8280};
    8381
     82size_t default_mmap_start() __attribute__(( weak )) {
     83        return __CFA_DEFAULT_MMAP_START__;
     84} // default_mmap_start
     85
    8486size_t default_heap_expansion() __attribute__(( weak )) {
    8587        return __CFA_DEFAULT_HEAP_EXPANSION__;
    8688} // default_heap_expansion
    8789
    88 size_t default_mmap_start() __attribute__(( weak )) {
    89         return __CFA_DEFAULT_MMAP_START__;
    90 } // default_mmap_start
    91 
    9290
    9391#ifdef __CFA_DEBUG__
    94 static unsigned int allocFree;                                                  // running total of allocations minus frees
     92static size_t allocUnfreed;                                                             // running total of allocations minus frees
    9593
    9694static void prtUnfreed() {
    97         if ( allocFree != 0 ) {
     95        if ( allocUnfreed != 0 ) {
    9896                // DO NOT USE STREAMS AS THEY MAY BE UNAVAILABLE AT THIS POINT.
    9997                char helpText[512];
    100                 int len = snprintf( helpText, sizeof(helpText), "CFA warning (UNIX pid:%ld) : program terminating with %u(0x%x) bytes of storage allocated but not freed.\n"
     98                int len = snprintf( helpText, sizeof(helpText), "CFA warning (UNIX pid:%ld) : program terminating with %zu(0x%zx) bytes of storage allocated but not freed.\n"
    10199                                                        "Possible cause is unfreed storage allocated by the program or system/library routines called from the program.\n",
    102                                                         (long int)getpid(), allocFree, allocFree ); // always print the UNIX pid
     100                                                        (long int)getpid(), allocUnfreed, allocUnfreed ); // always print the UNIX pid
    103101                __cfaabi_bits_write( STDERR_FILENO, helpText, len ); // print debug/nodebug
    104102        } // if
     
    107105extern "C" {
    108106        void heapAppStart() {                                                           // called by __cfaabi_appready_startup
    109                 allocFree = 0;
     107                allocUnfreed = 0;
    110108        } // heapAppStart
    111109
     
    128126#define LOCKFREE 1
    129127#define BUCKETLOCK SPINLOCK
    130 #if BUCKETLOCK == LOCKFREE
    131 #include <uStackLF.h>
     128#if BUCKETLOCK == SPINLOCK
     129#elif BUCKETLOCK == LOCKFREE
     130#include <stackLockFree.hfa>
     131#else
     132        #error undefined lock type for bucket lock
    132133#endif // LOCKFREE
    133134
     
    137138
    138139struct HeapManager {
    139 //      struct FreeHeader;                                                                      // forward declaration
    140 
    141140        struct Storage {
    142141                struct Header {                                                                 // header
     
    146145                                                struct {                                                // 4-byte word => 8-byte header, 8-byte word => 16-byte header
    147146                                                        #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ && __SIZEOF_POINTER__ == 4
    148                                                         uint32_t padding;                       // unused, force home/blocksize to overlay alignment in fake header
     147                                                        uint64_t padding;                       // unused, force home/blocksize to overlay alignment in fake header
    149148                                                        #endif // __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ && __SIZEOF_POINTER__ == 4
    150149
    151150                                                        union {
    152 //                                                              FreeHeader * home;              // allocated block points back to home locations (must overlay alignment)
     151                                                                // FreeHeader * home;           // allocated block points back to home locations (must overlay alignment)
    153152                                                                // 2nd low-order bit => zero filled
    154153                                                                void * home;                    // allocated block points back to home locations (must overlay alignment)
    155154                                                                size_t blockSize;               // size for munmap (must overlay alignment)
    156                                                                 #if BUCKLOCK == SPINLOCK
     155                                                                #if BUCKETLOCK == SPINLOCK
    157156                                                                Storage * next;                 // freed block points next freed block of same size
    158157                                                                #endif // SPINLOCK
    159158                                                        };
     159                                                        size_t size;                            // allocation size in bytes
    160160
    161161                                                        #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ && __SIZEOF_POINTER__ == 4
    162                                                         uint32_t padding;                       // unused, force home/blocksize to overlay alignment in fake header
     162                                                        uint64_t padding;                       // unused, force home/blocksize to overlay alignment in fake header
    163163                                                        #endif // __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ && __SIZEOF_POINTER__ == 4
    164164                                                };
    165                                                 // future code
    166                                                 #if BUCKLOCK == LOCKFREE
    167                                                 Stack<Storage>::Link next;              // freed block points next freed block of same size (double-wide)
     165                                                #if BUCKETLOCK == LOCKFREE
     166                                                Link(Storage) next;                             // freed block points next freed block of same size (double-wide)
    168167                                                #endif // LOCKFREE
    169168                                        };
    170169                                } real; // RealHeader
     170
    171171                                struct FakeHeader {
    172172                                        #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
    173                                         // 1st low-order bit => fake header & alignment
    174                                         uint32_t alignment;
     173                                        uint32_t alignment;                                     // 1st low-order bit => fake header & alignment
    175174                                        #endif // __ORDER_LITTLE_ENDIAN__
    176175
     
    182181                                } fake; // FakeHeader
    183182                        } kind; // Kind
    184                         size_t size;                                                            // allocation size in bytes
    185183                } header; // Header
    186184                char pad[libAlign() - sizeof( Header )];
     
    191189
    192190        struct FreeHeader {
    193                 #if BUCKLOCK == SPINLOCK
     191                #if BUCKETLOCK == SPINLOCK
    194192                __spinlock_t lock;                                                              // must be first field for alignment
    195193                Storage * freeList;
    196                 #elif BUCKLOCK == LOCKFREE
    197                 // future code
    198                 StackLF<Storage> freeList;
    199194                #else
    200                         #error undefined lock type for bucket lock
    201                 #endif // SPINLOCK
     195                StackLF(Storage) freeList;
     196                #endif // BUCKETLOCK
    202197                size_t blockSize;                                                               // size of allocations on this list
    203198        }; // FreeHeader
     
    212207}; // HeapManager
    213208
     209#if BUCKETLOCK == LOCKFREE
     210static inline {
     211        Link(HeapManager.Storage) * ?`next( HeapManager.Storage * this ) { return &this->header.kind.real.next; }
     212        void ?{}( HeapManager.FreeHeader & ) {}
     213        void ^?{}( HeapManager.FreeHeader & ) {}
     214} // distribution
     215#endif // LOCKFREE
     216
    214217static inline size_t getKey( const HeapManager.FreeHeader & freeheader ) { return freeheader.blockSize; }
    215218
     
    218221#define __STATISTICS__
    219222
    220 // Bucket size must be multiple of 16.
    221 // Powers of 2 are common allocation sizes, so make powers of 2 generate the minimum required size.
     223// Size of array must harmonize with NoBucketSizes and individual bucket sizes must be multiple of 16.
     224// Smaller multiples of 16 and powers of 2 are common allocation sizes, so make them generate the minimum required bucket size.
     225// malloc(0) returns 0p, so no bucket is necessary for 0 bytes returning an address that can be freed.
    222226static const unsigned int bucketSizes[] @= {                    // different bucket sizes
    223         16, 32, 48, 64 + sizeof(HeapManager.Storage), // 4
    224         96, 112, 128 + sizeof(HeapManager.Storage), // 3
     227        16 + sizeof(HeapManager.Storage), 32 + sizeof(HeapManager.Storage), 48 + sizeof(HeapManager.Storage), 64 + sizeof(HeapManager.Storage), // 4
     228        96 + sizeof(HeapManager.Storage), 112 + sizeof(HeapManager.Storage), 128 + sizeof(HeapManager.Storage), // 3
    225229        160, 192, 224, 256 + sizeof(HeapManager.Storage), // 4
    226230        320, 384, 448, 512 + sizeof(HeapManager.Storage), // 4
     
    240244};
    241245
    242 static_assert( NoBucketSizes == sizeof(bucketSizes) / sizeof(bucketSizes[0]), "size of bucket array wrong" );
     246static_assert( NoBucketSizes == sizeof(bucketSizes) / sizeof(bucketSizes[0] ), "size of bucket array wrong" );
    243247
    244248#ifdef FASTLOOKUP
     
    251255static bool heapBoot = 0;                                                               // detect recursion during boot
    252256#endif // __CFA_DEBUG__
     257
     258// The constructor for heapManager is called explicitly in memory_startup.
    253259static HeapManager heapManager __attribute__(( aligned (128) )) @= {}; // size of cache line to prevent false sharing
    254260
     
    256262#ifdef __STATISTICS__
    257263// Heap statistics counters.
     264static unsigned int malloc_calls;
     265static unsigned long long int malloc_storage;
     266static unsigned int aalloc_calls;
     267static unsigned long long int aalloc_storage;
     268static unsigned int calloc_calls;
     269static unsigned long long int calloc_storage;
     270static unsigned int memalign_calls;
     271static unsigned long long int memalign_storage;
     272static unsigned int amemalign_calls;
     273static unsigned long long int amemalign_storage;
     274static unsigned int cmemalign_calls;
     275static unsigned long long int cmemalign_storage;
     276static unsigned int resize_calls;
     277static unsigned long long int resize_storage;
     278static unsigned int realloc_calls;
     279static unsigned long long int realloc_storage;
     280static unsigned int free_calls;
     281static unsigned long long int free_storage;
     282static unsigned int mmap_calls;
    258283static unsigned long long int mmap_storage;
    259 static unsigned int mmap_calls;
     284static unsigned int munmap_calls;
    260285static unsigned long long int munmap_storage;
    261 static unsigned int munmap_calls;
     286static unsigned int sbrk_calls;
    262287static unsigned long long int sbrk_storage;
    263 static unsigned int sbrk_calls;
    264 static unsigned long long int malloc_storage;
    265 static unsigned int malloc_calls;
    266 static unsigned long long int free_storage;
    267 static unsigned int free_calls;
    268 static unsigned long long int aalloc_storage;
    269 static unsigned int aalloc_calls;
    270 static unsigned long long int calloc_storage;
    271 static unsigned int calloc_calls;
    272 static unsigned long long int memalign_storage;
    273 static unsigned int memalign_calls;
    274 static unsigned long long int amemalign_storage;
    275 static unsigned int amemalign_calls;
    276 static unsigned long long int cmemalign_storage;
    277 static unsigned int cmemalign_calls;
    278 static unsigned long long int resize_storage;
    279 static unsigned int resize_calls;
    280 static unsigned long long int realloc_storage;
    281 static unsigned int realloc_calls;
    282288// Statistics file descriptor (changed by malloc_stats_fd).
    283 static int statfd = STDERR_FILENO;                                              // default stderr
     289static int stat_fd = STDERR_FILENO;                                             // default stderr
    284290
    285291// Use "write" because streams may be shutdown when calls are made.
     
    301307                                                                        "  sbrk: calls %u / storage %llu\n",
    302308                                                                        malloc_calls, malloc_storage,
    303                                                                         aalloc_calls, calloc_storage,
     309                                                                        aalloc_calls, aalloc_storage,
    304310                                                                        calloc_calls, calloc_storage,
    305311                                                                        memalign_calls, memalign_storage,
     
    354360
    355361
    356 // static inline void noMemory() {
    357 //      abort( "Heap memory exhausted at %zu bytes.\n"
    358 //                 "Possible cause is very large memory allocation and/or large amount of unfreed storage allocated by the program or system/library routines.",
    359 //                 ((char *)(sbrk( 0 )) - (char *)(heapManager.heapBegin)) );
    360 // } // noMemory
    361 
    362 
    363362// thunk problem
    364363size_t Bsearchl( unsigned int key, const unsigned int * vals, size_t dim ) {
     
    407406
    408407static inline void checkAlign( size_t alignment ) {
    409         if ( alignment < libAlign() || ! libPow2( alignment ) ) {
     408        if ( alignment < libAlign() || ! is_pow2( alignment ) ) {
    410409                abort( "Alignment %zu for memory allocation is less than %d and/or not a power of 2.", alignment, libAlign() );
    411410        } // if
     
    429428                #endif // __CFA_DEBUG__
    430429                header = realHeader( header );                                  // backup from fake to real header
     430        } else {
     431                alignment = libAlign();                                                 // => no fake header
    431432        } // if
    432433} // fakeHeader
    433434
    434435
    435 static inline bool headers( const char name[] __attribute__(( unused )), void * addr, HeapManager.Storage.Header *& header, HeapManager.FreeHeader *& freeElem, size_t & size, size_t & alignment ) with ( heapManager ) {
     436static inline bool headers( const char name[] __attribute__(( unused )), void * addr, HeapManager.Storage.Header *& header, HeapManager.FreeHeader *& freeElem,
     437                                                        size_t & size, size_t & alignment ) with( heapManager ) {
    436438        header = headerAddr( addr );
    437439
    438         if ( unlikely( heapEnd < addr ) ) {                                     // mmapped ?
     440  if ( unlikely( heapEnd < addr ) ) {                                   // mmapped ?
    439441                fakeHeader( header, alignment );
    440442                size = header->kind.real.blockSize & -3;                // mmap size
     
    464466} // headers
    465467
    466 
    467 static inline void * extend( size_t size ) with ( heapManager ) {
     468#define NO_MEMORY_MSG "insufficient heap memory available for allocating %zd new bytes."
     469
     470static inline void * extend( size_t size ) with( heapManager ) {
    468471        lock( extlock __cfaabi_dbg_ctx2 );
    469472        ptrdiff_t rem = heapRemaining - size;
     
    471474                // If the size requested is bigger than the current remaining storage, increase the size of the heap.
    472475
    473                 size_t increase = libCeiling( size > heapExpand ? size : heapExpand, libAlign() );
    474                 if ( sbrk( increase ) == (void *)-1 ) {
     476                size_t increase = ceiling2( size > heapExpand ? size : heapExpand, libAlign() );
     477                if ( sbrk( increase ) == (void *)-1 ) {                 // failed, no memory ?
    475478                        unlock( extlock );
    476                         errno = ENOMEM;
    477                         return 0p;
     479                        abort( NO_MEMORY_MSG, size );                           // give up
    478480                } // if
    479481                #ifdef __STATISTICS__
     
    496498
    497499
    498 static inline void * doMalloc( size_t size ) with ( heapManager ) {
     500static inline void * doMalloc( size_t size ) with( heapManager ) {
    499501        HeapManager.Storage * block;                                            // pointer to new block of storage
    500502
     
    512514                        posn = Bsearchl( (unsigned int)tsize, bucketSizes, (size_t)maxBucketsUsed );
    513515                HeapManager.FreeHeader * freeElem = &freeLists[posn];
    514                 // #ifdef FASTLOOKUP
    515                 // if ( tsize < LookupSizes )
    516                 //      freeElem = &freeLists[lookup[tsize]];
    517                 // else
    518                 // #endif // FASTLOOKUP
    519                 //      freeElem = bsearchl( tsize, freeLists, (size_t)maxBucketsUsed ); // binary search
    520                 // HeapManager.FreeHeader * freeElem =
    521                 //      #ifdef FASTLOOKUP
    522                 //      tsize < LookupSizes ? &freeLists[lookup[tsize]] :
    523                 //      #endif // FASTLOOKUP
    524                 //      bsearchl( tsize, freeLists, (size_t)maxBucketsUsed ); // binary search
    525                 assert( freeElem <= &freeLists[maxBucketsUsed] ); // subscripting error ?
    526                 assert( tsize <= freeElem->blockSize );                 // search failure ?
     516                verify( freeElem <= &freeLists[maxBucketsUsed] ); // subscripting error ?
     517                verify( tsize <= freeElem->blockSize );                 // search failure ?
    527518                tsize = freeElem->blockSize;                                    // total space needed for request
    528519
    529520                // Spin until the lock is acquired for this particular size of block.
    530521
    531                 #if defined( SPINLOCK )
     522                #if BUCKETLOCK == SPINLOCK
    532523                lock( freeElem->lock __cfaabi_dbg_ctx2 );
    533524                block = freeElem->freeList;                                             // remove node from stack
    534525                #else
    535                 block = freeElem->freeList.pop();
    536                 #endif // SPINLOCK
     526                block = pop( freeElem->freeList );
     527                #endif // BUCKETLOCK
    537528                if ( unlikely( block == 0p ) ) {                                // no free block ?
    538                         #if defined( SPINLOCK )
     529                        #if BUCKETLOCK == SPINLOCK
    539530                        unlock( freeElem->lock );
    540                         #endif // SPINLOCK
     531                        #endif // BUCKETLOCK
    541532
    542533                        // Freelist for that size was empty, so carve it out of the heap if there's enough left, or get some more
     
    544535
    545536                        block = (HeapManager.Storage *)extend( tsize ); // mutual exclusion on call
    546   if ( unlikely( block == 0p ) ) return 0p;
    547                 #if defined( SPINLOCK )
     537                #if BUCKETLOCK == SPINLOCK
    548538                } else {
    549539                        freeElem->freeList = block->header.kind.real.next;
    550540                        unlock( freeElem->lock );
    551                 #endif // SPINLOCK
     541                #endif // BUCKETLOCK
    552542                } // if
    553543
     
    555545        } else {                                                                                        // large size => mmap
    556546  if ( unlikely( size > ULONG_MAX - pageSize ) ) return 0p;
    557                 tsize = libCeiling( tsize, pageSize );                  // must be multiple of page size
     547                tsize = ceiling2( tsize, pageSize );                    // must be multiple of page size
    558548                #ifdef __STATISTICS__
    559549                __atomic_add_fetch( &mmap_calls, 1, __ATOMIC_SEQ_CST );
    560550                __atomic_add_fetch( &mmap_storage, tsize, __ATOMIC_SEQ_CST );
    561551                #endif // __STATISTICS__
     552
    562553                block = (HeapManager.Storage *)mmap( 0, tsize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, mmapFd, 0 );
    563                 if ( block == (HeapManager.Storage *)MAP_FAILED ) {
     554                if ( block == (HeapManager.Storage *)MAP_FAILED ) { // failed ?
     555                        if ( errno == ENOMEM ) abort( NO_MEMORY_MSG, tsize ); // no memory
    564556                        // Do not call strerror( errno ) as it may call malloc.
    565557                        abort( "(HeapManager &)0x%p.doMalloc() : internal error, mmap failure, size:%zu error:%d.", &heapManager, tsize, errno );
    566                 } // if
     558                } //if
    567559                #ifdef __CFA_DEBUG__
    568560                // Set new memory to garbage so subsequent uninitialized usages might fail.
     
    572564        } // if
    573565
    574         block->header.size = size;                                                      // store allocation size
     566        block->header.kind.real.size = size;                            // store allocation size
    575567        void * addr = &(block->data);                                           // adjust off header to user bytes
     568        verify( ((uintptr_t)addr & (libAlign() - 1)) == 0 ); // minimum alignment ?
    576569
    577570        #ifdef __CFA_DEBUG__
    578         assert( ((uintptr_t)addr & (libAlign() - 1)) == 0 ); // minimum alignment ?
    579         __atomic_add_fetch( &allocFree, tsize, __ATOMIC_SEQ_CST );
     571        __atomic_add_fetch( &allocUnfreed, tsize, __ATOMIC_SEQ_CST );
    580572        if ( traceHeap() ) {
    581573                enum { BufferSize = 64 };
    582574                char helpText[BufferSize];
    583575                int len = snprintf( helpText, BufferSize, "%p = Malloc( %zu ) (allocated %zu)\n", addr, size, tsize );
    584                 // int len = snprintf( helpText, BufferSize, "Malloc %p %zu\n", addr, size );
    585576                __cfaabi_bits_write( STDERR_FILENO, helpText, len ); // print debug/nodebug
    586577        } // if
     
    591582
    592583
    593 static inline void doFree( void * addr ) with ( heapManager ) {
     584static inline void doFree( void * addr ) with( heapManager ) {
    594585        #ifdef __CFA_DEBUG__
    595586        if ( unlikely( heapManager.heapBegin == 0p ) ) {
     
    623614                free_storage += size;
    624615                #endif // __STATISTICS__
    625                 #if defined( SPINLOCK )
     616                #if BUCKETLOCK == SPINLOCK
    626617                lock( freeElem->lock __cfaabi_dbg_ctx2 );               // acquire spin lock
    627618                header->kind.real.next = freeElem->freeList;    // push on stack
     
    629620                unlock( freeElem->lock );                                               // release spin lock
    630621                #else
    631                 freeElem->freeList.push( *(HeapManager.Storage *)header );
    632                 #endif // SPINLOCK
     622                push( freeElem->freeList, *(HeapManager.Storage *)header );
     623                #endif // BUCKETLOCK
    633624        } // if
    634625
    635626        #ifdef __CFA_DEBUG__
    636         __atomic_add_fetch( &allocFree, -size, __ATOMIC_SEQ_CST );
     627        __atomic_add_fetch( &allocUnfreed, -size, __ATOMIC_SEQ_CST );
    637628        if ( traceHeap() ) {
    638                 enum { BufferSize = 64 };
    639                 char helpText[BufferSize];
     629                char helpText[64];
    640630                int len = snprintf( helpText, sizeof(helpText), "Free( %p ) size:%zu\n", addr, size );
    641631                __cfaabi_bits_write( STDERR_FILENO, helpText, len ); // print debug/nodebug
     
    645635
    646636
    647 size_t prtFree( HeapManager & manager ) with ( manager ) {
     637size_t prtFree( HeapManager & manager ) with( manager ) {
    648638        size_t total = 0;
    649639        #ifdef __STATISTICS__
     
    657647                #endif // __STATISTICS__
    658648
    659                 #if defined( SPINLOCK )
     649                #if BUCKETLOCK == SPINLOCK
    660650                for ( HeapManager.Storage * p = freeLists[i].freeList; p != 0p; p = p->header.kind.real.next ) {
    661651                #else
    662                 for ( HeapManager.Storage * p = freeLists[i].freeList.top(); p != 0p; p = p->header.kind.real.next.top ) {
    663                 #endif // SPINLOCK
     652                for ( HeapManager.Storage * p = top( freeLists[i].freeList ); p != 0p; p = (p)`next->top ) {
     653                #endif // BUCKETLOCK
    664654                        total += size;
    665655                        #ifdef __STATISTICS__
     
    681671
    682672
    683 static void ?{}( HeapManager & manager ) with ( manager ) {
     673static void ?{}( HeapManager & manager ) with( manager ) {
    684674        pageSize = sysconf( _SC_PAGESIZE );
    685675
     
    702692
    703693        char * end = (char *)sbrk( 0 );
    704         heapBegin = heapEnd = sbrk( (char *)libCeiling( (long unsigned int)end, libAlign() ) - end ); // move start of heap to multiple of alignment
     694        heapBegin = heapEnd = sbrk( (char *)ceiling2( (long unsigned int)end, libAlign() ) - end ); // move start of heap to multiple of alignment
    705695} // HeapManager
    706696
     
    710700        if ( traceHeapTerm() ) {
    711701                printStats();
    712                 // if ( prtfree() ) prtFree( heapManager, true );
     702                // prtUnfreed() called in heapAppStop()
    713703        } // if
    714704        #endif // __STATISTICS__
     
    719709void memory_startup( void ) {
    720710        #ifdef __CFA_DEBUG__
    721         if ( unlikely( heapBoot ) ) {                                           // check for recursion during system boot
     711        if ( heapBoot ) {                                                                       // check for recursion during system boot
    722712                // DO NOT USE STREAMS AS THEY MAY BE UNAVAILABLE AT THIS POINT.
    723713                abort( "boot() : internal error, recursively invoked during system boot." );
     
    726716        #endif // __CFA_DEBUG__
    727717
    728         //assert( heapManager.heapBegin != 0 );
     718        //verify( heapManager.heapBegin != 0 );
    729719        //heapManager{};
    730720        if ( heapManager.heapBegin == 0p ) heapManager{};       // sanity check
     
    738728
    739729static inline void * mallocNoStats( size_t size ) {             // necessary for malloc statistics
    740         //assert( heapManager.heapBegin != 0 );
    741         if ( unlikely( heapManager.heapBegin == 0p ) ) heapManager{}; // called before memory_startup ?
     730        verify( heapManager.heapBegin != 0p );                          // called before memory_startup ?
     731  if ( unlikely( size ) == 0 ) return 0p;                               // 0 BYTE ALLOCATION RETURNS NULL POINTER
     732
    742733#if __SIZEOF_POINTER__ == 8
    743734        verify( size < ((typeof(size_t))1 << 48) );
    744735#endif // __SIZEOF_POINTER__ == 8
    745         void * addr = doMalloc( size );
    746         if ( unlikely( addr == 0p ) ) errno = ENOMEM;           // POSIX
    747         return addr;
     736        return doMalloc( size );
    748737} // mallocNoStats
    749738
     
    751740static inline void * callocNoStats( size_t dim, size_t elemSize ) {
    752741        size_t size = dim * elemSize;
     742  if ( unlikely( size ) == 0 ) return 0p;                               // 0 BYTE ALLOCATION RETURNS NULL POINTER
    753743        char * addr = (char *)mallocNoStats( size );
    754   if ( unlikely( addr == 0p ) ) return 0p;
    755744
    756745        HeapManager.Storage.Header * header;
    757746        HeapManager.FreeHeader * freeElem;
    758747        size_t bsize, alignment;
    759         bool mapped __attribute__(( unused )) = headers( "calloc", addr, header, freeElem, bsize, alignment );
    760748        #ifndef __CFA_DEBUG__
     749        bool mapped =
     750        #endif // __CFA_DEBUG__
     751                headers( "calloc", addr, header, freeElem, bsize, alignment );
     752        #ifndef __CFA_DEBUG__
     753
    761754        // Mapped storage is zero filled, but in debug mode mapped memory is scrubbed in doMalloc, so it has to be reset to zero.
    762755        if ( ! mapped )
    763756        #endif // __CFA_DEBUG__
    764                 // Zero entire data space even when > than size => realloc without a new allocation and zero fill works.
    765                 // <-------00000000000000000000000000000000000000000000000000000> bsize (bucket size)
     757                // <-------0000000000000000000000000000UUUUUUUUUUUUUUUUUUUUUUUUU> bsize (bucket size) U => undefined
    766758                // `-header`-addr                      `-size
    767                 memset( addr, '\0', bsize - sizeof(HeapManager.Storage) ); // set to zeros
     759                memset( addr, '\0', size );                                             // set to zeros
    768760
    769761        header->kind.real.blockSize |= 2;                                       // mark as zero filled
     
    772764
    773765
    774 static inline void * memalignNoStats( size_t alignment, size_t size ) { // necessary for malloc statistics
     766static inline void * memalignNoStats( size_t alignment, size_t size ) {
     767  if ( unlikely( size ) == 0 ) return 0p;                               // 0 BYTE ALLOCATION RETURNS NULL POINTER
     768
    775769        #ifdef __CFA_DEBUG__
    776770        checkAlign( alignment );                                                        // check alignment
     
    790784        // add sizeof(Storage) for fake header
    791785        char * addr = (char *)mallocNoStats( size + alignment - libAlign() + sizeof(HeapManager.Storage) );
    792   if ( unlikely( addr == 0p ) ) return addr;
    793786
    794787        // address in the block of the "next" alignment address
    795         char * user = (char *)libCeiling( (uintptr_t)(addr + sizeof(HeapManager.Storage)), alignment );
     788        char * user = (char *)ceiling2( (uintptr_t)(addr + sizeof(HeapManager.Storage)), alignment );
    796789
    797790        // address of header from malloc
    798791        HeapManager.Storage.Header * realHeader = headerAddr( addr );
     792        realHeader->kind.real.size = size;                                      // correct size to eliminate above alignment offset
    799793        // address of fake header * before* the alignment location
    800794        HeapManager.Storage.Header * fakeHeader = headerAddr( user );
     
    810804static inline void * cmemalignNoStats( size_t alignment, size_t dim, size_t elemSize ) {
    811805        size_t size = dim * elemSize;
     806  if ( unlikely( size ) == 0 ) return 0p;                               // 0 BYTE ALLOCATION RETURNS NULL POINTER
    812807        char * addr = (char *)memalignNoStats( alignment, size );
    813   if ( unlikely( addr == 0p ) ) return 0p;
     808
    814809        HeapManager.Storage.Header * header;
    815810        HeapManager.FreeHeader * freeElem;
    816811        size_t bsize;
    817         bool mapped __attribute__(( unused )) = headers( "cmemalign", addr, header, freeElem, bsize, alignment );
    818812        #ifndef __CFA_DEBUG__
     813        bool mapped =
     814        #endif // __CFA_DEBUG__
     815                headers( "cmemalign", addr, header, freeElem, bsize, alignment );
     816
    819817        // Mapped storage is zero filled, but in debug mode mapped memory is scrubbed in doMalloc, so it has to be reset to zero.
     818        #ifndef __CFA_DEBUG__
    820819        if ( ! mapped )
    821820        #endif // __CFA_DEBUG__
    822                 memset( addr, '\0', dataStorage( bsize, addr, header ) ); // set to zeros
     821                // <-------0000000000000000000000000000UUUUUUUUUUUUUUUUUUUUUUUUU> bsize (bucket size) U => undefined
     822                // `-header`-addr                      `-size
     823                memset( addr, '\0', size );                                             // set to zeros
    823824
    824825        header->kind.real.blockSize |= 2;                                       // mark as zero filled
    825826        return addr;
    826827} // cmemalignNoStats
    827 
    828 
    829 // supported mallopt options
    830 #ifndef M_MMAP_THRESHOLD
    831 #define M_MMAP_THRESHOLD (-1)
    832 #endif // M_TOP_PAD
    833 #ifndef M_TOP_PAD
    834 #define M_TOP_PAD (-2)
    835 #endif // M_TOP_PAD
    836828
    837829
     
    851843        // Same as malloc() except size bytes is an array of dim elements each of elemSize bytes.
    852844        void * aalloc( size_t dim, size_t elemSize ) {
     845                size_t size = dim * elemSize;
    853846                #ifdef __STATISTICS__
    854847                __atomic_add_fetch( &aalloc_calls, 1, __ATOMIC_SEQ_CST );
    855                 __atomic_add_fetch( &aalloc_storage, dim * elemSize, __ATOMIC_SEQ_CST );
    856                 #endif // __STATISTICS__
    857 
    858                 return mallocNoStats( dim * elemSize );
     848                __atomic_add_fetch( &aalloc_storage, size, __ATOMIC_SEQ_CST );
     849                #endif // __STATISTICS__
     850
     851                return mallocNoStats( size );
    859852        } // aalloc
    860853
     
    869862                return callocNoStats( dim, elemSize );
    870863        } // calloc
     864
    871865
    872866        // Change the size of the memory block pointed to by oaddr to size bytes. The contents are undefined.  If oaddr is
     
    877871                #ifdef __STATISTICS__
    878872                __atomic_add_fetch( &resize_calls, 1, __ATOMIC_SEQ_CST );
    879                 __atomic_add_fetch( &resize_storage, size, __ATOMIC_SEQ_CST );
    880873                #endif // __STATISTICS__
    881874
    882875                // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned.
    883           if ( unlikely( size == 0 ) ) { free( oaddr ); return mallocNoStats( size ); } // special cases
    884           if ( unlikely( oaddr == 0p ) ) return mallocNoStats( size );
     876          if ( unlikely( size == 0 ) ) { free( oaddr ); return 0p; } // special cases
     877          if ( unlikely( oaddr == 0p ) ) {
     878                        #ifdef __STATISTICS__
     879                        __atomic_add_fetch( &resize_storage, size, __ATOMIC_SEQ_CST );
     880                        #endif // __STATISTICS__
     881                        return mallocNoStats( size );
     882                } // if
    885883
    886884                HeapManager.Storage.Header * header;
    887885                HeapManager.FreeHeader * freeElem;
    888                 size_t bsize, oalign = 0;
     886                size_t bsize, oalign;
    889887                headers( "resize", oaddr, header, freeElem, bsize, oalign );
    890888
    891889                size_t odsize = dataStorage( bsize, oaddr, header ); // data storage available in bucket
    892890                // same size, DO NOT preserve STICKY PROPERTIES.
    893           if ( oalign == 0 && size <= odsize && odsize <= size * 2 ) { // allow 50% wasted storage for smaller size
     891                if ( oalign <= libAlign() && size <= odsize && odsize <= size * 2 ) { // allow 50% wasted storage for smaller size
    894892                        header->kind.real.blockSize &= -2;                      // no alignment and turn off 0 fill
     893                        header->kind.real.size = size;                          // reset allocation size
    895894                        return oaddr;
    896895                } // if
    897        
     896
     897                #ifdef __STATISTICS__
     898                __atomic_add_fetch( &resize_storage, size, __ATOMIC_SEQ_CST );
     899                #endif // __STATISTICS__
     900
    898901                // change size, DO NOT preserve STICKY PROPERTIES.
    899902                free( oaddr );
    900                 void * naddr = mallocNoStats( size );                   // create new area
    901                 return naddr;
     903                return mallocNoStats( size );                                   // create new area
    902904        } // resize
    903905
     
    908910                #ifdef __STATISTICS__
    909911                __atomic_add_fetch( &realloc_calls, 1, __ATOMIC_SEQ_CST );
    910                 __atomic_add_fetch( &realloc_storage, size, __ATOMIC_SEQ_CST );
    911912                #endif // __STATISTICS__
    912913
    913914                // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned.
    914           if ( unlikely( size == 0 ) ) { free( oaddr ); return mallocNoStats( size ); } // special cases
    915           if ( unlikely( oaddr == 0p ) ) return mallocNoStats( size );
     915          if ( unlikely( size == 0 ) ) { free( oaddr ); return 0p; } // special cases
     916          if ( unlikely( oaddr == 0p ) ) {
     917                        #ifdef __STATISTICS__
     918                        __atomic_add_fetch( &realloc_storage, size, __ATOMIC_SEQ_CST );
     919                        #endif // __STATISTICS__
     920                        return mallocNoStats( size );
     921                } // if
    916922
    917923                HeapManager.Storage.Header * header;
    918924                HeapManager.FreeHeader * freeElem;
    919                 size_t bsize, oalign = 0;
     925                size_t bsize, oalign;
    920926                headers( "realloc", oaddr, header, freeElem, bsize, oalign );
    921927
    922928                size_t odsize = dataStorage( bsize, oaddr, header ); // data storage available in bucket
    923           if ( size <= odsize && odsize <= size * 2 ) { // allow up to 50% wasted storage in smaller size
    924                         // Do not know size of original allocation => cannot do 0 fill for any additional space because do not know
    925                         // where to start filling, i.e., do not overwrite existing values in space.
     929                size_t osize = header->kind.real.size;                  // old allocation size
     930                bool ozfill = (header->kind.real.blockSize & 2) != 0; // old allocation zero filled
     931          if ( unlikely( size <= odsize ) && size > odsize / 2 ) { // allow up to 50% wasted storage
     932                        header->kind.real.size = size;                          // reset allocation size
     933                        if ( unlikely( ozfill ) && size > osize ) {     // previous request zero fill and larger ?
     934                                memset( (char *)oaddr + osize, (int)'\0', size - osize ); // initialize added storage
     935                        } // if
    926936                        return oaddr;
    927937                } // if
    928938
     939                #ifdef __STATISTICS__
     940                __atomic_add_fetch( &realloc_storage, size, __ATOMIC_SEQ_CST );
     941                #endif // __STATISTICS__
     942
    929943                // change size and copy old content to new storage
    930944
    931945                void * naddr;
    932                 if ( unlikely( oalign != 0 ) ) {                                // previous request memalign?
    933                         if ( unlikely( header->kind.real.blockSize & 2 ) ) { // previous request zero fill
    934                                 naddr = cmemalignNoStats( oalign, 1, size ); // create new aligned area
    935                         } else {
    936                                 naddr = memalignNoStats( oalign, size ); // create new aligned area
     946                if ( likely( oalign <= libAlign() ) ) {                 // previous request not aligned ?
     947                        naddr = mallocNoStats( size );                          // create new area
     948                } else {
     949                        naddr = memalignNoStats( oalign, size );        // create new aligned area
     950                } // if
     951
     952                headers( "realloc", naddr, header, freeElem, bsize, oalign );
     953                memcpy( naddr, oaddr, MIN( osize, size ) );             // copy bytes
     954                free( oaddr );
     955
     956                if ( unlikely( ozfill ) ) {                                             // previous request zero fill ?
     957                        header->kind.real.blockSize |= 2;                       // mark new request as zero filled
     958                        if ( size > osize ) {                                           // previous request larger ?
     959                                memset( (char *)naddr + osize, (int)'\0', size - osize ); // initialize added storage
    937960                        } // if
    938                 } else {
    939                         if ( unlikely( header->kind.real.blockSize & 2 ) ) { // previous request zero fill
    940                                 naddr = callocNoStats( 1, size );               // create new area
    941                         } else {
    942                                 naddr = mallocNoStats( size );                  // create new area
    943                         } // if
    944                 } // if
    945           if ( unlikely( naddr == 0p ) ) return 0p;
    946 
    947                 headers( "realloc", naddr, header, freeElem, bsize, oalign );
    948                 size_t ndsize = dataStorage( bsize, naddr, header ); // data storage avilable in bucket
    949                 // To preserve prior fill, the entire bucket must be copied versus the size.
    950                 memcpy( naddr, oaddr, MIN( odsize, ndsize ) );  // copy bytes
    951                 free( oaddr );
     961                } // if
    952962                return naddr;
    953963        } // realloc
    954964
     965
    955966        // Same as malloc() except the memory address is a multiple of alignment, which must be a power of two. (obsolete)
    956967        void * memalign( size_t alignment, size_t size ) {
     
    966977        // Same as aalloc() with memory alignment.
    967978        void * amemalign( size_t alignment, size_t dim, size_t elemSize ) {
     979                size_t size = dim * elemSize;
    968980                #ifdef __STATISTICS__
    969981                __atomic_add_fetch( &cmemalign_calls, 1, __ATOMIC_SEQ_CST );
    970                 __atomic_add_fetch( &cmemalign_storage, dim * elemSize, __ATOMIC_SEQ_CST );
    971                 #endif // __STATISTICS__
    972 
    973                 return memalignNoStats( alignment, dim * elemSize );
     982                __atomic_add_fetch( &cmemalign_storage, size, __ATOMIC_SEQ_CST );
     983                #endif // __STATISTICS__
     984
     985                return memalignNoStats( alignment, size );
    974986        } // amemalign
    975987
     
    9971009        // free(3).
    9981010        int posix_memalign( void ** memptr, size_t alignment, size_t size ) {
    999           if ( alignment < sizeof(void *) || ! libPow2( alignment ) ) return EINVAL; // check alignment
     1011          if ( alignment < libAlign() || ! is_pow2( alignment ) ) return EINVAL; // check alignment
    10001012                * memptr = memalign( alignment, size );
    1001           if ( unlikely( * memptr == 0p ) ) return ENOMEM;
    10021013                return 0;
    10031014        } // posix_memalign
     
    10121023        // Same as valloc but rounds size to multiple of page size.
    10131024        void * pvalloc( size_t size ) {
    1014                 return memalign( pageSize, libCeiling( size, pageSize ) );
     1025                return memalign( pageSize, ceiling2( size, pageSize ) );
    10151026        } // pvalloc
    10161027
     
    10501061        } // malloc_alignment
    10511062
     1063
    10521064        // Set the alignment for an the allocation and return previous alignment or 0 if no alignment.
    10531065        size_t $malloc_alignment_set( void * addr, size_t alignment ) {
     
    10901102        // Returns original total allocation size (not bucket size) => array size is dimension * sizeif(T).
    10911103        size_t malloc_size( void * addr ) {
    1092           if ( unlikely( addr == 0p ) ) return false;           // null allocation is not zero fill
     1104          if ( unlikely( addr == 0p ) ) return 0;                       // null allocation has zero size
    10931105                HeapManager.Storage.Header * header = headerAddr( addr );
    10941106                if ( (header->kind.fake.alignment & 1) == 1 ) { // fake header ?
    10951107                        header = realHeader( header );                          // backup from fake to real header
    10961108                } // if
    1097                 return header->size;
     1109                return header->kind.real.size;
    10981110        } // malloc_size
    10991111
    11001112        // Set allocation size and return previous size.
    11011113        size_t $malloc_size_set( void * addr, size_t size ) {
    1102           if ( unlikely( addr == 0p ) ) return false;           // null allocation is not zero fill
     1114          if ( unlikely( addr == 0p ) ) return 0;                       // null allocation has 0 size
    11031115                HeapManager.Storage.Header * header = headerAddr( addr );
    11041116                if ( (header->kind.fake.alignment & 1) == 1 ) { // fake header ?
    11051117                        header = realHeader( header );                          // backup from fake to real header
    11061118                } // if
    1107                 size_t ret = header->size;
    1108                 header->size = size;
     1119                size_t ret = header->kind.real.size;
     1120                header->kind.real.size = size;
    11091121                return ret;
    11101122        } // $malloc_size_set
     
    11201132
    11211133                headers( "malloc_usable_size", addr, header, freeElem, bsize, alignment );
    1122                 return dataStorage( bsize, addr, header );      // data storage in bucket
     1134                return dataStorage( bsize, addr, header );              // data storage in bucket
    11231135        } // malloc_usable_size
    11241136
     
    11321144        } // malloc_stats
    11331145
     1146
    11341147        // Changes the file descripter where malloc_stats() writes statistics.
    11351148        int malloc_stats_fd( int fd __attribute__(( unused )) ) {
    11361149                #ifdef __STATISTICS__
    1137                 int temp = statfd;
    1138                 statfd = fd;
     1150                int temp = stat_fd;
     1151                stat_fd = fd;
    11391152                return temp;
    11401153                #else
     
    11571170        } // mallopt
    11581171
     1172
    11591173        // Attempt to release free memory at the top of the heap (by calling sbrk with a suitable argument).
    11601174        int malloc_trim( size_t ) {
     
    11671181        // malloc).
    11681182        int malloc_info( int options, FILE * stream ) {
    1169                 if ( options != 0 ) { errno = EINVAL; return -1; }
     1183          if ( options != 0 ) { errno = EINVAL; return -1; }
     1184                #ifdef __STATISTICS__
    11701185                return printStatsXML( stream );
     1186                #else
     1187                return 0;                                                                               // unsupported
     1188                #endif // __STATISTICS__
    11711189        } // malloc_info
    11721190
     
    11831201        // Restores the state of all malloc internal bookkeeping variables to the values recorded in the opaque data
    11841202        // structure pointed to by state.
    1185         int malloc_set_state( void * ptr ) {
     1203        int malloc_set_state( void * ) {
    11861204                return 0;                                                                               // unsupported
    11871205        } // malloc_set_state
     
    11931211        #ifdef __STATISTICS__
    11941212        __atomic_add_fetch( &resize_calls, 1, __ATOMIC_SEQ_CST );
    1195         __atomic_add_fetch( &resize_storage, size, __ATOMIC_SEQ_CST );
    11961213        #endif // __STATISTICS__
    11971214
    11981215        // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned.
    1199   if ( unlikely( size == 0 ) ) { free( oaddr ); return memalignNoStats( nalign, size ); } // special cases
    1200   if ( unlikely( oaddr == 0p ) ) return memalignNoStats( nalign, size );
    1201 
    1202 
    1203         if ( unlikely( nalign == 0 ) ) nalign = libAlign();     // reset alignment to minimum
     1216  if ( unlikely( size == 0 ) ) { free( oaddr ); return 0p; } // special cases
     1217  if ( unlikely( oaddr == 0p ) ) {
     1218                #ifdef __STATISTICS__
     1219                __atomic_add_fetch( &resize_storage, size, __ATOMIC_SEQ_CST );
     1220                #endif // __STATISTICS__
     1221                return memalignNoStats( nalign, size );
     1222        } // if
     1223
     1224        if ( unlikely( nalign < libAlign() ) ) nalign = libAlign(); // reset alignment to minimum
    12041225        #ifdef __CFA_DEBUG__
    12051226        else
     
    12091230        HeapManager.Storage.Header * header;
    12101231        HeapManager.FreeHeader * freeElem;
    1211         size_t bsize, oalign = 0;
     1232        size_t bsize, oalign;
    12121233        headers( "resize", oaddr, header, freeElem, bsize, oalign );
    12131234        size_t odsize = dataStorage( bsize, oaddr, header ); // data storage available in bucket
    12141235
    12151236        if ( oalign <= nalign && (uintptr_t)oaddr % nalign == 0 ) { // <= alignment and new alignment happens to match
    1216                 if ( oalign >= libAlign() ) {                                   // fake header ?
     1237                if ( oalign > libAlign() ) {                                    // fake header ?
    12171238                        headerAddr( oaddr )->kind.fake.alignment = nalign | 1; // update alignment (could be the same)
    12181239                } // if
    12191240                if ( size <= odsize && odsize <= size * 2 ) {   // allow 50% wasted storage for smaller size
    12201241                        header->kind.real.blockSize &= -2;                      // turn off 0 fill
     1242                        header->kind.real.size = size;                          // reset allocation size
    12211243                        return oaddr;
    12221244                } // if
    12231245        } // if
    12241246
    1225         // change size
    1226 
    1227         void * naddr;
    1228         if ( unlikely( header->kind.real.blockSize & 2 ) ) { // previous request zero fill
    1229                 naddr = cmemalignNoStats( nalign, 1, size );    // create new aligned area
    1230         } else {
    1231                 naddr = memalignNoStats( nalign, size );                // create new aligned area
    1232         } // if
    1233 
     1247        #ifdef __STATISTICS__
     1248        __atomic_add_fetch( &resize_storage, size, __ATOMIC_SEQ_CST );
     1249        #endif // __STATISTICS__
     1250
     1251        // change size, DO NOT preserve STICKY PROPERTIES.
    12341252        free( oaddr );
    1235         return naddr;
     1253        return memalignNoStats( nalign, size );                         // create new aligned area
    12361254} // resize
    12371255
    12381256
    12391257void * realloc( void * oaddr, size_t nalign, size_t size ) {
    1240         if ( unlikely( nalign == 0 ) ) nalign = libAlign();     // reset alignment to minimum
     1258        if ( unlikely( nalign < libAlign() ) ) nalign = libAlign(); // reset alignment to minimum
    12411259        #ifdef __CFA_DEBUG__
    12421260        else
     
    12461264        HeapManager.Storage.Header * header;
    12471265        HeapManager.FreeHeader * freeElem;
    1248         size_t bsize, oalign = 0;
     1266        size_t bsize, oalign;
    12491267        headers( "realloc", oaddr, header, freeElem, bsize, oalign );
    1250         size_t odsize = dataStorage( bsize, oaddr, header ); // data storage available in bucket
    12511268
    12521269        if ( oalign <= nalign && (uintptr_t)oaddr % nalign == 0 ) { // <= alignment and new alignment happens to match
    1253                 if ( oalign >= libAlign() ) {                                   // fake header ?
     1270                if ( oalign > libAlign() ) {                                    // fake header ?
    12541271                        headerAddr( oaddr )->kind.fake.alignment = nalign | 1; // update alignment (could be the same)
    12551272                } // if
     
    12651282
    12661283        // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned.
    1267   if ( unlikely( size == 0 ) ) { free( oaddr ); return memalignNoStats( nalign, size ); } // special cases
     1284  if ( unlikely( size == 0 ) ) { free( oaddr ); return 0p; } // special cases
    12681285  if ( unlikely( oaddr == 0p ) ) return memalignNoStats( nalign, size );
    12691286
    1270         void * naddr;
    1271         if ( unlikely( header->kind.real.blockSize & 2 ) ) { // previous request zero fill
    1272                 naddr = cmemalignNoStats( nalign, 1, size );    // create new aligned area
    1273         } else {
    1274                 naddr = memalignNoStats( nalign, size );                // create new aligned area
    1275         } // if
     1287        size_t osize = header->kind.real.size;                          // old allocation size
     1288        bool ozfill = (header->kind.real.blockSize & 2) != 0; // old allocation zero filled
     1289
     1290        void * naddr = memalignNoStats( nalign, size );         // create new aligned area
    12761291
    12771292        headers( "realloc", naddr, header, freeElem, bsize, oalign );
    1278         size_t ndsize = dataStorage( bsize, naddr, header ); // data storage available in bucket
    1279         // To preserve prior fill, the entire bucket must be copied versus the size.
    1280         memcpy( naddr, oaddr, MIN( odsize, ndsize ) );          // copy bytes
     1293        memcpy( naddr, oaddr, MIN( osize, size ) );                     // copy bytes
    12811294        free( oaddr );
     1295
     1296        if ( unlikely( ozfill ) ) {                                                     // previous request zero fill ?
     1297                header->kind.real.blockSize |= 2;                               // mark new request as zero filled
     1298                if ( size > osize ) {                                                   // previous request larger ?
     1299                        memset( (char *)naddr + osize, (int)'\0', size - osize ); // initialize added storage
     1300                } // if
     1301        } // if
    12821302        return naddr;
    12831303} // realloc
Note: See TracChangeset for help on using the changeset viewer.