これは、元のソース コードから抽出したコード サンプルです。コンパイルは正常に行われますが、ほぼランダムにクラッシュします。
#include <iostream>
#include <cstdio>
#include <cstring>
class base
{
public:
base() {}
virtual const char f(void) = 0 ;
};
class d1 : public base
{
static const char s = 15;
public:
d1()
{
}
const char f()
{
return s;
}
};
class d2 : public base
{
static const char n = 25;
public:
d2()
{
}
const char f()
{
return n;
}
};
void method(char* p, size_t len)
{
memset(p, 0, ((len * sizeof(char)) + 10));
}
int main(int argc, char **argv)
{
base *p = NULL;
if(argc == 2)
{
printf("p shall be instance of d2\n");
p = new d2();
}
else
{
printf("p shall be instance of d1\n");
p = new d1();
}
char arr[p->f()];
printf("Size of arr is %d\n", sizeof(arr));
method(arr, p->f());
}
GDB と Address Sanitizer ツールを使用したいくつかのデバッグ セッションの後、次のことがわかりました。
char arr[p->f()];
スタックの破損の原因は 1 つです。
p が実行時にインスタンス化され、配列サイズの宣言がコンパイル時に固定値で行われることを知っている場合、これはどのように文句なしにコンパイルされるのでしょうか? コンパイル時の p->f() の値は?
また、memset (「未定」配列サイズの余分な 10 バイトの書き込み) がセグメンテーション違反なしで実行されるのはなぜですか?