1

プログラムの特定の時点でプログラムのスタックとヒープを保存 (および復元) するにはどうすればよいですか?

次のようなプログラムを考えてみましょう:

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;
}

出力は次のようになります。

1 2

要するに (そうですか?): スタックとヒープへのポインターとそのサイズを取得するにはどうすればよいですか?

編集

これは色々と使いたいと思います。そのうちの 1 つは、チェックポイントを設定し、チェックポイントが設定された状態で再起動できるようにすることで、ハードウェア障害を処理できるコードを作成することです。

スタックに注目しましょう。ヒープ割り当ては別の方法で追跡できます (たとえば、古き良き malloc プリロード)。

コードは再利用可能でなければなりません。スタックには、可能な数とタイプの変数が存在する可能性があります。

標準の C99 が最適です。次善の Posix 準拠。次善の Linux 準拠。

私は通常GCCを使用していますが、組み込みを使用したくない...

4

3 に答える 3

1
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;
}
于 2013-09-20T14:57:26.900 に答える
1

あなたは達成しようとしていることの範囲をあまり示していませんが、私はいくつかの視点と、少なくともあなたが始めることができる何かに取り組みます.

要するに (そうですか?): スタックとヒープへのポインターとそのサイズを取得するにはどうすればよいですか?

スタックは大きなものであり、多くの場合、サイズを拡張できます。すべてのヒープを保存するのに苦労するので、ヒープ ビットをスキップします (意味がありません)。スタックへのポインターを取得するのは、変数を宣言してその参照を取得するのと同じくらい簡単です。

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

ただし、これはスタックのベース アドレスではありません。多くのメソッド、さらには API がある可能性があることを知りたい場合 (Windows にはあると思います)。ページ フォールトが発生するまで、スタック上のアドレスから両方向に移動することもできます。これは、スタックの開始と終了を示す可能性があります。以下は動作する可能性がありますが、保証はありません。アプリがクラッシュしないように、ページ フォールトを処理する例外ハンドラーを設定する必要があります。

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

そのため、スタックのベース アドレスとエンド アドレスがわかっている場合は、それをメモリに memcpy できます (ただし、スタックは使用しないことをお勧めします!)。

いくつかの変数だけをコピーしたい場合、スタック全体をコピーするのはおかしいので、従来の方法は呼び出しの前にそれらを保存することです

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

スタック上に 10,000 個の変数を持つ関数を作成しており、それらすべてを手動で保存する必要はないと仮定します。この場合、以下が機能するはずです。を使用_AddressOfReturnAddressして、現在の関数スタックの可能な限り高いアドレスを取得し、いくつかのスタック メモリを割り当てて、現在の最小値を取得します。次に、その間のすべてをコピーします。

免責事項: これは編集されておらず、すぐに使用できる可能性は低いですが、理論は正しいと思います。

// 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);

あなたの質問の限られた情報で私が提供できるのはこれくらいです。

于 2013-09-20T16:12:44.767 に答える
0

この場合、変数名 a と b を再利用しようとしていると思いますか? 別のスコープで同じ名前の新しい変数を宣言する必要があります!

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
}
于 2013-09-20T15:27:15.770 に答える