c++ - CLang:std::thread 中的运行函数导致结构创建时出现 BAD_ACCESS

标签 c++ multithreading clang exc-bad-access sctp

我最近从 Kubuntu 16.04 切换到 Mac OS High Sierra,并开始定期移植我使用的部分代码。其中有一个用于 libsctp-dev 的 C++ 包装器库。

我正在使用 SCTP kernel extension拥有与我的 Linux 机器上相同的 SCTP API。虽然 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();
}

最后是receive方法的代码(Server是Receiver的子类,Receiver又是Endpoint的子类):

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);
        }
    }
}

奇怪的是,初始化“peer_addr”时出现BAD_ACCESS异常:

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 并共享一个链接(目前它仅在私有(private) git 服务器上)。

最佳 帕斯卡

最佳答案

如果 max_buffer_size 很大,您可能会遇到堆栈溢出。

堆栈的大小非常有限,在 OSX 上可能比在 Linux 上更小(例如,默认的 pthread 堆栈大小仅为 512K https://developer.apple.com/library/archive/qa/qa1419/_index.html)。

大型缓冲区应该分配在堆上而不是分配在堆栈上。

OSX 不太擅长检测堆栈溢出,并且经常引发令人困惑的 EXC_BAD_ACCESS 错误,而不是更有用的堆栈溢出错误。

关于c++ - CLang:std::thread 中的运行函数导致结构创建时出现 BAD_ACCESS,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51764655/

相关文章:

cmake - 如何在 CMake 中将组合编译器选项与 target_compile_options 一起传递?

签名后的 C++ 参数声明

c++ - 获取 RGBDemo 的鼠标位置坐标

php - 如何在 PHP 中使用 C 静态库(.a 文件)

c++ - 有什么方法可以知道线程使用了多少内存?

c++ - 是否有作为一组 Clang 工具实现的 C++ 重构模式?

c++ - Boost bjam 不会将编译器版本放在文件名中

java - 在线程上调用不同的方法

ios - 线程正在执行行,但无效

function - vim脚本(clang_complete)如何完成功能、模板?