CLang: Запуск функции в std :: thread вызывает BAD_ACCESS при создании структуры

Недавно я перешел с Kubuntu 16.04 на Mac OS High Sierra и начал портировать части кода, с которым я работаю на регулярной основе. Среди них библиотека обёрток C ++ для libsctp-dev.

Я использую Расширение ядра SCTP иметь тот же API SCTP, что и на моей машине с Linux. Хотя вызовы API не создают проблем, использование потоков, предоставляемых стандартной библиотекой C ++, похоже, создает проблемы. Проблема может быть найдена в следующих фрагментах кода:

void Server::start(int32_t port) {
//This allocates the socket with the SCTP protocol assigned
Receiver::start();
//This function now binds the desired port to the created socket
this->_bind(port);

//Here I register handlers for network events that can occur
this->notificationHandler.setAssocChangeHandler(std::bind(&Server::handleAssocChange, this, _1));
this->notificationHandler.setShutdownEventHandler(std::bind(&Server::handleShutdownEvent, this, _1));
this->notificationHandler.setSendFailedHandler(std::bind(&Server::handleSendFailed, this, _1));

//This is the interesting part - this will lead to BAD_ACCESS
//exceptions in the receive function
dummy = this;
this->receiveThread = std::thread(dummyReceive);

//However, if I run it in the same thread, everything works fine
//(except that I need the receive loop to run in a separate thread)
//dummyReceive();

//This is the original call, I just used the dummy function to be
//sure that the bind function does not create the problem
//this->receiveThread = std::thread(std::bind(&Server::receive, this));
}

Это та часть, где определяется функция dummyReceive:

Server *dummy = NULL;
void dummyReceive(){
dummy->receive();
}

Наконец, это код метода приема (сервер является подклассом Receiver, который, в свою очередь, является подклассом конечной точки):

void Receiver::receive() {

uint8_t buffer[this->max_buffer_size];
uint32_t buffer_size = 0;

struct sockaddr_in peer_addr = {};
socklen_t peer_addr_size = sizeof(peer_addr);

struct sctp_sndrcvinfo info = {};
int32_t flags = 0;

while (this->can_receive) {
buffer_size = Endpoint::receive(buffer, max_buffer_size, peer_addr, peer_addr_size, info, flags);
if (buffer_size == 0) {
// Notification was sent
} else if (buffer_size == -1) {
CERR("Endpoint::receive(...) returned -1" << std::endl);
} else {
this->receiveCallback(buffer, buffer_size, peer_addr, peer_addr_size, info);
}
}
}

Странно то, что исключение BAD_ACCESS возникает, когда инициализируется «peer_addr»:

struct sockaddr_in peer_addr = {};

Вот что CLion выдает мне как сообщение об ошибке:

EXC_BAD_ACCESS (code=1, address=0x70000807bb88)

Я могу избежать этого, инициализируя структуры «peer_addr» и «info» прямо в начале функции. Однако затем вызов «Endpoint :: receive» снова завершается с исключением BAD_ACCESS. На этот раз со следующими параметрами:

EXC_BAD_ACCESS (code=1, address=0x70000c4adb90)

У кого-нибудь есть идеи, что тут не так? Я использую набор инструментов Xcode 9.4.1 (который, насколько мне известно, использует clang) с CMake 3.12.0 (я использую CLion в качестве IDE). Если кому-то нужен полный библиотечный код, я могу загрузить его в git и поделиться ссылкой (в настоящее время он находится только на частном git-сервере).

Лучший
паскаль

0

Решение

Если max_buffer_size велика, вы, вероятно, столкнетесь с переполнением стека.

Размер стека очень ограничен и, вероятно, меньше в OSX, чем в Linux (например, размер стека pthread по умолчанию составляет всего 512 КБ). https://developer.apple.com/library/archive/qa/qa1419/_index.html).

Большие буферы должны быть распределены в куче, а не в стеке.

OSX не очень хорош в обнаружении переполнения стека и часто вызывает путаницу EXC_BAD_ACCESS ошибка вместо более полезной ошибки переполнения стека.

1

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

Других решений пока нет …

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