/*-------------------------------------------------------------------------- 
 Demonstration of problem with -fcheck-stack in gcc
 Most of the complexity in this demo is to demonstrate that -fcheck-stack
 is working properly for user-created threads.  The bug is only
 in the main thread.  Workaround: be extremely sparing of stack space
 in the main thread if you want your program to work with -fcheck-stack.

 case 1: bug
 To reproduce, compile with -fcheck-stack and run under gdb.
 It will crash not where you expect it, but immediately on
 startup!  You can remove everything but main(), foo, and exit,
 and it will still crash.

 case 2: normal
 Reduce the size of the 'foo' array in main to 2000 bytes, compile with
 -fcheck-stack, and run under gdb.  A SIGSEGV will be generated on the
 first call to threadMain, as intended.

 case 3: normal
 With the size of the 'foo' array in main still 2000 bytes as in case 2, 
 compile without -fcheck-stack, and run under gdb.  A SIGSEGV will 
 be generated on the second call to threadMain.  This 
 indicates that -fcheck-stack properly helps locate thread stack
 overruns early.
--------------------------------------------------------------------------*/

#include <pthread.h>
#include <assert.h>

#define MYSTACKSIZE (1<<18)

/* A thread function that uses two pages more stack
 * than the stack size.  Assuming this program uses
 * the default single guard page, this will not trigger
 * a SIGSEGV unless stack checks are turned on with
 * -fstack-check.
 * This works properly; -fstack-check catches the problem
 * sooner!
 */
void *threadMain(void *arg)
{
	char foo[MYSTACKSIZE + 2*4096];
	return threadMain(arg);
}

int main(int argc, char **argv)
{
	/* Here's the rub: the main thread seems to only have a 4K stack! */
	/* Increasing foo much past 2000 causes a segfault. */
	char foo[4017];
	int err;
	pthread_t thr;
	pthread_attr_t attrs;

	pthread_attr_init(&attrs);
	err = pthread_attr_setstacksize(&attrs, MYSTACKSIZE);
	assert(err == 0);
	err = pthread_create(&thr, &attrs, threadMain, 0);
	assert(err == 0);
	sleep(2);
	exit(0);
}
