简体   繁体   中英

How to save stack and heap

How can I save (and restore) the stack and the heap of a program at a specific point in the program?

Consider a program like this:

int main()
{
  int a;
  int *b;
  b = (int*)malloc(sizeof(int))
  a = 1;
  *b = 2;
  save_stack_and_heap(); // looking for this...
  a = 3;
  *b = 4;
  restore_stack_and_heap() // ... and this
  printf("%d %d\n",a,*b);
  return 0;
}

The output should be:

1 2

It boils down to (am I right?): How do I get the pointers to the stack and to the heap and their sizes?

edit

I want to use this for a number of things. One of them is to write code that can handle hardware failure by checkpointing and being able to restart at a checkpointed state.

Let's focus on the stack, as heap allocations can be tracked otherwise (good old malloc preload for instance).

The code should be reusable. There can be any possible number and type of variables on the stack.

The best would be standard C99. Next best Posix conform. Next best Linux conform.

I am usually using GCC but I would prefer not to use built ins...

int main()
{
    int a = 1;
    int *b = malloc(sizeof(int));
    *b = 2;
    if (fork() == 0) {
        a = 3;
        *b = 4;
        return 0;
    }
    int status;
    wait(&status);
    printf("%d %d\n",a,*b);
    return 0;
}

So you haven't given a lot of scope of what you are trying to achieve but I will try and tackle a few perspectives and at least something that can get you started.

It boils down to (am I right?): How do I get the pointers to the stack and to the heap and their sizes?

The stack is a large thing, and often expandable in size. I'm going to skip the heap bit as you are going to struggle to save all the heaps (that kinda doesn't make any sense). Getting a pointer to the stack is as easy as declaring a variable and taking a reference to it like so.

int a = 5;
void *stack_ptr = &a;
void *another_stack_ptr = &stack_ptr;
// We could could go on forever with this....

That is not the base address of the stack however. If you want to find that there may be many methods, and even API's (I think there is on Windows). You can even just walk in both directions from an address on the stack until you get a page fault. That is likely to mark the beginning and end of the stack. The following might work, no guarantees. You will need to set up an exception handler to handle the page fault so your app doesn't crash.

int variable = 5;
int *stack_start = &variable;
int *stack_end = stack_start;

int *last_good_address = NULL;
// Setup an exception handler
...
// Try accessing addresses lower than the variable address
for(;;)
{
    int try_read = stack_start[0];
    // The read didn't trigger an exception, so store the address
    last_good_address = stack_start
    stack_start--;
}

// Catch exception
... stack_start = last_good_address


// Setup an exception handler
...
// Try accessing addresses higher than the variable address
for(;;)
{
    int try_read = stack_end[0];
    // The read didn't trigger an exception, so store the address
    last_good_address = stack_end
    stack_end--;
}
// Catch exception
... stack_end = last_good_address

So if you have the base and end address of the stack you can now memcpy it into some memory (I'd advise against the stack though!).

If you just want to copy a few variables, because copying the entire stack would be crazy, the conventional method would be to save them prior to a call

int a = 5;
int b = 6;
int c = 7;

// save old values
int a_old = a;
int b_old = b;
int c_old = c;

some_call(&a, &b, &c);

// do whatever with old values

I'll assume that you have written a function that has 10,000 variables on the stack, and you don't want to have to save them all manually. The following should work in this case. It uses _AddressOfReturnAddress to get the highest possible address for the current functions stack and allocates some stack memory to get the lowest current value. It then copies everything in between.

Disclaimer: This has not been compiled, and is unlikely to work out of the box, but I believe the theory is sound.

// Get the address of the return address, this is the highest address in the current stack frame.
// If you over-write this you are in trouble
char *end_of_function_stack = _AddressOfReturnAddress();
// Allocate some fresh memory on the stack
char *start_of_function_stack = alloca(16);

// Calculate the difference between our freshly allocated memory and the address of the return address
// Remember to subtract the size of our allocation from this to not include it in the stack size.
ptrdiff_t stack_size = (end_of_function_stack - start_of_function_stack) - 16);

// Calculation should not be negative 
assert(stack_size > 0)
// Allocate some memory to save stack variables
void *save_the_stack = malloc(stack_size);

// Copy the variables
memcpy(save_the_stack, &start_of_function_stack[16], stack_size);

That's about all I can offer you with the limited information in your question.

I think you're looking to reuse the variable names a and b in this case? You should declare new variable of the same name on different scope!

int main()
{
    int a=1;
    int *b = (int*)malloc(sizeof(int));
    *b=2;
    {
        int a=3;
        int *b = (int*)malloc(sizeof(int));
        *b=4
    }//beware, other lang such as C# may persist stack variables after this point
    //old a,b should be reachable here
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM