Получение нового несоответствия типа удаления из ASAN

Я скомпилировал свой код, используя -fsanitize=address, и получаю эту ошибку:

==53702==ERROR: AddressSanitizer: new-delete-type-mismatch on 0x60300000efe0 in thread T0:
  object passed to delete has wrong type:
  size of the allocated type:   24 bytes;
  size of the deallocated type: 1 bytes.
    #0 0x7fd544b7b0a0 in operator delete(void*, unsigned long) /home/user/objdir/../gcc-6.3.0/libsanitizer/asan/asan_new_delete.cc:108
    #1 0x4010c4 in foo() /home/user/asan.cpp:27
    #2 0x40117e in main /home/user/asan.cpp:33
    #3 0x7fd543e7082f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
    #4 0x400f48 in _start (/home/user/a.out+0x400f48)

Пример кода:

#include <memory>

struct T {
  T() : v(100) {}
  std::vector<int> v;
};

struct A {};

struct B : public A {
  T t;
};

int main() {
  A *a = new B;
  delete a;

  std::unique_ptr<A> a1 = std::make_unique<B>();

  return 0;
}

person mrks    schedule 09.01.2017    source источник


Ответы (1)


C++ неоднократно дает вам ощущение, что вы все еще не понимаете даже фундаментальных понятий. В данном случае: Наследование.

Добавив операторы печати к ctors и dtors, вы обнаружите, что для обоих указателей (старого стиля и умного указателя) вызывается только ~A, а не ~B. Это потому, что dtor A не является виртуальным.

Скотт Мейерс говорит: «Полиморфные базовые классы должны объявлять виртуальные деструкторы. Если класс имеет какие-либо виртуальные функции, он должен иметь виртуальный деструктор».

Исправьте это, добавив

struct A {
  virtual ~A() = default;
};
person mrks    schedule 09.01.2017
comment
Что я делаю: объявляю каждый класс, который я создаю, как final, и если я хочу получить его, мне нужно перейти к определению класса и удалить final. Тогда я (надеюсь: P) не забуду пометить деструктор как виртуальный. - person Rakete1111; 09.01.2017
comment
Соответствующая документация: удаление объекта с помощью указателя на базу вызывает неопределенное поведение, если только деструктор в базовом классе не является виртуальным [...] Общее правило заключается в том, что деструктор для базового класса должен быть либо общедоступным и виртуальным, либо защищенным и невиртуальным - en.cppreference.com/w/cpp/language/ - person talz; 27.05.2021