libzmq icon indicating copy to clipboard operation
libzmq copied to clipboard

Hangs on recv when using -fsanitize=thread

Open stkw0 opened this issue 1 year ago • 2 comments

Issue description

When compiling the attached test code with g++ test.cpp -o test -lzmq -fsanitize=thread it hangs when claling to recv(). Without tsan it works correctly.

Environment

  • libzmq version (commit hash if unreleased): 4.3.5
  • cppzmq: 4.10.0
  • gcc: 14.2.1 (but it can reproduce also with clang)
  • OS: Gentoo

Minimal test code / Steps to reproduce the issue

#include <mutex>
#include <string_view>
#include <thread>
#include <iostream>

#include <zmq.hpp>

static zmq::context_t ctxt{0};

class InternalDataPub {
  public:
    InternalDataPub() {_pub.bind("inproc://cdm");}

    void publish(const std::string_view& m) {
    	    zmq::message_t msg(m.data(), m.size());
	    _pub.send(msg, zmq::send_flags::none);
    }

  private:
    zmq::socket_t _pub{ctxt, zmq::socket_type::pub};
    std::mutex _mutex;
};

class InternalDataSub {
  public:
    InternalDataSub() {_sub.connect("inproc://cdm");}

    void subscribe(const std::string_view& s ) {
	    _sub.set(zmq::sockopt::subscribe, s);
    }

    std::string recv() {
	    zmq::message_t m;
	    (void)_sub.recv(m, zmq::recv_flags::none);
	    return m.to_string();
    }

  private:
    zmq::socket_t _sub{ctxt, zmq::socket_type::sub};
};

int main() {
	auto publisher = []() {
            InternalDataPub pub;
            pub.publish("A.B.C");
        };

        std::thread t(publisher);
        InternalDataSub sub;
        sub.subscribe("A");
        std::cout << "Before recv" << std::endl;
        std::cout << sub.recv() << std::endl;
        t.join();
}

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

It just hangs without any information, crash or error

What's the expected result?

It shows the published message

stkw0 avatar Oct 31 '24 15:10 stkw0

this looks a race condition, you send before you recv on a pub sub pair.

you have to wait a little before sending a message or the receiver will never see anything. You might just send a message every few milliseconds and it should be ok.

Asmod4n avatar Dec 01 '24 11:12 Asmod4n

I didn't know if the publisher would queue the messages until high watermark is hit before dropping, if it did then this would work, if not I would receive a TSAN log. Thinking it now, it would be dumb to queue messages that way, in a pub/sub at least.

In any case, I would expect fsanitize=thread to throw something in a case like that. I was also using -DENABLE_INTRINSITCS for ZMQ, which, afaik, helps the sanitizer instrument the code better.

stkw0 avatar Dec 02 '24 10:12 stkw0