src/common/reactor.cc: Fixed stack corruption when Aio::AsyncImpl is...

src/common/reactor.cc: Fixed stack corruption when Aio::AsyncImpl is constructed with more than 255 worker threads requested...
src/common/reactor.cc: Cleaner move semantics in worker thread construction...
src/common/reactor.cc: Use simpler structured binding with decodeKey() return value...
tests/reactor_test.cc: Added reactor_exceed_max_threads test to reactor_test suite...
{include/pistache/reactor.h, src/common/reactor.cc}: Use std::array and safer bounds checking with containers...
CMakeLists.txt: Added better general detection for buffer overflows and stack protection...
{debian/changelog,version.txt}: Bumped versioning...
parent 0b6cb299
...@@ -11,7 +11,7 @@ if(NOT CMAKE_BUILD_TYPE) ...@@ -11,7 +11,7 @@ if(NOT CMAKE_BUILD_TYPE)
endif() endif()
if(CMAKE_BUILD_TYPE MATCHES "Debug") if(CMAKE_BUILD_TYPE MATCHES "Debug")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage -fstack-protector-all --param=ssp-buffer-size=4")
endif() endif()
option(PISTACHE_BUILD_TESTS "build tests alongside the project" OFF) option(PISTACHE_BUILD_TESTS "build tests alongside the project" OFF)
......
pistache (0.0.001-git20191231-kip1) eoan; urgency=medium
* Latest upstream.
-- Kip Warner <kip@thevertigo.com> Tue, 31 Dec 2019 11:21:10 -0800
pistache (0.0.001-git20191031-kip1) eoan; urgency=medium pistache (0.0.001-git20191031-kip1) eoan; urgency=medium
* Latest upstream and first build for eoan. * Latest upstream and first build for eoan.
......
...@@ -68,7 +68,7 @@ public: ...@@ -68,7 +68,7 @@ public:
} }
const Entry& operator[](size_t index) const { const Entry& operator[](size_t index) const {
return events_[index]; return events_.at(index);
} }
iterator begin() { iterator begin() {
......
...@@ -10,9 +10,12 @@ ...@@ -10,9 +10,12 @@
#include <atomic> #include <atomic>
#include <memory> #include <memory>
#include <mutex> #include <mutex>
#include <string>
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
using namespace std::string_literals;
namespace Pistache { namespace Pistache {
namespace Aio { namespace Aio {
...@@ -88,7 +91,7 @@ public: ...@@ -88,7 +91,7 @@ public:
} }
std::shared_ptr<Handler> handler(const Reactor::Key& key) const { std::shared_ptr<Handler> handler(const Reactor::Key& key) const {
return handlers_[key.data()]; return handlers_.at(key.data());
} }
std::vector<std::shared_ptr<Handler>> handlers(const Reactor::Key& key) const override { std::vector<std::shared_ptr<Handler>> handlers(const Reactor::Key& key) const override {
...@@ -183,7 +186,7 @@ private: ...@@ -183,7 +186,7 @@ private:
// Fast-path: if we only have one handler, do not bother scanning the fds to find // Fast-path: if we only have one handler, do not bother scanning the fds to find
// the right handlers // the right handlers
if (handlers_.size() == 1) if (handlers_.size() == 1)
handlers_[0]->onReady(FdSet(std::move(events))); handlers_.at(0)->onReady(FdSet(std::move(events)));
else { else {
std::unordered_map<std::shared_ptr<Handler>, std::vector<Polling::Event>> fdHandlers; std::unordered_map<std::shared_ptr<Handler>, std::vector<Polling::Event>> fdHandlers;
...@@ -192,8 +195,8 @@ private: ...@@ -192,8 +195,8 @@ private:
uint64_t value; uint64_t value;
std::tie(index, value) = decodeTag(event.tag); std::tie(index, value) = decodeTag(event.tag);
auto handler = handlers_[index]; auto handler = handlers_.at(index);
auto& evs = fdHandlers[handler]; auto& evs = fdHandlers.at(handler);
evs.push_back(std::move(event)); evs.push_back(std::move(event));
} }
...@@ -230,7 +233,7 @@ private: ...@@ -230,7 +233,7 @@ private:
HandlerList list; HandlerList list;
for (size_t i = 0; i < index_; ++i) { for (size_t i = 0; i < index_; ++i) {
list.handlers[i] = handlers[i]->clone(); list.handlers.at(i) = handlers.at(i)->clone();
} }
list.index_ = index_; list.index_ = index_;
...@@ -242,20 +245,20 @@ private: ...@@ -242,20 +245,20 @@ private:
throw std::runtime_error("Maximum handlers reached"); throw std::runtime_error("Maximum handlers reached");
Reactor::Key key(index_); Reactor::Key key(index_);
handlers[index_++] = handler; handlers.at(index_++) = handler;
return key; return key;
} }
std::shared_ptr<Handler> operator[](size_t index) const { std::shared_ptr<Handler> operator[](size_t index) const {
return handlers[index]; return handlers.at(index);
} }
std::shared_ptr<Handler> at(size_t index) const { std::shared_ptr<Handler> at(size_t index) const {
if (index >= index_) if (index >= index_)
throw std::runtime_error("Attempting to retrieve invalid handler"); throw std::runtime_error("Attempting to retrieve invalid handler");
return handlers[index]; return handlers.at(index);
} }
bool empty() const { bool empty() const {
...@@ -287,7 +290,7 @@ private: ...@@ -287,7 +290,7 @@ private:
template<typename Func> template<typename Func>
void forEachHandler(Func func) const { void forEachHandler(Func func) const {
for (size_t i = 0; i < index_; ++i) for (size_t i = 0; i < index_; ++i)
func(handlers[i]); func(handlers.at(i));
} }
private: private:
...@@ -337,38 +340,41 @@ public: ...@@ -337,38 +340,41 @@ public:
AsyncImpl(Reactor* reactor, size_t threads, const std::string& threadsName) AsyncImpl(Reactor* reactor, size_t threads, const std::string& threadsName)
: Reactor::Impl(reactor) { : Reactor::Impl(reactor) {
for (size_t i = 0; i < threads; ++i) { if(threads > SyncImpl::MaxHandlers())
std::unique_ptr<Worker> wrk(new Worker(reactor, threadsName)); throw std::runtime_error(
workers_.push_back(std::move(wrk)); "Too many worker threads requested (max "s +
} std::to_string(SyncImpl::MaxHandlers()) +
")."s);
for (size_t i = 0; i < threads; ++i)
workers_.emplace_back(std::make_unique<Worker>(reactor, threadsName));
} }
Reactor::Key addHandler( Reactor::Key addHandler(
const std::shared_ptr<Handler>& handler, bool) override { const std::shared_ptr<Handler>& handler, bool) override {
Reactor::Key keys[SyncImpl::MaxHandlers()]; std::array<Reactor::Key, SyncImpl::MaxHandlers()> keys;
for (size_t i = 0; i < workers_.size(); ++i) { for (size_t i = 0; i < workers_.size(); ++i) {
auto &wrk = workers_[i]; auto &wrk = workers_.at(i);
auto cl = handler->clone(); auto cl = handler->clone();
auto key = wrk->sync->addHandler(cl, false /* setKey */); auto key = wrk->sync->addHandler(cl, false /* setKey */);
auto newKey = encodeKey(key, i); auto newKey = encodeKey(key, i);
cl->key_ = newKey; cl->key_ = newKey;
keys[i] = key; keys.at(i) = key;
} }
auto data = keys[0].data() << 32 | KeyMarker; auto data = keys.at(0).data() << 32 | KeyMarker;
return Reactor::Key(data); return Reactor::Key(data);
} }
std::vector<std::shared_ptr<Handler>> handlers(const Reactor::Key& key) const override { std::vector<std::shared_ptr<Handler>> handlers(const Reactor::Key& key) const override {
uint32_t idx;
uint32_t marker; const auto [idx, marker] = decodeKey(key);
std::tie(idx, marker) = decodeKey(key);
if (marker != KeyMarker) if (marker != KeyMarker)
throw std::runtime_error("Invalid key"); throw std::runtime_error("Invalid key");
...@@ -444,7 +450,7 @@ private: ...@@ -444,7 +450,7 @@ private:
template<typename Func, typename... Args> template<typename Func, typename... Args>
void dispatchCall(const Reactor::Key& key, Func func, Args&& ...args) const { void dispatchCall(const Reactor::Key& key, Func func, Args&& ...args) const {
auto decoded = decodeKey(key); auto decoded = decodeKey(key);
auto& wrk = workers_[decoded.second]; auto& wrk = workers_.at(decoded.second);
Reactor::Key originalKey(decoded.first); Reactor::Key originalKey(decoded.first);
CALL_MEMBER_FN(wrk->sync.get(), func)(originalKey, std::forward<Args>(args)...); CALL_MEMBER_FN(wrk->sync.get(), func)(originalKey, std::forward<Args>(args)...);
......
...@@ -63,7 +63,7 @@ private: ...@@ -63,7 +63,7 @@ private:
TEST(reactor_test, reactor_creation) TEST(reactor_test, reactor_creation)
{ {
const size_t NUM_THREADS = 2; constexpr size_t NUM_THREADS = 2;
std::shared_ptr<Aio::Reactor> reactor = Aio::Reactor::create(); std::shared_ptr<Aio::Reactor> reactor = Aio::Reactor::create();
reactor->init(Aio::AsyncContext(NUM_THREADS)); reactor->init(Aio::AsyncContext(NUM_THREADS));
auto key = reactor->addHandler(std::make_shared<TransportMock>()); auto key = reactor->addHandler(std::make_shared<TransportMock>());
...@@ -98,4 +98,14 @@ TEST(reactor_test, reactor_creation) ...@@ -98,4 +98,14 @@ TEST(reactor_test, reactor_creation)
ASSERT_NE(resulted_values.find(values[i][j]), resulted_values.end()); ASSERT_NE(resulted_values.find(values[i][j]), resulted_values.end());
} }
} }
} }
\ No newline at end of file
TEST(reactor_test, reactor_exceed_max_threads)
{
constexpr size_t MAX_SUPPORTED_THREADS = 255;
std::shared_ptr<Aio::Reactor> reactor = Aio::Reactor::create();
ASSERT_THROW(
reactor->init(Aio::AsyncContext(5 * MAX_SUPPORTED_THREADS + 1)),
std::runtime_error);
}
VERSION_MAJOR 0 VERSION_MAJOR 0
VERSION_MINOR 0 VERSION_MINOR 0
VERSION_PATCH 001 VERSION_PATCH 001
VERSION_GIT_DATE 20191031 VERSION_GIT_DATE 20191231
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment