Skip to content

Commit 85a9805

Browse files
authored
Merge pull request #208 from kurdybacha/poller-fix
Problem: poller_t invalid behavior on moved sockets
2 parents e317fc8 + f5b9fcc commit 85a9805

File tree

2 files changed

+39
-12
lines changed

2 files changed

+39
-12
lines changed

tests/poller.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,4 +228,28 @@ TEST(poller, client_server)
228228
ASSERT_TRUE(got_pollout);
229229
}
230230

231+
TEST(poller, poller_add_invalid_socket_throws)
232+
{
233+
zmq::context_t context;
234+
zmq::poller_t poller;
235+
zmq::socket_t a {context, zmq::socket_type::router};
236+
zmq::socket_t b {std::move (a)};
237+
ASSERT_THROW (poller.add (a, ZMQ_POLLIN, zmq::poller_t::handler_t {}),
238+
zmq::error_t);
239+
ASSERT_EQ (0u, poller.size ());
240+
}
241+
242+
TEST(poller, poller_remove_invalid_socket_throws)
243+
{
244+
zmq::context_t context;
245+
zmq::socket_t socket {context, zmq::socket_type::router};
246+
zmq::poller_t poller;
247+
ASSERT_NO_THROW (poller.add (socket, ZMQ_POLLIN, zmq::poller_t::handler_t {}));
248+
ASSERT_EQ (1u, poller.size ());
249+
std::vector<zmq::socket_t> sockets;
250+
sockets.emplace_back (std::move (socket));
251+
ASSERT_THROW (poller.remove (socket), zmq::error_t);
252+
ASSERT_EQ (1u, poller.size ());
253+
}
254+
231255
#endif

zmq.hpp

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,11 @@ namespace zmq
536536
{
537537
return ptr;
538538
}
539+
540+
inline operator bool() const ZMQ_NOTHROW
541+
{
542+
return ptr != NULL;
543+
}
539544
private:
540545

541546
void *ptr;
@@ -1053,26 +1058,24 @@ namespace zmq
10531058

10541059
void add (zmq::socket_t &socket, short events, handler_t handler)
10551060
{
1056-
handler_t *handler_ptr = nullptr;
1057-
/// \todo is it sensible to allow handler to be empty? doesn't this lead to an error when the event is signalled? (perhaps it should already lead to an error in zmq_poller_add then)
1058-
if (handler) {
1059-
auto emplace_res = handlers.emplace(&socket, std::move(handler));
1060-
handler_ptr = &emplace_res.first->second;
1061-
}
1062-
if (0 == zmq_poller_add (poller_ptr, socket.ptr, handler_ptr, events)) {
1061+
auto it = std::end (handlers);
1062+
auto inserted = false;
1063+
if (handler)
1064+
std::tie(it, inserted) = handlers.emplace (socket.ptr, std::move (handler));
1065+
if (0 == zmq_poller_add (poller_ptr, socket.ptr, inserted ? &(it->second) : nullptr, events)) {
10631066
poller_events.emplace_back (zmq_poller_event_t ());
10641067
return;
10651068
}
1069+
// rollback
1070+
if (inserted)
1071+
handlers.erase (socket.ptr);
10661072
throw error_t ();
10671073
}
10681074

10691075
void remove (zmq::socket_t &socket)
10701076
{
10711077
if (0 == zmq_poller_remove (poller_ptr, socket.ptr)) {
1072-
auto it = handlers.find (&socket);
1073-
if (it != handlers.end ()) { /// \todo this may only be false if handler was empty on add
1074-
handlers.erase (it);
1075-
}
1078+
handlers.erase (socket.ptr);
10761079
poller_events.pop_back ();
10771080
return;
10781081
}
@@ -1108,7 +1111,7 @@ namespace zmq
11081111
private:
11091112
void *poller_ptr;
11101113
std::vector<zmq_poller_event_t> poller_events;
1111-
std::unordered_map<socket_t*, handler_t> handlers;
1114+
std::unordered_map<void*, handler_t> handlers;
11121115
}; // class poller_t
11131116
#endif // defined(ZMQ_BUILD_DRAFT_API) && defined(ZMQ_CPP11) && defined(ZMQ_HAVE_POLLER)
11141117

0 commit comments

Comments
 (0)