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 24void _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 40extern int atexit(void(*)(void)); 41extern 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 62typedef struct ______mallinfo Mallinfo_t; 63#undef mallopt 64#undef mstats 65typedef 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 141static Vmulong_t _Vmdbstart = 0; 142static Vmulong_t _Vmdbcheck = 0; 143static Vmulong_t _Vmdbtime = 0; 144static 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 192extern int _sigblock(void); 193extern void _sigunblock(int); 194extern 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 208static char* 209lcl_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 233static 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 246static int vmflinit(void) 247#else 248static 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 272static Vmalloc_t *Region[64]; /* list of concurrent regions */ 273static unsigned int Regmax = 64; /* max number of regions */ 274#else 275static Vmalloc_t* Region[1]; /* list of concurrent regions */ 276static unsigned int Regmax = 0; 277#endif 278static unsigned int Regnum = 0; /* current #concurrent regions */ 279 280/* statistics */ 281static unsigned int Regopen = 0; /* #allocation calls opened */ 282static unsigned int Reglock = 0; /* #allocation calls locked */ 283static unsigned int Regprobe = 0; /* #probes to find a region */ 284 285int 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 */ 296int _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 */ 327static 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 */ 358typedef struct _regfree_s 359{ struct _regfree_s* next; 360} Regfree_t; 361static Regfree_t *Regfree; 362 363static 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 375static 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 */ 399typedef struct _regdisc_s 400{ Vmdisc_t disc; 401 char slop[64]; /* to absorb any extra data in Vmdcsystem */ 402} Regdisc_t; 403 404static 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 414static 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 487extern Void_t* calloc(reg size_t n_obj, reg size_t s_obj) 488#else 489extern Void_t* calloc(n_obj, s_obj) 490reg size_t n_obj; 491reg 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 509extern Void_t* malloc(reg size_t size) 510#else 511extern Void_t* malloc(size) 512reg 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 530extern Void_t* realloc(reg Void_t* data, reg size_t size) 531#else 532extern Void_t* realloc(data,size) 533reg Void_t* data; /* block to be reallocated */ 534reg 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 583extern void free(reg Void_t* data) 584#else 585extern void free(data) 586reg 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 617extern void cfree(reg Void_t* data) 618#else 619extern void cfree(data) 620reg Void_t* data; 621#endif 622{ 623 free(data); 624} 625 626#if __STD_C 627extern Void_t* memalign(reg size_t align, reg size_t size) 628#else 629extern Void_t* memalign(align, size) 630reg size_t align; 631reg 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 651extern int posix_memalign(reg Void_t **memptr, reg size_t align, reg size_t size) 652#else 653extern int posix_memalign(memptr, align, size) 654reg Void_t** memptr; 655reg size_t align; 656reg 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 672extern Void_t* valloc(reg size_t size) 673#else 674extern Void_t* valloc(size) 675reg size_t size; 676#endif 677{ 678 VMFLINIT(); 679 680 GETPAGESIZE(_Vmpagesize); 681 return VMRECORD(memalign(_Vmpagesize, size)); 682} 683 684#if __STD_C 685extern Void_t* pvalloc(reg size_t size) 686#else 687extern Void_t* pvalloc(size) 688reg 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 699char* strdup(const char* s) 700#else 701char* strdup(s) 702char* 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 723typedef struct _alloca_s Alloca_t; 724union _alloca_u 725{ struct 726 { char* addr; 727 Alloca_t* next; 728 } head; 729 char array[ALIGN]; 730}; 731struct _alloca_s 732{ union _alloca_u head; 733 Vmuchar_t data[1]; 734}; 735 736#if __STD_C 737extern Void_t* alloca(size_t size) 738#else 739extern Void_t* alloca(size) 740size_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 789static void vm_free_hook(void* ptr, const void* caller) 790{ 791 free(ptr); 792} 793 794static void* vm_malloc_hook(size_t size, const void* caller) 795{ 796 void* r; 797 798 r = malloc(size); 799 return r; 800} 801 802static 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 810static 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 818static 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 826void (*__malloc_initialize_hook)(void) = vm_initialize_hook; 827 828#if 0 /* 2012-02-29 this may be needed to cover shared libs */ 829 830void __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 843extern Void_t* F2(_calloc, size_t,n, size_t,m) { return calloc(n, m); } 844extern Void_t F1(_cfree, Void_t*,p) { free(p); } 845extern Void_t F1(_free, Void_t*,p) { free(p); } 846extern Void_t* F1(_malloc, size_t,n) { return malloc(n); } 847#if _lib_memalign 848extern Void_t* F2(_memalign, size_t,a, size_t,n) { return memalign(a, n); } 849#endif 850#if _lib_pvalloc 851extern Void_t* F1(_pvalloc, size_t,n) { return pvalloc(n); } 852#endif 853extern Void_t* F2(_realloc, Void_t*,p, size_t,n) { return realloc(p, n); } 854#if _lib_valloc 855extern Void_t* F1(_valloc, size_t,n) { return valloc(n); } 856#endif 857#endif 858 859#if _lib___malloc 860extern Void_t* F2(__calloc, size_t,n, size_t,m) { return calloc(n, m); } 861extern Void_t F1(__cfree, Void_t*,p) { free(p); } 862extern Void_t F1(__free, Void_t*,p) { free(p); } 863extern Void_t* F1(__malloc, size_t,n) { return malloc(n); } 864#if _lib_memalign 865extern Void_t* F2(__memalign, size_t,a, size_t,n) { return memalign(a, n); } 866#endif 867#if _lib_pvalloc 868extern Void_t* F1(__pvalloc, size_t,n) { return pvalloc(n); } 869#endif 870extern Void_t* F2(__realloc, Void_t*,p, size_t,n) { return realloc(p, n); } 871#if _lib_valloc 872extern Void_t* F1(__valloc, size_t,n) { return valloc(n); } 873#endif 874#endif 875 876#if _lib___libc_malloc 877extern Void_t* F2(__libc_calloc, size_t,n, size_t,m) { return calloc(n, m); } 878extern Void_t F1(__libc_cfree, Void_t*,p) { free(p); } 879extern Void_t F1(__libc_free, Void_t*,p) { free(p); } 880extern Void_t* F1(__libc_malloc, size_t,n) { return malloc(n); } 881#if _lib_memalign 882extern Void_t* F2(__libc_memalign, size_t,a, size_t,n) { return memalign(a, n); } 883#endif 884#if _lib_pvalloc 885extern Void_t* F1(__libc_pvalloc, size_t,n) { return pvalloc(n); } 886#endif 887extern Void_t* F2(__libc_realloc, Void_t*,p, size_t,n) { return realloc(p, n); } 888#if _lib_valloc 889extern 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 920typedef struct mallinfo Mallinfo_t; 921typedef 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 931extern int mallopt(int cmd, int value) 932#else 933extern int mallopt(cmd, value) 934int cmd; 935int 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 945extern Mallinfo_t mallinfo(void) 946#else 947extern 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 967extern Mstats_t mstats(void) 968#else 969extern 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 1002extern Void_t* calloc _ARG_((size_t, size_t)); 1003 1004#undef cfree 1005extern void cfree _ARG_((Void_t*)); 1006 1007#undef free 1008extern void free _ARG_((Void_t*)); 1009 1010#undef malloc 1011extern Void_t* malloc _ARG_((size_t)); 1012 1013#if _lib_memalign 1014#undef memalign 1015extern Void_t* memalign _ARG_((size_t, size_t)); 1016#endif 1017 1018#if _lib_pvalloc 1019#undef pvalloc 1020extern Void_t* pvalloc _ARG_((size_t)); 1021#endif 1022 1023#undef realloc 1024extern Void_t* realloc _ARG_((Void_t*, size_t)); 1025 1026#if _lib_valloc 1027#undef valloc 1028extern 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 1037extern Void_t F1(_ast_free, Void_t*,p) { free(p); } 1038extern Void_t* F1(_ast_malloc, size_t,n) { return malloc(n); } 1039#if _lib_memalign 1040extern Void_t* F2(_ast_memalign, size_t,a, size_t,n) { return memalign(a, n); } 1041#endif 1042extern Void_t* F2(_ast_realloc, Void_t*,p, size_t,n) { return realloc(p, n); } 1043 1044#endif 1045 1046extern Void_t* F2(_ast_calloc, size_t,n, size_t,m) { return calloc(n, m); } 1047extern Void_t F1(_ast_cfree, Void_t*,p) { free(p); } 1048#if _lib_pvalloc 1049extern Void_t* F1(_ast_pvalloc, size_t,n) { return pvalloc(n); } 1050#endif 1051#if _lib_valloc 1052extern 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 1079typedef struct mallinfo Mallinfo_t; 1080typedef struct mstats Mstats_t; 1081 1082#endif 1083 1084#if defined(__EXPORT__) 1085#define extern __EXPORT__ 1086#endif 1087 1088#if _lib_mallopt 1089extern int F2(_ast_mallopt, int,cmd, int,value) { return mallopt(cmd, value); } 1090#endif 1091 1092#if _lib_mallinfo && _mem_arena_mallinfo 1093extern Mallinfo_t F0(_ast_mallinfo, void) { return mallinfo(); } 1094#endif 1095 1096#if _lib_mstats && _mem_bytes_total_mstats 1097extern 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 1107static Vmulong_t atou(char** sp) 1108#else 1109static Vmulong_t atou(sp) 1110char** 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 1140static char* insertpid(char* begs, char* ends) 1141#else 1142static char* insertpid(begs,ends) 1143char* begs; 1144char* 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 1167int _vmfd(int fd) 1168#else 1169int _vmfd(fd) 1170int 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 1190static int createfile(char* file) 1191#else 1192static int createfile(file) 1193char* 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 1249static void pfprint(void) 1250#else 1251static 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 1265void _vmoptions(void) 1266#else 1267void _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 1458int 1459#if __STD_C 1460_vmkeep(int v) 1461#else 1462_vmkeep(v) 1463int 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