Getting gc leak-detector to work on linux. Non-nspr changes. code=beard,wade r=warren

This commit is contained in:
warren%netscape.com 2000-08-11 00:13:39 +00:00
Родитель 0a7bf6c176
Коммит 80ee64b1e3
17 изменённых файлов: 315 добавлений и 78 удалений

Просмотреть файл

@ -55,13 +55,13 @@ DIRS += \
$(NULL)
endif
DIRS += $(NSPRPUB_DIR)
# boehm needs to be built before XPCOM
ifdef GC_LEAK_DETECTOR
DIRS += gc/boehm
endif
DIRS += $(NSPRPUB_DIR)
DIRS += dbm modules/libreg js xpcom js/src/xpconnect
ifdef MOZ_OJI

Просмотреть файл

@ -5,3 +5,4 @@ NO_MDUPDATE=@MOZ_NSPRENV_NO_MDUPDATE@
NS_USE_NATIVE=@MOZ_NSPRENV_NS_USE_NATIVE@
MOZILLA_CLIENT=@MOZ_NSPRENV_MOZILLA_CLIENT@
CLASSIC_NSPR=@MOZ_NSPRENV_CLASSIC_NSPR@
GC_LEAK_DETECTOR=@MOZ_NSPRENV_GC_LEAK_DETECTOR@

5
configure поставляемый
Просмотреть файл

@ -9900,7 +9900,6 @@ if test "${enable_tests+set}" = set; then
fi
MOZ_MONOLITHIC_TOOLKIT=1
case "$target" in
@ -11611,6 +11610,8 @@ then
MOZ_NSPRENV_USE_PTHREADS=$USE_PTHREADS
MOZ_NSPRENV_GC_LEAK_DETECTOR=$GC_LEAK_DETECTOR
MOZ_NSPRENV_CLASSIC_NSPR=
case "$target" in
*-linux*)
@ -11670,6 +11671,7 @@ esac
fi
@ -12076,6 +12078,7 @@ s%@MOZ_NSPRENV_MOZILLA_CLIENT@%$MOZ_NSPRENV_MOZILLA_CLIENT%g
s%@MOZ_NSPRENV_CLASSIC_NSPR@%$MOZ_NSPRENV_CLASSIC_NSPR%g
s%@MOZ_NSPRENV_DIST@%$MOZ_NSPRENV_DIST%g
s%@MOZ_NSPRENV_OVERRIDE_MAKE@%$MOZ_NSPRENV_OVERRIDE_MAKE%g
s%@MOZ_NSPRENV_GC_LEAK_DETECTOR@%$MOZ_NSPRENV_GC_LEAK_DETECTOR%g
s%@MOZ_DEFINES@%$MOZ_DEFINES%g
CEOF

Просмотреть файл

@ -3939,6 +3939,11 @@ dnl Same as detected above.
dnl
MOZ_NSPRENV_USE_PTHREADS=$USE_PTHREADS
dnl
dnl GC_LEAK_DETECTOR
dnl
MOZ_NSPRENV_GC_LEAK_DETECTOR=$GC_LEAK_DETECTOR
dnl
dnl CLASSIC_NSPR
dnl
@ -4037,6 +4042,7 @@ AC_SUBST(MOZ_NSPRENV_MOZILLA_CLIENT)
AC_SUBST(MOZ_NSPRENV_CLASSIC_NSPR)
AC_SUBST(MOZ_NSPRENV_DIST)
AC_SUBST(MOZ_NSPRENV_OVERRIDE_MAKE)
AC_SUBST(MOZ_NSPRENV_GC_LEAK_DETECTOR)
fi
dnl ========================================================

Просмотреть файл

@ -27,12 +27,17 @@ include $(DEPTH)/config/autoconf.mk
MODULE=boehm
LIBRARY_NAME=boehm
DEFINES += -DATOMIC_UNCOLLECTABLE -DNO_SIGNALS -DNO_EXECUTE_PERMISSION -DALL_INTERIOR_POINTERS -DSILENT -DLARGE_CONFIG
DEFINES += -DNO_SIGNALS -DNO_EXECUTE_PERMISSION -DALL_INTERIOR_POINTERS -DLARGE_CONFIG
DEFINES += -DREDIRECT_MALLOC=GC_malloc
# Define following when attempting to take over ALL calls to malloc/free. For now just
# intercepting new/delete to concentrate on making collector work on Linux.
#DEFINES += -DREDIRECT_MALLOC=GC_MALLOC_UNCOLLECTABLE
DEFINES += -DREDIRECT_MALLOC=GC_MALLOC
#DEFINES += -DSILENT
ifeq ($(OS_ARCH),Linux)
DEFINES += -DLINUX_THREADS -D_REENTRANT
#DEFINES += -DLINUX_THREADS -D_REENTRANT
DEFINES += -DTHREADS -DGENERIC_THREADS -D_REENTRANT -DGC_DEBUG -DFIND_LEAK -DOPERATOR_NEW_ARRAY -DSAVE_CALL_CHAIN -DUSE_PROC
endif
ifdef ($(OS_ARCH)$(OS_RELEASE),SUNOS5)
DEFINES += -DSOLARIS_THREADS -D_SOLARIS_PTHREADS -D_REENTRANT
@ -83,4 +88,6 @@ LOBJS := $(LCPPSRCS:.cc=.$(OBJ_SUFFIX))
include $(topsrcdir)/config/rules.mk
export::
make install

Просмотреть файл

@ -408,6 +408,10 @@ GC_PTR p;
register GC_PTR base = GC_base(p);
register ptr_t clobbered;
/* ignore free(NULL) */
if (p == 0)
return;
if (base == 0) {
GC_err_printf1("Attempt to free invalid pointer %lx\n",
(unsigned long)p);

Просмотреть файл

@ -260,7 +260,76 @@ void GC_register_dynamic_libraries()
# endif /* !USE_PROC ... */
# endif /* SUNOS */
#if defined(LINUX) && defined(__ELF__) || defined(SCO_ELF)
#if defined(LINUX) && defined(USE_PROC)
#include <fcntl.h>
#include <unistd.h>
#define BUFSIZE 32000
/* Register all possible root segments using kernel proces info read
from /proc. This adds every read/write piece of the virtual address
space to the root set, so it does more than register dynamic
libraries */
void GC_register_dynamic_libraries()
{
int mapfile;
char *fname = "/proc/self/maps";
unsigned int start, end, offset, inode;
char perms[10], path[512];
static char buffer[BUFSIZE];
int e;
GC_printf0("[[register mmap data start.]]\n");
memset(buffer,0,BUFSIZE);
mapfile = open(fname, O_RDONLY); /* Don't use fopen - it mallocs */
offset = 0;
do {
e = read(mapfile, buffer + offset, BUFSIZE - offset - 1);
offset = offset + e;
} while (e > 0);
if (offset >= (BUFSIZE - 1)) {
ABORT("map buffer too small\n");
} else {
int result, count;
char *next = buffer;
close(mapfile);
buffer[offset] = '\0';
do {
result = sscanf(next,
"%x-%x %s %x %*s %d %n",
&start, &end, perms, &offset, &inode, &count);
next = next + count;
if (result > 0) {
char *c = strstr(perms, "rw");
int isroot = (c != 0);
/* GC_printf6("%8x-%8x %s %8x device %8d %d",
start, end, perms, offset, inode, isroot); */
if (inode != 0) {
result = sscanf(next, "%s\n%n", path, &count);
next = next + count;
} else {
strcpy(path, "mmap zero"); /* dumb... */
}
GC_printf3("[[registering roots %8x-%8x for mmap: %s]]\n",
start, end, path);
if (isroot) {
GC_add_roots_inner((char *)start, (char *)end, TRUE);
}
}
} while (result > 0);
}
GC_printf0("[[register mmap data finish.]]\n");
}
#endif
#if defined(LINUX) && !defined(USE_PROC)
/* This code shouldn't be used anymore - the /proc version is more complete */
/* Dynamic loading code for Linux running ELF. Somewhat tested on
* Linux/x86, untested but hopefully should work on Linux/Alpha.
@ -311,6 +380,8 @@ void GC_register_dynamic_libraries()
struct link_map *lm = GC_FirstDLOpenedLinkMap();
GC_printf0("[[register dynamic libraries start.]]\n");
for (lm = GC_FirstDLOpenedLinkMap();
lm != (struct link_map *) 0; lm = lm->l_next)
{
@ -320,6 +391,8 @@ void GC_register_dynamic_libraries()
char * start;
register int i;
GC_printf1("[[registering roots for library: %s]]\n", lm->l_name);
e = (ElfW(Ehdr) *) lm->l_addr;
p = ((ElfW(Phdr) *)(((char *)(e)) + e->e_phoff));
offset = ((unsigned long)(lm->l_addr));
@ -336,7 +409,12 @@ void GC_register_dynamic_libraries()
break;
}
}
/* as a hack, register the link_map itself as a root. */
GC_add_roots_inner(lm, lm + 1, TRUE);
}
GC_printf0("[[register dynamic libraries finish.]]\n");
}
#endif

Просмотреть файл

@ -26,11 +26,15 @@ Authors: John R. Ellis and Jesse Hull
#include "gc_cpp.h"
void* operator new( size_t size ) {
return GC_MALLOC_UNCOLLECTABLE( size );}
void* operator new( size_t size )
{
return GC_MALLOC( size );
}
void operator delete( void* obj ) {
GC_FREE( obj );}
void operator delete( void* obj )
{
GC_FREE( obj );
}
#ifdef _MSC_VER
// This new operator is used by VC++ in case of Debug builds !
@ -49,11 +53,15 @@ void* operator new( size_t size,
#ifdef OPERATOR_NEW_ARRAY
void* operator new[]( size_t size ) {
return GC_MALLOC_UNCOLLECTABLE( size );}
void* operator new[]( size_t size )
{
return GC_MALLOC( size );
}
void operator delete[]( void* obj ) {
GC_FREE( obj );}
void operator delete[]( void* obj )
{
GC_FREE( obj );
}
#endif /* OPERATOR_NEW_ARRAY */

Просмотреть файл

@ -441,6 +441,7 @@ void GC_print_callers (/* struct callinfo info[NFRAMES] */);
# define UNLOCK() mutex_unlock(&GC_allocate_ml);
# endif
# ifdef LINUX_THREADS
#error "DADDY?"
# include <pthread.h>
# ifdef __i386__
inline static int GC_test_and_set(volatile unsigned int *addr) {

Просмотреть файл

@ -661,7 +661,7 @@
# endif
# ifdef LINUX
# define OS_TYPE "LINUX"
# define STACKBOTTOM ((ptr_t)0xc0000000)
# define STACKBOTTOM ((ptr_t)0xbffffb44) /* address of argv */
/* Appears to be 0xe0000000 for at least one 2.1.91 kernel. */
/* Probably needs to be more flexible, but I don't yet */
/* fully understand how flexible. */

Просмотреть файл

@ -1,10 +1,10 @@
/*
generic_threads.c
A module that permits clients of the GC to supply callback functions
for thread stack scanning.
by Patrick C. Beard.
generic_threads.c
A module that permits clients of the GC to supply callback functions
for thread stack scanning.
by Patrick C. Beard.
*/
#include "generic_threads.h"
@ -13,10 +13,14 @@
static void mark_range(char* begin, char* end)
{
while (begin < end) {
GC_PUSH_ONE_STACK(*(word*)begin, 0);
begin += ALIGNMENT;
}
/* use the mark stack API, which will do more sanity checking. */
GC_push_all(begin, end);
/*
while (begin < end) {
GC_PUSH_ONE_STACK(*(word*)begin, 0);
begin += ALIGNMENT;
}
*/
}
/*
@ -27,9 +31,9 @@ static void mark_range(char* begin, char* end)
static void default_mark_all_stacks(GC_mark_range_proc marker)
{
#ifdef STACK_GROWS_DOWN
mark_range(GC_approx_sp(), GC_get_stack_base());
mark_range(GC_approx_sp(), GC_get_stack_base());
#else
mark_range(GC_get_stack_base(), GC_approx_sp());
mark_range(GC_get_stack_base(), GC_approx_sp());
#endif
}
@ -43,34 +47,34 @@ GC_generic_proc GC_generic_stopper = &default_proc;
GC_generic_proc GC_generic_starter = &default_proc;
void GC_generic_init_threads(GC_generic_mark_all_stacks_proc mark_all_stacks,
void* mutex,
GC_generic_proc locker, GC_generic_proc unlocker,
GC_generic_proc stopper, GC_generic_proc starter)
void* mutex,
GC_generic_proc locker, GC_generic_proc unlocker,
GC_generic_proc stopper, GC_generic_proc starter)
{
GC_generic_mark_all_stacks = mark_all_stacks;
GC_generic_mutex = mutex;
GC_generic_locker = locker;
GC_generic_unlocker = unlocker;
GC_generic_stopper = stopper;
GC_generic_starter = starter;
GC_generic_mark_all_stacks = mark_all_stacks;
GC_generic_mutex = mutex;
GC_generic_locker = locker;
GC_generic_unlocker = unlocker;
GC_generic_stopper = stopper;
GC_generic_starter = starter;
GC_dont_expand = 1;
// GC_set_max_heap_size(20L * 1024L * 1024L);
GC_dont_expand = 1;
// GC_set_max_heap_size(20L * 1024L * 1024L);
}
#if !defined(WIN32_THREADS) && !defined(LINUX_THREADS)
void GC_push_all_stacks()
{
GC_generic_mark_all_stacks(&mark_range);
GC_generic_mark_all_stacks(&mark_range);
}
void GC_stop_world()
{
GC_generic_stopper(GC_generic_mutex);
GC_generic_stopper(GC_generic_mutex);
}
void GC_start_world()
{
GC_generic_starter(GC_generic_mutex);
GC_generic_starter(GC_generic_mutex);
}
#endif /* WIN32_THREADS */

Просмотреть файл

@ -14,6 +14,8 @@
/* Boehm, February 7, 1996 4:32 pm PST */
#include <stdio.h>
#include <signal.h>
#include "gc_priv.h"
extern ptr_t GC_clear_stack(); /* in misc.c, behaves like identity */
@ -354,7 +356,7 @@ int obj_kind;
size_t lb;
# endif
{
return(GC_realloc(p, lb));
return(GC_REALLOC(p, lb));
}
# endif /* REDIRECT_MALLOC */
@ -429,7 +431,16 @@ int obj_kind;
# endif
{
# ifndef IGNORE_FREE
GC_free(p);
GC_FREE(p);
# endif
}
# endif /* REDIRECT_MALLOC */
/* fake __mmap() */
__ptr_t
__mmap (__ptr_t addr, size_t len, int prot, int flags, int fd, off_t offset)
{
raise(SIGINT);
return NULL;
}

Просмотреть файл

@ -437,7 +437,7 @@ void GC_mark_from_mark_stack()
# define SPLIT_RANGE_WORDS 128 /* Must be power of 2. */
GC_objects_are_marked = TRUE;
# ifdef OS2 /* Use untweaked version to circumvent compiler problem */
# if defined(OS2) /* Use untweaked version to circumvent compiler problem */
while (GC_mark_stack_top_reg >= GC_mark_stack_reg && credit >= 0) {
# else
while ((((ptr_t)GC_mark_stack_top_reg - (ptr_t)GC_mark_stack_reg) | credit)

Просмотреть файл

@ -858,7 +858,35 @@ void GC_print_callers(struct callinfo info[NFRAMES])
}
}
#endif /* NFRAMES > 1 */
#endif /* NFRAMES > 2 */
#elif defined(LINUX)
#define __USE_GNU
#include <dlfcn.h>
#include "call_tree.h"
void GC_print_callers(struct callinfo info[NFRAMES])
{
register int i;
call_tree* current_tree;
Dl_info dlinfo;
/* static char symbol_name[1024], unmangled_name[1024], file_name[256]; */
current_tree = (call_tree*)(info[0].ci_pc);
GC_err_printf0("Callers at location:\n");
while (current_tree && current_tree->pc) {
if (dladdr(current_tree->pc, &dlinfo) >= 0) {
GC_err_printf4("%s[%s,0x%08X,0x%08X]\n", dlinfo.dli_sname, dlinfo.dli_fname, current_tree->pc, dlinfo.dli_saddr);
} else {
/* pc2name((word)current_tree->pc, symbol_name, sizeof(symbol_name)); */
/* MWUnmangle(symbol_name, unmangled_name, sizeof(unmangled_name)); */
GC_err_printf2("%s(%08X)\n", "(unknown)", current_tree->pc);
}
current_tree = current_tree->parent;
}
}
#else

Просмотреть файл

@ -1862,6 +1862,7 @@ word len;
((ptr_t)end_block - (ptr_t)start_block) + HBLKSIZE);
}
#if 0
#ifndef MSWIN32
/* Replacement for UNIX system call. */
/* Other calls that write to the heap */
@ -1902,6 +1903,8 @@ word len;
return(result);
}
#endif /* !MSWIN32 */
#endif
/*ARGSUSED*/
GC_bool GC_page_was_ever_dirty(h)
@ -2392,3 +2395,86 @@ void GC_save_callers(struct callinfo info[NFRAMES])
#endif
#endif /* POWERPC && MACOS */
#if defined(SAVE_CALL_CHAIN) && defined(LINUX)
#include <setjmp.h>
#include "call_tree.h"
typedef struct stack_frame stack_frame;
#if defined(__i386)
struct stack_frame {
stack_frame* next;
void* pc;
};
static stack_frame* getStackFrame()
{
jmp_buf jb;
stack_frame* currentFrame;
setjmp(jb);
currentFrame = (stack_frame*)(jb[0].__jmpbuf[JB_BP]);
currentFrame = currentFrame->next;
return currentFrame;
}
#endif /* __i386 */
static call_tree* find_tree(stack_frame* frame)
{
/* primordial root of the call tree. */
static call_tree root = { 0, 0, 0, 0 };
long pc = (long)frame->pc;
if ((pc < 0x08000000) || (pc > 0x7fffffff) || (frame->next < frame)) {
return &root;
} else {
call_tree* parent = find_tree(frame->next);
call_tree** link = &parent->children;
call_tree* tree = *link;
while (tree != NULL) {
if (tree->pc == frame->pc)
break;
link = &tree->siblings;
tree = *link;
}
if (tree == NULL) {
/* no tree exists for this frame, so we create one. */
tree = (call_tree*) GC_scratch_alloc(sizeof(call_tree));
if (tree != NULL) {
tree->pc = frame->pc;
tree->parent = parent;
tree->siblings = parent->children;
parent->children = tree;
tree->children = NULL;
}
} else {
if (parent->children != tree) {
/* splay tree to front of list. */
*link = tree->siblings;
tree->siblings = parent->children;
parent->children = tree;
}
}
return tree;
}
}
void GC_save_callers(struct callinfo info[NFRAMES])
{
stack_frame* currentFrame;
call_tree* currentTree;
currentFrame = getStackFrame(); // GC_save_callers's frame.
currentFrame = currentFrame->next; // GC_debug_malloc's frame.
currentFrame = currentFrame->next; // GC_debug_malloc's caller's frame.
currentTree = find_tree(currentFrame);
info[0].ci_pc = (word) currentTree;
}
#endif /* defined(SAVE_CALL_CHAIN) && defined(LINUX) */

Просмотреть файл

@ -109,36 +109,36 @@ register word sz;
- WORDS_TO_BYTES(sz));
/* go through all words in block */
while( p <= plim ) {
if( mark_bit_from_hdr(hhdr, word_no) ) {
p += sz;
} else {
FOUND_FREE(hbp, word_no);
INCR_WORDS(sz);
while( p <= plim ) {
if( mark_bit_from_hdr(hhdr, word_no) ) {
p += sz;
} else {
FOUND_FREE(hbp, word_no);
INCR_WORDS(sz);
#if !defined(FIND_LEAK) || 1
if (GC_root_size) {
/* object is available - put on list */
obj_link(p) = list;
list = ((ptr_t)p);
/* Clear object, advance p to next object in the process */
q = p + sz;
p++; /* Skip link field */
while (p < q) {
*p++ = 0;
}
} else {
/* roots gone, just advance. */
p += sz;
}
#else
/* let leaks accumulate. */
p += sz;
#endif
}
word_no += sz;
if (GC_root_size) {
/* object is available - put on list */
obj_link(p) = list;
list = ((ptr_t)p);
/* Clear object, advance p to next object in the process */
q = p + sz;
p++; /* Skip link field */
while (p < q) {
*p++ = 0;
}
} else {
/* roots gone, just advance. */
p += sz;
}
#else
/* let leaks accumulate. */
p += sz;
#endif
}
word_no += sz;
}
# ifdef GATHERSTATS
GC_mem_found += n_words_found;
GC_mem_found += n_words_found;
# endif
return(list);
}

Просмотреть файл

@ -271,6 +271,11 @@ nsresult NS_COM NS_InitXPCOM(nsIServiceManager* *result,
rv = servMgr->RegisterService(kComponentManagerCID, NS_STATIC_CAST(nsIComponentManager*, compMgr));
if (NS_FAILED(rv)) return rv;
#ifdef GC_LEAK_DETECTOR
rv = NS_InitLeakDetector();
if (NS_FAILED(rv)) return rv;
#endif
// 3. Register the global services with the component manager so that
// clients can create new objects.
@ -305,11 +310,6 @@ nsresult NS_COM NS_InitXPCOM(nsIServiceManager* *result,
return rv;
}
#ifdef GC_LEAK_DETECTOR
rv = NS_InitLeakDetector();
if (NS_FAILED(rv)) return rv;
#endif
rv = RegisterGenericFactory(compMgr, kMemoryCID,
NS_MEMORY_CLASSNAME,
NS_MEMORY_PROGID,