/***********************************************************************
* *
* This software is part of the ast package *
* Copyright (c) 1985-2012 AT&T Intellectual Property *
* and is licensed under the *
* Eclipse Public License, Version 1.0 *
* by AT&T Intellectual Property *
* *
* A copy of the License is available at *
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
* *
* Information and Software Systems Research *
* AT&T Research *
* Florham Park NJ *
* *
* Glenn Fowler <gsf@research.att.com> *
* David Korn <dgk@research.att.com> *
* Phong Vo <kpv@research.att.com> *
* *
***********************************************************************/
void _STUB_malloc(){}
#else
#if _UWIN
extern int atexit(void(*)(void));
extern char* getenv(const char*);
#endif
#include "vmhdr.h"
#include <errno.h>
#if _UWIN
#include <malloc.h>
#endif
#if __STD_C
#else
#endif
/*
* define _AST_std_malloc=1 to force the standard malloc
* if _map_malloc is also defined then _ast_malloc etc.
* will simply call malloc etc.
*/
#if !defined(_AST_std_malloc) && __CYGWIN__
#endif
/* malloc compatibility functions
**
** VMALLOC_OPTIONS environment variable which is a comma or space
** separated list of [no]name[=value] options:
**
** abort if Vmregion==Vmdebug then VM_DBABORT is set,
** otherwise _BLD_DEBUG enabled assertions abort()
** on failure
** break try sbrk() block allocator first
** check if Vmregion==Vmbest then the region is checked every op
** free disable addfreelist()
** keep disable free -- if code works with this enabled then it
** probably accesses free'd data
** method=m sets Vmregion=m if not defined, m (Vm prefix optional)
** may be one of { best debug last profile }
** mmap try mmap() block allocator first
** period=n sets Vmregion=Vmdebug if not defined, if
** Vmregion==Vmdebug the region is checked every n ops
** profile=f sets Vmregion=Vmprofile if not set, if
** Vmregion==Vmprofile then profile info printed to file f
** start=n sets Vmregion=Vmdebug if not defined, if
** Vmregion==Vmdebug region checking starts after n ops
** trace=f enables tracing to file f
** warn=f sets Vmregion=Vmdebug if not defined, if
** Vmregion==Vmdebug then warnings printed to file f
** watch=a sets Vmregion=Vmdebug if not defined, if
** Vmregion==Vmdebug then address a is watched
**
** the file descriptor n which must be open for writing. The pattern %p
** in a file name is replaced by the process ID.
**
** VMALLOC_OPTIONS combines the features of these previously used env vars:
** { VMCHECK VMDEBUG VMETHOD VMPROFILE VMTRACE }
**
** Written by Kiem-Phong Vo, kpv@research.att.com, 01/16/94.
*/
#if _sys_stat
#endif
#include <fcntl.h>
#ifdef S_IRUSR
#else
#endif
#if !_map_malloc
#if _malloc_hook
#include <malloc.h>
#endif
#endif
#if _WINIX
#include <ast_windows.h>
#if _UWIN
extern int _sigblock(void);
extern void _sigunblock(int);
extern unsigned long _record[2048];
{
register unsigned long v = ((unsigned long)p)>>16;
return p;
}
#else
static char*
lcl_getenv(const char* s)
{
int n;
return 0;
return buf;
}
#endif /* _UWIN */
#endif /* _WINIX */
#ifndef VMRECORD
#define VMRECORD(p) (p)
#define VMBLOCK
#define VMUNBLOCK
#endif
#if defined(__EXPORT__)
#define extern extern __EXPORT__
#endif
static int _Vmflinit = 0;
#define VMFLINIT() \
if(_Vmdbcheck) \
} \
}
#if __STD_C
static int vmflinit(void)
#else
static int vmflinit()
#endif
{
char* file;
int line;
/* this must be done now to avoid any inadvertent recursion (more below) */
_Vmflinit = 1;
/* if getenv() calls malloc(), the options may not affect the eventual region */
VMOPTIONS();
/* reset file and line number to correct values for the call */
return 0;
}
/* use multiple regions to reduce blocking by concurrent threads */
#if _mem_mmap_anon || _mem_mmap_zero
#else
static unsigned int Regmax = 0;
#endif
/* statistics */
{
return oldmax;
}
/* return statistics */
{
int k;
return -1;
for(k = 0; k < Regnum; ++k)
{ if(!Region[k])
continue;
return -1;
}
return 0;
}
/* find the region that a block was allocated from */
{
int k;
#if USE_NATIVE
#else
#define CAUTIOUS 0
#endif
{ /* addr will not be dereferenced here */
return Vmregion;
for(k = 0; k < Regnum; ++k)
return Region[k];
}
else
{ /* fast, but susceptible to bad data */
return Vmregion;
for(k = 0; k < Regnum; ++k)
return Region[k];
}
}
/* manage a cache of free objects */
typedef struct _regfree_s
} Regfree_t;
{
unsigned int k;
for(k = 0;; ASOLOOP(k) )
return;
}
}
static void clrfreelist()
{
return; /* nothing to do */
return; /* somebody else is doing it */
}
}
}
}
/* get a suitable region to allocate from */
typedef struct _regdisc_s
} Regdisc_t;
{
{ if(data) /* make vmopen allocate all memory using discipline */
return 0;
}
return 0;
}
{
int p, pos;
clrfreelist();
if(Regmax <= 0 )
{ /* uni-process/thread */
*local = 1;
return Vmregion;
}
{ /* Vmregion is open, so use it */
*local = 1;
return Vmregion;
}
if(Regnum == 0)
pos = 0;
{ *local = 1;
return Region[p];
}
break;
}
/* grab the next open slot for a new region */
break;
if(p < Regmax) /* this slot is now ours */
}
*local = 1;
}
}
/* must return something */
{ *local = 1;
}
else
{ *local = 0;
}
return vm;
}
#if __STD_C
#else
#endif
{
int local = 0;
VMFLINIT();
if(local)
}
}
#if __STD_C
#else
#endif
{
int local = 0;
VMFLINIT();
if(local)
}
}
#if __STD_C
#else
#endif
{
VMFLINIT();
if(!data)
}
}
}
else /* this may block but it is the best that we can do now */
}
}
else /* not our data */
{
#if USE_NATIVE
#if __STD_C
#else
#endif
#else
#endif
}
}
#if __STD_C
#else
#endif
{
VMFLINIT();
return;
{
return;
}
else /* not our data */
{
#if USE_NATIVE
#if __STD_C
#else
extern void free();
#endif
#endif
return;
}
}
#if __STD_C
#else
#endif
{
}
#if __STD_C
#else
#endif
{
int local = 0;
VMFLINIT();
if(local)
}
}
#if __STD_C
#else
#endif
{
return EINVAL;
return ENOMEM;
return 0;
}
#if __STD_C
#else
#endif
{
VMFLINIT();
}
#if __STD_C
#else
#endif
{
VMFLINIT();
}
#if !_PACKAGE_ast
#if __STD_C
char* strdup(const char* s)
#else
char* strdup(s)
char* s;
#endif
{
char *ns;
size_t n;
if(!s)
return NIL(char*);
else
{ n = strlen(s);
return ns;
}
}
#endif /* _PACKAGE_ast */
#if !_lib_alloca || _mal_alloca
#ifndef _stk_down
#define _stk_down 0
#endif
union _alloca_u
{ struct
{ char* addr;
} head;
};
struct _alloca_s
};
#if __STD_C
#else
#endif
char* file;
int line;
Alloca_t* f;
VMFLINIT();
while(Frame) /* free unused frames */
/* else: something bad happened. just keep going */
}
else break;
}
/* if f is NULL, this mimics a stack overflow with a memory error! */
Frame = f;
}
#endif /*!_lib_alloca || _mal_alloca*/
#if _map_malloc
/* not sure of all the implications -- 0 is conservative for now */
#else
#if _malloc_hook
{
}
{
void* r;
return r;
}
{
void* r;
return r;
}
{
void* r;
return r;
}
static void vm_initialize_hook(void)
{
}
#if 0 /* 2012-02-29 this may be needed to cover shared libs */
{
}
#endif
#else
/* intercept _* __* __libc_* variants */
#if __lib__malloc
#if _lib_memalign
#endif
#if _lib_pvalloc
#endif
#if _lib_valloc
#endif
#endif
#if _lib___malloc
#if _lib_memalign
#endif
#if _lib_pvalloc
#endif
#if _lib_valloc
#endif
#endif
#if _lib_memalign
#endif
#if _lib_pvalloc
#endif
#if _lib_valloc
#endif
#endif
#endif /* _malloc_hook */
#endif /* _map_malloc */
#undef extern
#if _hdr_malloc /* need the mallint interface for statistics, etc. */
#if !_UWIN
#include <malloc.h>
#endif
#if defined(__EXPORT__)
#define extern __EXPORT__
#endif
#if _lib_mallopt
#if __STD_C
#else
int cmd;
int value;
#endif
{
VMFLINIT();
return 0;
}
#endif /*_lib_mallopt*/
#if _lib_mallinfo && _mem_arena_mallinfo
#if __STD_C
#else
extern Mallinfo_t mallinfo()
#endif
{
VMFLINIT();
}
return mi;
}
#endif /* _lib_mallinfo */
#if __STD_C
#else
#endif
{
VMFLINIT();
}
return ms;
}
#endif /*_lib_mstats*/
#undef extern
#endif/*_hdr_malloc*/
#else
/*
* even though there is no malloc override, still provide
* _ast_* counterparts for object compatibility
*/
#define setregmax(n)
#if _lib_memalign
#endif
#if _lib_pvalloc
#endif
#if _lib_valloc
#endif
#if defined(__EXPORT__)
#define extern __EXPORT__
#endif
#if !_malloc_hook
#if _lib_memalign
#endif
#endif
#if _lib_pvalloc
#endif
#if _lib_valloc
#endif
#undef extern
#if _hdr_malloc
#if !_UWIN
#if !_malloc_hook
#include <malloc.h>
#endif
#endif
#if defined(__EXPORT__)
#define extern __EXPORT__
#endif
#if _lib_mallopt
#endif
#if _lib_mallinfo && _mem_arena_mallinfo
#endif
#endif
#undef extern
#endif /*_hdr_malloc*/
#endif /*!_std_malloc*/
#if __STD_C
#else
char** sp;
#endif
{
char* s = *sp;
Vmulong_t v = 0;
if(s[0] == '0' && (s[1] == 'x' || s[1] == 'X') )
{ for(s += 2; *s; ++s)
{ if(*s >= '0' && *s <= '9')
v = (v << 4) + (*s - '0');
else if(*s >= 'a' && *s <= 'f')
v = (v << 4) + (*s - 'a') + 10;
else if(*s >= 'A' && *s <= 'F')
v = (v << 4) + (*s - 'A') + 10;
else break;
}
}
else
{ for(; *s; ++s)
{ if(*s >= '0' && *s <= '9')
v = v*10 + (*s - '0');
else break;
}
}
*sp = s;
return v;
}
#if __STD_C
#else
char* begs;
char* ends;
#endif
{ int pid;
char* s;
return NIL(char*);
s = ends;
do
{ if(s == begs)
return NIL(char*);
} while((pid /= 10) > 0);
while(s < ends)
*begs++ = *s++;
return begs;
}
#if __STD_C
#else
int fd;
#endif
{
int pd;
if (fd >= 0)
{
{
}
#ifdef FD_CLOEXEC
#endif
}
return fd;
}
#if __STD_C
#else
static int createfile(file)
char* file;
#endif
{
int fd;
while(*file)
{ if(*file == '%')
{ switch(file[1])
{
case 'p' :
return -1;
file += 2;
break;
default :
goto copy;
}
}
else
{ copy:
}
return -1;
}
*next = '\0';
else if (*file)
{
#if _PACKAGE_ast
#else
#endif
}
else
return -1;
#if _PACKAGE_ast
#ifdef FD_CLOEXEC
if (fd >= 0)
#endif
#endif
return fd;
}
#if __STD_C
static void pfprint(void)
#else
static void pfprint()
#endif
{
}
/*
* initialize runtime options from the VMALLOC_OPTIONS env var
*/
#define COPY(t,e,f) while ((*t = *f++) && t < e) t++
#if __STD_C
void _vmoptions(void)
#else
void _vmoptions()
#endif
{
char* trace = 0;
char* s;
char* t;
char* v;
Vmulong_t n;
int fd;
_Vmoptions = 1;
t = buf;
if (s = getenv("VMALLOC_OPTIONS"))
COPY(t, v, s);
if (t > buf)
{
*t = 0;
s = buf;
for (;;)
{
while (*s == ',' || *s == ' ' || *s == '\t' || *s == '\r' || *s == '\n')
s++;
if (!*(t = s))
break;
v = 0;
while (*s)
if (*s == ',' || *s == ' ' || *s == '\t' || *s == '\r' || *s == '\n')
{
*s++ = 0;
break;
}
else if (!v && *s == '=')
{
*s++ = 0;
if (!*(v = s))
v = 0;
}
else
s++;
if (t[0] == 'n' && t[1] == 'o')
continue;
switch (t[0])
{
case 'a': /* abort */
if (!vm)
else
break;
case 'b': /* break */
break;
case 'c': /* check */
break;
case 'f': /* free */
break;
case 'k': /* keep */
break;
case 'm':
if (v)
switch (t[1])
{
case 'e': /* method=METHOD */
if (!vm)
{
if ((v[0] == 'V' || v[0] == 'v') && (v[1] == 'M' || v[1] == 'm'))
v += 2;
if (strcmp(v, "debug") == 0)
else if (strcmp(v, "profile") == 0)
else if (strcmp(v, "last") == 0)
else if (strcmp(v, "best") == 0)
}
break;
case 'm': /* mmap */
break;
}
break;
case 'p':
if (v)
switch (t[1])
{
case 'e': /* period=<count> */
if (!vm)
_Vmdbcheck = atou(&v);
break;
case 'r': /* profile=<path> */
if (!vm)
_Vmpffd = createfile(v);
break;
}
break;
case 's': /* start=<count> */
if (!vm)
_Vmdbstart = atou(&v);
break;
case 't': /* trace=<path> */
trace = v;
break;
case 'w':
if (t[1] == 'a')
switch (t[2])
{
case 'r': /* warn=<path> */
if (!vm)
break;
case 't': /* watch=<addr> */
if (!vm)
break;
}
break;
}
}
}
/* slip in the new region now so that malloc() will work fine */
if (vm)
{
_Vmdbcheck = 1;
}
/* enable tracing -- this currently disables multiple regions */
if (trace)
{
setregmax(0);
{
}
}
setregmax(0);
/* make sure that profile data is output upon exiting */
{
if (_Vmpffd < 0)
_Vmpffd = 2;
/* this may wind up calling malloc(), but region is ok now */
}
else if (_Vmpffd >= 0)
{
_Vmpffd = -1;
}
}
/*
* ast semi-private workaround for system functions
* that misbehave by passing bogus addresses to free()
*
* not prototyped in any header to keep it ast semi-private
*
* to keep malloc() data by disabling free()
* extern _vmkeep(int);
* int r = _vmkeep(1);
* and to restore to the previous state
* (void)_vmkeep(r);
*/
int
#if __STD_C
_vmkeep(int v)
#else
_vmkeep(v)
int v;
#endif
{
int r;
if (v)
else
return r;
}
#endif /*_UWIN*/