简体   繁体   English

如何保存堆栈和堆

[英]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). 让我们集中讨论堆栈,因为否则可以跟踪堆分配(例如,良好的旧malloc预加载)。

The code should be reusable. 该代码应可重用。 There can be any possible number and type of variables on the stack. 堆栈上可以有任何数量和类型的变量。

The best would be standard C99. 最好的是标准的C99。 Next best Posix conform. 次佳的Posix符合。 Next best Linux conform. 次佳的Linux标准。

I am usually using GCC but I would prefer not to use built ins... 我通常使用GCC,但我不希望使用内置插件...

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). 如果您想发现可能有很多方法,甚至还有API(我认为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. 我假设您已经编写了一个在堆栈上具有10,000个变量的函数,并且您不想手动保存所有变量。 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. 它使用_AddressOfReturnAddress获取当前函数堆栈的最高可能地址,并分配一些堆栈内存以获取最低的当前值。 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? 我认为您正在寻找在这种情况下重用变量名a和b的方法? 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
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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