Ошибка сегментации gcc 6.1.0 — ошибка gcc?

Давайте рассмотрим следующий код. На самом деле это узкая проблема, которую я нашел, используя метод gmock и mocking void (void).

class Base {
public:
virtual ~Base() {}
};

class Derived : public Base
{
public:
void GetValueAndDelete()  { delete this; } //here we crash
};

int main() {
Derived* p = 0;
p->GetValueAndDelete();
}

Строя это с:

/tools/gcc6.1/bin/g++ --version
g++ (GCC) 6.1.0

с уровнем оптимизации, отличным от -O0, и выполнение результата вызывает ошибку сегментации.

Это ошибка GCC или что-то с кодом C ++ (да, да, я знаю, что он использует побочные эффекты, но он работает с другими компиляторами и без оптимизации)

0

Решение

Это ошибка GCC

Нет.

или что-то с кодом C ++

Да. Вы используете оператор стрелки на указателе, который не указывает на допустимый объект. Это имеет неопределенное поведение.

Разыменование нулевого указателя и вызывающего метода таким способом, который не использует никаких членов, это хорошо.

Это не отлично в соответствии со стандартом. Это UB.

Что вызывает метод по указателю?

Это конкретная реализация.

Удаление это ничего особенного.

Удаление this это очень особенное.

Вы должны позаботиться о том, чтобы не использовать какой-либо член после

Да это а также Вы должны убедиться, что только new был использован для создания всех экземпляров, для которых функция когда-либо вызывалась. Нет автоматических объектов, нет статических объектов нет new[]нет malloc + размещение нового.

Так что да, ты Можно delete this, но будь осторожен.

4

Другие решения

Ваша интуиция здесь выглядит так:

  1. p-> все в порядке, потому что это просто синтаксис для заполнения this,
  2. delete this в порядке, потому что вы не используете this после delete,

Но вышеприведенное может не соответствовать действительности, потому что разыменование нулевого указателя — это всегда неопределенное поведение. Без включенной оптимизации это может не вызвать никаких проблем, потому что компилятор выполняет «базовую компиляцию», которая в некоторой степени соответствует тому, что вы представляете, когда «компилируете в своем уме». Однако с оптимизацией GCC сделает много вещей, которые он обычно не делал бы, например, не потрудившись выдавать «правильные» инструкции, когда сталкивался с неверным исходным кодом. Там буквально не нужно ничего делать, когда вы говорите p-> как первый акт вашей программы — он может просто притворяться main() был пуст (или вылет, как в вашем случае).

2

Я знаю, что вызов метода для nullptr не соответствует стандарту, но до сих пор я не видел компилятора, который бы не справился с этим описанным способом. Кажется, что gcc6.1 работает по-другому (все еще согласно спецификации). Так что это ошибка Gmock. Интересно, сколько других проектов зависит от такого поведения компилятора 🙂

Стоит упомянуть, что метод вызывается, «this» внутри равно нулю, как и ожидалось, и затем удаление завершается неудачно. Я посмотрел на сборку и есть mov (% rax),% rbx, который не работает, потому что rax содержит ноль.

0
По вопросам рекламы [email protected]