1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1985-2012 AT&T Intellectual Property * 5 * and is licensed under the * 6 * Eclipse Public License, Version 1.0 * 7 * by AT&T Intellectual Property * 8 * * 9 * A copy of the License is available at * 10 * http://www.eclipse.org/org/documents/epl-v10.html * 11 * (with md5 checksum b35adb5213ca9657e911e9befb180842) * 12 * * 13 * Information and Software Systems Research * 14 * AT&T Research * 15 * Florham Park NJ * 16 * * 17 * Glenn Fowler <gsf@research.att.com> * 18 * David Korn <dgk@research.att.com> * 19 * Phong Vo <kpv@research.att.com> * 20 * * 21 ***********************************************************************/ 22 #if defined(_UWIN) && defined(_BLD_ast) 23 24 void _STUB_malloc(){} 25 26 #else 27 28 #if _UWIN 29 30 #define calloc ______calloc 31 #define _ast_free ______free 32 #define malloc ______malloc 33 #define mallinfo ______mallinfo 34 #define mallopt ______mallopt 35 #define mstats ______mstats 36 #define realloc ______realloc 37 38 #define _STDLIB_H_ 1 39 40 extern int atexit(void(*)(void)); 41 extern char* getenv(const char*); 42 43 #endif 44 45 #include "vmhdr.h" 46 #include <errno.h> 47 48 #if _UWIN 49 50 #include <malloc.h> 51 52 #define _map_malloc 1 53 #define _mal_alloca 1 54 55 #undef calloc 56 #define calloc _ast_calloc 57 #undef _ast_free 58 #define free _ast_free 59 #undef malloc 60 #define malloc _ast_malloc 61 #undef mallinfo 62 typedef struct ______mallinfo Mallinfo_t; 63 #undef mallopt 64 #undef mstats 65 typedef struct ______mstats Mstats_t; 66 #undef realloc 67 #define realloc _ast_realloc 68 69 #endif 70 71 #if __STD_C 72 #define F0(f,t0) f(t0) 73 #define F1(f,t1,a1) f(t1 a1) 74 #define F2(f,t1,a1,t2,a2) f(t1 a1, t2 a2) 75 #else 76 #define F0(f,t0) f() 77 #define F1(f,t1,a1) f(a1) t1 a1; 78 #define F2(f,t1,a1,t2,a2) f(a1, a2) t1 a1; t2 a2; 79 #endif 80 81 /* 82 * define _AST_std_malloc=1 to force the standard malloc 83 * if _map_malloc is also defined then _ast_malloc etc. 84 * will simply call malloc etc. 85 */ 86 87 #if !defined(_AST_std_malloc) && __CYGWIN__ 88 #define _AST_std_malloc 1 89 #endif 90 91 /* malloc compatibility functions 92 ** 93 ** These are aware of debugging/profiling and are driven by the 94 ** VMALLOC_OPTIONS environment variable which is a comma or space 95 ** separated list of [no]name[=value] options: 96 ** 97 ** abort if Vmregion==Vmdebug then VM_DBABORT is set, 98 ** otherwise _BLD_DEBUG enabled assertions abort() 99 ** on failure 100 ** break try sbrk() block allocator first 101 ** check if Vmregion==Vmbest then the region is checked every op 102 ** free disable addfreelist() 103 ** keep disable free -- if code works with this enabled then it 104 ** probably accesses free'd data 105 ** method=m sets Vmregion=m if not defined, m (Vm prefix optional) 106 ** may be one of { best debug last profile } 107 ** mmap try mmap() block allocator first 108 ** period=n sets Vmregion=Vmdebug if not defined, if 109 ** Vmregion==Vmdebug the region is checked every n ops 110 ** profile=f sets Vmregion=Vmprofile if not set, if 111 ** Vmregion==Vmprofile then profile info printed to file f 112 ** start=n sets Vmregion=Vmdebug if not defined, if 113 ** Vmregion==Vmdebug region checking starts after n ops 114 ** trace=f enables tracing to file f 115 ** warn=f sets Vmregion=Vmdebug if not defined, if 116 ** Vmregion==Vmdebug then warnings printed to file f 117 ** watch=a sets Vmregion=Vmdebug if not defined, if 118 ** Vmregion==Vmdebug then address a is watched 119 ** 120 ** Output files are created if they don't exist. &n and /dev/fd/n name 121 ** the file descriptor n which must be open for writing. The pattern %p 122 ** in a file name is replaced by the process ID. 123 ** 124 ** VMALLOC_OPTIONS combines the features of these previously used env vars: 125 ** { VMCHECK VMDEBUG VMETHOD VMPROFILE VMTRACE } 126 ** 127 ** Written by Kiem-Phong Vo, kpv@research.att.com, 01/16/94. 128 */ 129 130 #if _sys_stat 131 #include <sys/stat.h> 132 #endif 133 #include <fcntl.h> 134 135 #ifdef S_IRUSR 136 #define CREAT_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) 137 #else 138 #define CREAT_MODE 0644 139 #endif 140 141 static Vmulong_t _Vmdbstart = 0; 142 static Vmulong_t _Vmdbcheck = 0; 143 static Vmulong_t _Vmdbtime = 0; 144 static int _Vmpffd = -1; 145 146 #if ( !_std_malloc || !_BLD_ast ) && !_AST_std_malloc 147 148 #if !_map_malloc 149 #undef calloc 150 #undef cfree 151 #undef free 152 #undef mallinfo 153 #undef malloc 154 #undef mallopt 155 #undef memalign 156 #undef mstats 157 #undef realloc 158 #undef valloc 159 160 #if _malloc_hook 161 162 #include <malloc.h> 163 164 #undef calloc 165 #undef cfree 166 #undef free 167 #undef malloc 168 #undef memalign 169 #undef realloc 170 171 #define calloc _ast_calloc 172 #define cfree _ast_cfree 173 #define free _ast_free 174 #define malloc _ast_malloc 175 #define memalign _ast_memalign 176 #define realloc _ast_realloc 177 178 #endif 179 180 #endif 181 182 #if _WINIX 183 184 #include <ast_windows.h> 185 186 #if _UWIN 187 188 #define VMRECORD(p) _vmrecord(p) 189 #define VMBLOCK { int _vmblock = _sigblock(); 190 #define VMUNBLOCK _sigunblock(_vmblock); } 191 192 extern int _sigblock(void); 193 extern void _sigunblock(int); 194 extern unsigned long _record[2048]; 195 196 __inline Void_t* _vmrecord(Void_t* p) 197 { 198 register unsigned long v = ((unsigned long)p)>>16; 199 200 _record[v>>5] |= 1<<((v&0x1f)); 201 return p; 202 } 203 204 #else 205 206 #define getenv(s) lcl_getenv(s) 207 208 static char* 209 lcl_getenv(const char* s) 210 { 211 int n; 212 static char buf[512]; 213 214 if (!(n = GetEnvironmentVariable(s, buf, sizeof(buf))) || n > sizeof(buf)) 215 return 0; 216 return buf; 217 } 218 219 #endif /* _UWIN */ 220 221 #endif /* _WINIX */ 222 223 #ifndef VMRECORD 224 #define VMRECORD(p) (p) 225 #define VMBLOCK 226 #define VMUNBLOCK 227 #endif 228 229 #if defined(__EXPORT__) 230 #define extern extern __EXPORT__ 231 #endif 232 233 static int _Vmflinit = 0; 234 #define VMFLINIT() \ 235 { if(!_Vmflinit) vmflinit(); \ 236 if(_Vmdbcheck) \ 237 { if(_Vmdbtime < _Vmdbstart) _Vmdbtime += 1; \ 238 else if((_Vmdbtime += 1) < _Vmdbstart) _Vmdbtime = _Vmdbstart; \ 239 if(_Vmdbtime >= _Vmdbstart && (_Vmdbtime % _Vmdbcheck) == 0 && \ 240 Vmregion->meth.meth == VM_MTDEBUG) \ 241 vmdbcheck(Vmregion); \ 242 } \ 243 } 244 245 #if __STD_C 246 static int vmflinit(void) 247 #else 248 static int vmflinit() 249 #endif 250 { 251 char* file; 252 int line; 253 Void_t* func; 254 255 /* this must be done now to avoid any inadvertent recursion (more below) */ 256 _Vmflinit = 1; 257 VMFLF(Vmregion,file,line,func); 258 259 /* if getenv() calls malloc(), the options may not affect the eventual region */ 260 VMOPTIONS(); 261 262 /* reset file and line number to correct values for the call */ 263 Vmregion->file = file; 264 Vmregion->line = line; 265 Vmregion->func = func; 266 267 return 0; 268 } 269 270 /* use multiple regions to reduce blocking by concurrent threads */ 271 #if _mem_mmap_anon || _mem_mmap_zero 272 static Vmalloc_t *Region[64]; /* list of concurrent regions */ 273 static unsigned int Regmax = 64; /* max number of regions */ 274 #else 275 static Vmalloc_t* Region[1]; /* list of concurrent regions */ 276 static unsigned int Regmax = 0; 277 #endif 278 static unsigned int Regnum = 0; /* current #concurrent regions */ 279 280 /* statistics */ 281 static unsigned int Regopen = 0; /* #allocation calls opened */ 282 static unsigned int Reglock = 0; /* #allocation calls locked */ 283 static unsigned int Regprobe = 0; /* #probes to find a region */ 284 285 int setregmax(int regmax) 286 { 287 int oldmax = Regmax; 288 289 if(regmax >= Regnum && regmax <= sizeof(Region)/sizeof(Region[0])) 290 Regmax = regmax; 291 292 return oldmax; 293 } 294 295 /* return statistics */ 296 int _mallocstat(Vmstat_t* st) 297 { 298 Vmstat_t vmst; 299 int k; 300 301 if(vmstat(Vmregion, st) < 0) /* add up all stats */ 302 return -1; 303 for(k = 0; k < Regnum; ++k) 304 { if(!Region[k]) 305 continue; 306 if(vmstat(Region[k], &vmst) < 0 ) 307 return -1; 308 st->n_busy += vmst.n_busy; 309 st->n_free += vmst.n_free; 310 st->s_busy += vmst.s_busy; 311 st->s_free += vmst.s_free; 312 st->m_busy += vmst.m_busy; 313 st->m_free += vmst.m_free; 314 st->n_seg += vmst.n_seg; 315 st->extent += vmst.extent; 316 } 317 318 st->n_region = Regnum+1; 319 st->n_open = Regopen; 320 st->n_lock = Reglock; 321 st->n_probe = Regprobe; 322 323 return 0; 324 } 325 326 /* find the region that a block was allocated from */ 327 static Vmalloc_t* regionof(Void_t* addr) 328 { 329 int k; 330 331 #if USE_NATIVE 332 #define CAUTIOUS 1 333 #else 334 #define CAUTIOUS 0 335 #endif 336 if(CAUTIOUS || Vmregion->meth.meth != VM_MTBEST ) 337 { /* addr will not be dereferenced here */ 338 if(vmaddr(Vmregion,addr) == 0 ) 339 return Vmregion; 340 for(k = 0; k < Regnum; ++k) 341 if(Region[k] && vmaddr(Region[k], addr) == 0 ) 342 return Region[k]; 343 return NIL(Vmalloc_t*); 344 } 345 else 346 { /* fast, but susceptible to bad data */ 347 Vmdata_t *vd = SEG(BLOCK(addr))->vmdt; 348 if(Vmregion->data == vd ) 349 return Vmregion; 350 for(k = 0; k < Regnum; ++k) 351 if(Region[k] && Region[k]->data == vd) 352 return Region[k]; 353 return NIL(Vmalloc_t*); 354 } 355 } 356 357 /* manage a cache of free objects */ 358 typedef struct _regfree_s 359 { struct _regfree_s* next; 360 } Regfree_t; 361 static Regfree_t *Regfree; 362 363 static void addfreelist(Regfree_t* data) 364 { 365 unsigned int k; 366 Regfree_t *head; 367 368 for(k = 0;; ASOLOOP(k) ) 369 { data->next = head = Regfree; 370 if(asocasptr(&Regfree, head, data) == (Void_t*)head ) 371 return; 372 } 373 } 374 375 static void clrfreelist() 376 { 377 Regfree_t *list, *next; 378 Vmalloc_t *vm; 379 380 if(!(list = Regfree) ) 381 return; /* nothing to do */ 382 383 if(asocasptr(&Regfree, list, NIL(Regfree_t*)) != list ) 384 return; /* somebody else is doing it */ 385 386 for(; list; list = next) 387 { next = list->next; 388 if(vm = regionof((Void_t*)list)) 389 { if(asocasint(&vm->data->lock, 0, 1) == 0) /* can free this now */ 390 { (void)(*vm->meth.freef)(vm, (Void_t*)list, 1); 391 vm->data->lock = 0; 392 } 393 else addfreelist(list); /* ah well, back in the queue */ 394 } 395 } 396 } 397 398 /* get a suitable region to allocate from */ 399 typedef struct _regdisc_s 400 { Vmdisc_t disc; 401 char slop[64]; /* to absorb any extra data in Vmdcsystem */ 402 } Regdisc_t; 403 404 static int regexcept(Vmalloc_t* vm, int type, Void_t* data, Vmdisc_t* disc) 405 { 406 if(type == VM_OPEN) 407 { if(data) /* make vmopen allocate all memory using discipline */ 408 *(Void_t**)data = data; /* just make it non-NULL */ 409 return 0; 410 } 411 return 0; 412 } 413 414 static Vmalloc_t* getregion(int* local) 415 { 416 Vmalloc_t *vm; 417 int p, pos; 418 419 static unsigned int Rand = 0xdeadbeef; /* a cheap prng */ 420 #define RAND() (Rand = Rand*16777617 + 3) 421 422 clrfreelist(); 423 424 if(Regmax <= 0 ) 425 { /* uni-process/thread */ 426 *local = 1; 427 Vmregion->data->lock = 1; 428 return Vmregion; 429 } 430 else if(asocasint(&Vmregion->data->lock, 0, 1) == 0 ) 431 { /* Vmregion is open, so use it */ 432 *local = 1; 433 asoincint(&Regopen); 434 return Vmregion; 435 } 436 437 asoincint(&Regprobe); /* probe Region[] to find an open region */ 438 if(Regnum == 0) 439 pos = 0; 440 else for(pos = p = RAND()%Regnum;; ) 441 { if(Region[p] && asocasint(&Region[p]->data->lock, 0, 1) == 0 ) 442 { *local = 1; 443 asoincint(&Regopen); 444 return Region[p]; 445 } 446 if((p = (p+1)%Regnum) == pos ) 447 break; 448 } 449 450 /* grab the next open slot for a new region */ 451 while((p = Regnum) < Regmax) 452 if(asocasint(&Regnum, p, p+1) == p ) 453 break; 454 if(p < Regmax) /* this slot is now ours */ 455 { static Regdisc_t Regdisc; 456 if(!Regdisc.disc.exceptf) /* one time initialization */ 457 { GETPAGESIZE(_Vmpagesize); 458 memcpy(&Regdisc, Vmdcsystem, Vmdcsystem->size); 459 Regdisc.disc.round = ROUND(_Vmpagesize, 64*1024); 460 Regdisc.disc.exceptf = regexcept; 461 } 462 463 /**/ASSERT(Region[p] == NIL(Vmalloc_t*)); 464 if((vm = vmopen(&Regdisc.disc, Vmbest, VM_SHARE)) != NIL(Vmalloc_t*) ) 465 { vm->data->lock = 1; /* lock new region now */ 466 *local = 1; 467 asoincint(&Regopen); 468 return (Region[p] = vm); 469 } 470 else Region[p] = Vmregion; /* better than nothing */ 471 } 472 473 /* must return something */ 474 vm = Region[pos] ? Region[pos] : Vmregion; 475 if(asocasint(&vm->data->lock, 0, 1) == 0) 476 { *local = 1; 477 asoincint(&Regopen); 478 } 479 else 480 { *local = 0; 481 asoincint(&Reglock); 482 } 483 return vm; 484 } 485 486 #if __STD_C 487 extern Void_t* calloc(reg size_t n_obj, reg size_t s_obj) 488 #else 489 extern Void_t* calloc(n_obj, s_obj) 490 reg size_t n_obj; 491 reg size_t s_obj; 492 #endif 493 { 494 Void_t *addr; 495 Vmalloc_t *vm; 496 int local = 0; 497 VMFLINIT(); 498 499 vm = getregion(&local); 500 addr = (*vm->meth.resizef)(vm, NIL(Void_t*), n_obj*s_obj, VM_RSZERO, local); 501 if(local) 502 { /**/ASSERT(vm->data->lock == 1); 503 vm->data->lock = 0; 504 } 505 return VMRECORD(addr); 506 } 507 508 #if __STD_C 509 extern Void_t* malloc(reg size_t size) 510 #else 511 extern Void_t* malloc(size) 512 reg size_t size; 513 #endif 514 { 515 Void_t *addr; 516 Vmalloc_t *vm; 517 int local = 0; 518 VMFLINIT(); 519 520 vm = getregion(&local); 521 addr = (*vm->meth.allocf)(vm, size, local); 522 if(local) 523 { /**/ASSERT(vm->data->lock == 1); 524 vm->data->lock = 0; 525 } 526 return VMRECORD(addr); 527 } 528 529 #if __STD_C 530 extern Void_t* realloc(reg Void_t* data, reg size_t size) 531 #else 532 extern Void_t* realloc(data,size) 533 reg Void_t* data; /* block to be reallocated */ 534 reg size_t size; /* new size */ 535 #endif 536 { 537 ssize_t copy; 538 Void_t *addr; 539 Vmalloc_t *vm; 540 VMFLINIT(); 541 542 if(!data) 543 return malloc(size); 544 else if((vm = regionof(data)) ) 545 { if(vm == Vmregion && vm != Vmheap) /* no multiple region usage here */ 546 { addr = (*vm->meth.resizef)(vm, data, size, VM_RSCOPY|VM_RSMOVE, 0); 547 return VMRECORD(addr); 548 } 549 if(asocasint(&vm->data->lock, 0, 1) == 0 ) /* region is open */ 550 { addr = (*vm->meth.resizef)(vm, data, size, VM_RSCOPY|VM_RSMOVE, 1); 551 vm->data->lock = 0; 552 return VMRECORD(addr); 553 } 554 else if(Regmax > 0 && Vmregion == Vmheap && (addr = malloc(size)) ) 555 { if((copy = SIZE(BLOCK(data))&~BITS) > size ) 556 copy = size; 557 memcpy(addr, data, copy); 558 addfreelist((Regfree_t*)data); 559 return VMRECORD(addr); 560 } 561 else /* this may block but it is the best that we can do now */ 562 { addr = (*vm->meth.resizef)(vm, data, size, VM_RSCOPY|VM_RSMOVE, 0); 563 return VMRECORD(addr); 564 } 565 } 566 else /* not our data */ 567 { 568 #if USE_NATIVE 569 #undef realloc /* let the native realloc() take care of it */ 570 #if __STD_C 571 extern Void_t* realloc(Void_t*, size_t); 572 #else 573 extern Void_t* realloc(); 574 #endif 575 return realloc(data, size); 576 #else 577 return NIL(Void_t*); 578 #endif 579 } 580 } 581 582 #if __STD_C 583 extern void free(reg Void_t* data) 584 #else 585 extern void free(data) 586 reg Void_t* data; 587 #endif 588 { 589 Vmalloc_t *vm; 590 VMFLINIT(); 591 592 if(!data || (_Vmassert & VM_keep)) 593 return; 594 else if((vm = regionof(data)) ) 595 { 596 if(vm == Vmregion && Vmregion != Vmheap || (_Vmassert & VM_free)) 597 (void)(*vm->meth.freef)(vm, data, 0); 598 else addfreelist((Regfree_t*)data); 599 return; 600 } 601 else /* not our data */ 602 { 603 #if USE_NATIVE 604 #undef free /* let the native free() take care of it */ 605 #if __STD_C 606 extern void free(Void_t*); 607 #else 608 extern void free(); 609 #endif 610 free(data); 611 #endif 612 return; 613 } 614 } 615 616 #if __STD_C 617 extern void cfree(reg Void_t* data) 618 #else 619 extern void cfree(data) 620 reg Void_t* data; 621 #endif 622 { 623 free(data); 624 } 625 626 #if __STD_C 627 extern Void_t* memalign(reg size_t align, reg size_t size) 628 #else 629 extern Void_t* memalign(align, size) 630 reg size_t align; 631 reg size_t size; 632 #endif 633 { 634 Void_t *addr; 635 Vmalloc_t *vm; 636 int local = 0; 637 VMFLINIT(); 638 639 vm = getregion(&local); 640 VMBLOCK 641 addr = (*vm->meth.alignf)(vm, size, align, local); 642 if(local) 643 { /**/ASSERT(vm->data->lock == 1); 644 vm->data->lock = 0; 645 } 646 VMUNBLOCK 647 return VMRECORD(addr); 648 } 649 650 #if __STD_C 651 extern int posix_memalign(reg Void_t **memptr, reg size_t align, reg size_t size) 652 #else 653 extern int posix_memalign(memptr, align, size) 654 reg Void_t** memptr; 655 reg size_t align; 656 reg size_t size; 657 #endif 658 { 659 Void_t *mem; 660 661 if(align == 0 || (align%sizeof(Void_t*)) != 0 || ((align-1)&align) != 0 ) 662 return EINVAL; 663 664 if(!(mem = memalign(align, size)) ) 665 return ENOMEM; 666 667 *memptr = mem; 668 return 0; 669 } 670 671 #if __STD_C 672 extern Void_t* valloc(reg size_t size) 673 #else 674 extern Void_t* valloc(size) 675 reg size_t size; 676 #endif 677 { 678 VMFLINIT(); 679 680 GETPAGESIZE(_Vmpagesize); 681 return VMRECORD(memalign(_Vmpagesize, size)); 682 } 683 684 #if __STD_C 685 extern Void_t* pvalloc(reg size_t size) 686 #else 687 extern Void_t* pvalloc(size) 688 reg size_t size; 689 #endif 690 { 691 VMFLINIT(); 692 693 GETPAGESIZE(_Vmpagesize); 694 return VMRECORD(memalign(_Vmpagesize, ROUND(size,_Vmpagesize)) ); 695 } 696 697 #if !_PACKAGE_ast 698 #if __STD_C 699 char* strdup(const char* s) 700 #else 701 char* strdup(s) 702 char* s; 703 #endif 704 { 705 char *ns; 706 size_t n; 707 708 if(!s) 709 return NIL(char*); 710 else 711 { n = strlen(s); 712 if((ns = malloc(n+1)) ) 713 memcpy(ns,s,n+1); 714 return ns; 715 } 716 } 717 #endif /* _PACKAGE_ast */ 718 719 #if !_lib_alloca || _mal_alloca 720 #ifndef _stk_down 721 #define _stk_down 0 722 #endif 723 typedef struct _alloca_s Alloca_t; 724 union _alloca_u 725 { struct 726 { char* addr; 727 Alloca_t* next; 728 } head; 729 char array[ALIGN]; 730 }; 731 struct _alloca_s 732 { union _alloca_u head; 733 Vmuchar_t data[1]; 734 }; 735 736 #if __STD_C 737 extern Void_t* alloca(size_t size) 738 #else 739 extern Void_t* alloca(size) 740 size_t size; 741 #endif 742 { char array[ALIGN]; 743 char* file; 744 int line; 745 Void_t* func; 746 Alloca_t* f; 747 Vmalloc_t *vm; 748 static Alloca_t* Frame; 749 750 VMFLINIT(); 751 752 VMFLF(Vmregion,file,line,func); /* save info before freeing frames */ 753 754 while(Frame) /* free unused frames */ 755 { if(( _stk_down && &array[0] > Frame->head.head.addr) || 756 (!_stk_down && &array[0] < Frame->head.head.addr) ) 757 { f = Frame; Frame = f->head.head.next; 758 if((vm = regionof(f)) ) 759 (void)(*vm->meth.freef)(vm, f, 0); 760 /* else: something bad happened. just keep going */ 761 } 762 else break; 763 } 764 765 Vmregion->file = file; /* restore file/line info before allocation */ 766 Vmregion->line = line; 767 Vmregion->func = func; 768 769 f = (Alloca_t*)(*Vmregion->meth.allocf)(Vmregion, size+sizeof(Alloca_t)-1, 0); 770 771 /* if f is NULL, this mimics a stack overflow with a memory error! */ 772 f->head.head.addr = &array[0]; 773 f->head.head.next = Frame; 774 Frame = f; 775 776 return (Void_t*)f->data; 777 } 778 #endif /*!_lib_alloca || _mal_alloca*/ 779 780 #if _map_malloc 781 782 /* not sure of all the implications -- 0 is conservative for now */ 783 #define USE_NATIVE 0 /* native free/realloc on non-vmalloc ptrs */ 784 785 #else 786 787 #if _malloc_hook 788 789 static void vm_free_hook(void* ptr, const void* caller) 790 { 791 free(ptr); 792 } 793 794 static void* vm_malloc_hook(size_t size, const void* caller) 795 { 796 void* r; 797 798 r = malloc(size); 799 return r; 800 } 801 802 static void* vm_memalign_hook(size_t align, size_t size, const void* caller) 803 { 804 void* r; 805 806 r = memalign(align, size); 807 return r; 808 } 809 810 static void* vm_realloc_hook(void* ptr, size_t size, const void* caller) 811 { 812 void* r; 813 814 r = realloc(ptr, size); 815 return r; 816 } 817 818 static void vm_initialize_hook(void) 819 { 820 __free_hook = vm_free_hook; 821 __malloc_hook = vm_malloc_hook; 822 __memalign_hook = vm_memalign_hook; 823 __realloc_hook = vm_realloc_hook; 824 } 825 826 void (*__malloc_initialize_hook)(void) = vm_initialize_hook; 827 828 #if 0 /* 2012-02-29 this may be needed to cover shared libs */ 829 830 void __attribute__ ((constructor)) vm_initialize_initialize_hook(void) 831 { 832 vm_initialize_hook(); 833 __malloc_initialize_hook = vm_initialize_hook; 834 } 835 836 #endif 837 838 #else 839 840 /* intercept _* __* __libc_* variants */ 841 842 #if __lib__malloc 843 extern Void_t* F2(_calloc, size_t,n, size_t,m) { return calloc(n, m); } 844 extern Void_t F1(_cfree, Void_t*,p) { free(p); } 845 extern Void_t F1(_free, Void_t*,p) { free(p); } 846 extern Void_t* F1(_malloc, size_t,n) { return malloc(n); } 847 #if _lib_memalign 848 extern Void_t* F2(_memalign, size_t,a, size_t,n) { return memalign(a, n); } 849 #endif 850 #if _lib_pvalloc 851 extern Void_t* F1(_pvalloc, size_t,n) { return pvalloc(n); } 852 #endif 853 extern Void_t* F2(_realloc, Void_t*,p, size_t,n) { return realloc(p, n); } 854 #if _lib_valloc 855 extern Void_t* F1(_valloc, size_t,n) { return valloc(n); } 856 #endif 857 #endif 858 859 #if _lib___malloc 860 extern Void_t* F2(__calloc, size_t,n, size_t,m) { return calloc(n, m); } 861 extern Void_t F1(__cfree, Void_t*,p) { free(p); } 862 extern Void_t F1(__free, Void_t*,p) { free(p); } 863 extern Void_t* F1(__malloc, size_t,n) { return malloc(n); } 864 #if _lib_memalign 865 extern Void_t* F2(__memalign, size_t,a, size_t,n) { return memalign(a, n); } 866 #endif 867 #if _lib_pvalloc 868 extern Void_t* F1(__pvalloc, size_t,n) { return pvalloc(n); } 869 #endif 870 extern Void_t* F2(__realloc, Void_t*,p, size_t,n) { return realloc(p, n); } 871 #if _lib_valloc 872 extern Void_t* F1(__valloc, size_t,n) { return valloc(n); } 873 #endif 874 #endif 875 876 #if _lib___libc_malloc 877 extern Void_t* F2(__libc_calloc, size_t,n, size_t,m) { return calloc(n, m); } 878 extern Void_t F1(__libc_cfree, Void_t*,p) { free(p); } 879 extern Void_t F1(__libc_free, Void_t*,p) { free(p); } 880 extern Void_t* F1(__libc_malloc, size_t,n) { return malloc(n); } 881 #if _lib_memalign 882 extern Void_t* F2(__libc_memalign, size_t,a, size_t,n) { return memalign(a, n); } 883 #endif 884 #if _lib_pvalloc 885 extern Void_t* F1(__libc_pvalloc, size_t,n) { return pvalloc(n); } 886 #endif 887 extern Void_t* F2(__libc_realloc, Void_t*,p, size_t,n) { return realloc(p, n); } 888 #if _lib_valloc 889 extern Void_t* F1(__libc_valloc, size_t,n) { return valloc(n); } 890 #endif 891 #endif 892 893 #endif /* _malloc_hook */ 894 895 #endif /* _map_malloc */ 896 897 #undef extern 898 899 #if _hdr_malloc /* need the mallint interface for statistics, etc. */ 900 901 #undef calloc 902 #define calloc ______calloc 903 #undef cfree 904 #define cfree ______cfree 905 #undef free 906 #define free ______free 907 #undef malloc 908 #define malloc ______malloc 909 #undef pvalloc 910 #define pvalloc ______pvalloc 911 #undef realloc 912 #define realloc ______realloc 913 #undef valloc 914 #define valloc ______valloc 915 916 #if !_UWIN 917 918 #include <malloc.h> 919 920 typedef struct mallinfo Mallinfo_t; 921 typedef struct mstats Mstats_t; 922 923 #endif 924 925 #if defined(__EXPORT__) 926 #define extern __EXPORT__ 927 #endif 928 929 #if _lib_mallopt 930 #if __STD_C 931 extern int mallopt(int cmd, int value) 932 #else 933 extern int mallopt(cmd, value) 934 int cmd; 935 int value; 936 #endif 937 { 938 VMFLINIT(); 939 return 0; 940 } 941 #endif /*_lib_mallopt*/ 942 943 #if _lib_mallinfo && _mem_arena_mallinfo 944 #if __STD_C 945 extern Mallinfo_t mallinfo(void) 946 #else 947 extern Mallinfo_t mallinfo() 948 #endif 949 { 950 Vmstat_t sb; 951 Mallinfo_t mi; 952 953 VMFLINIT(); 954 memset(&mi,0,sizeof(mi)); 955 if(vmstat(Vmregion,&sb) >= 0) 956 { mi.arena = sb.extent; 957 mi.ordblks = sb.n_busy+sb.n_free; 958 mi.uordblks = sb.s_busy; 959 mi.fordblks = sb.s_free; 960 } 961 return mi; 962 } 963 #endif /* _lib_mallinfo */ 964 965 #if _lib_mstats && _mem_bytes_total_mstats 966 #if __STD_C 967 extern Mstats_t mstats(void) 968 #else 969 extern Mstats_t mstats() 970 #endif 971 { 972 Vmstat_t sb; 973 Mstats_t ms; 974 975 VMFLINIT(); 976 memset(&ms,0,sizeof(ms)); 977 if(vmstat(Vmregion,&sb) >= 0) 978 { ms.bytes_total = sb.extent; 979 ms.chunks_used = sb.n_busy; 980 ms.bytes_used = sb.s_busy; 981 ms.chunks_free = sb.n_free; 982 ms.bytes_free = sb.s_free; 983 } 984 return ms; 985 } 986 #endif /*_lib_mstats*/ 987 988 #undef extern 989 990 #endif/*_hdr_malloc*/ 991 992 #else 993 994 /* 995 * even though there is no malloc override, still provide 996 * _ast_* counterparts for object compatibility 997 */ 998 999 #define setregmax(n) 1000 1001 #undef calloc 1002 extern Void_t* calloc _ARG_((size_t, size_t)); 1003 1004 #undef cfree 1005 extern void cfree _ARG_((Void_t*)); 1006 1007 #undef free 1008 extern void free _ARG_((Void_t*)); 1009 1010 #undef malloc 1011 extern Void_t* malloc _ARG_((size_t)); 1012 1013 #if _lib_memalign 1014 #undef memalign 1015 extern Void_t* memalign _ARG_((size_t, size_t)); 1016 #endif 1017 1018 #if _lib_pvalloc 1019 #undef pvalloc 1020 extern Void_t* pvalloc _ARG_((size_t)); 1021 #endif 1022 1023 #undef realloc 1024 extern Void_t* realloc _ARG_((Void_t*, size_t)); 1025 1026 #if _lib_valloc 1027 #undef valloc 1028 extern Void_t* valloc _ARG_((size_t)); 1029 #endif 1030 1031 #if defined(__EXPORT__) 1032 #define extern __EXPORT__ 1033 #endif 1034 1035 #if !_malloc_hook 1036 1037 extern Void_t F1(_ast_free, Void_t*,p) { free(p); } 1038 extern Void_t* F1(_ast_malloc, size_t,n) { return malloc(n); } 1039 #if _lib_memalign 1040 extern Void_t* F2(_ast_memalign, size_t,a, size_t,n) { return memalign(a, n); } 1041 #endif 1042 extern Void_t* F2(_ast_realloc, Void_t*,p, size_t,n) { return realloc(p, n); } 1043 1044 #endif 1045 1046 extern Void_t* F2(_ast_calloc, size_t,n, size_t,m) { return calloc(n, m); } 1047 extern Void_t F1(_ast_cfree, Void_t*,p) { free(p); } 1048 #if _lib_pvalloc 1049 extern Void_t* F1(_ast_pvalloc, size_t,n) { return pvalloc(n); } 1050 #endif 1051 #if _lib_valloc 1052 extern Void_t* F1(_ast_valloc, size_t,n) { return valloc(n); } 1053 #endif 1054 1055 #undef extern 1056 1057 #if _hdr_malloc 1058 1059 #undef mallinfo 1060 #undef mallopt 1061 #undef mstats 1062 1063 #define calloc ______calloc 1064 #define cfree ______cfree 1065 #define free ______free 1066 #define malloc ______malloc 1067 #define pvalloc ______pvalloc 1068 #define realloc ______realloc 1069 #define valloc ______valloc 1070 1071 #if !_UWIN 1072 1073 #if !_malloc_hook 1074 1075 #include <malloc.h> 1076 1077 #endif 1078 1079 typedef struct mallinfo Mallinfo_t; 1080 typedef struct mstats Mstats_t; 1081 1082 #endif 1083 1084 #if defined(__EXPORT__) 1085 #define extern __EXPORT__ 1086 #endif 1087 1088 #if _lib_mallopt 1089 extern int F2(_ast_mallopt, int,cmd, int,value) { return mallopt(cmd, value); } 1090 #endif 1091 1092 #if _lib_mallinfo && _mem_arena_mallinfo 1093 extern Mallinfo_t F0(_ast_mallinfo, void) { return mallinfo(); } 1094 #endif 1095 1096 #if _lib_mstats && _mem_bytes_total_mstats 1097 extern Mstats_t F0(_ast_mstats, void) { return mstats(); } 1098 #endif 1099 1100 #undef extern 1101 1102 #endif /*_hdr_malloc*/ 1103 1104 #endif /*!_std_malloc*/ 1105 1106 #if __STD_C 1107 static Vmulong_t atou(char** sp) 1108 #else 1109 static Vmulong_t atou(sp) 1110 char** sp; 1111 #endif 1112 { 1113 char* s = *sp; 1114 Vmulong_t v = 0; 1115 1116 if(s[0] == '0' && (s[1] == 'x' || s[1] == 'X') ) 1117 { for(s += 2; *s; ++s) 1118 { if(*s >= '0' && *s <= '9') 1119 v = (v << 4) + (*s - '0'); 1120 else if(*s >= 'a' && *s <= 'f') 1121 v = (v << 4) + (*s - 'a') + 10; 1122 else if(*s >= 'A' && *s <= 'F') 1123 v = (v << 4) + (*s - 'A') + 10; 1124 else break; 1125 } 1126 } 1127 else 1128 { for(; *s; ++s) 1129 { if(*s >= '0' && *s <= '9') 1130 v = v*10 + (*s - '0'); 1131 else break; 1132 } 1133 } 1134 1135 *sp = s; 1136 return v; 1137 } 1138 1139 #if __STD_C 1140 static char* insertpid(char* begs, char* ends) 1141 #else 1142 static char* insertpid(begs,ends) 1143 char* begs; 1144 char* ends; 1145 #endif 1146 { int pid; 1147 char* s; 1148 1149 if((pid = getpid()) < 0) 1150 return NIL(char*); 1151 1152 s = ends; 1153 do 1154 { if(s == begs) 1155 return NIL(char*); 1156 *--s = '0' + pid%10; 1157 } while((pid /= 10) > 0); 1158 while(s < ends) 1159 *begs++ = *s++; 1160 1161 return begs; 1162 } 1163 1164 #define FD_PRIVATE (3*OPEN_MAX/4) 1165 1166 #if __STD_C 1167 int _vmfd(int fd) 1168 #else 1169 int _vmfd(fd) 1170 int fd; 1171 #endif 1172 { 1173 int pd; 1174 1175 if (fd >= 0) 1176 { 1177 if (fd < FD_PRIVATE && (pd = fcntl(fd, F_DUPFD, FD_PRIVATE)) >= 0) 1178 { 1179 close(fd); 1180 fd = pd; 1181 } 1182 #ifdef FD_CLOEXEC 1183 fcntl(fd, F_SETFD, FD_CLOEXEC); 1184 #endif 1185 } 1186 return fd; 1187 } 1188 1189 #if __STD_C 1190 static int createfile(char* file) 1191 #else 1192 static int createfile(file) 1193 char* file; 1194 #endif 1195 { 1196 char buf[1024]; 1197 char *next, *endb; 1198 int fd; 1199 1200 next = buf; 1201 endb = buf + sizeof(buf); 1202 while(*file) 1203 { if(*file == '%') 1204 { switch(file[1]) 1205 { 1206 case 'p' : 1207 if(!(next = insertpid(next,endb)) ) 1208 return -1; 1209 file += 2; 1210 break; 1211 default : 1212 goto copy; 1213 } 1214 } 1215 else 1216 { copy: 1217 *next++ = *file++; 1218 } 1219 1220 if(next >= endb) 1221 return -1; 1222 } 1223 1224 *next = '\0'; 1225 file = buf; 1226 if (*file == '&' && *(file += 1) || strncmp(file, "/dev/fd/", 8) == 0 && *(file += 8)) 1227 fd = dup((int)atou(&file)); 1228 else if (*file) 1229 { 1230 #if _PACKAGE_ast 1231 fd = open(file, O_WRONLY|O_CREAT|O_TRUNC, CREAT_MODE); 1232 #else 1233 fd = creat(file, CREAT_MODE); 1234 #endif 1235 fd = _vmfd(fd); 1236 } 1237 else 1238 return -1; 1239 #if _PACKAGE_ast 1240 #ifdef FD_CLOEXEC 1241 if (fd >= 0) 1242 fcntl(fd, F_SETFD, FD_CLOEXEC); 1243 #endif 1244 #endif 1245 return fd; 1246 } 1247 1248 #if __STD_C 1249 static void pfprint(void) 1250 #else 1251 static void pfprint() 1252 #endif 1253 { 1254 if(Vmregion->meth.meth == VM_MTPROFILE) 1255 vmprofile(Vmregion,_Vmpffd); 1256 } 1257 1258 /* 1259 * initialize runtime options from the VMALLOC_OPTIONS env var 1260 */ 1261 1262 #define COPY(t,e,f) while ((*t = *f++) && t < e) t++ 1263 1264 #if __STD_C 1265 void _vmoptions(void) 1266 #else 1267 void _vmoptions() 1268 #endif 1269 { 1270 Vmalloc_t* vm = 0; 1271 char* trace = 0; 1272 char* s; 1273 char* t; 1274 char* v; 1275 Vmulong_t n; 1276 int fd; 1277 char buf[1024]; 1278 1279 _Vmoptions = 1; 1280 t = buf; 1281 v = &buf[sizeof(buf)-1]; 1282 if (s = getenv("VMALLOC_OPTIONS")) 1283 COPY(t, v, s); 1284 if (t > buf) 1285 { 1286 *t = 0; 1287 s = buf; 1288 for (;;) 1289 { 1290 while (*s == ',' || *s == ' ' || *s == '\t' || *s == '\r' || *s == '\n') 1291 s++; 1292 if (!*(t = s)) 1293 break; 1294 v = 0; 1295 while (*s) 1296 if (*s == ',' || *s == ' ' || *s == '\t' || *s == '\r' || *s == '\n') 1297 { 1298 *s++ = 0; 1299 break; 1300 } 1301 else if (!v && *s == '=') 1302 { 1303 *s++ = 0; 1304 if (!*(v = s)) 1305 v = 0; 1306 } 1307 else 1308 s++; 1309 if (t[0] == 'n' && t[1] == 'o') 1310 continue; 1311 switch (t[0]) 1312 { 1313 case 'a': /* abort */ 1314 if (!vm) 1315 vm = vmopen(Vmdcsystem, Vmdebug, 0); 1316 if (vm && vm->meth.meth == VM_MTDEBUG) 1317 vmset(vm, VM_DBABORT, 1); 1318 else 1319 _Vmassert |= VM_abort; 1320 break; 1321 case 'b': /* break */ 1322 _Vmassert |= VM_break; 1323 break; 1324 case 'c': /* check */ 1325 _Vmassert |= VM_check; 1326 break; 1327 case 'f': /* free */ 1328 _Vmassert |= VM_free; 1329 break; 1330 case 'k': /* keep */ 1331 _Vmassert |= VM_keep; 1332 break; 1333 case 'm': 1334 if (v) 1335 switch (t[1]) 1336 { 1337 case 'e': /* method=METHOD */ 1338 if (!vm) 1339 { 1340 if ((v[0] == 'V' || v[0] == 'v') && (v[1] == 'M' || v[1] == 'm')) 1341 v += 2; 1342 if (strcmp(v, "debug") == 0) 1343 vm = vmopen(Vmdcsystem, Vmdebug, 0); 1344 else if (strcmp(v, "profile") == 0) 1345 vm = vmopen(Vmdcsystem, Vmprofile, 0); 1346 else if (strcmp(v, "last") == 0) 1347 vm = vmopen(Vmdcsystem, Vmlast, 0); 1348 else if (strcmp(v, "best") == 0) 1349 vm = Vmheap; 1350 } 1351 break; 1352 case 'm': /* mmap */ 1353 _Vmassert |= VM_mmap; 1354 break; 1355 } 1356 break; 1357 case 'p': 1358 if (v) 1359 switch (t[1]) 1360 { 1361 case 'e': /* period=<count> */ 1362 if (!vm) 1363 vm = vmopen(Vmdcsystem, Vmdebug, 0); 1364 if (vm && vm->meth.meth == VM_MTDEBUG) 1365 _Vmdbcheck = atou(&v); 1366 break; 1367 case 'r': /* profile=<path> */ 1368 if (!vm) 1369 vm = vmopen(Vmdcsystem, Vmprofile, 0); 1370 if (v && vm && vm->meth.meth == VM_MTPROFILE) 1371 _Vmpffd = createfile(v); 1372 break; 1373 } 1374 break; 1375 case 's': /* start=<count> */ 1376 if (!vm) 1377 vm = vmopen(Vmdcsystem, Vmdebug, 0); 1378 if (v && vm && vm->meth.meth == VM_MTDEBUG) 1379 _Vmdbstart = atou(&v); 1380 break; 1381 case 't': /* trace=<path> */ 1382 trace = v; 1383 break; 1384 case 'w': 1385 if (t[1] == 'a') 1386 switch (t[2]) 1387 { 1388 case 'r': /* warn=<path> */ 1389 if (!vm) 1390 vm = vmopen(Vmdcsystem, Vmdebug, 0); 1391 if (v && vm && vm->meth.meth == VM_MTDEBUG && (fd = createfile(v)) >= 0) 1392 vmdebug(fd); 1393 break; 1394 case 't': /* watch=<addr> */ 1395 if (!vm) 1396 vm = vmopen(Vmdcsystem, Vmdebug, 0); 1397 if (v && vm && vm->meth.meth == VM_MTDEBUG && (n = atou(&v)) >= 0) 1398 vmdbwatch((Void_t*)n); 1399 break; 1400 } 1401 break; 1402 } 1403 } 1404 } 1405 1406 /* slip in the new region now so that malloc() will work fine */ 1407 1408 if (vm) 1409 { 1410 if (vm->meth.meth == VM_MTDEBUG) 1411 _Vmdbcheck = 1; 1412 Vmregion = vm; 1413 } 1414 1415 /* enable tracing -- this currently disables multiple regions */ 1416 1417 if (trace) 1418 { 1419 setregmax(0); 1420 if ((fd = createfile(trace)) >= 0) 1421 { 1422 vmset(Vmregion, VM_TRACE, 1); 1423 vmtrace(fd); 1424 } 1425 } 1426 else if (Vmregion != Vmheap || asometh(0, 0)->type == ASO_SIGNAL) 1427 setregmax(0); 1428 1429 /* make sure that profile data is output upon exiting */ 1430 1431 if (vm && vm->meth.meth == VM_MTPROFILE) 1432 { 1433 if (_Vmpffd < 0) 1434 _Vmpffd = 2; 1435 /* this may wind up calling malloc(), but region is ok now */ 1436 atexit(pfprint); 1437 } 1438 else if (_Vmpffd >= 0) 1439 { 1440 close(_Vmpffd); 1441 _Vmpffd = -1; 1442 } 1443 } 1444 1445 /* 1446 * ast semi-private workaround for system functions 1447 * that misbehave by passing bogus addresses to free() 1448 * 1449 * not prototyped in any header to keep it ast semi-private 1450 * 1451 * to keep malloc() data by disabling free() 1452 * extern _vmkeep(int); 1453 * int r = _vmkeep(1); 1454 * and to restore to the previous state 1455 * (void)_vmkeep(r); 1456 */ 1457 1458 int 1459 #if __STD_C 1460 _vmkeep(int v) 1461 #else 1462 _vmkeep(v) 1463 int v; 1464 #endif 1465 { 1466 int r; 1467 1468 r = !!(_Vmassert & VM_keep); 1469 if (v) 1470 _Vmassert |= VM_keep; 1471 else 1472 _Vmassert &= ~VM_keep; 1473 return r; 1474 } 1475 1476 #endif /*_UWIN*/ 1477