zeromq / libzmq

ZeroMQ core engine in C++, implements ZMTP/3.1
https://www.zeromq.org
Mozilla Public License 2.0
9.75k stars 2.36k forks source link

Bad address crash in tcp_recv under high memory #4473

Open lukaszsamson opened 1 year ago

lukaszsamson commented 1 year ago

Please use this template for reporting suspected bugs or requests for help.

Issue description

ZMQ crashes with Bad address in tcp_recv

Environment

Minimal test code / Steps to reproduce the issue

The system was operating under high memory conditions and at some point zmq crashed. I'm not sure if it's easy to reproduce.

What's the actual result? (include assertion message & call stack if applicable)

Bad address (src/tcp.cpp:306)

The error comes from this assert https://github.com/zeromq/libzmq/blob/4097855ddaaa65ed7b5e8cb86d143842a594eebd/src/tcp.cpp#L306

which means that recv returned EFAULT

according to https://man7.org/linux/man-pages/man2/recv.2.html

EFAULT The receive buffer pointer(s) point outside the process's address space.

What's the expected result?

No crash, error code returned or retry attempted with valid buffer

ljluestc commented 2 months ago

#include <zmq.hpp>
#include <iostream>
#include <cstring>
#include <cerrno>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>

void tcp_recv(zmq::socket_t& socket, zmq::message_t& message) {
    int rc = recv(socket.get_fd(), message.data(), message.size(), 0);

    if (rc == -1) {
        if (errno == EFAULT) {
            // Handle EFAULT error gracefully
            std::cerr << "Error: Buffer pointer outside process's address space" << std::endl;
            // You can implement retry logic or other error handling here
        } else {
            // Handle other errors
            std::cerr << "Error in recv: " << strerror(errno) << std::endl;
        }
        return;
    }

    if (rc == 0) {
        // Connection closed by peer
        std::cerr << "Connection closed" << std::endl;
        return;
    }

    // Handle successful reception
    message.rebuild(rc);
}