1 /***********************************************************************
3 * This software is part of the ast package *
4 * Copyright (c) 1985-2010 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Common Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
13 * Information and Software Systems Research *
17 * Glenn Fowler <gsf@research.att.com> *
18 * David Korn <dgk@research.att.com> *
19 * Phong Vo <kpv@research.att.com> *
21 ***********************************************************************/
22 #if defined(_UWIN) && defined(_BLD_ast)
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
40 extern int atexit(void(*)(void));
41 extern char* getenv(const char*);
56 #define calloc _ast_calloc
58 #define free _ast_free
60 #define malloc _ast_malloc
62 typedef struct ______mallinfo Mallinfo_t
;
65 typedef struct ______mstats Mstats_t
;
67 #define realloc _ast_realloc
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)
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;
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.
87 #if !defined(_AST_std_malloc) && __CYGWIN__
88 #define _AST_std_malloc 1
91 /* malloc compatibility functions
93 ** These are aware of debugging/profiling and are driven by the
94 ** VMALLOC_OPTIONS environment variable which is a space-separated
95 ** list of [no]name[=value] options:
97 ** abort if Vmregion==Vmdebug then VM_DBABORT is set,
98 ** otherwise _BLD_debug enabled assertions abort()
100 ** check if Vmregion==Vmbest then the region is checked every op
101 ** method=m sets Vmregion=m if not defined, m (Vm prefix optional)
102 ** may be one of { best debug last profile }
103 ** mmap prefer mmap() over brk() for region allocation
104 ** period=n sets Vmregion=Vmdebug if not defined, if
105 ** Vmregion==Vmdebug the region is checked every n ops
106 ** profile=f sets Vmregion=Vmprofile if not set, if
107 ** Vmregion==Vmprofile then profile info printed to file f
108 ** region if Vmregion==Vmbest then block free verifies
109 ** that the block belongs to the region
110 ** start=n sets Vmregion=Vmdebug if not defined, if
111 ** Vmregion==Vmdebug region checking starts after n ops
112 ** trace=f enables tracing to file f
113 ** warn=f sets Vmregion=Vmdebug if not defined, if
114 ** Vmregion==Vmdebug then warnings printed to file f
115 ** watch=a sets Vmregion=Vmdebug if not defined, if
116 ** Vmregion==Vmdebug then address a is watched
118 ** Output files are created if they don't exist. &n and /dev/fd/n name
119 ** the file descriptor n which must be open for writing. The pattern %p
120 ** in a file name is replaced by the process ID.
122 ** VMALLOC_OPTIONS combines the features of these previously used env vars:
123 ** { VMDEBUG VMETHOD VMPROFILE VMTRACE }
125 ** Written by Kiem-Phong Vo, kpv@research.att.com, 01/16/94.
129 #include <sys/stat.h>
134 #define CREAT_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
136 #define CREAT_MODE 0644
139 static Vmulong_t _Vmdbstart
= 0;
140 static Vmulong_t _Vmdbcheck
= 0;
141 static Vmulong_t _Vmdbtime
= 0;
142 static int _Vmpffd
= -1;
144 #if ( !_std_malloc || !_BLD_ast ) && !_AST_std_malloc
161 #include <ast_windows.h>
165 #define VMRECORD(p) _vmrecord(p)
166 #define VMBLOCK { int _vmblock = _sigblock();
167 #define VMUNBLOCK _sigunblock(_vmblock); }
169 extern int _sigblock(void);
170 extern void _sigunblock(int);
171 extern unsigned long _record
[2048];
173 __inline Void_t
* _vmrecord(Void_t
* p
)
175 register unsigned long v
= ((unsigned long)p
)>>16;
177 _record
[v
>>5] |= 1<<((v
&0x1f));
183 #define getenv(s) lcl_getenv(s)
186 lcl_getenv(const char* s
)
189 static char buf
[512];
191 if (!(n
= GetEnvironmentVariable(s
, buf
, sizeof(buf
))) || n
> sizeof(buf
))
201 #define VMRECORD(p) (p)
206 #if defined(__EXPORT__)
207 #define extern extern __EXPORT__
210 static int _Vmflinit
= 0;
212 { if(!_Vmflinit) vmflinit(); \
214 { if(_Vmdbtime < _Vmdbstart) _Vmdbtime += 1; \
215 else if((_Vmdbtime += 1) < _Vmdbstart) _Vmdbtime = _Vmdbstart; \
216 if(_Vmdbtime >= _Vmdbstart && (_Vmdbtime % _Vmdbcheck) == 0 && \
217 Vmregion->meth.meth == VM_MTDEBUG) \
218 vmdbcheck(Vmregion); \
223 static int vmflinit(void)
225 static int vmflinit()
232 /* this must be done now to avoid any inadvertent recursion (more below) */
234 VMFLF(Vmregion
,file
,line
,func
);
236 /* if getenv() calls malloc(), the options may not affect the eventual region */
239 /* reset file and line number to correct values for the call */
240 Vmregion
->file
= file
;
241 Vmregion
->line
= line
;
242 Vmregion
->func
= func
;
248 extern Void_t
* calloc(reg
size_t n_obj
, reg
size_t s_obj
)
250 extern Void_t
* calloc(n_obj
, s_obj
)
256 return VMRECORD((*Vmregion
->meth
.resizef
)(Vmregion
,NIL(Void_t
*),n_obj
*s_obj
,VM_RSZERO
));
260 extern Void_t
* malloc(reg
size_t size
)
262 extern Void_t
* malloc(size
)
267 return VMRECORD((*Vmregion
->meth
.allocf
)(Vmregion
,size
));
271 extern Void_t
* realloc(reg Void_t
* data
, reg
size_t size
)
273 extern Void_t
* realloc(data
,size
)
274 reg Void_t
* data
; /* block to be reallocated */
275 reg
size_t size
; /* new size */
281 extern Void_t
* realloc(Void_t
*, size_t);
283 extern Void_t
* realloc();
290 if(data
&& Vmregion
->meth
.meth
!= VM_MTDEBUG
&&
292 !(Vmregion
->data
->mode
&VM_TRUST
) &&
294 (*Vmregion
->meth
.addrf
)(Vmregion
,data
) != 0 )
297 return realloc(data
, size
);
300 if((newdata
= (*Vmregion
->meth
.allocf
)(Vmregion
,size
)) )
301 memcpy(newdata
,data
,size
);
302 return VMRECORD(newdata
);
309 if (newdata
= (*Vmregion
->meth
.resizef
)(Vmregion
,data
,size
,VM_RSCOPY
|VM_RSMOVE
))
311 return VMRECORD(realloc(data
, size
));
314 return VMRECORD((*Vmregion
->meth
.resizef
)(Vmregion
,data
,size
,VM_RSCOPY
|VM_RSMOVE
));
319 extern void free(reg Void_t
* data
)
321 extern void free(data
)
328 extern void free(Void_t
*);
337 if(data
&& Vmregion
->meth
.meth
!= VM_MTDEBUG
&&
339 !(Vmregion
->data
->mode
&VM_TRUST
) &&
341 (*Vmregion
->meth
.addrf
)(Vmregion
,data
) != 0)
351 if ((*Vmregion
->meth
.freef
)(Vmregion
,data
) != 0)
354 (void)(*Vmregion
->meth
.freef
)(Vmregion
,data
);
359 extern void cfree(reg Void_t
* data
)
361 extern void cfree(data
)
369 extern Void_t
* memalign(reg
size_t align
, reg
size_t size
)
371 extern Void_t
* memalign(align
, size
)
380 addr
= VMRECORD((*Vmregion
->meth
.alignf
)(Vmregion
,size
,align
));
386 extern int posix_memalign(reg Void_t
**memptr
, reg
size_t align
, reg
size_t size
)
388 extern int posix_memalign(memptr
, align
, size
)
396 if(align
== 0 || (align
%sizeof(Void_t
*)) != 0 || ((align
-1)&align
) != 0 )
399 if(!(mem
= memalign(align
, size
)) )
407 extern Void_t
* valloc(reg
size_t size
)
409 extern Void_t
* valloc(size
)
414 GETPAGESIZE(_Vmpagesize
);
415 return VMRECORD((*Vmregion
->meth
.alignf
)(Vmregion
,size
,_Vmpagesize
));
419 extern Void_t
* pvalloc(reg
size_t size
)
421 extern Void_t
* pvalloc(size
)
426 GETPAGESIZE(_Vmpagesize
);
427 return VMRECORD((*Vmregion
->meth
.alignf
)(Vmregion
,ROUND(size
,_Vmpagesize
),_Vmpagesize
));
432 char* strdup(const char* s
)
445 if((ns
= malloc(n
+1)) )
450 #endif /* _PACKAGE_ast */
452 #if !_lib_alloca || _mal_alloca
456 typedef struct _alloca_s Alloca_t
;
465 { union _alloca_u head
;
470 extern Void_t
* alloca(size_t size
)
472 extern Void_t
* alloca(size
)
480 static Alloca_t
* Frame
;
483 VMFLF(Vmregion
,file
,line
,func
);
485 { if(( _stk_down
&& &array
[0] > Frame
->head
.head
.addr
) ||
486 (!_stk_down
&& &array
[0] < Frame
->head
.head
.addr
) )
488 Frame
= f
->head
.head
.next
;
489 (void)(*Vmregion
->meth
.freef
)(Vmregion
,f
);
494 Vmregion
->file
= file
;
495 Vmregion
->line
= line
;
496 Vmregion
->func
= func
;
497 f
= (Alloca_t
*)(*Vmregion
->meth
.allocf
)(Vmregion
,size
+sizeof(Alloca_t
)-1);
499 f
->head
.head
.addr
= &array
[0];
500 f
->head
.head
.next
= Frame
;
503 return (Void_t
*)f
->data
;
505 #endif /*!_lib_alloca || _mal_alloca*/
509 /* not sure of all the implications -- 0 is conservative for now */
510 #define USE_NATIVE 0 /* native free/realloc on non-vmalloc ptrs */
514 /* intercept _* __* __libc_* variants */
517 extern Void_t
* F2(_calloc
, size_t,n
, size_t,m
) { return calloc(n
, m
); }
518 extern Void_t
F1(_cfree
, Void_t
*,p
) { free(p
); }
519 extern Void_t
F1(_free
, Void_t
*,p
) { free(p
); }
520 extern Void_t
* F1(_malloc
, size_t,n
) { return malloc(n
); }
522 extern Void_t
* F2(_memalign
, size_t,a
, size_t,n
) { return memalign(a
, n
); }
525 extern Void_t
* F1(_pvalloc
, size_t,n
) { return pvalloc(n
); }
527 extern Void_t
* F2(_realloc
, Void_t
*,p
, size_t,n
) { return realloc(p
, n
); }
529 extern Void_t
* F1(_valloc
, size_t,n
) { return valloc(n
); }
534 extern Void_t
* F2(__calloc
, size_t,n
, size_t,m
) { return calloc(n
, m
); }
535 extern Void_t
F1(__cfree
, Void_t
*,p
) { free(p
); }
536 extern Void_t
F1(__free
, Void_t
*,p
) { free(p
); }
537 extern Void_t
* F1(__malloc
, size_t,n
) { return malloc(n
); }
539 extern Void_t
* F2(__memalign
, size_t,a
, size_t,n
) { return memalign(a
, n
); }
542 extern Void_t
* F1(__pvalloc
, size_t,n
) { return pvalloc(n
); }
544 extern Void_t
* F2(__realloc
, Void_t
*,p
, size_t,n
) { return realloc(p
, n
); }
546 extern Void_t
* F1(__valloc
, size_t,n
) { return valloc(n
); }
550 #if _lib___libc_malloc
551 extern Void_t
* F2(__libc_calloc
, size_t,n
, size_t,m
) { return calloc(n
, m
); }
552 extern Void_t
F1(__libc_cfree
, Void_t
*,p
) { free(p
); }
553 extern Void_t
F1(__libc_free
, Void_t
*,p
) { free(p
); }
554 extern Void_t
* F1(__libc_malloc
, size_t,n
) { return malloc(n
); }
556 extern Void_t
* F2(__libc_memalign
, size_t,a
, size_t,n
) { return memalign(a
, n
); }
559 extern Void_t
* F1(__libc_pvalloc
, size_t,n
) { return pvalloc(n
); }
561 extern Void_t
* F2(__libc_realloc
, Void_t
*,p
, size_t,n
) { return realloc(p
, n
); }
563 extern Void_t
* F1(__libc_valloc
, size_t,n
) { return valloc(n
); }
567 #endif /* _map_malloc */
571 #if _hdr_malloc /* need the mallint interface for statistics, etc. */
574 #define calloc ______calloc
576 #define cfree ______cfree
578 #define free ______free
580 #define malloc ______malloc
582 #define pvalloc ______pvalloc
584 #define realloc ______realloc
586 #define valloc ______valloc
592 typedef struct mallinfo Mallinfo_t
;
593 typedef struct mstats Mstats_t
;
597 #if defined(__EXPORT__)
598 #define extern __EXPORT__
603 extern int mallopt(int cmd
, int value
)
605 extern int mallopt(cmd
, value
)
613 #endif /*_lib_mallopt*/
615 #if _lib_mallinfo && _mem_arena_mallinfo
617 extern Mallinfo_t
mallinfo(void)
619 extern Mallinfo_t
mallinfo()
626 memset(&mi
,0,sizeof(mi
));
627 if(vmstat(Vmregion
,&sb
) >= 0)
628 { mi
.arena
= sb
.extent
;
629 mi
.ordblks
= sb
.n_busy
+sb
.n_free
;
630 mi
.uordblks
= sb
.s_busy
;
631 mi
.fordblks
= sb
.s_free
;
635 #endif /* _lib_mallinfo */
637 #if _lib_mstats && _mem_bytes_total_mstats
639 extern Mstats_t
mstats(void)
641 extern Mstats_t
mstats()
648 memset(&ms
,0,sizeof(ms
));
649 if(vmstat(Vmregion
,&sb
) >= 0)
650 { ms
.bytes_total
= sb
.extent
;
651 ms
.chunks_used
= sb
.n_busy
;
652 ms
.bytes_used
= sb
.s_busy
;
653 ms
.chunks_free
= sb
.n_free
;
654 ms
.bytes_free
= sb
.s_free
;
658 #endif /*_lib_mstats*/
662 #endif/*_hdr_malloc*/
667 * even though there is no malloc override, still provide
668 * _ast_* counterparts for object compatibility
672 extern Void_t
* calloc
_ARG_((size_t, size_t));
675 extern void cfree
_ARG_((Void_t
*));
678 extern void free
_ARG_((Void_t
*));
681 extern Void_t
* malloc
_ARG_((size_t));
685 extern Void_t
* memalign
_ARG_((size_t, size_t));
690 extern Void_t
* pvalloc
_ARG_((size_t));
694 extern Void_t
* realloc
_ARG_((Void_t
*, size_t));
698 extern Void_t
* valloc
_ARG_((size_t));
701 #if defined(__EXPORT__)
702 #define extern __EXPORT__
705 extern Void_t
* F2(_ast_calloc
, size_t,n
, size_t,m
) { return calloc(n
, m
); }
706 extern Void_t
F1(_ast_cfree
, Void_t
*,p
) { free(p
); }
707 extern Void_t
F1(_ast_free
, Void_t
*,p
) { free(p
); }
708 extern Void_t
* F1(_ast_malloc
, size_t,n
) { return malloc(n
); }
710 extern Void_t
* F2(_ast_memalign
, size_t,a
, size_t,n
) { return memalign(a
, n
); }
713 extern Void_t
* F1(_ast_pvalloc
, size_t,n
) { return pvalloc(n
); }
715 extern Void_t
* F2(_ast_realloc
, Void_t
*,p
, size_t,n
) { return realloc(p
, n
); }
717 extern Void_t
* F1(_ast_valloc
, size_t,n
) { return valloc(n
); }
728 #define calloc ______calloc
729 #define cfree ______cfree
730 #define free ______free
731 #define malloc ______malloc
732 #define pvalloc ______pvalloc
733 #define realloc ______realloc
734 #define valloc ______valloc
740 typedef struct mallinfo Mallinfo_t
;
741 typedef struct mstats Mstats_t
;
745 #if defined(__EXPORT__)
746 #define extern __EXPORT__
750 extern int F2(_ast_mallopt
, int,cmd
, int,value
) { return mallopt(cmd
, value
); }
753 #if _lib_mallinfo && _mem_arena_mallinfo
754 extern Mallinfo_t
F0(_ast_mallinfo
, void) { return mallinfo(); }
757 #if _lib_mstats && _mem_bytes_total_mstats
758 extern Mstats_t
F0(_ast_mstats
, void) { return mstats(); }
763 #endif /*_hdr_malloc*/
765 #endif /*!_std_malloc*/
768 static Vmulong_t
atou(char** sp
)
770 static Vmulong_t
atou(sp
)
777 if(s
[0] == '0' && (s
[1] == 'x' || s
[1] == 'X') )
778 { for(s
+= 2; *s
; ++s
)
779 { if(*s
>= '0' && *s
<= '9')
780 v
= (v
<< 4) + (*s
- '0');
781 else if(*s
>= 'a' && *s
<= 'f')
782 v
= (v
<< 4) + (*s
- 'a') + 10;
783 else if(*s
>= 'A' && *s
<= 'F')
784 v
= (v
<< 4) + (*s
- 'A') + 10;
790 { if(*s
>= '0' && *s
<= '9')
791 v
= v
*10 + (*s
- '0');
801 static char* insertpid(char* begs
, char* ends
)
803 static char* insertpid(begs
,ends
)
810 if((pid
= getpid()) < 0)
818 } while((pid
/= 10) > 0);
826 static int createfile(char* file
)
828 static int createfile(file
)
837 endb
= buf
+ sizeof(buf
);
843 if(!(next
= insertpid(next
,endb
)) )
862 if (*file
== '&' && *(file
+= 1) || strncmp(file
, "/dev/fd/", 8) == 0 && *(file
+= 8))
863 fd
= dup((int)atou(&file
));
866 fd
= open(file
, O_WRONLY
|O_CREAT
|O_TRUNC
, CREAT_MODE
);
868 fd
= creat(file
, CREAT_MODE
);
875 fcntl(fd
, F_SETFD
, FD_CLOEXEC
);
882 static void pfprint(void)
884 static void pfprint()
887 if(Vmregion
->meth
.meth
== VM_MTPROFILE
)
888 vmprofile(Vmregion
,_Vmpffd
);
892 * initialize runtime options from the VMALLOC_OPTIONS env var
895 #define COPY(t,e,f) while ((*t = *f++) && t < e) t++
898 void _vmoptions(void)
914 v
= &buf
[sizeof(buf
)-1];
915 if (s
= getenv("VMALLOC_OPTIONS"))
917 #if 1 /* backwards compatibility until 2011 */
922 if (s
= getenv("VMDEBUG"))
952 if ((s
= getenv("VMETHOD")) && *s
)
958 if ((s
= getenv("VMPROFILE")) && *s
)
964 if ((s
= getenv("VMTRACE")) && *s
)
978 while (*s
== ' ' || *s
== '\t' || *s
== '\r' || *s
== '\n')
984 if (*s
== ' ' || *s
== '\t' || *s
== '\r' || *s
== '\n')
989 else if (!v
&& *s
== '=')
997 if (t
[0] == 'n' && t
[1] == 'o')
1001 case 'a': /* abort */
1003 vm
= vmopen(Vmdcsbrk
, Vmdebug
, 0);
1004 if (vm
&& vm
->meth
.meth
== VM_MTDEBUG
)
1005 vmset(vm
, VM_DBABORT
, 1);
1007 _Vmassert
|= VM_abort
;
1009 case 'c': /* check */
1010 _Vmassert
|= VM_check
;
1015 case 'e': /* method=<method> */
1018 if ((v
[0] == 'V' || v
[0] == 'v') && (v
[1] == 'M' || v
[1] == 'm'))
1020 if (strcmp(v
, "debug") == 0)
1021 vm
= vmopen(Vmdcsbrk
, Vmdebug
, 0);
1022 else if (strcmp(v
, "profile") == 0)
1023 vm
= vmopen(Vmdcsbrk
, Vmprofile
, 0);
1024 else if (strcmp(v
, "last") == 0)
1025 vm
= vmopen(Vmdcsbrk
, Vmlast
, 0);
1026 else if (strcmp(v
, "best") == 0)
1030 case 'm': /* mmap */
1031 #if _mem_mmap_anon || _mem_mmap_zero
1032 _Vmassert
|= VM_mmap
;
1041 case 'e': /* period=<count> */
1043 vm
= vmopen(Vmdcsbrk
, Vmdebug
, 0);
1044 if (vm
&& vm
->meth
.meth
== VM_MTDEBUG
)
1045 _Vmdbcheck
= atou(&v
);
1047 case 'r': /* profile=<path> */
1049 vm
= vmopen(Vmdcsbrk
, Vmprofile
, 0);
1050 if (v
&& vm
&& vm
->meth
.meth
== VM_MTPROFILE
)
1051 _Vmpffd
= createfile(v
);
1055 case 'r': /* region */
1056 _Vmassert
|= VM_region
;
1058 case 's': /* start=<count> */
1060 vm
= vmopen(Vmdcsbrk
, Vmdebug
, 0);
1061 if (v
&& vm
&& vm
->meth
.meth
== VM_MTDEBUG
)
1062 _Vmdbstart
= atou(&v
);
1064 case 't': /* trace=<path> */
1071 case 'r': /* warn=<path> */
1073 vm
= vmopen(Vmdcsbrk
, Vmdebug
, 0);
1074 if (v
&& vm
&& vm
->meth
.meth
== VM_MTDEBUG
&& (fd
= createfile(v
)) >= 0)
1077 case 't': /* watch=<addr> */
1079 vm
= vmopen(Vmdcsbrk
, Vmdebug
, 0);
1080 if (v
&& vm
&& vm
->meth
.meth
== VM_MTDEBUG
&& (n
= atou(&v
)) >= 0)
1081 vmdbwatch((Void_t
*)n
);
1089 /* slip in the new region now so that malloc() will work fine */
1093 if (vm
->meth
.meth
== VM_MTDEBUG
)
1098 /* enable tracing */
1100 if (trace
&& (fd
= createfile(trace
)) >= 0)
1102 vmset(Vmregion
, VM_TRACE
, 1);
1106 /* make sure that profile data is output upon exiting */
1108 if (vm
&& vm
->meth
.meth
== VM_MTPROFILE
)
1112 /* this may wind up calling malloc(), but region is ok now */
1115 else if (_Vmpffd
>= 0)