Недавно я перешел с 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-сервере).
Лучший
паскаль
Если max_buffer_size
велика, вы, вероятно, столкнетесь с переполнением стека.
Размер стека очень ограничен и, вероятно, меньше в OSX, чем в Linux (например, размер стека pthread по умолчанию составляет всего 512 КБ). https://developer.apple.com/library/archive/qa/qa1419/_index.html).
Большие буферы должны быть распределены в куче, а не в стеке.
OSX не очень хорош в обнаружении переполнения стека и часто вызывает путаницу EXC_BAD_ACCESS
ошибка вместо более полезной ошибки переполнения стека.
Других решений пока нет …