The garbage collection function, gc(), estimates the stack usage to switch the allocation method. For the allocation of 'struct moveinfo', it adds the size given to alloca(). http://sourceware.org/cgi-bin/cvsweb.cgi/libc/nscd/mem.c.diff?r1=1.3.2.8&r2=1.3.2.9&cvsroot=glibc In fucntion gc(): new_move = alloca (sizeof (*new_move)); stack_used += sizeof (*new_move); However, alloca() seems to allocate additional +16 bytes for each allocation in my case (Fedora 9, x86_64). As a result, the estimation gets wrong and gc() ends up to segmentation fault. Simply summing up the extra 16 bytes to the estimation would solve the problem. Or if there is a better method to determine the current stack usage, it might be better to switch the whole estimation stuff to use that.
I've fixed that in cvs by using real stack use information for x86-64.
Thank you for the fix on x86_64, but I confirmed the same problem occurs on i386 system. (alloca() pads the extra 16 bytes on Fedora 9 i386, too. May also on other archs but I don't have machines to check with.) Could you put a "%%esp" version of the stackinfo_get_sp/stackinfo_sub_sp macros to sysdeps/i386, too? http://sources.redhat.com/cgi-bin/cvsweb.cgi/libc/sysdeps/x86_64/stackinfo.h.diff?r1=1.1&r2=1.2&cvsroot=glibc Also, the following fallback macro in alloca.h doesn't compile anyway: # define alloca_account(size, avar) \ ({ size_t s__ = (size); \ avar += size__; \ __alloca (size__); }) http://sources.redhat.com/cgi-bin/cvsweb.cgi/libc/include/alloca.h.diff?r1=1.8&r2=1.9&cvsroot=glibc Should "s__" be "size__"?
In case anyone have archs other than i386/x86_64, try the following test program to see whether the default alloca_account works. ---------------------------------------------------------------------------- #include <stdio.h> #include <alloca.h> #if !defined(alloca_account) #define alloca_account(size, avar) \ ({ size_t size__ = (size); \ avar += size__; \ alloca (size__); }) #endif int test_alloc_size[] = { 4, 8, 16, 32, 48, 64, 100, }; void test_alloca(size_t sz) { int i; char *cur, *prev; int stk_usage = 0, stk_usage_real = 0; printf("unit allocation size = %d\n", sz); prev = alloca(sz); for (i = 0; i < 3; i++) { cur = alloca_account(sz, stk_usage); stk_usage_real += prev - cur; prev = cur; printf("# [%d] stack used: %d (accounted as %d)\n", i, stk_usage_real, stk_usage); } if (stk_usage != stk_usage_real) printf("FAIL: accounted usage differs from the real usage\n"); else printf("PASS\n"); printf("\n"); } int main(int argc, char **argv) { int n = 0; while (test_alloc_size[n]) { test_alloca(test_alloc_size[n]); n++; } } ----------------------------------------------------------------------------
Oops, sorry. In the previous comment, this: int test_alloc_size[] = { 4, 8, 16, 32, 48, 64, 100, }; should be: int test_alloc_size[] = { 4, 8, 16, 32, 48, 64, 100, 0, };
Don't attach comments without keeping the bug FIXED.