Changes in / [9aa1317:f1397d14]
- Files:
-
- 8 edited
-
libcfa/prelude/builtins.c (modified) (2 diffs)
-
libcfa/src/heap.cfa (modified) (46 diffs)
-
libcfa/src/stdlib.cfa (modified) (2 diffs)
-
libcfa/src/stdlib.hfa (modified) (7 diffs)
-
tests/.expect/alloc-ERROR.txt (modified) (4 diffs)
-
tests/.expect/alloc.txt (modified) (1 diff)
-
tests/alloc.cfa (modified) (4 diffs)
-
tests/heap.cfa (modified) (20 diffs)
Legend:
- Unmodified
- Added
- Removed
-
libcfa/prelude/builtins.c
r9aa1317 rf1397d14 10 10 // Created On : Fri Jul 21 16:21:03 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : T hu Nov 21 16:31:39201913 // Update Count : 10112 // Last Modified On : Tue Jun 25 18:06:52 2019 13 // Update Count : 97 14 14 // 15 15 … … 69 69 70 70 // universal typed pointer constant 71 static inline forall( dtype DT ) DT * intptr( uintptr_t addr ) { return (DT *)addr; } 71 // Compiler issue: there is a problem with anonymous types that do not have a size. 72 static inline forall( dtype DT | sized(DT) ) DT * intptr( uintptr_t addr ) { return (DT *)addr; } 72 73 73 74 // exponentiation operator implementation -
libcfa/src/heap.cfa
r9aa1317 rf1397d14 10 10 // Created On : Tue Dec 19 21:58:35 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Nov 22 14:16:30201913 // Update Count : 62612 // Last Modified On : Fri Oct 18 07:42:09 2019 13 // Update Count : 556 14 14 // 15 15 … … 30 30 #include "malloc.h" 31 31 32 #define MIN(x, y) (y > x ? x : y)33 32 34 33 static bool traceHeap = false; … … 51 50 52 51 53 static bool prtFree = false;54 55 inline bool prtFree() {56 return prtFree;57 } // prtFree58 59 bool prtFreeOn() {60 bool temp = prtFree;61 prtFree = true;52 static bool checkFree = false; 53 54 inline bool checkFree() { 55 return checkFree; 56 } // checkFree 57 58 bool checkFreeOn() { 59 bool temp = checkFree; 60 checkFree = true; 62 61 return temp; 63 } // prtFreeOn64 65 bool prtFreeOff() {66 bool temp = prtFree;67 prtFree = false;62 } // checkFreeOn 63 64 bool checkFreeOff() { 65 bool temp = checkFree; 66 checkFree = false; 68 67 return temp; 69 } // prtFreeOff68 } // checkFreeOff 70 69 71 70 … … 106 105 static unsigned int allocFree; // running total of allocations minus frees 107 106 108 static void prtUnfreed() {107 static void checkUnfreed() { 109 108 if ( allocFree != 0 ) { 110 109 // DO NOT USE STREAMS AS THEY MAY BE UNAVAILABLE AT THIS POINT. … … 113 112 // "Possible cause is unfreed storage allocated by the program or system/library routines called from the program.\n", 114 113 // (long int)getpid(), allocFree, allocFree ); // always print the UNIX pid 115 // __cfaabi_dbg_bits_write( STDERR_FILENO, helpText, len ); // print debug/nodebug116 } // if 117 } // prtUnfreed114 // __cfaabi_dbg_bits_write( helpText, len ); 115 } // if 116 } // checkUnfreed 118 117 119 118 extern "C" { … … 124 123 void heapAppStop() { // called by __cfaabi_appready_startdown 125 124 fclose( stdin ); fclose( stdout ); 126 prtUnfreed();125 checkUnfreed(); 127 126 } // heapAppStop 128 127 } // extern "C" … … 135 134 static unsigned int maxBucketsUsed; // maximum number of buckets in use 136 135 136 137 // #comment TD : This defined is significantly different from the __ALIGN__ define from locks.hfa 138 #define ALIGN 16 137 139 138 140 #define SPINLOCK 0 … … 145 147 // Recursive definitions: HeapManager needs size of bucket array and bucket area needs sizeof HeapManager storage. 146 148 // Break recusion by hardcoding number of buckets and statically checking number is correct after bucket array defined. 147 enum { NoBucketSizes = 9 1}; // number of buckets sizes149 enum { NoBucketSizes = 93 }; // number of buckets sizes 148 150 149 151 struct HeapManager { … … 192 194 } kind; // Kind 193 195 } header; // Header 194 char pad[ libAlign()- sizeof( Header )];196 char pad[ALIGN - sizeof( Header )]; 195 197 char data[0]; // storage 196 198 }; // Storage 197 199 198 static_assert( libAlign() >= sizeof( Storage ), "libAlign()< sizeof( Storage )" );200 static_assert( ALIGN >= sizeof( Storage ), "ALIGN < sizeof( Storage )" ); 199 201 200 202 struct FreeHeader { … … 228 230 // Powers of 2 are common allocation sizes, so make powers of 2 generate the minimum required size. 229 231 static const unsigned int bucketSizes[] @= { // different bucket sizes 230 16, 32, 48, 64 + sizeof(HeapManager.Storage), // 4 231 96, 112, 128 + sizeof(HeapManager.Storage), // 3 232 160, 192, 224, 256 + sizeof(HeapManager.Storage), // 4 233 320, 384, 448, 512 + sizeof(HeapManager.Storage), // 4 234 640, 768, 896, 1_024 + sizeof(HeapManager.Storage), // 4 235 1_536, 2_048 + sizeof(HeapManager.Storage), // 2 236 2_560, 3_072, 3_584, 4_096 + sizeof(HeapManager.Storage), // 4 237 6_144, 8_192 + sizeof(HeapManager.Storage), // 2 238 9_216, 10_240, 11_264, 12_288, 13_312, 14_336, 15_360, 16_384 + sizeof(HeapManager.Storage), // 8 239 18_432, 20_480, 22_528, 24_576, 26_624, 28_672, 30_720, 32_768 + sizeof(HeapManager.Storage), // 8 240 36_864, 40_960, 45_056, 49_152, 53_248, 57_344, 61_440, 65_536 + sizeof(HeapManager.Storage), // 8 241 73_728, 81_920, 90_112, 98_304, 106_496, 114_688, 122_880, 131_072 + sizeof(HeapManager.Storage), // 8 242 147_456, 163_840, 180_224, 196_608, 212_992, 229_376, 245_760, 262_144 + sizeof(HeapManager.Storage), // 8 243 294_912, 327_680, 360_448, 393_216, 425_984, 458_752, 491_520, 524_288 + sizeof(HeapManager.Storage), // 8 244 655_360, 786_432, 917_504, 1_048_576 + sizeof(HeapManager.Storage), // 4 245 1_179_648, 1_310_720, 1_441_792, 1_572_864, 1_703_936, 1_835_008, 1_966_080, 2_097_152 + sizeof(HeapManager.Storage), // 8 246 2_621_440, 3_145_728, 3_670_016, 4_194_304 + sizeof(HeapManager.Storage), // 4 232 16, 32, 48, 64, 233 64 + sizeof(HeapManager.Storage), 96, 112, 128, 128 + sizeof(HeapManager.Storage), 160, 192, 224, 234 256 + sizeof(HeapManager.Storage), 320, 384, 448, 512 + sizeof(HeapManager.Storage), 640, 768, 896, 235 1_024 + sizeof(HeapManager.Storage), 1_536, 2_048 + sizeof(HeapManager.Storage), 2_560, 3_072, 3_584, 4_096 + sizeof(HeapManager.Storage), 6_144, 236 8_192 + sizeof(HeapManager.Storage), 9_216, 10_240, 11_264, 12_288, 13_312, 14_336, 15_360, 237 16_384 + sizeof(HeapManager.Storage), 18_432, 20_480, 22_528, 24_576, 26_624, 28_672, 30_720, 238 32_768 + sizeof(HeapManager.Storage), 36_864, 40_960, 45_056, 49_152, 53_248, 57_344, 61_440, 239 65_536 + sizeof(HeapManager.Storage), 73_728, 81_920, 90_112, 98_304, 106_496, 114_688, 122_880, 240 131_072 + sizeof(HeapManager.Storage), 147_456, 163_840, 180_224, 196_608, 212_992, 229_376, 245_760, 241 262_144 + sizeof(HeapManager.Storage), 294_912, 327_680, 360_448, 393_216, 425_984, 458_752, 491_520, 242 524_288 + sizeof(HeapManager.Storage), 655_360, 786_432, 917_504, 1_048_576 + sizeof(HeapManager.Storage), 1_179_648, 1_310_720, 1_441_792, 243 1_572_864, 1_703_936, 1_835_008, 1_966_080, 2_097_152 + sizeof(HeapManager.Storage), 2_621_440, 3_145_728, 3_670_016, 244 4_194_304 + sizeof(HeapManager.Storage) 247 245 }; 248 246 … … 253 251 static unsigned char lookup[LookupSizes]; // O(1) lookup for small sizes 254 252 #endif // FASTLOOKUP 255 256 253 static int mmapFd = -1; // fake or actual fd for anonymous file 254 255 257 256 #ifdef __CFA_DEBUG__ 258 257 static bool heapBoot = 0; // detect recursion during boot … … 260 259 static HeapManager heapManager __attribute__(( aligned (128) )) @= {}; // size of cache line to prevent false sharing 261 260 261 // #comment TD : The return type of this function should be commented 262 static inline bool setMmapStart( size_t value ) { 263 if ( value < pageSize || bucketSizes[NoBucketSizes - 1] < value ) return true; 264 mmapStart = value; // set global 265 266 // find the closest bucket size less than or equal to the mmapStart size 267 maxBucketsUsed = bsearchl( (unsigned int)mmapStart, bucketSizes, NoBucketSizes ); // binary search 268 assert( maxBucketsUsed < NoBucketSizes ); // subscript failure ? 269 assert( mmapStart <= bucketSizes[maxBucketsUsed] ); // search failure ? 270 return false; 271 } // setMmapStart 272 273 274 static void ?{}( HeapManager & manager ) with ( manager ) { 275 pageSize = sysconf( _SC_PAGESIZE ); 276 277 for ( unsigned int i = 0; i < NoBucketSizes; i += 1 ) { // initialize the free lists 278 freeLists[i].blockSize = bucketSizes[i]; 279 } // for 280 281 #ifdef FASTLOOKUP 282 unsigned int idx = 0; 283 for ( unsigned int i = 0; i < LookupSizes; i += 1 ) { 284 if ( i > bucketSizes[idx] ) idx += 1; 285 lookup[i] = idx; 286 } // for 287 #endif // FASTLOOKUP 288 289 if ( setMmapStart( default_mmap_start() ) ) { 290 abort( "HeapManager : internal error, mmap start initialization failure." ); 291 } // if 292 heapExpand = default_heap_expansion(); 293 294 char * End = (char *)sbrk( 0 ); 295 sbrk( (char *)libCeiling( (long unsigned int)End, libAlign() ) - End ); // move start of heap to multiple of alignment 296 heapBegin = heapEnd = sbrk( 0 ); // get new start point 297 } // HeapManager 298 299 300 static void ^?{}( HeapManager & ) { 301 #ifdef __STATISTICS__ 302 // if ( traceHeapTerm() ) { 303 // printStats(); 304 // if ( checkfree() ) checkFree( heapManager, true ); 305 // } // if 306 #endif // __STATISTICS__ 307 } // ~HeapManager 308 309 310 static void memory_startup( void ) __attribute__(( constructor( STARTUP_PRIORITY_MEMORY ) )); 311 void memory_startup( void ) { 312 #ifdef __CFA_DEBUG__ 313 if ( unlikely( heapBoot ) ) { // check for recursion during system boot 314 // DO NOT USE STREAMS AS THEY MAY BE UNAVAILABLE AT THIS POINT. 315 abort( "boot() : internal error, recursively invoked during system boot." ); 316 } // if 317 heapBoot = true; 318 #endif // __CFA_DEBUG__ 319 320 //assert( heapManager.heapBegin != 0 ); 321 //heapManager{}; 322 if ( heapManager.heapBegin == 0 ) heapManager{}; 323 } // memory_startup 324 325 static void memory_shutdown( void ) __attribute__(( destructor( STARTUP_PRIORITY_MEMORY ) )); 326 void memory_shutdown( void ) { 327 ^heapManager{}; 328 } // memory_shutdown 329 262 330 263 331 #ifdef __STATISTICS__ 264 // Heap statistics counters. 265 static unsigned long long int mmap_storage; 332 static unsigned long long int mmap_storage; // heap statistics counters 266 333 static unsigned int mmap_calls; 267 334 static unsigned long long int munmap_storage; … … 281 348 static unsigned long long int realloc_storage; 282 349 static unsigned int realloc_calls; 283 // Statistics file descriptor (changed by malloc_stats_fd). 284 static int statfd = STDERR_FILENO; // default stderr 350 351 static int statfd; // statistics file descriptor (changed by malloc_stats_fd) 352 285 353 286 354 // Use "write" because streams may be shutdown when calls are made. 287 355 static void printStats() { 288 356 char helpText[512]; 289 __cfaabi_ bits_print_buffer( STDERR_FILENO,helpText, sizeof(helpText),357 __cfaabi_dbg_bits_print_buffer( helpText, sizeof(helpText), 290 358 "\nHeap statistics:\n" 291 359 " malloc: calls %u / storage %llu\n" … … 337 405 sbrk_calls, sbrk_storage 338 406 ); 339 __cfaabi_bits_write( fileno( stream ), helpText, len ); // ensures all bytes written or exit 340 return len; 407 return write( fileno( stream ), helpText, len ); // -1 => error 341 408 } // printStatsXML 342 409 #endif // __STATISTICS__ 343 344 410 345 411 // #comment TD : Is this the samething as Out-of-Memory? … … 352 418 353 419 static inline void checkAlign( size_t alignment ) { 354 if ( alignment < libAlign() || ! libPow2( alignment ) ) {355 abort( "Alignment %zu for memory allocation is less than %d and/or not a power of 2.", alignment, libAlign());420 if ( alignment < sizeof(void *) || ! libPow2( alignment ) ) { 421 abort( "Alignment %zu for memory allocation is less than sizeof(void *) and/or not a power of 2.", alignment ); 356 422 } // if 357 423 } // checkAlign … … 365 431 366 432 367 static inline bool setMmapStart( size_t value ) { // true => mmapped, false => sbrk368 if ( value < pageSize || bucketSizes[NoBucketSizes - 1] < value ) return true;369 mmapStart = value; // set global370 371 // find the closest bucket size less than or equal to the mmapStart size372 maxBucketsUsed = bsearchl( (unsigned int)mmapStart, bucketSizes, NoBucketSizes ); // binary search373 assert( maxBucketsUsed < NoBucketSizes ); // subscript failure ?374 assert( mmapStart <= bucketSizes[maxBucketsUsed] ); // search failure ?375 return false;376 } // setMmapStart377 378 379 433 static inline void checkHeader( bool check, const char * name, void * addr ) { 380 434 if ( unlikely( check ) ) { // bad address ? … … 385 439 } // checkHeader 386 440 387 388 static inline void fakeHeader( HeapManager.Storage.Header *& header, size_t & alignment ) { 441 // #comment TD : function should be commented and/or have a more evocative name 442 // this isn't either a check or a constructor which is what I would expect this function to be 443 static inline void fakeHeader( HeapManager.Storage.Header *& header, size_t & size, size_t & alignment ) { 389 444 if ( unlikely( (header->kind.fake.alignment & 1) == 1 ) ) { // fake header ? 390 445 size_t offset = header->kind.fake.offset; … … 397 452 } // fakeHeader 398 453 399 400 // <-------+----------------------------------------------------> bsize (bucket size) 401 // |header |addr 402 //================================================================================== 403 // | alignment 404 // <-----------------<------------+-----------------------------> bsize (bucket size) 405 // |fake-header | addr 454 // #comment TD : Why is this a define 406 455 #define headerAddr( addr ) ((HeapManager.Storage.Header *)( (char *)addr - sizeof(HeapManager.Storage) )) 407 456 408 // <-------<<--------------------- dsize ---------------------->> bsize (bucket size) 409 // |header |addr 410 //================================================================================== 411 // | alignment 412 // <------------------------------<<---------- dsize --------->>> bsize (bucket size) 413 // |fake-header |addr 414 #define dataStorage( bsize, addr, header ) (bsize - ( (char *)addr - (char *)header )) 415 416 417 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 ) { 457 static inline bool headers( const char * name, void * addr, HeapManager.Storage.Header *& header, HeapManager.FreeHeader *& freeElem, size_t & size, size_t & alignment ) with ( heapManager ) { 418 458 header = headerAddr( addr ); 419 459 420 460 if ( unlikely( heapEnd < addr ) ) { // mmapped ? 421 fakeHeader( header, alignment );461 fakeHeader( header, size, alignment ); 422 462 size = header->kind.real.blockSize & -3; // mmap size 423 463 return true; … … 428 468 #endif // __CFA_DEBUG__ 429 469 470 // #comment TD : This code looks weird... 471 // It's called as the first statement of both branches of the last if, with the same parameters in all cases 472 430 473 // header may be safe to dereference 431 fakeHeader( header, alignment );474 fakeHeader( header, size, alignment ); 432 475 #ifdef __CFA_DEBUG__ 433 476 checkHeader( header < (HeapManager.Storage.Header *)heapBegin || (HeapManager.Storage.Header *)heapEnd < header, name, addr ); // bad address ? (offset could be + or -) … … 457 500 unlock( extlock ); 458 501 errno = ENOMEM; 459 return 0 p;502 return 0; 460 503 } // if 461 504 #ifdef __STATISTICS__ … … 498 541 // along with the block and is a multiple of the alignment size. 499 542 500 if ( unlikely( size > ~0ul - sizeof(HeapManager.Storage) ) ) return 0 p;543 if ( unlikely( size > ~0ul - sizeof(HeapManager.Storage) ) ) return 0; 501 544 size_t tsize = size + sizeof(HeapManager.Storage); 502 545 if ( likely( tsize < mmapStart ) ) { // small size => sbrk … … 531 574 block = freeElem->freeList.pop(); 532 575 #endif // SPINLOCK 533 if ( unlikely( block == 0 p ) ) {// no free block ?576 if ( unlikely( block == 0 ) ) { // no free block ? 534 577 #if defined( SPINLOCK ) 535 578 unlock( freeElem->lock ); … … 540 583 541 584 block = (HeapManager.Storage *)extend( tsize ); // mutual exclusion on call 542 if ( unlikely( block == 0 p ) ) return 0p;585 if ( unlikely( block == 0 ) ) return 0; 543 586 #if defined( SPINLOCK ) 544 587 } else { … … 550 593 block->header.kind.real.home = freeElem; // pointer back to free list of apropriate size 551 594 } else { // large size => mmap 552 if ( unlikely( size > ~0ul - pageSize ) ) return 0 p;595 if ( unlikely( size > ~0ul - pageSize ) ) return 0; 553 596 tsize = libCeiling( tsize, pageSize ); // must be multiple of page size 554 597 #ifdef __STATISTICS__ … … 568 611 } // if 569 612 570 void * a ddr= &(block->data); // adjust off header to user bytes613 void * area = &(block->data); // adjust off header to user bytes 571 614 572 615 #ifdef __CFA_DEBUG__ 573 assert( ((uintptr_t)a ddr& (libAlign() - 1)) == 0 ); // minimum alignment ?616 assert( ((uintptr_t)area & (libAlign() - 1)) == 0 ); // minimum alignment ? 574 617 __atomic_add_fetch( &allocFree, tsize, __ATOMIC_SEQ_CST ); 575 618 if ( traceHeap() ) { 576 619 enum { BufferSize = 64 }; 577 620 char helpText[BufferSize]; 578 int len = snprintf( helpText, BufferSize, "%p = Malloc( %zu ) (allocated %zu)\n", a ddr, size, tsize );579 // int len = snprintf( helpText, BufferSize, "Malloc %p %zu\n", a ddr, size );580 __cfaabi_ bits_write( STDERR_FILENO, helpText, len ); // print debug/nodebug621 int len = snprintf( helpText, BufferSize, "%p = Malloc( %zu ) (allocated %zu)\n", area, size, tsize ); 622 // int len = snprintf( helpText, BufferSize, "Malloc %p %zu\n", area, size ); 623 __cfaabi_dbg_bits_write( helpText, len ); 581 624 } // if 582 625 #endif // __CFA_DEBUG__ 583 626 584 return a ddr;627 return area; 585 628 } // doMalloc 586 629 … … 588 631 static inline void doFree( void * addr ) with ( heapManager ) { 589 632 #ifdef __CFA_DEBUG__ 590 if ( unlikely( heapManager.heapBegin == 0 p) ) {633 if ( unlikely( heapManager.heapBegin == 0 ) ) { 591 634 abort( "doFree( %p ) : internal error, called before heap is initialized.", addr ); 592 635 } // if … … 634 677 char helpText[BufferSize]; 635 678 int len = snprintf( helpText, sizeof(helpText), "Free( %p ) size:%zu\n", addr, size ); 636 __cfaabi_ bits_write( STDERR_FILENO, helpText, len ); // print debug/nodebug679 __cfaabi_dbg_bits_write( helpText, len ); 637 680 } // if 638 681 #endif // __CFA_DEBUG__ … … 640 683 641 684 642 size_t prtFree( HeapManager & manager ) with ( manager ) {685 size_t checkFree( HeapManager & manager ) with ( manager ) { 643 686 size_t total = 0; 644 687 #ifdef __STATISTICS__ 645 __cfaabi_ bits_acquire();646 __cfaabi_ bits_print_nolock( STDERR_FILENO,"\nBin lists (bin size : free blocks on list)\n" );688 __cfaabi_dbg_bits_acquire(); 689 __cfaabi_dbg_bits_print_nolock( "\nBin lists (bin size : free blocks on list)\n" ); 647 690 #endif // __STATISTICS__ 648 691 for ( unsigned int i = 0; i < maxBucketsUsed; i += 1 ) { … … 653 696 654 697 #if defined( SPINLOCK ) 655 for ( HeapManager.Storage * p = freeLists[i].freeList; p != 0 p; p = p->header.kind.real.next ) {698 for ( HeapManager.Storage * p = freeLists[i].freeList; p != 0; p = p->header.kind.real.next ) { 656 699 #else 657 for ( HeapManager.Storage * p = freeLists[i].freeList.top(); p != 0 p; p = p->header.kind.real.next.top ) {700 for ( HeapManager.Storage * p = freeLists[i].freeList.top(); p != 0; p = p->header.kind.real.next.top ) { 658 701 #endif // SPINLOCK 659 702 total += size; … … 664 707 665 708 #ifdef __STATISTICS__ 666 __cfaabi_ bits_print_nolock( STDERR_FILENO,"%7zu, %-7u ", size, N );667 if ( (i + 1) % 8 == 0 ) __cfaabi_ bits_print_nolock( STDERR_FILENO,"\n" );709 __cfaabi_dbg_bits_print_nolock( "%7zu, %-7u ", size, N ); 710 if ( (i + 1) % 8 == 0 ) __cfaabi_dbg_bits_print_nolock( "\n" ); 668 711 #endif // __STATISTICS__ 669 712 } // for 670 713 #ifdef __STATISTICS__ 671 __cfaabi_ bits_print_nolock( STDERR_FILENO,"\ntotal free blocks:%zu\n", total );672 __cfaabi_ bits_release();714 __cfaabi_dbg_bits_print_nolock( "\ntotal free blocks:%zu\n", total ); 715 __cfaabi_dbg_bits_release(); 673 716 #endif // __STATISTICS__ 674 717 return (char *)heapEnd - (char *)heapBegin - total; 675 } // prtFree 676 677 678 static void ?{}( HeapManager & manager ) with ( manager ) { 679 pageSize = sysconf( _SC_PAGESIZE ); 680 681 for ( unsigned int i = 0; i < NoBucketSizes; i += 1 ) { // initialize the free lists 682 freeLists[i].blockSize = bucketSizes[i]; 683 } // for 684 685 #ifdef FASTLOOKUP 686 unsigned int idx = 0; 687 for ( unsigned int i = 0; i < LookupSizes; i += 1 ) { 688 if ( i > bucketSizes[idx] ) idx += 1; 689 lookup[i] = idx; 690 } // for 691 #endif // FASTLOOKUP 692 693 if ( setMmapStart( default_mmap_start() ) ) { 694 abort( "HeapManager : internal error, mmap start initialization failure." ); 695 } // if 696 heapExpand = default_heap_expansion(); 697 698 char * End = (char *)sbrk( 0 ); 699 sbrk( (char *)libCeiling( (long unsigned int)End, libAlign() ) - End ); // move start of heap to multiple of alignment 700 heapBegin = heapEnd = sbrk( 0 ); // get new start point 701 } // HeapManager 702 703 704 static void ^?{}( HeapManager & ) { 705 #ifdef __STATISTICS__ 706 // if ( traceHeapTerm() ) { 707 // printStats(); 708 // if ( prtfree() ) prtFree( heapManager, true ); 709 // } // if 710 #endif // __STATISTICS__ 711 } // ~HeapManager 712 713 714 static void memory_startup( void ) __attribute__(( constructor( STARTUP_PRIORITY_MEMORY ) )); 715 void memory_startup( void ) { 716 #ifdef __CFA_DEBUG__ 717 if ( unlikely( heapBoot ) ) { // check for recursion during system boot 718 // DO NOT USE STREAMS AS THEY MAY BE UNAVAILABLE AT THIS POINT. 719 abort( "boot() : internal error, recursively invoked during system boot." ); 720 } // if 721 heapBoot = true; 722 #endif // __CFA_DEBUG__ 723 724 //assert( heapManager.heapBegin != 0 ); 725 //heapManager{}; 726 if ( heapManager.heapBegin == 0p ) heapManager{}; 727 } // memory_startup 728 729 static void memory_shutdown( void ) __attribute__(( destructor( STARTUP_PRIORITY_MEMORY ) )); 730 void memory_shutdown( void ) { 731 ^heapManager{}; 732 } // memory_shutdown 718 } // checkFree 733 719 734 720 735 721 static inline void * mallocNoStats( size_t size ) { // necessary for malloc statistics 736 722 //assert( heapManager.heapBegin != 0 ); 737 if ( unlikely( heapManager.heapBegin == 0 p) ) heapManager{}; // called before memory_startup ?738 void * a ddr= doMalloc( size );739 if ( unlikely( a ddr == 0p) ) errno = ENOMEM; // POSIX740 return a ddr;723 if ( unlikely( heapManager.heapBegin == 0 ) ) heapManager{}; // called before memory_startup ? 724 void * area = doMalloc( size ); 725 if ( unlikely( area == 0 ) ) errno = ENOMEM; // POSIX 726 return area; 741 727 } // mallocNoStats 742 743 744 static inline void * callocNoStats( size_t noOfElems, size_t elemSize ) {745 size_t size = noOfElems * elemSize;746 char * addr = (char *)mallocNoStats( size );747 if ( unlikely( addr == 0p ) ) return 0p;748 749 HeapManager.Storage.Header * header;750 HeapManager.FreeHeader * freeElem;751 size_t bsize, alignment;752 bool mapped __attribute__(( unused )) = headers( "calloc", addr, header, freeElem, bsize, alignment );753 #ifndef __CFA_DEBUG__754 // Mapped storage is zero filled, but in debug mode mapped memory is scrubbed in doMalloc, so it has to be reset to zero.755 if ( ! mapped )756 #endif // __CFA_DEBUG__757 // Zero entire data space even when > than size => realloc without a new allocation and zero fill works.758 // <-------00000000000000000000000000000000000000000000000000000> bsize (bucket size)759 // `-header`-addr `-size760 memset( addr, '\0', bsize - sizeof(HeapManager.Storage) ); // set to zeros761 762 header->kind.real.blockSize |= 2; // mark as zero filled763 return addr;764 } // callocNoStats765 728 766 729 … … 782 745 // subtract libAlign() because it is already the minimum alignment 783 746 // add sizeof(Storage) for fake header 784 char * addr = (char *)mallocNoStats( size + alignment - libAlign() + sizeof(HeapManager.Storage) ); 785 if ( unlikely( addr == 0p ) ) return addr; 747 // #comment TD : this is the only place that calls doMalloc without calling mallocNoStats, why ? 748 char * area = (char *)doMalloc( size + alignment - libAlign() + sizeof(HeapManager.Storage) ); 749 if ( unlikely( area == 0 ) ) return area; 786 750 787 751 // address in the block of the "next" alignment address 788 char * user = (char *)libCeiling( (uintptr_t)(a ddr+ sizeof(HeapManager.Storage)), alignment );752 char * user = (char *)libCeiling( (uintptr_t)(area + sizeof(HeapManager.Storage)), alignment ); 789 753 790 754 // address of header from malloc 791 HeapManager.Storage.Header * realHeader = headerAddr( a ddr);755 HeapManager.Storage.Header * realHeader = headerAddr( area ); 792 756 // address of fake header * before* the alignment location 793 757 HeapManager.Storage.Header * fakeHeader = headerAddr( user ); … … 799 763 return user; 800 764 } // memalignNoStats 801 802 803 static inline void * cmemalignNoStats( size_t alignment, size_t noOfElems, size_t elemSize ) {804 size_t size = noOfElems * elemSize;805 char * addr = (char *)memalignNoStats( alignment, size );806 if ( unlikely( addr == 0p ) ) return 0p;807 HeapManager.Storage.Header * header;808 HeapManager.FreeHeader * freeElem;809 size_t bsize;810 bool mapped __attribute__(( unused )) = headers( "cmemalign", addr, header, freeElem, bsize, alignment );811 #ifndef __CFA_DEBUG__812 // Mapped storage is zero filled, but in debug mode mapped memory is scrubbed in doMalloc, so it has to be reset to zero.813 if ( ! mapped )814 #endif // __CFA_DEBUG__815 memset( addr, '\0', dataStorage( bsize, addr, header ) ); // set to zeros816 header->kind.real.blockSize |= 2; // mark as zero filled817 818 return addr;819 } // cmemalignNoStats820 765 821 766 … … 831 776 extern "C" { 832 777 // The malloc() function allocates size bytes and returns a pointer to the allocated memory. The memory is not 833 // initialized. If size is 0, then malloc() returns either 0p, or a unique pointer value that can later be778 // initialized. If size is 0, then malloc() returns either NULL, or a unique pointer value that can later be 834 779 // successfully passed to free(). 835 780 void * malloc( size_t size ) { … … 843 788 844 789 // The calloc() function allocates memory for an array of nmemb elements of size bytes each and returns a pointer to 845 // the allocated memory. The memory is set to zero. If nmemb or size is 0, then calloc() returns either 0p, or a790 // the allocated memory. The memory is set to zero. If nmemb or size is 0, then calloc() returns either NULL, or a 846 791 // unique pointer value that can later be successfully passed to free(). 847 792 void * calloc( size_t noOfElems, size_t elemSize ) { 793 size_t size = noOfElems * elemSize; 848 794 #ifdef __STATISTICS__ 849 795 __atomic_add_fetch( &calloc_calls, 1, __ATOMIC_SEQ_CST ); 850 __atomic_add_fetch( &calloc_storage, noOfElems * elemSize, __ATOMIC_SEQ_CST ); 851 #endif // __STATISTICS__ 852 853 return callocNoStats( noOfElems, elemSize ); 796 __atomic_add_fetch( &calloc_storage, size, __ATOMIC_SEQ_CST ); 797 #endif // __STATISTICS__ 798 799 char * area = (char *)mallocNoStats( size ); 800 if ( unlikely( area == 0 ) ) return 0; 801 802 HeapManager.Storage.Header * header; 803 HeapManager.FreeHeader * freeElem; 804 size_t asize, alignment; 805 bool mapped __attribute__(( unused )) = headers( "calloc", area, header, freeElem, asize, alignment ); 806 #ifndef __CFA_DEBUG__ 807 // Mapped storage is zero filled, but in debug mode mapped memory is scrubbed in doMalloc, so it has to be reset to zero. 808 if ( ! mapped ) 809 #endif // __CFA_DEBUG__ 810 memset( area, '\0', asize - sizeof(HeapManager.Storage) ); // set to zeros 811 812 header->kind.real.blockSize |= 2; // mark as zero filled 813 return area; 854 814 } // calloc 815 816 // #comment TD : Document this function 817 void * cmemalign( size_t alignment, size_t noOfElems, size_t elemSize ) { 818 size_t size = noOfElems * elemSize; 819 #ifdef __STATISTICS__ 820 __atomic_add_fetch( &cmemalign_calls, 1, __ATOMIC_SEQ_CST ); 821 __atomic_add_fetch( &cmemalign_storage, size, __ATOMIC_SEQ_CST ); 822 #endif // __STATISTICS__ 823 824 char * area = (char *)memalignNoStats( alignment, size ); 825 if ( unlikely( area == 0 ) ) return 0; 826 HeapManager.Storage.Header * header; 827 HeapManager.FreeHeader * freeElem; 828 size_t asize; 829 bool mapped __attribute__(( unused )) = headers( "cmemalign", area, header, freeElem, asize, alignment ); 830 #ifndef __CFA_DEBUG__ 831 // Mapped storage is zero filled, but in debug mode mapped memory is scrubbed in doMalloc, so it has to be reset to zero. 832 if ( ! mapped ) 833 #endif // __CFA_DEBUG__ 834 memset( area, '\0', asize - ( (char *)area - (char *)header ) ); // set to zeros 835 header->kind.real.blockSize |= 2; // mark as zero filled 836 837 return area; 838 } // cmemalign 855 839 856 840 // The realloc() function changes the size of the memory block pointed to by ptr to size bytes. The contents will be 857 841 // unchanged in the range from the start of the region up to the minimum of the old and new sizes. If the new size 858 // is larger than the old size, the added memory will not be initialized. If ptr is 0p, then the call is859 // equivalent to malloc(size), for all values of size; if size is equal to zero, and ptr is not 0p, then the call860 // is equivalent to free(ptr). Unless ptr is 0p, it must have been returned by an earlier call to malloc(),842 // is larger than the old size, the added memory will not be initialized. If ptr is NULL, then the call is 843 // equivalent to malloc(size), for all values of size; if size is equal to zero, and ptr is not NULL, then the call 844 // is equivalent to free(ptr). Unless ptr is NULL, it must have been returned by an earlier call to malloc(), 861 845 // calloc() or realloc(). If the area pointed to was moved, a free(ptr) is done. 862 void * realloc( void * oaddr, size_t size ) {846 void * realloc( void * addr, size_t size ) { 863 847 #ifdef __STATISTICS__ 864 848 __atomic_add_fetch( &realloc_calls, 1, __ATOMIC_SEQ_CST ); 865 849 #endif // __STATISTICS__ 866 850 867 if ( unlikely( size == 0 ) ) { free( oaddr ); return 0p; }// special cases868 if ( unlikely( oaddr == 0p ) ) return mallocNoStats( size );851 if ( unlikely( addr == 0 ) ) return mallocNoStats( size ); // special cases 852 if ( unlikely( size == 0 ) ) { free( addr ); return 0; } 869 853 870 854 HeapManager.Storage.Header * header; 871 855 HeapManager.FreeHeader * freeElem; 872 size_t bsize, oalign = 0; 873 headers( "realloc", oaddr, header, freeElem, bsize, oalign ); 874 875 size_t odsize = dataStorage( bsize, oaddr, header ); // data storage available in bucket 876 if ( size <= odsize && odsize <= size * 2 ) { // allow up to 50% wasted storage in smaller size 877 // Do not know size of original allocation => cannot do 0 fill for any additional space because do not know 878 // where to start filling, i.e., do not overwrite existing values in space. 879 // 856 size_t asize, alignment = 0; 857 headers( "realloc", addr, header, freeElem, asize, alignment ); 858 859 size_t usize = asize - ( (char *)addr - (char *)header ); // compute the amount of user storage in the block 860 if ( usize >= size ) { // already sufficient storage 880 861 // This case does not result in a new profiler entry because the previous one still exists and it must match with 881 862 // the free for this memory. Hence, this realloc does not appear in the profiler output. 882 return oaddr;863 return addr; 883 864 } // if 884 865 … … 887 868 #endif // __STATISTICS__ 888 869 889 // change size and copy old content to new storage 890 891 void * naddr; 892 if ( unlikely( oalign != 0 ) ) { // previous request memalign? 893 if ( unlikely( header->kind.real.blockSize & 2 ) ) { // previous request zero fill 894 naddr = cmemalignNoStats( oalign, 1, size ); // create new aligned area 895 } else { 896 naddr = memalignNoStats( oalign, size ); // create new aligned area 897 } // if 870 void * area; 871 if ( unlikely( alignment != 0 ) ) { // previous request memalign? 872 area = memalign( alignment, size ); // create new aligned area 898 873 } else { 899 if ( unlikely( header->kind.real.blockSize & 2 ) ) { // previous request zero fill 900 naddr = callocNoStats( 1, size ); // create new area 901 } else { 902 naddr = mallocNoStats( size ); // create new area 903 } // if 874 area = mallocNoStats( size ); // create new area 904 875 } // if 905 if ( unlikely( naddr == 0p ) ) return 0p; 906 headers( "realloc", naddr, header, freeElem, bsize, oalign ); 907 size_t ndsize = dataStorage( bsize, naddr, header ); // data storage avilable in bucket 908 // To preserve prior fill, the entire bucket must be copied versus the size. 909 memcpy( naddr, oaddr, MIN( odsize, ndsize ) ); // copy bytes 910 free( oaddr ); 911 return naddr; 876 if ( unlikely( area == 0 ) ) return 0; 877 if ( unlikely( header->kind.real.blockSize & 2 ) ) { // previous request zero fill (calloc/cmemalign) ? 878 assert( (header->kind.real.blockSize & 1) == 0 ); 879 bool mapped __attribute__(( unused )) = headers( "realloc", area, header, freeElem, asize, alignment ); 880 #ifndef __CFA_DEBUG__ 881 // Mapped storage is zero filled, but in debug mode mapped memory is scrubbed in doMalloc, so it has to be reset to zero. 882 if ( ! mapped ) 883 #endif // __CFA_DEBUG__ 884 memset( (char *)area + usize, '\0', asize - ( (char *)area - (char *)header ) - usize ); // zero-fill back part 885 header->kind.real.blockSize |= 2; // mark new request as zero fill 886 } // if 887 memcpy( area, addr, usize ); // copy bytes 888 free( addr ); 889 return area; 912 890 } // realloc 913 891 … … 920 898 #endif // __STATISTICS__ 921 899 922 return memalignNoStats( alignment, size ); 900 void * area = memalignNoStats( alignment, size ); 901 902 return area; 923 903 } // memalign 924 925 926 // The cmemalign() function is the same as calloc() with memory alignment.927 void * cmemalign( size_t alignment, size_t noOfElems, size_t elemSize ) {928 #ifdef __STATISTICS__929 __atomic_add_fetch( &cmemalign_calls, 1, __ATOMIC_SEQ_CST );930 __atomic_add_fetch( &cmemalign_storage, noOfElems * elemSize, __ATOMIC_SEQ_CST );931 #endif // __STATISTICS__932 933 return cmemalignNoStats( alignment, noOfElems, elemSize );934 } // cmemalign935 904 936 905 // The function aligned_alloc() is the same as memalign(), except for the added restriction that size should be a … … 943 912 // The function posix_memalign() allocates size bytes and places the address of the allocated memory in *memptr. The 944 913 // address of the allocated memory will be a multiple of alignment, which must be a power of two and a multiple of 945 // sizeof(void *). If size is 0, then posix_memalign() returns either 0p, or a unique pointer value that can later914 // sizeof(void *). If size is 0, then posix_memalign() returns either NULL, or a unique pointer value that can later 946 915 // be successfully passed to free(3). 947 916 int posix_memalign( void ** memptr, size_t alignment, size_t size ) { 948 917 if ( alignment < sizeof(void *) || ! libPow2( alignment ) ) return EINVAL; // check alignment 949 918 * memptr = memalign( alignment, size ); 950 if ( unlikely( * memptr == 0 p) ) return ENOMEM;919 if ( unlikely( * memptr == 0 ) ) return ENOMEM; 951 920 return 0; 952 921 } // posix_memalign … … 961 930 // The free() function frees the memory space pointed to by ptr, which must have been returned by a previous call to 962 931 // malloc(), calloc() or realloc(). Otherwise, or if free(ptr) has already been called before, undefined behavior 963 // occurs. If ptr is 0p, no operation is performed.932 // occurs. If ptr is NULL, no operation is performed. 964 933 void free( void * addr ) { 965 934 #ifdef __STATISTICS__ … … 967 936 #endif // __STATISTICS__ 968 937 969 if ( unlikely( addr == 0p ) ) { // special case 970 // #ifdef __CFA_DEBUG__ 971 // if ( traceHeap() ) { 972 // #define nullmsg "Free( 0x0 ) size:0\n" 973 // // Do not debug print free( 0 ), as it can cause recursive entry from sprintf. 974 // __cfaabi_dbg_write( nullmsg, sizeof(nullmsg) - 1 ); 975 // } // if 976 // #endif // __CFA_DEBUG__ 938 // #comment TD : To decrease nesting I would but the special case in the 939 // else instead, plus it reads more naturally to have the 940 // short / normal case instead 941 if ( unlikely( addr == 0 ) ) { // special case 942 #ifdef __CFA_DEBUG__ 943 if ( traceHeap() ) { 944 #define nullmsg "Free( 0x0 ) size:0\n" 945 // Do not debug print free( 0 ), as it can cause recursive entry from sprintf. 946 __cfaabi_dbg_bits_write( nullmsg, sizeof(nullmsg) - 1 ); 947 } // if 948 #endif // __CFA_DEBUG__ 977 949 return; 978 950 } // exit … … 981 953 } // free 982 954 955 // The mallopt() function adjusts parameters that control the behavior of the memory-allocation functions (see 956 // malloc(3)). The param argument specifies the parameter to be modified, and value specifies the new value for that 957 // parameter. 958 int mallopt( int option, int value ) { 959 choose( option ) { 960 case M_TOP_PAD: 961 if ( setHeapExpand( value ) ) fallthru default; 962 case M_MMAP_THRESHOLD: 963 if ( setMmapStart( value ) ) fallthru default; 964 default: 965 // #comment TD : 1 for unsopported feels wrong 966 return 1; // success, or unsupported 967 } // switch 968 return 0; // error 969 } // mallopt 970 971 // The malloc_trim() function attempts to release free memory at the top of the heap (by calling sbrk(2) with a 972 // suitable argument). 973 int malloc_trim( size_t ) { 974 return 0; // => impossible to release memory 975 } // malloc_trim 976 977 // The malloc_usable_size() function returns the number of usable bytes in the block pointed to by ptr, a pointer to 978 // a block of memory allocated by malloc(3) or a related function. 979 size_t malloc_usable_size( void * addr ) { 980 if ( unlikely( addr == 0 ) ) return 0; // null allocation has 0 size 981 982 HeapManager.Storage.Header * header; 983 HeapManager.FreeHeader * freeElem; 984 size_t size, alignment; 985 986 headers( "malloc_usable_size", addr, header, freeElem, size, alignment ); 987 size_t usize = size - ( (char *)addr - (char *)header ); // compute the amount of user storage in the block 988 return usize; 989 } // malloc_usable_size 990 983 991 984 992 // The malloc_alignment() function returns the alignment of the allocation. 985 993 size_t malloc_alignment( void * addr ) { 986 if ( unlikely( addr == 0 p) ) return libAlign(); // minimum alignment994 if ( unlikely( addr == 0 ) ) return libAlign(); // minimum alignment 987 995 HeapManager.Storage.Header * header = headerAddr( addr ); 988 996 if ( (header->kind.fake.alignment & 1) == 1 ) { // fake header ? … … 996 1004 // The malloc_zero_fill() function returns true if the allocation is zero filled, i.e., initially allocated by calloc(). 997 1005 bool malloc_zero_fill( void * addr ) { 998 if ( unlikely( addr == 0 p) ) return false; // null allocation is not zero fill1006 if ( unlikely( addr == 0 ) ) return false; // null allocation is not zero fill 999 1007 HeapManager.Storage.Header * header = headerAddr( addr ); 1000 1008 if ( (header->kind.fake.alignment & 1) == 1 ) { // fake header ? … … 1005 1013 1006 1014 1007 // The malloc_usable_size() function returns the number of usable bytes in the block pointed to by ptr, a pointer to1008 // a block of memory allocated by malloc(3) or a related function.1009 size_t malloc_usable_size( void * addr ) {1010 if ( unlikely( addr == 0p ) ) return 0; // null allocation has 0 size1011 HeapManager.Storage.Header * header;1012 HeapManager.FreeHeader * freeElem;1013 size_t bsize, alignment;1014 1015 headers( "malloc_usable_size", addr, header, freeElem, bsize, alignment );1016 return dataStorage( bsize, addr, header ); // data storage in bucket1017 } // malloc_usable_size1018 1019 1020 1015 // The malloc_stats() function prints (on default standard error) statistics about memory allocated by malloc(3) and 1021 1016 // related functions. … … 1023 1018 #ifdef __STATISTICS__ 1024 1019 printStats(); 1025 if ( prtFree() ) prtFree( heapManager );1020 if ( checkFree() ) checkFree( heapManager ); 1026 1021 #endif // __STATISTICS__ 1027 1022 } // malloc_stats 1028 1023 1029 1024 // The malloc_stats_fd() function changes the file descripter where malloc_stats() writes the statistics. 1030 int malloc_stats_fd( int fd __attribute__(( unused ))) {1025 int malloc_stats_fd( int fd ) { 1031 1026 #ifdef __STATISTICS__ 1032 1027 int temp = statfd; … … 1038 1033 } // malloc_stats_fd 1039 1034 1040 1041 // The mallopt() function adjusts parameters that control the behavior of the memory-allocation functions (see1042 // malloc(3)). The param argument specifies the parameter to be modified, and value specifies the new value for that1043 // parameter.1044 int mallopt( int option, int value ) {1045 choose( option ) {1046 case M_TOP_PAD:1047 if ( setHeapExpand( value ) ) return 1;1048 case M_MMAP_THRESHOLD:1049 if ( setMmapStart( value ) ) return 1;1050 } // switch1051 return 0; // error, unsupported1052 } // mallopt1053 1054 // The malloc_trim() function attempts to release free memory at the top of the heap (by calling sbrk(2) with a1055 // suitable argument).1056 int malloc_trim( size_t ) {1057 return 0; // => impossible to release memory1058 } // malloc_trim1059 1060 1061 1035 // The malloc_info() function exports an XML string that describes the current state of the memory-allocation 1062 1036 // implementation in the caller. The string is printed on the file stream stream. The exported string includes 1063 1037 // information about all arenas (see malloc(3)). 1064 1038 int malloc_info( int options, FILE * stream ) { 1065 if ( options != 0 ) { errno = EINVAL; return -1; }1066 1039 return printStatsXML( stream ); 1067 1040 } // malloc_info … … 1073 1046 // structure is returned as the function result. (It is the caller's responsibility to free(3) this memory.) 1074 1047 void * malloc_get_state( void ) { 1075 return 0 p; // unsupported1048 return 0; // unsupported 1076 1049 } // malloc_get_state 1077 1050 … … 1085 1058 1086 1059 1087 // Must have CFA linkage to overload with C linkage realloc.1088 void * realloc( void * oaddr, size_t nalign, size_t size ) {1089 #ifdef __STATISTICS__1090 __atomic_add_fetch( &realloc_calls, 1, __ATOMIC_SEQ_CST );1091 #endif // __STATISTICS__1092 1093 if ( unlikely( size == 0 ) ) { free( oaddr ); return 0p; } // special cases1094 if ( unlikely( oaddr == 0p ) ) return mallocNoStats( size );1095 1096 if ( unlikely( nalign == 0 ) ) nalign = libAlign(); // reset alignment to minimum1097 #ifdef __CFA_DEBUG__1098 else1099 checkAlign( nalign ); // check alignment1100 #endif // __CFA_DEBUG__1101 1102 HeapManager.Storage.Header * header;1103 HeapManager.FreeHeader * freeElem;1104 size_t bsize, oalign = 0;1105 headers( "realloc", oaddr, header, freeElem, bsize, oalign );1106 1107 size_t odsize = dataStorage( bsize, oaddr, header ); // data storage available in bucket1108 1109 if ( oalign != 0 && (uintptr_t)oaddr % nalign == 0 ) { // has alignment and just happens to work out1110 headerAddr( oaddr )->kind.fake.alignment = nalign | 1; // update alignment (could be the same)1111 return realloc( oaddr, size );1112 } // if1113 1114 #ifdef __STATISTICS__1115 __atomic_add_fetch( &realloc_storage, size, __ATOMIC_SEQ_CST );1116 #endif // __STATISTICS__1117 1118 // change size and copy old content to new storage1119 1120 void * naddr;1121 if ( unlikely( header->kind.real.blockSize & 2 ) ) { // previous request zero fill1122 naddr = cmemalignNoStats( nalign, 1, size ); // create new aligned area1123 } else {1124 naddr = memalignNoStats( nalign, size ); // create new aligned area1125 } // if1126 size_t ndsize = dataStorage( bsize, naddr, header ); // data storage avilable in bucket1127 // To preserve prior fill, the entire bucket must be copied versus the size.1128 memcpy( naddr, oaddr, MIN( odsize, ndsize ) ); // copy bytes1129 free( oaddr );1130 return naddr;1131 } // realloc1132 1133 1134 1060 // Local Variables: // 1135 1061 // tab-width: 4 // -
libcfa/src/stdlib.cfa
r9aa1317 rf1397d14 10 10 // Created On : Thu Jan 28 17:10:29 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Nov 20 17:22:47201913 // Update Count : 4 8512 // Last Modified On : Tue Oct 22 08:57:52 2019 13 // Update Count : 478 14 14 // 15 15 … … 30 30 T * alloc_set( T ptr[], size_t dim, char fill ) { // realloc array with fill 31 31 size_t olen = malloc_usable_size( ptr ); // current allocation 32 void * nptr = (void*)realloc( (void *)ptr, dim * sizeof(T) ); // C realloc32 char * nptr = (char *)realloc( (void *)ptr, dim * sizeof(T) ); // C realloc 33 33 size_t nlen = malloc_usable_size( nptr ); // new allocation 34 34 if ( nlen > olen ) { // larger ? 35 memset( (char *)nptr + olen, (int)fill, nlen - olen ); // initialize added storage35 memset( nptr + olen, (int)fill, nlen - olen ); // initialize added storage 36 36 } // if 37 37 return (T *)nptr; 38 38 } // alloc_set 39 39 40 T * alloc_align( T ptr[], size_t align ) { // aligned realloc array 41 char * nptr; 42 size_t alignment = malloc_alignment( ptr ); 43 if ( align != alignment && (uintptr_t)ptr % align != 0 ) { 44 size_t olen = malloc_usable_size( ptr ); // current allocation 45 nptr = (char *)memalign( align, olen ); 46 size_t nlen = malloc_usable_size( nptr ); // new allocation 47 size_t lnth = olen < nlen ? olen : nlen; // min 48 memcpy( nptr, ptr, lnth ); // initialize storage 49 free( ptr ); 50 } else { 51 nptr = (char *)ptr; 52 } // if 53 return (T *)nptr; 54 } // alloc_align 55 56 T * alloc_align( T ptr[], size_t align, size_t dim ) { // aligned realloc array 57 char * nptr; 58 size_t alignment = malloc_alignment( ptr ); 59 if ( align != alignment ) { 60 size_t olen = malloc_usable_size( ptr ); // current allocation 61 nptr = (char *)memalign( align, dim * sizeof(T) ); 62 size_t nlen = malloc_usable_size( nptr ); // new allocation 63 size_t lnth = olen < nlen ? olen : nlen; // min 64 memcpy( nptr, ptr, lnth ); // initialize storage 65 free( ptr ); 66 } else { 67 nptr = (char *)realloc( (void *)ptr, dim * sizeof(T) ); // C realloc 68 } // if 69 return (T *)nptr; 70 } // alloc_align 71 40 72 T * alloc_align_set( T ptr[], size_t align, char fill ) { // aligned realloc with fill 41 73 size_t olen = malloc_usable_size( ptr ); // current allocation 42 void * nptr = (void *)realloc( (void *)ptr, align, sizeof(T) ); // CFA realloc 43 // char * nptr = alloc_align( ptr, align ); 74 char * nptr = alloc_align( ptr, align ); 44 75 size_t nlen = malloc_usable_size( nptr ); // new allocation 45 76 if ( nlen > olen ) { // larger ? 46 memset( (char *)nptr + olen, (int)fill, nlen - olen ); // initialize added storage77 memset( nptr + olen, (int)fill, nlen - olen ); // initialize added storage 47 78 } // if 48 79 return (T *)nptr; -
libcfa/src/stdlib.hfa
r9aa1317 rf1397d14 10 10 // Created On : Thu Jan 28 17:12:35 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Nov 22 15:13:14201913 // Update Count : 39 912 // Last Modified On : Sun Oct 20 22:57:33 2019 13 // Update Count : 390 14 14 // 15 15 … … 28 28 } // extern "C" 29 29 30 void * realloc( void * oaddr, size_t nalign, size_t size ); // CFA heap31 32 30 //--------------------------------------- 33 31 … … 52 50 } // calloc 53 51 54 T * realloc( T * ptr, size_t size ) { // CFA realloc, eliminate return-type cast 52 T * realloc( T * ptr, size_t size ) { 53 if ( unlikely( ptr == 0 ) ) return malloc(); 55 54 return (T *)(void *)realloc( (void *)ptr, size ); // C realloc 56 55 } // realloc … … 60 59 } // memalign 61 60 62 T * cmemalign( size_t align, size_t dim ) {63 return (T *)cmemalign( align, dim, sizeof(T) ); // CFA cmemalign64 } // cmemalign65 66 61 T * aligned_alloc( size_t align ) { 67 62 return (T *)aligned_alloc( align, sizeof(T) ); // C aligned_alloc … … 84 79 85 80 T * alloc( T ptr[], size_t dim ) { // realloc 86 return (T *)(void *)realloc( (void *)ptr, dim * sizeof(T) ); // C realloc81 return realloc( ptr, dim * sizeof(T) ); 87 82 } // alloc 88 83 … … 123 118 } // alloc_align 124 119 125 T * alloc_align( T ptr[], size_t align ) { // aligned realloc array126 return (T *)(void *)realloc( (void *)ptr, align, sizeof(T) ); // CFA realloc127 } // alloc_align128 129 T * alloc_align( T ptr[], size_t align, size_t dim ) { // aligned realloc array130 return (T *)(void *)realloc( (void *)ptr, align, dim * sizeof(T) ); // CFA realloc131 } // alloc_align132 133 120 T * alloc_align_set( size_t align, char fill ) { 134 121 return (T *)memset( (T *)alloc_align( align ), (int)fill, sizeof(T) ); // initialize with fill value … … 155 142 156 143 forall( dtype T | sized(T) ) { 144 T * alloc_align( T ptr[], size_t align ); // realign 145 T * alloc_align( T ptr[], size_t align, size_t dim ); // aligned realloc array 157 146 T * alloc_align_set( T ptr[], size_t align, size_t dim, char fill ); // aligned realloc array with fill 158 147 } // distribution -
tests/.expect/alloc-ERROR.txt
r9aa1317 rf1397d14 1 alloc.cfa:31 7:1 error: No reasonable alternatives for expression Applying untyped:1 alloc.cfa:311:1 error: No reasonable alternatives for expression Applying untyped: 2 2 Name: ?=? 3 3 ...to: … … 19 19 20 20 21 alloc.cfa:31 8:1 error: No reasonable alternatives for expression Applying untyped:21 alloc.cfa:312:1 error: No reasonable alternatives for expression Applying untyped: 22 22 Name: ?=? 23 23 ...to: … … 39 39 40 40 41 alloc.cfa:31 9:1 error: No reasonable alternatives for expression Applying untyped:41 alloc.cfa:313:1 error: No reasonable alternatives for expression Applying untyped: 42 42 Name: ?=? 43 43 ...to: … … 50 50 51 51 52 alloc.cfa:3 20:1 error: No reasonable alternatives for expression Applying untyped:52 alloc.cfa:314:1 error: No reasonable alternatives for expression Applying untyped: 53 53 Name: ?=? 54 54 ...to: -
tests/.expect/alloc.txt
r9aa1317 rf1397d14 30 30 CFA resize array alloc 31 31 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 32 CFA resize array alloc 32 CFA resize array alloc, fill 33 33 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 34 CFA resize array alloc 34 CFA resize array alloc, fill 35 35 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 36 36 CFA resize array alloc, fill 37 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x dededede 0xdededede 0xdededede 0xdededede0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede37 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 38 38 39 39 C memalign 42 42.5 -
tests/alloc.cfa
r9aa1317 rf1397d14 10 10 // Created On : Wed Feb 3 07:56:22 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Nov 22 15:34:19201913 // Update Count : 40412 // Last Modified On : Sun Oct 20 21:45:21 2019 13 // Update Count : 391 14 14 // 15 15 … … 126 126 127 127 p = alloc( p, 2 * dim ); // CFA resize array alloc 128 for ( i; dim ~ 2 * dim ) { p[i] = 0x1010101; } // fill upper part128 for ( i; dim ~ 2 * dim ) { p[i] = 0x1010101; } 129 129 printf( "CFA resize array alloc\n" ); 130 130 for ( i; 2 * dim ) { printf( "%#x ", p[i] ); } … … 139 139 140 140 p = alloc_set( p, 3 * dim, fill ); // CFA resize array alloc, fill 141 printf( "CFA resize array alloc \n" );141 printf( "CFA resize array alloc, fill\n" ); 142 142 for ( i; 3 * dim ) { printf( "%#x ", p[i] ); } 143 143 printf( "\n" ); … … 145 145 146 146 p = alloc_set( p, dim, fill ); // CFA resize array alloc, fill 147 printf( "CFA resize array alloc \n" );147 printf( "CFA resize array alloc, fill\n" ); 148 148 for ( i; dim ) { printf( "%#x ", p[i] ); } 149 149 printf( "\n" ); -
tests/heap.cfa
r9aa1317 rf1397d14 10 10 // Created On : Tue Nov 6 17:54:56 2018 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Nov 20 16:10:24 201913 // Update Count : 2512 // Last Modified On : Fri Jul 19 08:22:34 2019 13 // Update Count : 19 14 14 // 15 15 … … 74 74 size_t s = (i + 1) * 20; 75 75 char * area = (char *)malloc( s ); 76 if ( area == 0 p) abort( "malloc/free out of memory" );76 if ( area == 0 ) abort( "malloc/free out of memory" ); 77 77 area[0] = '\345'; area[s - 1] = '\345'; // fill first/last 78 78 area[malloc_usable_size( area ) - 1] = '\345'; // fill ultimate byte … … 83 83 size_t s = i + 1; // +1 to make initialization simpler 84 84 locns[i] = (char *)malloc( s ); 85 if ( locns[i] == 0 p) abort( "malloc/free out of memory" );85 if ( locns[i] == 0 ) abort( "malloc/free out of memory" ); 86 86 locns[i][0] = '\345'; locns[i][s - 1] = '\345'; // fill first/last 87 87 locns[i][malloc_usable_size( locns[i] ) - 1] = '\345'; // fill ultimate byte … … 99 99 size_t s = i + default_mmap_start(); // cross over point 100 100 char * area = (char *)malloc( s ); 101 if ( area == 0 p) abort( "malloc/free out of memory" );101 if ( area == 0 ) abort( "malloc/free out of memory" ); 102 102 area[0] = '\345'; area[s - 1] = '\345'; // fill first/last 103 103 area[malloc_usable_size( area ) - 1] = '\345'; // fill ultimate byte … … 108 108 size_t s = i + default_mmap_start(); // cross over point 109 109 locns[i] = (char *)malloc( s ); 110 if ( locns[i] == 0 p) abort( "malloc/free out of memory" );110 if ( locns[i] == 0 ) abort( "malloc/free out of memory" ); 111 111 locns[i][0] = '\345'; locns[i][s - 1] = '\345'; // fill first/last 112 112 locns[i][malloc_usable_size( locns[i] ) - 1] = '\345'; // fill ultimate byte … … 124 124 size_t s = (i + 1) * 20; 125 125 char * area = (char *)calloc( 5, s ); 126 if ( area == 0 p) abort( "calloc/free out of memory" );126 if ( area == 0 ) abort( "calloc/free out of memory" ); 127 127 if ( area[0] != '\0' || area[s - 1] != '\0' || 128 128 area[malloc_usable_size( area ) - 1] != '\0' || … … 136 136 size_t s = i + 1; 137 137 locns[i] = (char *)calloc( 5, s ); 138 if ( locns[i] == 0 p) abort( "calloc/free out of memory" );138 if ( locns[i] == 0 ) abort( "calloc/free out of memory" ); 139 139 if ( locns[i][0] != '\0' || locns[i][s - 1] != '\0' || 140 140 locns[i][malloc_usable_size( locns[i] ) - 1] != '\0' || … … 155 155 size_t s = i + default_mmap_start(); // cross over point 156 156 char * area = (char *)calloc( 1, s ); 157 if ( area == 0 p) abort( "calloc/free out of memory" );157 if ( area == 0 ) abort( "calloc/free out of memory" ); 158 158 if ( area[0] != '\0' || area[s - 1] != '\0' ) abort( "calloc/free corrupt storage4.1" ); 159 159 if ( area[malloc_usable_size( area ) - 1] != '\0' ) abort( "calloc/free corrupt storage4.2" ); … … 167 167 size_t s = i + default_mmap_start(); // cross over point 168 168 locns[i] = (char *)calloc( 1, s ); 169 if ( locns[i] == 0 p) abort( "calloc/free out of memory" );169 if ( locns[i] == 0 ) abort( "calloc/free out of memory" ); 170 170 if ( locns[i][0] != '\0' || locns[i][s - 1] != '\0' || 171 171 locns[i][malloc_usable_size( locns[i] ) - 1] != '\0' || … … 189 189 for ( s; 1 ~ NoOfAllocs ) { // allocation of size 0 can return null 190 190 char * area = (char *)memalign( a, s ); 191 if ( area == 0 p) abort( "memalign/free out of memory" );192 //sout | i | area;191 if ( area == 0 ) abort( "memalign/free out of memory" ); 192 //sout | i | " " | area; 193 193 if ( (size_t)area % a != 0 || malloc_alignment( area ) != a ) { // check for initial alignment 194 194 abort( "memalign/free bad alignment : memalign(%d,%d) = %p", (int)a, s, area ); 195 195 } // if 196 area[0] = '\345'; area[s - 1] = '\345'; // fill first/last byte196 area[0] = '\345'; area[s - 1] = '\345'; // fill first/last byte 197 197 area[malloc_usable_size( area ) - 1] = '\345'; // fill ultimate byte 198 198 free( area ); … … 207 207 size_t s = i + default_mmap_start(); // cross over point 208 208 char * area = (char *)memalign( a, s ); 209 if ( area == 0 p) abort( "memalign/free out of memory" );210 //sout | i | area;209 if ( area == 0 ) abort( "memalign/free out of memory" ); 210 //sout | i | " " | area; 211 211 if ( (size_t)area % a != 0 || malloc_alignment( area ) != a ) { // check for initial alignment 212 212 abort( "memalign/free bad alignment : memalign(%d,%d) = %p", (int)a, (int)s, area ); … … 223 223 // initial N byte allocation 224 224 char * area = (char *)calloc( 5, i ); 225 if ( area == 0 p) abort( "calloc/realloc/free out of memory" );225 if ( area == 0 ) abort( "calloc/realloc/free out of memory" ); 226 226 if ( area[0] != '\0' || area[i - 1] != '\0' || 227 227 area[malloc_usable_size( area ) - 1] != '\0' || … … 231 231 for ( s; i ~ 256 * 1024 ~ 26 ) { // start at initial memory request 232 232 area = (char *)realloc( area, s ); // attempt to reuse storage 233 if ( area == 0 p) abort( "calloc/realloc/free out of memory" );233 if ( area == 0 ) abort( "calloc/realloc/free out of memory" ); 234 234 if ( area[0] != '\0' || area[s - 1] != '\0' || 235 235 area[malloc_usable_size( area ) - 1] != '\0' || … … 245 245 size_t s = i + default_mmap_start(); // cross over point 246 246 char * area = (char *)calloc( 1, s ); 247 if ( area == 0 p) abort( "calloc/realloc/free out of memory" );247 if ( area == 0 ) abort( "calloc/realloc/free out of memory" ); 248 248 if ( area[0] != '\0' || area[s - 1] != '\0' || 249 249 area[malloc_usable_size( area ) - 1] != '\0' || … … 253 253 for ( r; i ~ 256 * 1024 ~ 26 ) { // start at initial memory request 254 254 area = (char *)realloc( area, r ); // attempt to reuse storage 255 if ( area == 0 p) abort( "calloc/realloc/free out of memory" );255 if ( area == 0 ) abort( "calloc/realloc/free out of memory" ); 256 256 if ( area[0] != '\0' || area[r - 1] != '\0' || 257 257 area[malloc_usable_size( area ) - 1] != '\0' || … … 267 267 // initial N byte allocation 268 268 char * area = (char *)memalign( a, amount ); // aligned N-byte allocation 269 if ( area == 0 p) abort( "memalign/realloc/free out of memory" ); // no storage ?270 //sout | alignments[a] | area;269 if ( area == 0 ) abort( "memalign/realloc/free out of memory" ); // no storage ? 270 //sout | alignments[a] | " " | area; 271 271 if ( (size_t)area % a != 0 || malloc_alignment( area ) != a ) { // check for initial alignment 272 272 abort( "memalign/realloc/free bad alignment : memalign(%d,%d) = %p", (int)a, (int)amount, area ); … … 278 278 if ( area[0] != '\345' || area[s - 2] != '\345' ) abort( "memalign/realloc/free corrupt storage" ); 279 279 area = (char *)realloc( area, s ); // attempt to reuse storage 280 if ( area == 0 p) abort( "memalign/realloc/free out of memory" ); // no storage ?281 //sout | i | area;280 if ( area == 0 ) abort( "memalign/realloc/free out of memory" ); // no storage ? 281 //sout | i | " " | area; 282 282 if ( (size_t)area % a != 0 ) { // check for initial alignment 283 283 abort( "memalign/realloc/free bad alignment %p", area ); … … 294 294 for ( s; 1 ~ limit ) { // allocation of size 0 can return null 295 295 char * area = (char *)cmemalign( a, 1, s ); 296 if ( area == 0 p) abort( "cmemalign/free out of memory" );297 //sout | i | area;296 if ( area == 0 ) abort( "cmemalign/free out of memory" ); 297 //sout | i | " " | area; 298 298 if ( (size_t)area % a != 0 || malloc_alignment( area ) != a ) { // check for initial alignment 299 299 abort( "cmemalign/free bad alignment : cmemalign(%d,%d) = %p", (int)a, s, area ); … … 313 313 // initial N byte allocation 314 314 char * area = (char *)cmemalign( a, 1, amount ); // aligned N-byte allocation 315 if ( area == 0 p) abort( "cmemalign/realloc/free out of memory" ); // no storage ?316 //sout | alignments[a] | area;315 if ( area == 0 ) abort( "cmemalign/realloc/free out of memory" ); // no storage ? 316 //sout | alignments[a] | " " | area; 317 317 if ( (size_t)area % a != 0 || malloc_alignment( area ) != a ) { // check for initial alignment 318 318 abort( "cmemalign/realloc/free bad alignment : cmemalign(%d,%d) = %p", (int)a, (int)amount, area ); … … 327 327 if ( area[0] != '\345' || area[s - 2] != '\345' ) abort( "cmemalign/realloc/free corrupt storage2" ); 328 328 area = (char *)realloc( area, s ); // attempt to reuse storage 329 if ( area == 0 p) abort( "cmemalign/realloc/free out of memory" ); // no storage ?330 //sout | i | area;329 if ( area == 0 ) abort( "cmemalign/realloc/free out of memory" ); // no storage ? 330 //sout | i | " " | area; 331 331 if ( (size_t)area % a != 0 || malloc_alignment( area ) != a ) { // check for initial alignment 332 332 abort( "cmemalign/realloc/free bad alignment %p", area ); 333 } // if334 if ( area[s - 1] != '\0' || area[s - 1] != '\0' ||335 area[malloc_usable_size( area ) - 1] != '\0' ||336 ! malloc_zero_fill( area ) ) abort( "cmemalign/realloc/free corrupt storage3" );337 area[s - 1] = '\345'; // fill last byte338 } // for339 free( area );340 } // for341 342 // check memalign/realloc with align/free343 344 amount = 2;345 for ( a; libAlign() ~= limit ~ a ) { // generate powers of 2346 // initial N byte allocation347 char * area = (char *)memalign( a, amount ); // aligned N-byte allocation348 if ( area == 0p ) abort( "memalign/realloc with align/free out of memory" ); // no storage ?349 //sout | alignments[a] | area | endl;350 if ( (size_t)area % a != 0 || malloc_alignment( area ) != a ) { // check for initial alignment351 abort( "memalign/realloc with align/free bad alignment : memalign(%d,%d) = %p", (int)a, (int)amount, area );352 } // if353 area[0] = '\345'; area[amount - 2] = '\345'; // fill first/penultimate byte354 355 // Do not start this loop index at 0 because realloc of 0 bytes frees the storage.356 for ( s; amount ~ 256 * 1024 ) { // start at initial memory request357 if ( area[0] != '\345' || area[s - 2] != '\345' ) abort( "memalign/realloc/free corrupt storage" );358 area = (char *)realloc( area, a * 2, s ); // attempt to reuse storage359 if ( area == 0p ) abort( "memalign/realloc with align/free out of memory" ); // no storage ?360 //sout | i | area | endl;361 if ( (size_t)area % a * 2 != 0 ) { // check for initial alignment362 abort( "memalign/realloc with align/free bad alignment %p", area );363 } // if364 area[s - 1] = '\345'; // fill last byte365 } // for366 free( area );367 } // for368 369 // check cmemalign/realloc with align/free370 371 amount = 2;372 for ( size_t a = libAlign() + libAlign(); a <= limit; a += a ) { // generate powers of 2373 // initial N byte allocation374 char *area = (char *)cmemalign( a, 1, amount ); // aligned N-byte allocation375 if ( area == 0p ) abort( "cmemalign/realloc with align/free out of memory" ); // no storage ?376 //sout | alignments[a] | area | endl;377 if ( (size_t)area % a != 0 || malloc_alignment( area ) != a ) { // check for initial alignment378 abort( "cmemalign/realloc with align/free bad alignment : cmemalign(%d,%d) = %p", (int)a, (int)amount, area );379 } // if380 if ( area[0] != '\0' || area[amount - 1] != '\0' ||381 area[malloc_usable_size( area ) - 1] != '\0' ||382 ! malloc_zero_fill( area ) ) abort( "cmemalign/realloc with align/free corrupt storage1" );383 area[0] = '\345'; area[amount - 2] = '\345'; // fill first/penultimate byte384 385 // Do not start this loop index at 0 because realloc of 0 bytes frees the storage.386 for ( int s = amount; s < 256 * 1024; s += 1 ) { // start at initial memory request387 if ( area[0] != '\345' || area[s - 2] != '\345' ) abort( "cmemalign/realloc with align/free corrupt storage2" );388 area = (char *)realloc( area, a * 2, s ); // attempt to reuse storage389 if ( area == 0p ) abort( "cmemalign/realloc with align/free out of memory" ); // no storage ?390 //sout | i | area | endl;391 if ( (size_t)area % a * 2 != 0 || malloc_alignment( area ) != a * 2 ) { // check for initial alignment392 abort( "cmemalign/realloc with align/free bad alignment %p %jd %jd", area, malloc_alignment( area ), a * 2 );393 333 } // if 394 334 if ( area[s - 1] != '\0' || area[s - 1] != '\0' ||
Note:
See TracChangeset
for help on using the changeset viewer.