1 /***********************************************************************
2 *                                                                      *
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                     *
8 *                                                                      *
9 *                A copy of the License is available at                 *
10 *            http://www.opensource.org/licenses/cpl1.0.txt             *
11 *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
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 space-separated
95 **	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 **	    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
117 **
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.
121 **
122 **	VMALLOC_OPTIONS combines the features of these previously used env vars:
123 **	    { VMDEBUG VMETHOD VMPROFILE VMTRACE }
124 **
125 **	Written by Kiem-Phong Vo, kpv@research.att.com, 01/16/94.
126 */
127 
128 #if _sys_stat
129 #include	<sys/stat.h>
130 #endif
131 #include	<fcntl.h>
132 
133 #ifdef S_IRUSR
134 #define CREAT_MODE	(S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
135 #else
136 #define CREAT_MODE	0644
137 #endif
138 
139 static Vmulong_t	_Vmdbstart = 0;
140 static Vmulong_t	_Vmdbcheck = 0;
141 static Vmulong_t	_Vmdbtime = 0;
142 static int		_Vmpffd = -1;
143 
144 #if ( !_std_malloc || !_BLD_ast ) && !_AST_std_malloc
145 
146 #if !_map_malloc
147 #undef calloc
148 #undef cfree
149 #undef free
150 #undef mallinfo
151 #undef malloc
152 #undef mallopt
153 #undef memalign
154 #undef mstats
155 #undef realloc
156 #undef valloc
157 #endif
158 
159 #if _WINIX
160 
161 #include <ast_windows.h>
162 
163 #if _UWIN
164 
165 #define VMRECORD(p)	_vmrecord(p)
166 #define VMBLOCK		{ int _vmblock = _sigblock();
167 #define VMUNBLOCK	_sigunblock(_vmblock); }
168 
169 extern int		_sigblock(void);
170 extern void		_sigunblock(int);
171 extern unsigned long	_record[2048];
172 
173 __inline Void_t* _vmrecord(Void_t* p)
174 {
175 	register unsigned long	v = ((unsigned long)p)>>16;
176 
177 	_record[v>>5] |= 1<<((v&0x1f));
178 	return p;
179 }
180 
181 #else
182 
183 #define getenv(s)	lcl_getenv(s)
184 
185 static char*
186 lcl_getenv(const char* s)
187 {
188 	int		n;
189 	static char	buf[512];
190 
191 	if (!(n = GetEnvironmentVariable(s, buf, sizeof(buf))) || n > sizeof(buf))
192 		return 0;
193 	return buf;
194 }
195 
196 #endif /* _UWIN */
197 
198 #endif /* _WINIX */
199 
200 #ifndef VMRECORD
201 #define VMRECORD(p)	(p)
202 #define VMBLOCK
203 #define VMUNBLOCK
204 #endif
205 
206 #if defined(__EXPORT__)
207 #define extern		extern __EXPORT__
208 #endif
209 
210 static int		_Vmflinit = 0;
211 #define VMFLINIT() \
212 	{ if(!_Vmflinit)	vmflinit(); \
213 	  if(_Vmdbcheck) \
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); \
219 	  } \
220 	}
221 
222 #if __STD_C
223 static int vmflinit(void)
224 #else
225 static int vmflinit()
226 #endif
227 {
228 	char*		file;
229 	int		line;
230 	Void_t*		func;
231 
232 	/* this must be done now to avoid any inadvertent recursion (more below) */
233 	_Vmflinit = 1;
234 	VMFLF(Vmregion,file,line,func);
235 
236 	/* if getenv() calls malloc(), the options may not affect the eventual region */
237 	VMOPTIONS();
238 
239 	/* reset file and line number to correct values for the call */
240 	Vmregion->file = file;
241 	Vmregion->line = line;
242 	Vmregion->func = func;
243 
244 	return 0;
245 }
246 
247 #if __STD_C
248 extern Void_t* calloc(reg size_t n_obj, reg size_t s_obj)
249 #else
250 extern Void_t* calloc(n_obj, s_obj)
251 reg size_t	n_obj;
252 reg size_t	s_obj;
253 #endif
254 {
255 	VMFLINIT();
256 	return VMRECORD((*Vmregion->meth.resizef)(Vmregion,NIL(Void_t*),n_obj*s_obj,VM_RSZERO));
257 }
258 
259 #if __STD_C
260 extern Void_t* malloc(reg size_t size)
261 #else
262 extern Void_t* malloc(size)
263 reg size_t	size;
264 #endif
265 {
266 	VMFLINIT();
267 	return VMRECORD((*Vmregion->meth.allocf)(Vmregion,size));
268 }
269 
270 #if __STD_C
271 extern Void_t* realloc(reg Void_t* data, reg size_t size)
272 #else
273 extern Void_t* realloc(data,size)
274 reg Void_t*	data;	/* block to be reallocated	*/
275 reg size_t	size;	/* new size			*/
276 #endif
277 {
278 #if USE_NATIVE
279 #undef	realloc
280 #if __STD_C
281 	extern Void_t*	realloc(Void_t*, size_t);
282 #else
283 	extern Void_t*	realloc();
284 #endif
285 #endif
286 
287 	VMFLINIT();
288 
289 #if _PACKAGE_ast
290 	if(data && Vmregion->meth.meth != VM_MTDEBUG &&
291 #if !USE_NATIVE
292 	   !(Vmregion->data->mode&VM_TRUST) &&
293 #endif
294 	   (*Vmregion->meth.addrf)(Vmregion,data) != 0 )
295 	{
296 #if USE_NATIVE
297 		return realloc(data, size);
298 #else
299 		Void_t*	newdata;
300 		if((newdata = (*Vmregion->meth.allocf)(Vmregion,size)) )
301 			memcpy(newdata,data,size);
302 		return VMRECORD(newdata);
303 #endif
304 	}
305 #endif
306 
307 #if USE_NATIVE
308 	{	Void_t*	newdata;
309 		if (newdata = (*Vmregion->meth.resizef)(Vmregion,data,size,VM_RSCOPY|VM_RSMOVE))
310 			return newdata;
311 		return VMRECORD(realloc(data, size));
312 	}
313 #else
314 	return VMRECORD((*Vmregion->meth.resizef)(Vmregion,data,size,VM_RSCOPY|VM_RSMOVE));
315 #endif
316 }
317 
318 #if __STD_C
319 extern void free(reg Void_t* data)
320 #else
321 extern void free(data)
322 reg Void_t*	data;
323 #endif
324 {
325 #if USE_NATIVE
326 #undef	free
327 #if __STD_C
328 	extern void	free(Void_t*);
329 #else
330 	extern void	free();
331 #endif
332 #endif
333 
334 	VMFLINIT();
335 
336 #if _PACKAGE_ast
337 	if(data && Vmregion->meth.meth != VM_MTDEBUG &&
338 #if !USE_NATIVE
339 	   !(Vmregion->data->mode&VM_TRUST) &&
340 #endif
341 	   (*Vmregion->meth.addrf)(Vmregion,data) != 0)
342 	{
343 #if USE_NATIVE
344 		free(data);
345 #endif
346 		return;
347 	}
348 #endif
349 
350 #if USE_NATIVE
351 	if ((*Vmregion->meth.freef)(Vmregion,data) != 0)
352 		free(data);
353 #else
354 	(void)(*Vmregion->meth.freef)(Vmregion,data);
355 #endif
356 }
357 
358 #if __STD_C
359 extern void cfree(reg Void_t* data)
360 #else
361 extern void cfree(data)
362 reg Void_t*	data;
363 #endif
364 {
365 	free(data);
366 }
367 
368 #if __STD_C
369 extern Void_t* memalign(reg size_t align, reg size_t size)
370 #else
371 extern Void_t* memalign(align, size)
372 reg size_t	align;
373 reg size_t	size;
374 #endif
375 {
376 	Void_t*	addr;
377 
378 	VMFLINIT();
379 	VMBLOCK
380 	addr = VMRECORD((*Vmregion->meth.alignf)(Vmregion,size,align));
381 	VMUNBLOCK
382 	return addr;
383 }
384 
385 #if __STD_C
386 extern int posix_memalign(reg Void_t **memptr, reg size_t align, reg size_t size)
387 #else
388 extern int posix_memalign(memptr, align, size)
389 reg Void_t**	memptr;
390 reg size_t	align;
391 reg size_t	size;
392 #endif
393 {
394 	Void_t	*mem;
395 
396 	if(align == 0 || (align%sizeof(Void_t*)) != 0 || ((align-1)&align) != 0 )
397 		return EINVAL;
398 
399 	if(!(mem = memalign(align, size)) )
400 		return ENOMEM;
401 
402 	*memptr = mem;
403 	return 0;
404 }
405 
406 #if __STD_C
407 extern Void_t* valloc(reg size_t size)
408 #else
409 extern Void_t* valloc(size)
410 reg size_t	size;
411 #endif
412 {
413 	VMFLINIT();
414 	GETPAGESIZE(_Vmpagesize);
415 	return VMRECORD((*Vmregion->meth.alignf)(Vmregion,size,_Vmpagesize));
416 }
417 
418 #if __STD_C
419 extern Void_t* pvalloc(reg size_t size)
420 #else
421 extern Void_t* pvalloc(size)
422 reg size_t	size;
423 #endif
424 {
425 	VMFLINIT();
426 	GETPAGESIZE(_Vmpagesize);
427 	return VMRECORD((*Vmregion->meth.alignf)(Vmregion,ROUND(size,_Vmpagesize),_Vmpagesize));
428 }
429 
430 #if !_PACKAGE_ast
431 #if __STD_C
432 char* strdup(const char* s)
433 #else
434 char* strdup(s)
435 char*	s;
436 #endif
437 {
438 	char	*ns;
439 	size_t	n;
440 
441 	if(!s)
442 		return NIL(char*);
443 	else
444 	{	n = strlen(s);
445 		if((ns = malloc(n+1)) )
446 			memcpy(ns,s,n+1);
447 		return ns;
448 	}
449 }
450 #endif /* _PACKAGE_ast */
451 
452 #if !_lib_alloca || _mal_alloca
453 #ifndef _stk_down
454 #define _stk_down	0
455 #endif
456 typedef struct _alloca_s	Alloca_t;
457 union _alloca_u
458 {	struct
459 	{	char*		addr;
460 		Alloca_t*	next;
461 	} head;
462 	char	array[ALIGN];
463 };
464 struct _alloca_s
465 {	union _alloca_u	head;
466 	Vmuchar_t	data[1];
467 };
468 
469 #if __STD_C
470 extern Void_t* alloca(size_t size)
471 #else
472 extern Void_t* alloca(size)
473 size_t	size;
474 #endif
475 {	char		array[ALIGN];
476 	char*		file;
477 	int		line;
478 	Void_t*		func;
479 	reg Alloca_t*	f;
480 	static Alloca_t* Frame;
481 
482 	VMFLINIT();
483 	VMFLF(Vmregion,file,line,func);
484 	while(Frame)
485 	{	if(( _stk_down && &array[0] > Frame->head.head.addr) ||
486 		   (!_stk_down && &array[0] < Frame->head.head.addr) )
487 		{	f = Frame;
488 			Frame = f->head.head.next;
489 			(void)(*Vmregion->meth.freef)(Vmregion,f);
490 		}
491 		else	break;
492 	}
493 
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);
498 
499 	f->head.head.addr = &array[0];
500 	f->head.head.next = Frame;
501 	Frame = f;
502 
503 	return (Void_t*)f->data;
504 }
505 #endif /*!_lib_alloca || _mal_alloca*/
506 
507 #if _map_malloc
508 
509 /* not sure of all the implications -- 0 is conservative for now */
510 #define USE_NATIVE	0	/* native free/realloc on non-vmalloc ptrs */
511 
512 #else
513 
514 /* intercept _* __* __libc_* variants */
515 
516 #if __lib__malloc
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); }
521 #if _lib_memalign
522 extern Void_t*	F2(_memalign, size_t,a, size_t,n) { return memalign(a, n); }
523 #endif
524 #if _lib_pvalloc
525 extern Void_t*	F1(_pvalloc, size_t,n) { return pvalloc(n); }
526 #endif
527 extern Void_t*	F2(_realloc, Void_t*,p, size_t,n) { return realloc(p, n); }
528 #if _lib_valloc
529 extern Void_t*	F1(_valloc, size_t,n) { return valloc(n); }
530 #endif
531 #endif
532 
533 #if _lib___malloc
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); }
538 #if _lib_memalign
539 extern Void_t*	F2(__memalign, size_t,a, size_t,n) { return memalign(a, n); }
540 #endif
541 #if _lib_pvalloc
542 extern Void_t*	F1(__pvalloc, size_t,n) { return pvalloc(n); }
543 #endif
544 extern Void_t*	F2(__realloc, Void_t*,p, size_t,n) { return realloc(p, n); }
545 #if _lib_valloc
546 extern Void_t*	F1(__valloc, size_t,n) { return valloc(n); }
547 #endif
548 #endif
549 
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); }
555 #if _lib_memalign
556 extern Void_t*	F2(__libc_memalign, size_t,a, size_t,n) { return memalign(a, n); }
557 #endif
558 #if _lib_pvalloc
559 extern Void_t*	F1(__libc_pvalloc, size_t,n) { return pvalloc(n); }
560 #endif
561 extern Void_t*	F2(__libc_realloc, Void_t*,p, size_t,n) { return realloc(p, n); }
562 #if _lib_valloc
563 extern Void_t*	F1(__libc_valloc, size_t,n) { return valloc(n); }
564 #endif
565 #endif
566 
567 #endif /* _map_malloc */
568 
569 #undef	extern
570 
571 #if _hdr_malloc /* need the mallint interface for statistics, etc. */
572 
573 #undef	calloc
574 #define calloc		______calloc
575 #undef	cfree
576 #define cfree		______cfree
577 #undef	free
578 #define free		______free
579 #undef	malloc
580 #define malloc		______malloc
581 #undef	pvalloc
582 #define pvalloc		______pvalloc
583 #undef	realloc
584 #define realloc		______realloc
585 #undef	valloc
586 #define valloc		______valloc
587 
588 #if !_UWIN
589 
590 #include	<malloc.h>
591 
592 typedef struct mallinfo Mallinfo_t;
593 typedef struct mstats Mstats_t;
594 
595 #endif
596 
597 #if defined(__EXPORT__)
598 #define extern		__EXPORT__
599 #endif
600 
601 #if _lib_mallopt
602 #if __STD_C
603 extern int mallopt(int cmd, int value)
604 #else
605 extern int mallopt(cmd, value)
606 int	cmd;
607 int	value;
608 #endif
609 {
610 	VMFLINIT();
611 	return 0;
612 }
613 #endif /*_lib_mallopt*/
614 
615 #if _lib_mallinfo && _mem_arena_mallinfo
616 #if __STD_C
617 extern Mallinfo_t mallinfo(void)
618 #else
619 extern Mallinfo_t mallinfo()
620 #endif
621 {
622 	Vmstat_t	sb;
623 	Mallinfo_t	mi;
624 
625 	VMFLINIT();
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;
632 	}
633 	return mi;
634 }
635 #endif /* _lib_mallinfo */
636 
637 #if _lib_mstats && _mem_bytes_total_mstats
638 #if __STD_C
639 extern Mstats_t mstats(void)
640 #else
641 extern Mstats_t mstats()
642 #endif
643 {
644 	Vmstat_t	sb;
645 	Mstats_t	ms;
646 
647 	VMFLINIT();
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;
655 	}
656 	return ms;
657 }
658 #endif /*_lib_mstats*/
659 
660 #undef	extern
661 
662 #endif/*_hdr_malloc*/
663 
664 #else
665 
666 /*
667  * even though there is no malloc override, still provide
668  * _ast_* counterparts for object compatibility
669  */
670 
671 #undef	calloc
672 extern Void_t*	calloc _ARG_((size_t, size_t));
673 
674 #undef	cfree
675 extern void	cfree _ARG_((Void_t*));
676 
677 #undef	free
678 extern void	free _ARG_((Void_t*));
679 
680 #undef	malloc
681 extern Void_t*	malloc _ARG_((size_t));
682 
683 #if _lib_memalign
684 #undef	memalign
685 extern Void_t*	memalign _ARG_((size_t, size_t));
686 #endif
687 
688 #if _lib_pvalloc
689 #undef	pvalloc
690 extern Void_t*	pvalloc _ARG_((size_t));
691 #endif
692 
693 #undef	realloc
694 extern Void_t*	realloc _ARG_((Void_t*, size_t));
695 
696 #if _lib_valloc
697 #undef	valloc
698 extern Void_t*	valloc _ARG_((size_t));
699 #endif
700 
701 #if defined(__EXPORT__)
702 #define extern		__EXPORT__
703 #endif
704 
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); }
709 #if _lib_memalign
710 extern Void_t*	F2(_ast_memalign, size_t,a, size_t,n) { return memalign(a, n); }
711 #endif
712 #if _lib_pvalloc
713 extern Void_t*	F1(_ast_pvalloc, size_t,n) { return pvalloc(n); }
714 #endif
715 extern Void_t*	F2(_ast_realloc, Void_t*,p, size_t,n) { return realloc(p, n); }
716 #if _lib_valloc
717 extern Void_t*	F1(_ast_valloc, size_t,n) { return valloc(n); }
718 #endif
719 
720 #undef	extern
721 
722 #if _hdr_malloc
723 
724 #undef	mallinfo
725 #undef	mallopt
726 #undef	mstats
727 
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
735 
736 #if !_UWIN
737 
738 #include	<malloc.h>
739 
740 typedef struct mallinfo Mallinfo_t;
741 typedef struct mstats Mstats_t;
742 
743 #endif
744 
745 #if defined(__EXPORT__)
746 #define extern		__EXPORT__
747 #endif
748 
749 #if _lib_mallopt
750 extern int	F2(_ast_mallopt, int,cmd, int,value) { return mallopt(cmd, value); }
751 #endif
752 
753 #if _lib_mallinfo && _mem_arena_mallinfo
754 extern Mallinfo_t	F0(_ast_mallinfo, void) { return mallinfo(); }
755 #endif
756 
757 #if _lib_mstats && _mem_bytes_total_mstats
758 extern Mstats_t		F0(_ast_mstats, void) { return mstats(); }
759 #endif
760 
761 #undef	extern
762 
763 #endif /*_hdr_malloc*/
764 
765 #endif /*!_std_malloc*/
766 
767 #if __STD_C
768 static Vmulong_t atou(char** sp)
769 #else
770 static Vmulong_t atou(sp)
771 char**	sp;
772 #endif
773 {
774 	char*		s = *sp;
775 	Vmulong_t	v = 0;
776 
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;
785 			else break;
786 		}
787 	}
788 	else
789 	{	for(; *s; ++s)
790 		{	if(*s >= '0' && *s <= '9')
791 				v = v*10 + (*s - '0');
792 			else break;
793 		}
794 	}
795 
796 	*sp = s;
797 	return v;
798 }
799 
800 #if __STD_C
801 static char* insertpid(char* begs, char* ends)
802 #else
803 static char* insertpid(begs,ends)
804 char*	begs;
805 char*	ends;
806 #endif
807 {	int	pid;
808 	char*	s;
809 
810 	if((pid = getpid()) < 0)
811 		return NIL(char*);
812 
813 	s = ends;
814 	do
815 	{	if(s == begs)
816 			return NIL(char*);
817 		*--s = '0' + pid%10;
818 	} while((pid /= 10) > 0);
819 	while(s < ends)
820 		*begs++ = *s++;
821 
822 	return begs;
823 }
824 
825 #if __STD_C
826 static int createfile(char* file)
827 #else
828 static int createfile(file)
829 char*	file;
830 #endif
831 {
832 	char	buf[1024];
833 	char	*next, *endb;
834 	int	fd;
835 
836 	next = buf;
837 	endb = buf + sizeof(buf);
838 	while(*file)
839 	{	if(*file == '%')
840 		{	switch(file[1])
841 			{
842 			case 'p' :
843 				if(!(next = insertpid(next,endb)) )
844 					return -1;
845 				file += 2;
846 				break;
847 			default :
848 				goto copy;
849 			}
850 		}
851 		else
852 		{ copy:
853 			*next++ = *file++;
854 		}
855 
856 		if(next >= endb)
857 			return -1;
858 	}
859 
860 	*next = '\0';
861 	file = buf;
862 	if (*file == '&' && *(file += 1) || strncmp(file, "/dev/fd/", 8) == 0 && *(file += 8))
863 		fd = dup((int)atou(&file));
864 	else if (*file)
865 #if _PACKAGE_ast
866 		fd = open(file, O_WRONLY|O_CREAT|O_TRUNC, CREAT_MODE);
867 #else
868 		fd = creat(file, CREAT_MODE);
869 #endif
870 	else
871 		return -1;
872 #if _PACKAGE_ast
873 #ifdef FD_CLOEXEC
874 	if (fd >= 0)
875 		fcntl(fd, F_SETFD, FD_CLOEXEC);
876 #endif
877 #endif
878 	return fd;
879 }
880 
881 #if __STD_C
882 static void pfprint(void)
883 #else
884 static void pfprint()
885 #endif
886 {
887 	if(Vmregion->meth.meth == VM_MTPROFILE)
888 		vmprofile(Vmregion,_Vmpffd);
889 }
890 
891 /*
892  * initialize runtime options from the VMALLOC_OPTIONS env var
893  */
894 
895 #define COPY(t,e,f)	while ((*t = *f++) && t < e) t++
896 
897 #if __STD_C
898 void _vmoptions(void)
899 #else
900 void _vmoptions()
901 #endif
902 {
903 	Vmalloc_t*	vm = 0;
904 	char*		trace = 0;
905 	char*		s;
906 	char*		t;
907 	char*		v;
908 	Vmulong_t	n;
909 	int		fd;
910 	char		buf[1024];
911 
912 	_Vmoptions = 1;
913 	t = buf;
914 	v = &buf[sizeof(buf)-1];
915 	if (s = getenv("VMALLOC_OPTIONS"))
916 		COPY(t, v, s);
917 #if 1 /* backwards compatibility until 2011 */
918 	else
919 	{
920 		char*	p;
921 
922 		if (s = getenv("VMDEBUG"))
923 		{
924 			switch (*s++)
925 			{
926 			case 0:
927 				break;
928 			case 'a':
929 				p = " abort";
930 				COPY(t, v, p);
931 				break;
932 			case 'w':
933 				p = " warn";
934 				COPY(t, v, p);
935 				break;
936 			case '0':
937 				if (*s-- == 'x')
938 				{
939 					p = " watch=";
940 					COPY(t, v, p);
941 					COPY(t, v, s);
942 					break;
943 				}
944 				/*FALLTHROUGH*/
945 			default:
946 				p = " period=";
947 				COPY(t, v, p);
948 				COPY(t, v, s);
949 				break;
950 			}
951 		}
952 		if ((s = getenv("VMETHOD")) && *s)
953 		{
954 			p = " method=";
955 			COPY(t, v, p);
956 			COPY(t, v, s);
957 		}
958 		if ((s = getenv("VMPROFILE")) && *s)
959 		{
960 			p = " profile=";
961 			COPY(t, v, p);
962 			COPY(t, v, s);
963 		}
964 		if ((s = getenv("VMTRACE")) && *s)
965 		{
966 			p = " trace=";
967 			COPY(t, v, p);
968 			COPY(t, v, s);
969 		}
970 	}
971 #endif
972 	if (t > buf)
973 	{
974 		*t = 0;
975 		s = buf;
976 		for (;;)
977 		{
978 			while (*s == ' ' || *s == '\t' || *s == '\r' || *s == '\n')
979 				s++;
980 			if (!*(t = s))
981 				break;
982 			v = 0;
983 			while (*s)
984 				if (*s == ' ' || *s == '\t' || *s == '\r' || *s == '\n')
985 				{
986 					*s++ = 0;
987 					break;
988 				}
989 				else if (!v && *s == '=')
990 				{
991 					*s++ = 0;
992 					if (!*(v = s))
993 						v = 0;
994 				}
995 				else
996 					s++;
997 			if (t[0] == 'n' && t[1] == 'o')
998 				continue;
999 			switch (t[0])
1000 			{
1001 			case 'a':		/* abort */
1002 				if (!vm)
1003 					vm = vmopen(Vmdcsbrk, Vmdebug, 0);
1004 				if (vm && vm->meth.meth == VM_MTDEBUG)
1005 					vmset(vm, VM_DBABORT, 1);
1006 				else
1007 					_Vmassert |= VM_abort;
1008 				break;
1009 			case 'c':		/* check */
1010 				_Vmassert |= VM_check;
1011 				break;
1012 			case 'm':
1013 				switch (t[1])
1014 				{
1015 				case 'e':	/* method=<method> */
1016 					if (v && !vm)
1017 					{
1018 						if ((v[0] == 'V' || v[0] == 'v') && (v[1] == 'M' || v[1] == 'm'))
1019 							v += 2;
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)
1027 							vm = Vmheap;
1028 					}
1029 					break;
1030 				case 'm':	/* mmap */
1031 #if _mem_mmap_anon || _mem_mmap_zero
1032 					_Vmassert |= VM_mmap;
1033 #endif
1034 					break;
1035 				}
1036 				break;
1037 			case 'p':
1038 				if (v)
1039 					switch (t[1])
1040 					{
1041 					case 'e':	/* period=<count> */
1042 						if (!vm)
1043 							vm = vmopen(Vmdcsbrk, Vmdebug, 0);
1044 						if (vm && vm->meth.meth == VM_MTDEBUG)
1045 							_Vmdbcheck = atou(&v);
1046 						break;
1047 					case 'r':	/* profile=<path> */
1048 						if (!vm)
1049 							vm = vmopen(Vmdcsbrk, Vmprofile, 0);
1050 						if (v && vm && vm->meth.meth == VM_MTPROFILE)
1051 							_Vmpffd = createfile(v);
1052 						break;
1053 					}
1054 				break;
1055 			case 'r':		/* region */
1056 				_Vmassert |= VM_region;
1057 				break;
1058 			case 's':		/* start=<count> */
1059 				if (!vm)
1060 					vm = vmopen(Vmdcsbrk, Vmdebug, 0);
1061 				if (v && vm && vm->meth.meth == VM_MTDEBUG)
1062 					_Vmdbstart = atou(&v);
1063 				break;
1064 			case 't':		/* trace=<path> */
1065 				trace = v;
1066 				break;
1067 			case 'w':
1068 				if (t[1] == 'a')
1069 					switch (t[2])
1070 					{
1071 					case 'r':	/* warn=<path> */
1072 						if (!vm)
1073 							vm = vmopen(Vmdcsbrk, Vmdebug, 0);
1074 						if (v && vm && vm->meth.meth == VM_MTDEBUG && (fd = createfile(v)) >= 0)
1075 							vmdebug(fd);
1076 						break;
1077 					case 't':	/* watch=<addr> */
1078 						if (!vm)
1079 							vm = vmopen(Vmdcsbrk, Vmdebug, 0);
1080 						if (v && vm && vm->meth.meth == VM_MTDEBUG && (n = atou(&v)) >= 0)
1081 							vmdbwatch((Void_t*)n);
1082 						break;
1083 					}
1084 				break;
1085 			}
1086 		}
1087 	}
1088 
1089 	/* slip in the new region now so that malloc() will work fine */
1090 
1091 	if (vm)
1092 	{
1093 		if (vm->meth.meth == VM_MTDEBUG)
1094 			_Vmdbcheck = 1;
1095 		Vmregion = vm;
1096 	}
1097 
1098 	/* enable tracing */
1099 
1100 	if (trace && (fd = createfile(trace)) >= 0)
1101 	{
1102 		vmset(Vmregion, VM_TRACE, 1);
1103 		vmtrace(fd);
1104 	}
1105 
1106 	/* make sure that profile data is output upon exiting */
1107 
1108 	if (vm && vm->meth.meth == VM_MTPROFILE)
1109 	{
1110 		if (_Vmpffd < 0)
1111 			_Vmpffd = 2;
1112 		/* this may wind up calling malloc(), but region is ok now */
1113 		atexit(pfprint);
1114 	}
1115 	else if (_Vmpffd >= 0)
1116 	{
1117 		close(_Vmpffd);
1118 		_Vmpffd = -1;
1119 	}
1120 }
1121 
1122 #endif /*_UWIN*/
1123