Here's a program that demonstrates the actual issue at hand. Basically, libgc finds the stack address from either glibc or the kernel, which is not what it wants because valgrind messes with the address space of the host program. This is only on Linux, but I understand the issue is similar on other BSD systems.
This is the Mono file that contains some workarounds (specifically mono/metadata/boehm-gc.c:mono_gc_base_init) . Contrary to the comments in the file the issue does not appear to be thread-related, although it is solved using pthread functionality. http://anonsvn.mono-project.com/viewvc/trunk/mono/mono/metadata/boehm-gc.c?view=log The attached program grabs the stack address from the kernel, glibc, and by taking the address of a stack object, then prints the difference. When run normally, the differences are minimal, but when run under valgrind, there is a giant difference between the base of the actual program and the base given by the kernel. Ideally, this would be patched in libgc, but we'd need a way to detect whether the program is running under valgrind and the current workaround would only work for threaded versions. I'm going to take a crack at libgc CVS later on.
/* demo valgrind program: cc -o demo demo.c */ #include <assert.h> #include <stddef.h> #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #define STAT_BUFFER_SIZE 4096 #define STAT_SKIP 27 extern ptrdiff_t __libc_stack_end; int main(void) { int dummy; /* lifted from os_dep.c in libgc */ char stat_buf[STAT_BUFFER_SIZE]; int f = open("/proc/self/stat", O_RDONLY); if(f < 0 || read(f, stat_buf, STAT_BUFFER_SIZE) < 2 * STAT_SKIP) { perror("/proc/self/stat"); return -1; } size_t buf_offset = 0; char c = stat_buf[buf_offset++]; size_t i; for(i = 0; i < STAT_SKIP; ++i) { while(isspace(c)) c = stat_buf[buf_offset++]; while(!isspace(c)) c = stat_buf[buf_offset++]; } while(isspace(c)) c = stat_buf[buf_offset++]; ptrdiff_t result = 0; while(isdigit(c)) { result *= 10; result += c - '0'; c = stat_buf[buf_offset++]; } close(f); printf("kernel stack base: %p\nlibc stack base: %p\ndumb stack base: %p\ndifference between kernel and dumb: %zd bytes\n", (void*) result, (void*) __libc_stack_end, (void*) &dummy, (void*) (result - (ptrdiff_t) &dummy)); }