Skip to content

Instantly share code, notes, and snippets.

@submachine
Created February 16, 2015 23:37
Show Gist options
  • Save submachine/3eb356045cf1d9ed1cea to your computer and use it in GitHub Desktop.
Save submachine/3eb356045cf1d9ed1cea to your computer and use it in GitHub Desktop.
A program that tests valgrind's '--max-stackframe' option on an x86-64 running Linux
/*
$ gcc -Wall -pedantic -o test-stack-switching test-stack-switching.c
$ valgrind ./test-stack-switching
Expected program output:
> 55
> 55
> 55
Expected valgrind output: Three warnings that look like;
> client switching stacks? SP change: 0xffefff880 --> 0x5101b78
*/
#include <stdio.h>
#include <stdlib.h>
#define STACK_SIZE 2500000
int buf[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
__attribute__ ((noreturn))
void callee (int *);
__attribute__ ((noreturn))
void call_on_new_stack (char *, void (*)(int *), int *);
char *prepare_new_stack (void);
int
main (void)
{
char *new_stack;
new_stack = prepare_new_stack ();
call_on_new_stack (new_stack, callee, buf);
return 0;
}
void
callee (int *arr)
{
int i, sum = 0;
static int remaining_calls = 2;
char *new_stack;
for (i = 0; i < 10; i++)
{
sum += arr[i];
}
printf ("%d\n", sum);
if (remaining_calls--)
{
new_stack = prepare_new_stack ();
call_on_new_stack (new_stack, callee, buf);
}
exit (0);
}
void
call_on_new_stack (char *stack, void (*f) (int *), int *arg)
{
asm ("movq %rdi, %rsp\n\t" /* Set stack. */
"pushq $0\n\t" /* Return address is 0, we'll never return. */
"movq %rdx, %rdi\n\t" /* arg for f. */
"pushq %rsi\n\t" /* push function addr for use by 'ret' insn. */
"ret\n\t" /* this will pop 'f's addr and execute it. */
"ud2"); /* invalid opcode. Should never be executed. */
exit (0);
}
char *
prepare_new_stack (void)
{
static char *block = NULL;
static char *stacks[3];
static int call_count = 0;
if (!block)
{
block = malloc (4 * STACK_SIZE);
/* We expect three calls, each in a new stack. */
stacks[0] = block + 2 * STACK_SIZE;
stacks[1] = block + 3 * STACK_SIZE; /* Guarantees huge increase in sp. */
stacks[2] = block + 1 * STACK_SIZE; /* Guarantees huge decrease in sp. */
}
return stacks[call_count++];
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment