这是我设法从可以干净编译但或多或少随机方式崩溃的原始源代码中提取的代码示例:
#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()];
是堆栈损坏的罪魁祸首。
知道 p 在运行时实例化并且数组大小声明是在编译时以固定值完成的,如何编译而不抱怨?编译时 p->f() 的值是多少?
此外,为什么 memset(写入额外 10 个字节的“未确定”数组大小)运行时没有分段错误?