Skip to content

Commit d237615

Browse files
committed
Problem: Active poller double add mutates handler
Solution: Check if socket already added before storing.
1 parent 3e3fe85 commit d237615

File tree

2 files changed

+22
-18
lines changed

2 files changed

+22
-18
lines changed

tests/active_poller.cpp

+13-6
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ TEST_CASE("create destroy", "[active_poller]")
1414
}
1515

1616
static_assert(!std::is_copy_constructible<zmq::active_poller_t>::value,
17-
"active_active_poller_t should not be copy-constructible");
17+
"active_poller_t should not be copy-constructible");
1818
static_assert(!std::is_copy_assignable<zmq::active_poller_t>::value,
19-
"active_active_poller_t should not be copy-assignable");
19+
"active_poller_t should not be copy-assignable");
2020

2121
static const zmq::active_poller_t::handler_type no_op_handler =
2222
[](zmq::event_flags) {};
@@ -115,12 +115,19 @@ TEST_CASE("add handler invalid events type", "[active_poller]")
115115

116116
TEST_CASE("add handler twice throws", "[active_poller]")
117117
{
118-
zmq::context_t context;
119-
zmq::socket_t socket{context, zmq::socket_type::router};
118+
common_server_client_setup s;
119+
120+
CHECK(s.client.send(zmq::message_t{}, zmq::send_flags::none));
121+
120122
zmq::active_poller_t active_poller;
121-
active_poller.add(socket, zmq::event_flags::pollin, no_op_handler);
123+
bool message_received = false;
124+
active_poller.add(
125+
s.server, zmq::event_flags::pollin,
126+
[&message_received](zmq::event_flags) { message_received = true; });
122127
CHECK_THROWS_ZMQ_ERROR(
123-
EINVAL, active_poller.add(socket, zmq::event_flags::pollin, no_op_handler));
128+
EINVAL, active_poller.add(s.server, zmq::event_flags::pollin, no_op_handler));
129+
CHECK(1 == active_poller.wait(std::chrono::milliseconds{-1}));
130+
CHECK(message_received); // handler unmodified
124131
}
125132

126133
TEST_CASE("wait with no handlers throws", "[active_poller]")

zmq_addon.hpp

+9-12
Original file line numberDiff line numberDiff line change
@@ -675,20 +675,17 @@ class active_poller_t
675675
{
676676
if (!handler)
677677
throw std::invalid_argument("null handler in active_poller_t::add");
678-
auto it = decltype(handlers)::iterator{};
679-
auto inserted = bool{};
680-
std::tie(it, inserted) = handlers.emplace(
678+
auto ret = handlers.emplace(
681679
socket, std::make_shared<handler_type>(std::move(handler)));
680+
if (!ret.second)
681+
throw error_t(EINVAL); // already added
682682
try {
683-
base_poller.add(socket, events,
684-
inserted && *(it->second) ? it->second.get() : nullptr);
685-
need_rebuild |= inserted;
683+
base_poller.add(socket, events, ret.first->second.get());
684+
need_rebuild = true;
686685
}
687-
catch (const zmq::error_t &) {
686+
catch (...) {
688687
// rollback
689-
if (inserted) {
690-
handlers.erase(socket);
691-
}
688+
handlers.erase(socket);
692689
throw;
693690
}
694691
}
@@ -720,8 +717,8 @@ class active_poller_t
720717
std::for_each(poller_events.begin(),
721718
poller_events.begin() + static_cast<ptrdiff_t>(count),
722719
[](decltype(base_poller)::event_type &event) {
723-
if (event.user_data != nullptr)
724-
(*event.user_data)(event.events);
720+
assert(event.user_data != nullptr);
721+
(*event.user_data)(event.events);
725722
});
726723
return count;
727724
}

0 commit comments

Comments
 (0)