Ошибка сегментации в новом операторе - PullRequest
0 голосов
/ 05 марта 2020

обновление : ошибка сегментации все еще существует после исправления malloc(sizeof(500))

Я сталкиваюсь с ошибкой сегментации в следующем коде:

#include <iostream>
#include <vector>
#include <functional>

struct Data {
  std::string name;

  std::function<int()> work;

  std::vector<int*> v1 {nullptr, nullptr, nullptr, nullptr};
  std::vector<int*> v2 {nullptr, nullptr, nullptr, nullptr};

  int* v3 {nullptr};
  int* v4 {nullptr};
};

int main() {
  std::cout << sizeof(Data) << "\n";   // Just to make sure sizeof(Data) < 500

  auto raw = malloc(500);      // Allocate memory

  auto int_ptr = static_cast<int*>(raw);
  int_ptr ++; 

  auto ptr = reinterpret_cast<Data*>(int_ptr);
  new (ptr) Data();                     // GDB reports segmentation fault here

  free(raw);
}

Команда компиляции:

clang++-9 -std=c++14 -stdlib=libc++ -ggdb3 prog.cpp -lc++abi -O2

Я думаю, что память должна быть достаточно большой, чтобы хранить Data, но почему в new?

происходит ошибка сегментации

Ответы [ 3 ]

4 голосов
/ 05 марта 2020

Ваша проблема здесь:

auto raw = malloc(sizeof(500)); 

'500' - это целое число, поэтому sizeof(500) возвращает 4. Я думаю, что вы хотели сделать:

auto raw = malloc(500); 

Не связано, но Вы можете захотеть сделать:

  auto int_ptr = static_cast<int*>(raw);
  int_ptr += 2; 

Просто чтобы указатели оставались выровненными по 8 байт (при условии, что вы используете 64-битную ОС) . А также, не забудьте позвонить в dtor до вызова free (иначе у вас утечка памяти)

ptr->~Data();
1 голос
/ 05 марта 2020

Как правило, ваш код имеет неопределенное поведение из-за неправильного выравнивания . Я попытаюсь объяснить это на следующем примере.

Давайте предположим, что вы работаете на 64-битной архитектуре с 4-байтовым int. В таких системах malloc обычно дает 16-байтовый выровненный фрагмент памяти. Затем, когда вы добавляете 4 байта к этой границе (raw плюс 4 байта), результирующий адрес (ptr) выравнивается на 4 байта, но не выравнивается ни на 8 байтов, ни на 16 байтов.

Теперь Data имеет некоторое естественное выравнивание, очень вероятно, 8 байтов. Вы можете узнать это по выражению alignof(Data). Когда вы пытаетесь создать объект типа Data на 4-байтовом выровненном адресе, это приводит к неопределенному поведению .


Также, как указали другие, вы необходимо вручную вызвать деструктор для объекта, созданного с помощью размещения new .

0 голосов
/ 05 марта 2020

Если вы пишете на C ++, обычно не очень хорошо использовать mallo c. Вы можете использовать вектор в качестве буфера или создать массив символов.

int main() {
  std::vector<char> buffer(500);

  auto ptr = reinterpret_cast<Data*>(buffer.data());
  new (ptr) Data;   
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...