Это пример кода, который мне удалось извлечь из исходного исходного кода, который компилируется чисто, но вылетает более или менее случайным образом:
#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 байтов «неопределенного» размера массива) работает без ошибки сегментации?
Вот почему вы всегда должны компилировать с включенными предупреждениями. В этом случае соответствующим является:
main.cpp:66:20: warning: ISO C++ forbids variable length array 'arr' [-Wvla]
char arr[p->f()];
^
(Обратите внимание, что есть и другие предупреждения, это только соответствующее). Массивы переменной длины разрешены gcc как расширение, поэтому ваш код скомпилирован. Но если бы вы видели это предупреждение, вероятно, вы бы приняли другое решение. -Wall -Wextra
твой друг.
Кроме того, почему memset (запись дополнительных 10 байтов «неопределенного» размера массива) работает без ошибки сегментации?
Неопределенное поведение не определено, оно не обязательно требует ошибки сегментации.
Других решений пока нет …