Segmentation Faults when testing typed actors with custom atoms - c++-actor-framework

I am trying to use the testing macros with my actors but I am getting a lot of segmentation faults. I believe I have narrowed down the problem to my use of custom atoms. To demonstrate the issue I modified the 'simple actor test' from here to make the adder strongly typed.
#include "caf/test/dsl.hpp"
#include "caf/test/unit_test_impl.hpp"
#include "caf/all.hpp"
namespace {
struct fixture {
caf::actor_system_config cfg;
caf::actor_system sys;
caf::scoped_actor self;
fixture() : sys(cfg), self(sys) {
// nop
}
};
using calculator_type = caf::typed_actor<caf::result<int>(int, int)>;
calculator_type::behavior_type adder() {
return {
[=](int x, int y) {
return x + y;
}
};
}
} // namespace
CAF_TEST_FIXTURE_SCOPE(actor_tests, fixture)
CAF_TEST(simple actor test) {
// Our Actor-Under-Test.
auto aut = self->spawn(adder);
self->request(aut, caf::infinite, 3, 4).receive(
[=](int r) {
CAF_CHECK(r == 7);
},
[&](caf::error& err) {
// Must not happen, stop test.
CAF_FAIL(err);
});
}
CAF_TEST_FIXTURE_SCOPE_END()
This works great. I then took it one step further to add a custom atom called "add_numbers"
#include "caf/test/dsl.hpp"
#include "caf/test/unit_test_impl.hpp"
#include "caf/all.hpp"
CAF_BEGIN_TYPE_ID_BLOCK(calc_msgs, first_custom_type_id)
CAF_ADD_ATOM(calc_msgs, add_numbers)
CAF_END_TYPE_ID_BLOCK(calc_msgs)
namespace {
struct fixture {
caf::actor_system_config cfg;
caf::actor_system sys;
caf::scoped_actor self;
fixture() : sys(cfg), self(sys) {
// nop
}
};
using calculator_type = caf::typed_actor<caf::result<int>(add_numbers, int, int)>;
calculator_type::behavior_type adder() {
return {
[=](add_numbers, int x, int y) {
return x + y;
}
};
}
} // namespace
CAF_TEST_FIXTURE_SCOPE(actor_tests, fixture)
CAF_TEST(simple actor test) {
// Our Actor-Under-Test.
auto aut = self->spawn(adder);
self->request(aut, caf::infinite, add_numbers_v, 3, 4).receive(
[=](int r) {
CAF_CHECK(r == 7);
},
[&](caf::error& err) {
// Must not happen, stop test.
CAF_FAIL(err);
});
}
CAF_TEST_FIXTURE_SCOPE_END()
This compiles fine but produces a segmentation fault at runtime. I suspect it has something to do with the fact that I am not passing calc_msgs to anything. How do I do that? Or is something else going on?

The ID block adds the compile-time meta data. But you also need to initialize some run-time state via
init_global_meta_objects<caf::id_block::calc_msgs>();
Ideally, you initialize this state before calling any other CAF function. In particular before initializing the actor system. CAF itself uses custom main functions for its test suites to do that (cf. core-test.cpp). In your case, it would look somewhat like this:
int main(int argc, char** argv) {
using namespace caf;
init_global_meta_objects<id_block::calc_msgs>();
core::init_global_meta_objects();
return test::main(argc, argv);
}
This probably means that you would need to put the type ID block into a header file. This is nothing special about the unit tests, though. If you run a regular CAF application, you need to initialize the global meta objects as well. CAF_MAIN can do that for you as long as you pass it the type ID block(s) or you need to call the functions by hand. The CAF manual covers this in a bit more detail here: https://actor-framework.readthedocs.io/en/0.18.5/ConfiguringActorApplications.html#configuring-actor-applications.
If this is your only test at the moment, you can define CAF_TEST_NO_MAIN before including caf/test/unit_test_impl.hpp and then add the custom main function. Once you have multiple test suites, it makes sense to move the main to its own file, though.

Related

nghttp2: Using server-sent events to be use by EventSource

I'm using nghttp2 to implement a REST server which should use HTTP/2 and server-sent events (to be consumed by an EventSource in the browser). However, based on the examples it is unclear to me how to implement SSE. Using res.push() as in asio-sv.cc doesn't seem to be the right approach.
What would be the right way to do it? I'd prefer to use nghttp2's C++ API, but the C API would do as well.
Yup, I did something like that back in 2018. The documentation was rather sparse :).
First of all, ignore response::push because that's the HTTP2 push -- something for proactively sending unsolicited objects to the client before it requests them. I know it sounds like what you need, but it is not -- the typical use case would be proactively sending a CSS file and some images along with the originally requested HTML page.
The key thing is that your end() callback must eventually return NGHTTP2_ERR_DEFERRED whenever you run out of data to send. When your application somehow obtains more data to be sent, call http::response::resume().
Here's a simple code. Build it as g++ -std=c++17 -Wall -O3 -ggdb clock.cpp -lssl -lcrypto -pthread -lnghttp2_asio -lspdlog -lfmt. Be careful, modern browsers don't do HTTP/2 over a plaintext socket, so you'll need to reverse-proxy it via something like nghttpx -f '*,8080;no-tls' -b '::1,10080;;proto=h2'.
#include <boost/asio/io_service.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/signals2.hpp>
#include <chrono>
#include <list>
#include <nghttp2/asio_http2_server.h>
#define SPDLOG_FMT_EXTERNAL
#include <spdlog/spdlog.h>
#include <thread>
using namespace nghttp2::asio_http2;
using namespace std::literals;
using Signal = boost::signals2::signal<void(const std::string& message)>;
class Client {
const server::response& res;
enum State {
HasEvents,
WaitingForEvents,
};
std::atomic<State> state;
std::list<std::string> queue;
mutable std::mutex mtx;
boost::signals2::scoped_connection subscription;
size_t send_chunk(uint8_t* destination, std::size_t len, uint32_t* data_flags [[maybe_unused]])
{
std::size_t written{0};
std::lock_guard lock{mtx};
if (state != HasEvents) throw std::logic_error{std::to_string(__LINE__)};
while (!queue.empty()) {
auto num = std::min(queue.front().size(), len - written);
std::copy_n(queue.front().begin(), num, destination + written);
written += num;
if (num < queue.front().size()) {
queue.front() = queue.front().substr(num);
spdlog::debug("{} send_chunk: partial write", (void*)this);
return written;
}
queue.pop_front();
spdlog::debug("{} send_chunk: sent one event", (void*)this);
}
state = WaitingForEvents;
return written;
}
public:
Client(const server::request& req, const server::response& res, Signal& signal)
: res{res}
, state{WaitingForEvents}
, subscription{signal.connect([this](const auto& msg) {
enqueue(msg);
})}
{
spdlog::warn("{}: {} {} {}", (void*)this, boost::lexical_cast<std::string>(req.remote_endpoint()), req.method(), req.uri().raw_path);
res.write_head(200, {{"content-type", {"text/event-stream", false}}});
}
void onClose(const uint32_t ec)
{
spdlog::error("{} onClose", (void*)this);
subscription.disconnect();
}
ssize_t process(uint8_t* destination, std::size_t len, uint32_t* data_flags)
{
spdlog::trace("{} process", (void*)this);
switch (state) {
case HasEvents:
return send_chunk(destination, len, data_flags);
case WaitingForEvents:
return NGHTTP2_ERR_DEFERRED;
}
__builtin_unreachable();
}
void enqueue(const std::string& what)
{
{
std::lock_guard lock{mtx};
queue.push_back("data: " + what + "\n\n");
}
state = HasEvents;
res.resume();
}
};
int main(int argc [[maybe_unused]], char** argv [[maybe_unused]])
{
spdlog::set_level(spdlog::level::trace);
Signal sig;
std::thread timer{[&sig]() {
for (int i = 0; /* forever */; ++i) {
std::this_thread::sleep_for(std::chrono::milliseconds{666});
spdlog::info("tick: {}", i);
sig("ping #" + std::to_string(i));
}
}};
server::http2 server;
server.num_threads(4);
server.handle("/events", [&sig](const server::request& req, const server::response& res) {
auto client = std::make_shared<Client>(req, res, sig);
res.on_close([client](const auto ec) {
client->onClose(ec);
});
res.end([client](uint8_t* destination, std::size_t len, uint32_t* data_flags) {
return client->process(destination, len, data_flags);
});
});
server.handle("/", [](const auto& req, const auto& resp) {
spdlog::warn("{} {} {}", boost::lexical_cast<std::string>(req.remote_endpoint()), req.method(), req.uri().raw_path);
resp.write_head(200, {{"content-type", {"text/html", false}}});
resp.end(R"(<html><head><title>nghttp2 event stream</title></head>
<body><h1>events</h1><ul id="x"></ul>
<script type="text/javascript">
const ev = new EventSource("/events");
ev.onmessage = function(event) {
const li = document.createElement("li");
li.textContent = event.data;
document.getElementById("x").appendChild(li);
};
</script>
</body>
</html>)");
});
boost::system::error_code ec;
if (server.listen_and_serve(ec, "::", "10080")) {
return 1;
}
return 0;
}
I have a feeling that my queue handling is probably too complex. When testing via curl, I never seem to run out of buffer space. In other words, even if the client is not reading any data from the socket, the library keep invoking send_chunk, asking for up to 16kB of data at a time for me. Strange. I have no idea how it works when pushing more data more heavily.
My "real code" used to have a third state, Closed, but I think that blocking events via on_close is enough here. However, I think you never want to enter send_chunk if the client has already disconnected, but before the destructor gets called.

Using valgrind - "Invalid read of size 1" for strlen

I'm trying to write code that sets the name of a Student object to a new name, but I'm coming across memory leak errors when creating a character array. I assume it has to do with /0 at the end of the array and isn't terminating properly, but I don't know how to properly fix this. Thanks for the help.
#include "student.h"
#include <string>
#include <cstring>
#include <iostream>
using namespace std;
Student::Student(const char * const name, int perm) {
this->setName(name);
this->setPerm(perm);
}
int Student::getPerm() const {
return this->perm;
}
const char * const Student::getName() const {
return this->name;
}
void Student::setPerm(const int perm) {
this->perm = perm;
}
void Student::setName(const char * const newName) {
this->name = new char[strlen(newName)+1];
// this->name[srtlen(newName)+1] = '/0'; <---- My suggested fix, but doesn't work
strcpy(this->name,newName);
}
Student::Student(const Student &orig) {
this->setName(orig.getName());
this->setPerm(orig.getPerm());
}
Student::~Student() {
delete this->name;
this->perm = 0;
}
This is the valgrind error:
==13814== Invalid read of size 1
==13814== at 0x4C2BA12: strlen (vg_replace_strmem.c:454)
==13814== by 0x4F56FD6: UnknownInlinedFun (char_traits.h:267)
==13814== by 0x4F56FD6: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&) (basic_string.h:456)
==13814== by 0x401ED8: Student::toString[abi:cxx11]() const (student.cpp:64)
==13814== by 0x401A46: main (testStudent00.cpp:14)
==13814== Address 0x5302e8 is not stack'd, malloc'd or (recently) free'd
==13814==
Your assumption that you needed to add the 0 terminator is wrong, strcpy() will do that for you. Your attempt of doing so adds the 0 terminator one byte past the space you allocated (remember, array indexes start at zero), and the syntax is also wrong, you would need to do:
this->name[strlen(newName)] = '\0';
However, to fix your memory leak You need to delete the previous string, like
void Student::setName(const char * const newName)
{
delete [] this->name;
this->name = new char[strlen(newName)+1];
strcpy(this->name,newName);
}
Student::Student(const Student &orig) :
name(0) {
this->setName(orig.getName());
this->setPerm(orig.getPerm());
}
Student::~Student() {
delete [] this->name;
this->perm = 0;
}
Now, for this to work, you also need to fix your constructor and copy constructor to initialize the name member, so it isn't an uninitialized pointer for the first call to the setName() function, and you need to add an assignment operator too, so you can properly handle assignments.
Student::Student(const char * const name, int perm) :
name(0)
{
this->setName(name);
this->setPerm(perm);
}
Student &operator=(const Student &orig) {
this->setName(orig.getName());
this->setPerm(orig.getPerm());
}
Also, consider using std::string instead of your current low level way of handling strings, that way you don't need to even implement a copy constructor, assignment operator and destructor for this class, nor deal with correctly managing memory.

Error: C2280 Creating a vector of unique_ptr to Class

It seems that when using a unique_ptr in vector<unique_ptr<UserInterface>> I get an error stating:
Error 1 error C2280: 'std::unique_ptr<UserInterface,std::default_delete<_Ty>>::unique_ptr(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)' : attempting to reference a deleted function c:\pr...ude\xmemory0 593 1 Win32Project1
Seemingly, no configuration allows me to store [smart] pointers to the UserInterface class, which has a simple structure:
#define InterfaceContruct vector<unique_ptr<UserInterface>>
class UserInterfaceMgmt
{
public:
UserInterfaceMgmt();
~UserInterfaceMgmt();
InterfaceContruct Interface;
void AddUIElement();
void RemoveUIElement();
void DrawInterface();
void MoveElement();
private:
};
Even if no function is called, the error shows up (InterfaceContruct Interface; is instantiated) I tried putting the copy constructor in private but it persists.
The .cpp file is:
#include "stdafx.h"
#include "UserInterfaceMgmt.h"
UserInterfaceMgmt::UserInterfaceMgmt()
{
}
UserInterfaceMgmt::~UserInterfaceMgmt()
{
}
void UserInterfaceMgmt::DrawInterface(){
for (UINT i = 0; i < Interface.size(); i++)
{
Interface[i]->Draw();
}
}
std::vector (and most other containers in std::) require the value type to be copy-constructible. std::unique_ptr isn't copy constructible. Use std::shared_ptr or any other copy constructible types / pointers.
The clue is to look for attempting to reference a deleted function. This means there is some method which = delete has been used with. For instance:
struct Foo
{
Foo(const Foo & rhs) = delete; // A deleted function
}

Access to callable object inside an async task conflicts with use of std::cin

#include <iostream>
#include <functional>
#include <future>
#include <tchar.h>
void StartBackground(std::function<void()> notify)
{
auto background = std::async([&]
{
notify(); // (A)
});
}
int _tmain(int argc, _TCHAR* argv[])
{
StartBackground([](){});
char c; std::cin >> c; // (B)
while (1);
return 0;
}
1) Build and run the code above using Visual Studio 2012.
2) Line (A) triggers an Access Violation in _VARIADIC_EXPAND_P1_0(_CLASS_FUNC_CLASS_0, , , , ):
First-chance exception at 0x0F96271E (msvcp110d.dll) in
ConsoleApplication1.exe: 0xC0000005: Access violation writing location
0x0F9626D8
Most confusingly, the exception can be avoided by removing line (B).
Questions
Why does the callable object notify apparently conflict with the use of std::cin?
What's wrong with this code?
The real world scenario for this simplified example is a function that executes some code in parallel and have that code call a user-supplied notify function when done.
Edit
I found at least one problem im my code: The background variable is destroyed as soon as StartBackground() exits. Since std::async may or may not start a separate thread, and std::thread calls terminate() if the thread is still joinable, this might be causing the problem.
The following variant works because it gives the task enough time to complete:
void StartBackground(std::function<void()> notify)
{
auto background = std::async([&]
{
notify(); // (A)
});
std::this_thread::sleep_for(std::chrono::seconds(1));
}
Keeping the std::future object alive over a longer period instead of sleeping should also work. But the following code also causes the same access violation:
std::future<void> background;
void StartBackground(std::function<void()> notify)
{
background = std::async([&]
{
notify(); // (A)
});
}
whereas using a std::thread in the same manner works as expected:
std::thread background;
void StartBackground(std::function<void()> notify)
{
background = std::thread([&]
{
notify(); // (A)
});
}
I'm completely puzzled.
I must be missing some very crucial points here regarding std::async and std::thread.
The result of async is a future, not a running thread. You have to synchronize on the task by saying background.get(). Without that, the client procedure may never get executed.

How to use a QFile with std::iostream?

Is it possible to use a QFile like a std::iostream? I'm quite sure there must be a wrapper out there. The question is where?
I have another libs, which requires a std::istream as input parameter, but in my program i only have a QFile at this point.
I came up with my own solution using the following code:
#include <ios>
#include <QIODevice>
class QStdStreamBuf : public std::streambuf
{
public:
QStdStreamBuf(QIODevice *dev) : std::streambuf(), m_dev(dev)
{
// Initialize get pointer. This should be zero so that underflow is called upon first read.
this->setg(0, 0, 0);
}
protected:
virtual std::streamsize xsgetn(std::streambuf::char_type *str, std::streamsize n)
{
return m_dev->read(str, n);
}
virtual std::streamsize xsputn(const std::streambuf::char_type *str, std::streamsize n)
{
return m_dev->write(str, n);
}
virtual std::streambuf::pos_type seekoff(std::streambuf::off_type off, std::ios_base::seekdir dir, std::ios_base::openmode /*__mode*/)
{
switch(dir)
{
case std::ios_base::beg:
break;
case std::ios_base::end:
off = m_dev->size() - off;
break;
case std::ios_base::cur:
off = m_dev->pos() + off;
break;
}
if(m_dev->seek(off))
return m_dev->pos();
else
return std::streambuf::pos_type(std::streambuf::off_type(-1));
}
virtual std::streambuf::pos_type seekpos(std::streambuf::pos_type off, std::ios_base::openmode /*__mode*/)
{
if(m_dev->seek(off))
return m_dev->pos();
else
return std::streambuf::pos_type(std::streambuf::off_type(-1));
}
virtual std::streambuf::int_type underflow()
{
// Read enough bytes to fill the buffer.
std::streamsize len = sgetn(m_inbuf, sizeof(m_inbuf)/sizeof(m_inbuf[0]));
// Since the input buffer content is now valid (or is new)
// the get pointer should be initialized (or reset).
setg(m_inbuf, m_inbuf, m_inbuf + len);
// If nothing was read, then the end is here.
if(len == 0)
return traits_type::eof();
// Return the first character.
return traits_type::not_eof(m_inbuf[0]);
}
private:
static const std::streamsize BUFFER_SIZE = 1024;
std::streambuf::char_type m_inbuf[BUFFER_SIZE];
QIODevice *m_dev;
};
class QStdIStream : public std::istream
{
public:
QStdIStream(QIODevice *dev) : std::istream(m_buf = new QStdStreamBuf(dev)) {}
virtual ~QStdIStream()
{
rdbuf(0);
delete m_buf;
}
private:
QStdStreamBuf * m_buf;
};
I works fine for reading local files. I haven't tested it for writing files. This code is surely not perfect but it works.
I came up with my own solution (which uses the same idea Stephen Chu suggested)
#include <iostream>
#include <fstream>
#include <cstdio>
#include <QtCore>
using namespace std;
void externalLibFunction(istream & input_stream) {
copy(istream_iterator<string>(input_stream),
istream_iterator<string>(),
ostream_iterator<string>(cout, " "));
}
ifstream QFileToifstream(QFile & file) {
Q_ASSERT(file.isReadable());
return ifstream(::_fdopen(file.handle(), "r"));
}
int main(int argc, char ** argv)
{
QFile file("a file");
file.open(QIODevice::WriteOnly);
file.write(QString("some string").toLatin1());
file.close();
file.open(QIODevice::ReadOnly);
std::ifstream ifs(QFileToifstream(file));
externalLibFunction(ifs);
}
Output:
some string
This code uses std::ifstream move constructor (C++x0 feature) specified in 27.9.1.7 basic_ifstream constructors section of Working Draft, Standard for Programming Language C++:
basic_ifstream(basic_ifstream&& rhs);
Effects: Move constructs from the
rvalue rhs. This is accomplished by
move constructing the base class, and
the contained basic_filebuf. Next
basic_istream::set_rdbuf(&sb) is called to install the contained
basic_filebuf.
See How to return an fstream (C++0x) for discussion on this subject.
If the QFile object you get is not open for read already, you can get filename from it and open an ifstream object.
If it's already open, you can get file handle/descriptor with handle() and go from there. There's no portable way of getting a fstream from platform handle. You will have to find a workaround for your platforms.
Here's a good guide for subclassing std::streambuf to provide a non-seekable read-only std::istream: https://stackoverflow.com/a/14086442/316578
Here is a simple class based on that approach which adapts a QFile into an std::streambuf which can then be wrapped in an std::istream.
#include <iostream>
#include <QFile>
constexpr qint64 ERROR = -1;
constexpr qint64 BUFFER_SIZE = 1024;
class QFileInputStreamBuffer final : public std::streambuf {
private:
QFile &m_file;
QByteArray m_buffer;
public:
explicit QFileInputStreamBuffer(QFile &file)
: m_file(file),
m_buffer(BUFFER_SIZE, Qt::Uninitialized) {
}
virtual int underflow() override {
if (atEndOfBuffer()) {
// try to get more data
const qint64 bytesReadIntoBuffer = m_file.read(m_buffer.data(), BUFFER_SIZE);
if (bytesReadIntoBuffer != ERROR) {
setg(m_buffer.data(), m_buffer.data(), m_buffer.data() + bytesReadIntoBuffer);
}
}
if (atEndOfBuffer()) {
// no more data available
return std::char_traits<char>::eof();
}
else {
return std::char_traits<char>::to_int_type(*gptr());
}
}
private:
bool atEndOfBuffer() const {
return gptr() == egptr();
}
};
If you want to be able to more things like seek, write, etc., then you'd need one of the other more complex solutions here which override more streambuf functions.
If you don't care much for performance you can always read everything from the file and dump it into an std::stringstream and then pass that to your library. (or the otherway, buffer everything to a stringstream and then write to a QFile)
Other than that, it doesn't look like the two can inter-operate. At any rate, Qt to STL inter operations are often a cause for obscure bugs and subtle inconsistencies if the version of STL that Qt was compiled with is different in any way from the version of STL you are using. This can happen for instance if you change the version of Visual Studio.

Resources