Bug 9750 - nscd gc() segmentation fault by estimation failure of alloca()'s stack usage
Summary: nscd gc() segmentation fault by estimation failure of alloca()'s stack usage
Status: RESOLVED FIXED
Alias: None
Product: glibc
Classification: Unclassified
Component: nscd (show other bugs)
Version: unspecified
: P2 normal
Target Milestone: ---
Assignee: Ulrich Drepper
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2009-01-16 11:42 UTC by Jun'ichi Nomura
Modified: 2014-07-01 21:19 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Jun'ichi Nomura 2009-01-16 11:42:33 UTC
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.
Comment 1 Ulrich Drepper 2009-01-29 00:18:28 UTC
I've fixed that in cvs by using real stack use information for x86-64.
Comment 2 Jun'ichi Nomura 2009-01-29 04:31:19 UTC
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__"?
Comment 3 Jun'ichi Nomura 2009-01-29 05:24:31 UTC
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++;
	}
}
----------------------------------------------------------------------------
Comment 4 Jun'ichi Nomura 2009-01-29 05:27:56 UTC
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, };
Comment 5 Ulrich Drepper 2009-02-07 04:29:35 UTC
Don't attach comments without keeping the bug FIXED.