Commit 8e72ce6e authored by jan.koester's avatar jan.koester
Browse files

event: don't keep dead listeners in SSOCKETS across event loops

Every worker's poll object appends its listener to the file-static
SSOCKETS, and nothing ever removed them. cleanupConnections() copied the
list, so a later event loop in the same process closed the listeners of
an earlier one again -- after those sockets were gone (use-after-free;
idle_reaper_test segfaulted at exit in its third scenario).

cleanupConnections() now takes the list (swap) and closes each listener
once (every worker thread registered it). Same in poll.cpp and kqueue.cpp.

Co-Authored-By: default avatarClaude Opus 5.5 <noreply@anthropic.com>
parent e6154985
Loading
Loading
Loading
Loading
+7 −1
Changes for src/event/epoll.cpp: 7 added lines, 1 removed line.
Original line number Diff line number Diff line
@@ -812,13 +812,19 @@ namespace netplus {
        {
            std::unique_lock<std::shared_mutex> lk(POLL_HANDLER_MUTEX);

            servers = SSOCKETS;
            // Take the list instead of copying it: these listeners belong to this
            // run, and a later event loop (another instance, or the next one in
            // the same process) must not close them again after they are gone.
            servers.swap(SSOCKETS);
            for (auto& kv : CONNECTIONS)
                conns.push_back(kv.second);

            CONNECTIONS.clear();
        }

        // every worker thread registered its listener, so close each one once
        std::sort(servers.begin(), servers.end());
        servers.erase(std::unique(servers.begin(), servers.end()), servers.end());
        for (auto* s : servers) {
            try { s->close(); } catch (...) {}
        }
+7 −1
Changes for src/event/kqueue.cpp: 7 added lines, 1 removed line.
Original line number Diff line number Diff line
@@ -928,13 +928,19 @@ namespace netplus {
        {
            std::unique_lock<std::shared_mutex> lk(POLL_HANDLER_MUTEX);

            servers = SSOCKETS;
            // Take the list instead of copying it: these listeners belong to this
            // run, and a later event loop (another instance, or the next one in
            // the same process) must not close them again after they are gone.
            servers.swap(SSOCKETS);
            for (auto& kv : CONNECTIONS)
                conns.push_back(kv.second);

            CONNECTIONS.clear();
        }

        // every worker thread registered its listener, so close each one once
        std::sort(servers.begin(), servers.end());
        servers.erase(std::unique(servers.begin(), servers.end()), servers.end());
        for (auto* s : servers) {
            try { s->close(); } catch (...) {}
        }
+7 −1
Changes for src/event/poll.cpp: 7 added lines, 1 removed line.
Original line number Diff line number Diff line
@@ -744,13 +744,19 @@ namespace netplus {
        {
            std::lock_guard<std::mutex> lk(POLL_HANDLER_MUTEX);

            servers = SSOCKETS;
            // Take the list instead of copying it: these listeners belong to this
            // run, and a later event loop (another instance, or the next one in
            // the same process) must not close them again after they are gone.
            servers.swap(SSOCKETS);
            for (auto& kv : CONNECTIONS)
                conns.push_back(kv.second);

            CONNECTIONS.clear();
        }

        // every worker thread registered its listener, so close each one once
        std::sort(servers.begin(), servers.end());
        servers.erase(std::unique(servers.begin(), servers.end()), servers.end());
        for (auto* s : servers) {
            try { s->close(); } catch (...) {}
        }