Hangs on recv when using -fsanitize=thread
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
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.
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.