asio high_resolution_timer segmentation fault in async_wait - c++

I have implemented a task queue with priority from asio examples and a timer class which use this queue. Here is the code:
priority_task_queue.h
class handler_priority_queue
{
private:
class queued_handler{
private:
size_t _priority;
std::function<void()> _function;
public:
queued_handler(size_t p, std::function<void()> f): _priority(p), _function(f){}
friend bool operator<(const queued_handler& a, const queued_handler& b){
return a._priority < b._priority;
}
void operator()() {
_function();
}
};
std::priority_queue<queued_handler> _handlers;
public:
// A generic wrapper class for handlers to allow the invocation to be hooked.
template <typename Handler> class wrapped_handler
{
private:
handler_priority_queue& _queue;
size_t _priority;
Handler _handler;
public:
handler_priority_queue& queue() {return _queue;}
size_t priority() {return _priority;}
wrapped_handler(handler_priority_queue& q, size_t p, Handler h)
: _queue(q), _priority(p), _handler(h){}
template <typename ...Args>
void operator()(Args&&... args){
_handler(std::forward<Args>(args)...);
}
};
template <typename Handler> wrapped_handler<Handler> wrap(size_t priority, Handler handler){
return wrapped_handler<Handler>(*this, priority, handler);
}
void add(size_t priority, std::function<void()> function);
void execute_all();
void execute_one();
bool empty();
};
// Custom invocation hook for wrapped handlers.
template <typename Function, typename Handler>
void asio_handler_invoke(Function f, handler_priority_queue::wrapped_handler<Handler>* h){
h->queue().add(h->priority(), f);
std::cout<<"LLAMANDO AL INVOKE"<<std::endl; //BORRAR!!
}
class C_priority_task_queue{
private:
asio::io_service& _io;
handler_priority_queue _pri_queue;
public:
template <typename Handler> handler_priority_queue::wrapped_handler<Handler> wrap(int priority, Handler handler){
return _pri_queue.wrap(priority, handler);
}
explicit C_priority_task_queue(asio::io_service& io): _io(io){}
C_priority_task_queue(C_priority_task_queue const&) = delete;
C_priority_task_queue& operator =(C_priority_task_queue const&) = delete;
asio::io_service& io() {return _io;}
void run();
};
priority_task_queue.cpp
void handler_priority_queue::add(size_t priority, std::function<void()> function){
_handlers.push(queued_handler(priority, function));
}
void handler_priority_queue::execute_one(){
if(!_handlers.empty()){
queued_handler handler = _handlers.top();
handler();
_handlers.pop();
}
}
bool handler_priority_queue::empty(){
return _handlers.empty();
}
void C_priority_task_queue::run(){
while (_io.run_one())
{
_io.poll();
while(!_pri_queue.empty())
{
_io.poll();
_pri_queue.execute_one();
}
}
}
base_timer.h
class C_timer {
private:
asio::high_resolution_timer _timer;
uint8_t _timer_id;
C_priority_task_queue& _prio_queue;
void timer_handler_internal(const asio::error_code& e, uint8_t timer_id, const uint64_t sched_time);
virtual void timer_handler(const uint64_t sched_time)=0;
public:
size_t _priority;
explicit C_timer(C_priority_task_queue& prio_queue, size_t priority);
virtual ~C_timer();
void set_timer(uint64_t sched_time);
int cancel();
};
base_timer.cpp
C_timer::C_timer(C_priority_task_queue& prio_queue, size_t priority):
_timer(prio_queue.io()), _timer_id(0), _prio_queue(prio_queue), _priority(priority){}
C_timer::~C_timer(){}
void C_timer::set_timer(uint64_t sched_time){
++_timer_id;
_timer.expires_at(std::chrono::time_point<std::chrono::high_resolution_clock>(std::chrono::milliseconds(sched_time)));
_timer.async_wait(_prio_queue.wrap(_priority, std::bind(&C_timer::timer_handler_internal, this,
std::placeholders::_1/*error*/, _timer_id, sched_time)));
}
int C_timer::cancel(){
++_timer_id;
return _timer.cancel();
}
void C_timer::timer_handler_internal(const asio::error_code& e, uint8_t timer_id,
const uint64_t sched_time){
if(e==asio::error::operation_aborted || timer_id != _timer_id){
return;
}
timer_handler(sched_time);
}
test class
class C_timer_test: public C_timer{
private:
int _period;
virtual void timer_handler(const uint64_t sched_time) override{
std::cout<<"timer fired"<<std::endl;
uint64_t current_time = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now().time_since_epoch()).count();
set_timer(current_time + _period);
}
public:
C_timer_test(C_priority_task_queue& prio_queue, int priority, int period):C_timer(prio_queue, priority), _periodo(period){}
virtual ~C_timer_test(){}
void run(uint64_t delay=0){
uint64_t time = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now().time_since_epoch()).count();
set_timer(time + delay);
}
};
The problem is if I execute this :
int main()
{
asio::io_service io;
C_priority_task_queue prio_queue(io);
asio::io_service::work w(io);
C_timer_test ti1(prio_queue, 0, 2000);
ti1.run();
prio_queue.run();
return 0;
}
I get a segmentation fault.
However, if I execute the following code it works fine:
int main()
{
asio::io_service io;
C_priority_task_queue prio_queue(io);
asio::high_resolution_timer _timer1(io);
asio::io_service::work w(io);
C_timer_test ti1(prio_queue, 0, 2000);
ti1.run();
prio_queue.run();
return 0;
}
The only diference between both piece of code is in the second main I have added the following line asio::high_resolution_timer _timer1(io); that I haven't use in any place.
Debugging the program I have found that the signal is raising in this line:
func_(&owner, this, ec, bytes_transferred); in file task_io_service_operation.hpp
I am using asio version 1.10.6.
Any suggestion that what could be happening?
The backtrace from gdb:
gdb ./main
GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.2) 7.7.1
This GDB was configured as "i686-linux-gnu".
(gdb) r
[libthread_db enabled]
Using host libthread_db library "/lib/i386-linux-gnu/libthread_db.so.1".
Program received signal SIGSEGV, Segmentation fault.
0x0805f0d4 in ?? ()
(gdb) backtrace
#0 0x0805f0d4 in ?? ()
#1 0x080529fb in asio::detail::task_io_service::do_run_one (this=0x805f030, lock=..., this_thread=..., ec=...) at /src/cpp/external_lib/asio/include/asio/detail/impl/task_io_service.ipp:371
#2 0x080526ce in asio::detail::task_io_service::run_one (this=0x805f030, ec=...) at /src/cpp/external_lib/asio/include/asio/detail/impl/task_io_service.ipp:169
#3 0x08052c68 in asio::io_service::run_one (this=0xbffff08c) at /src/cpp/external_lib/asio/include/asio/impl/io_service.ipp:71
#4 0x08051f32 in C_priority_task_queue::run (this=0xbffff094) at priority_task_queue.cpp:19
#5 0x08049ac3 in main () at main.cpp:46
And here there is the MakeFile:
TARGET=main
SOURCES= main.cpp base_timer.cpp priority_task_queue.cpp
SOURCE_DIR=.
INCLUDE_LIB= -L/src/cpp/libcore
INCLUDE_DIR=-I/src/cpp/external_lib/asio/include \
-I/src/cpp/libcore/include
INSTALL_DIR=.
LIB=-pthread
CXX=g++
CFLAGS=-Wall -fexceptions -fpermissive -std=c++11 -DASIO_STANDALONE
CFLAGS_DEBUG = -g3 -DDEBUG
OBJDIR_DEBUG=obj
BINDIR_DEBUG=.
OBJECTS_DEBUG:= $(addprefix $(OBJDIR_DEBUG)/,$(SOURCES:.cpp=.o))
all: debug
$(OBJDIR_DEBUG)/%.o: $(SOURCE_DIR)/%.cpp
#test -d $(OBJDIR_DEBUG) || mkdir -p $(OBJDIR_DEBUG)
$(CXX) $(CFLAGS) $(CFLAGS_DEBUG) $(INCLUDE_DIR) -c $< -o $#
debug: $(OBJECTS_DEBUG)
#test -d $(BINDIR_DEBUG) || mkdir -p $(BINDIR_DEBUG)
$(CXX) -o $(BINDIR_DEBUG)/$(TARGET) $^ $(INCLUDE_LIB) $(LIB)
UPDATE
I my investigation, I have found that if I define the base_timer members (basically asio::high_resolution_timer) initializations in the .h, the code runs ok, but if I do this in the .cpp, the code crash.
I mean,
explicit C_timer(C_priority_task_queue& prio_queue, size_t priority):
_timer(prio_queue.io()), _timer_id(0), _prio_queue(prio_queue), _priority(priority){}
in .h works, but
C_timer::C_timer(C_priority_task_queue& prio_queue, size_t priority):
_timer(prio_queue.io()), _timer_id(0), _prio_queue(prio_queue), _priority(priority){}
in .cpp fails

Except for "unnatural" juggling with chrono (timepoint or duration, pick one!) the code looks ok. I can't reproduce any failure (GCC, linux):
Live On Coliru
If adding random variables make problems appear/disappear, you should think of Undefined Behaviour, use static analysis, valgrind/purify/... and code scrutiny to find your culprit. Valgrind, ASAN and UBSAN ran clean on my PC
#sehe thanks for your effort. The diference is If I put every code into a single file, main.cpp, it runs, but if I separate into several files, the problem still there. In other hand, If I instanciate a high_resolution_timer object in the main.cpp, no matter the place (inside main(), in separate function that never is called, ...) it runs, but without it, a segmentation fault is raised.
That's great: you have found a potential source of the UB: look at the use of static variables or inline functions that are not ODR-safe. (Double check all translation units are using the same compiler flags).
Also, keep in mind UB is UNDEFINED, so like adding an unrelated _timer1 changes the apparent behaviour (without changing the source of UB) the same thing could make it appear to work.
The fact that it runs clean on my machine tells you that this would have to be a platform-specific source of UB

The problem was that I had been using the version 1.10.2 of the library and it seems there was a bug.
I have updated to the last version 1.10.6 and now it runs ok.

Related

[Boost::ext].SML: Segmentation fault in guard with Mingw64 GCC, debug build

Code
#include <sml.hpp>
namespace {
struct Event {
bool pressed;
};
struct Guard1 {
[[nodiscard]] bool operator()(const Event& e) const {
return e.pressed;
}
} guard1;
struct Guard2 {
[[nodiscard]] bool operator()(const Event& e) const {
return true;
}
} guard2;
struct Guard3 {
[[nodiscard]] bool operator()(const Event& e) const {
return true;
}
} guard3;
}// namespace
namespace sml = boost::sml;
struct Fsm {
struct State {};
auto operator()() const {
using namespace boost::sml;
return make_transition_table(
// clang-format off
*state<State> + event<Event>[guard1 && guard2 && guard3] = state<State>
// clang-format on
);
}
};
int main() {
boost::sml::sm<Fsm> fsm{};
fsm.process_event(Event{});
}
Expected Behavior
No segmentation fault.
Actual Behavior
Segmentation fault when accessing the pressed field in Guard1.
Process finished with exit code -1073741819 (0xC0000005)
Event address is still ok in front::transition::execute:
But in front::call::execute it gets corrupted:
If I remove one of the guard, it works fine.
Steps to Reproduce the Problem
use gcc from MSYS2, gcc --version gcc.exe (Rev2, Built by MSYS2 project) 12.1.0
build with -g -std=gnu++20
run
Specifications
Version: 1.1.4, 1.1.5
Platform: Windows, GCC 12.1.0 (MSYS2 mingw-w64-x86_64-gcc)

invalid use of template-name ‘boost::asio::strand’ without an argument list

I have an older program that I want to compile on Centos 8 with GCC 8.3.1. The make command looks like this:
CXXFLAGS = -O2 -std=c++11
all: my_prog
my_prog: my_prog.o
g++ my_prog.o -o my_prog -lboost_filesystem -lboost_system -lsecond_level_include -lthird_level_include -lboost_regex -lboost_program_options `mysql_config --libs`
Here is the output for make:
In file included from /usr/local/include/redisclient/redissyncclient.h:16,
from /usr/local/include/third_level_include.hpp:11,
from /usr/local/include/second_level_include.hpp:40,
from my_prog.cpp:9:
/usr/local/include/redisclient/impl/redisclientimpl.h:72:5: error: invalid use of template-name ‘boost::asio::strand’ without an argument list
boost::asio::strand strand;
^~~~~
/usr/local/include/redisclient/impl/redisclientimpl.h:72:5: note: class template argument deduction is only available with -std=c++17 or -std=gnu++17
In file included from /usr/local/include/redisclient/impl/redisclientimpl.h:13,
from /usr/local/include/redisclient/redissyncclient.h:16,
from /usr/local/include/third_level_include.hpp:11,
from /usr/local/include/second_level_include.hpp:40,
from my_prog.cpp:9:
/usr/include/boost/asio/strand.hpp:29:7: note: ‘template<class Executor> class boost::asio::strand’ declared here
class strand
^~~~~~
[snip lots of output]
So I did what it suggested and replaced -std=c++11 with -std=gnu++17 and now
I get this:
g++ -O2 -std=gnu++17 -c -o my_prog.o my_prog.cpp
In file included from /usr/local/include/redisclient/redissyncclient.h:16,
from /usr/local/include/third_level_include.hpp:11,
from /usr/local/include/second_level_include.hpp:40,
from my_prog.cpp:9:
/usr/local/include/redisclient/impl/redisclientimpl.h:72:5: error: invalid use of template-name ‘boost::asio::strand’ without an argument list
boost::asio::strand strand;
^~~~~
make: *** [<builtin>: my_prog.o] Error 1
Considering that I'm not going to be changing the third party library code from Redis, is there a compiler flag or something I can use to make this error go away? The code compiled once upon a time with GCC 4.4.7 on Centos 6.
EDIT: here is the file that is the source of the error
/*
* Copyright (C) Alex Nekipelov (alex#nekipelov.net)
* License: MIT
*/
#ifndef REDISCLIENT_REDISCLIENTIMPL_H
#define REDISCLIENT_REDISCLIENTIMPL_H
#include <boost/array.hpp>
#include <boost/function.hpp>
#include <boost/noncopyable.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/strand.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <string>
#include <vector>
#include <queue>
#include <map>
#include "../redisparser.h"
#include "../redisbuffer.h"
#include "../config.h"
class RedisClientImpl : public boost::enable_shared_from_this<RedisClientImpl> {
public:
enum State {
NotConnected,
Connected,
Subscribed,
Closed
};
REDIS_CLIENT_DECL RedisClientImpl(boost::asio::io_service &ioService);
REDIS_CLIENT_DECL ~RedisClientImpl();
REDIS_CLIENT_DECL void handleAsyncConnect(
const boost::system::error_code &ec,
const boost::function<void(bool, const std::string &)> &handler);
REDIS_CLIENT_DECL void close();
REDIS_CLIENT_DECL State getState() const;
REDIS_CLIENT_DECL static std::vector<char> makeCommand(const std::vector<RedisBuffer> &items);
REDIS_CLIENT_DECL RedisValue doSyncCommand(const std::vector<RedisBuffer> &buff);
REDIS_CLIENT_DECL void doAsyncCommand(
const std::vector<char> &buff,
const boost::function<void(const RedisValue &)> &handler);
REDIS_CLIENT_DECL void sendNextCommand();
REDIS_CLIENT_DECL void processMessage();
REDIS_CLIENT_DECL void doProcessMessage(const RedisValue &v);
REDIS_CLIENT_DECL void asyncWrite(const boost::system::error_code &ec, const size_t);
REDIS_CLIENT_DECL void asyncRead(const boost::system::error_code &ec, const size_t);
REDIS_CLIENT_DECL void onRedisError(const RedisValue &);
REDIS_CLIENT_DECL static void defaulErrorHandler(const std::string &s);
REDIS_CLIENT_DECL static void append(std::vector<char> &vec, const RedisBuffer &buf);
REDIS_CLIENT_DECL static void append(std::vector<char> &vec, const std::string &s);
REDIS_CLIENT_DECL static void append(std::vector<char> &vec, const char *s);
REDIS_CLIENT_DECL static void append(std::vector<char> &vec, char c);
template<size_t size>
static inline void append(std::vector<char> &vec, const char (&s)[size]);
template<typename Handler>
inline void post(const Handler &handler);
boost::asio::strand strand; // Here it is!
boost::asio::ip::tcp::socket socket;
RedisParser redisParser;
boost::array<char, 4096> buf;
size_t subscribeSeq;
typedef std::pair<size_t, boost::function<void(const std::vector<char> &buf)> > MsgHandlerType;
typedef boost::function<void(const std::vector<char> &buf)> SingleShotHandlerType;
typedef std::multimap<std::string, MsgHandlerType> MsgHandlersMap;
typedef std::multimap<std::string, SingleShotHandlerType> SingleShotHandlersMap;
std::queue<boost::function<void(const RedisValue &v)> > handlers;
MsgHandlersMap msgHandlers;
SingleShotHandlersMap singleShotMsgHandlers;
struct QueueItem {
boost::function<void(const RedisValue &)> handler;
boost::shared_ptr<std::vector<char> > buff;
};
std::queue<QueueItem> queue;
boost::function<void(const std::string &)> errorHandler;
State state;
};
template<size_t size>
void RedisClientImpl::append(std::vector<char> &vec, const char (&s)[size])
{
vec.insert(vec.end(), s, s + size);
}
template<typename Handler>
inline void RedisClientImpl::post(const Handler &handler)
{
strand.post(handler);
}
#ifdef REDIS_CLIENT_HEADER_ONLY
#include "redisclientimpl.cpp"
#endif
#endif // REDISCLIENT_REDISCLIENTIMPL_H
UPDATE
You're using an old version of that library. Use v0.6.1 or higher:
https://github.com/nekipelov/redisclient/pull/53
All executor interfaces have been upgraded a (long) while ago.
Strands used to be nested typedefs (and there is still one for "legacy" compatibility in io_service if that is enabled).
However, the new type succeeding is is boost::asio::strand<Executor> (so e.g. boost::asio::io_context::executor_type). You can easily make a strand for any executor, e.g.:
auto s = make_strand(io_object.get_executor());
What you are seeing is apparent mix-up of these names. I suspect it may have to do with
local typedefs that alias strand
local variables named strand (though I don't see immediately how that would lead to the exact message mposted)
most likely: you have a using namespace that pulls in the new strand template
With this information, you should be able to sort it out.
Of course, had you posted the code, we could have shown it for you.

undefined reference to pthread create even with lpthread [duplicate]

This question already has answers here:
Difference between -pthread and -lpthread while compiling
(3 answers)
Closed 4 years ago.
I want to make use of pthread ad hence use the -lpthread flag to compile, but here's what I get:
$ g++ -lpthread pseudo_code.cpp
/tmp/cc3mPrvt.o: In function `MyThreadClass::StartInternalThread()':
pseudo_code.cpp:(.text._ZN13MyThreadClass19StartInternalThreadEv[_ZN13MyThreadClass19StartInternalThreadEv]+0x26): undefined reference to `pthread_create'
collect2: error: ld returned 1 exit status
The code I try to compile is below:
#include <pthread.h>
#include <iostream>
#include <vector>
#define OK 0
#define ERROR -1
//-- ThreadClass
class MyThreadClass
{
public:
MyThreadClass() {/* empty */}
virtual ~MyThreadClass() {/* empty */}
/** Returns true if the thread was successfully started, false if there was an error starting the thread */
bool StartInternalThread()
{
return (pthread_create(&_thread, NULL, InternalThreadEntryFunc, this) == 0);
}
/** Will not return until the internal thread has exited. */
void WaitForInternalThreadToExit()
{
(void) pthread_join(_thread, NULL);
}
protected:
/** Implement this method in your subclass with the code you want your thread to run. */
virtual void InternalThreadEntry() = 0;
private:
static void * InternalThreadEntryFunc(void * This) {
((MyThreadClass *)This)->InternalThreadEntry(); return NULL;
}
pthread_t _thread;
};
//-- /ThreadClass
//--- DUMMY DECLARATIONS BELOW TO MAKE IT COMPILE ---//
#define LOG_NS_ERROR std::cout
class test{
public:
int get_child(std::string x){return OK;};
};
test *_global;
typedef struct test_struct{} _db_transact;
class db_transact{
public:
db_transact(int,int&,int&){};
};
int _ns;
int _log_id;
//--- DUMMY DECLARATIONS ABOVE TO MAKE IT COMPILE ---//
class db_c_hndlr : public MyThreadClass{
public:
db_c_hndlr(void);
~db_c_hndlr(void);
db_transact *db_conn_get(void);
void InternalThreadEntry(void *func);
private:
int _stop;
std::vector<db_transact*> _db_pool;
};
//---------------------------------------------------------
db_c_hndlr::db_c_hndlr(void) {
}
//---------------------------------------------------------
void db_c_hndlr::InternatThreadEntry(void *func) {
while(!stop){
std::cout << "going!" << std::endl;
sleep(1);
}
}
//---------------------------------------------------------
db_c_hndlr::~db_c_hndlr() {
int i = 0;
std::vector<db_transact*>::iterator it;
for (i=0, it = _db_pool.begin();it!=_db_pool.end();it++, i++) {
if (_db_pool[i])
if (_db_pool[i]!=NULL)
delete _db_pool[i];
}
}
//---------------------------------------------------------
db_transact *db_c_hndlr::db_conn_get(void) {
db_transact *tmp;
tmp = new db_transact(_global->get_child("db_config"), _ns, _log_id);
_db_pool.push_back(tmp);
return tmp;
}
//---------------------------------------------------------
int main(void)
{
db_transact *conn=NULL;
db_c_hndlr db;
//db = new db_c_hndlr();
conn= db.db_conn_get();
return OK;
}
Probably you need to do this:
extern "C" {
#include <pthread.h>
}
That tells the compiler that this header is for a C library, and that it should not use C++ name mangling.
You also need to use -pthread instead of -lpthread, because the pthread library is special and GCC wants to explicitly know you are trying to use threads, not simply link against libpthread.
Please try to compile with the command.
g++ pseudo_code.cpp -lpthread
It makes a difference where in the command you write this option; the
linker searches and processes libraries and object files in the order
they are specified. Thus, foo.o -lz bar.o searches library z after
file foo.o but before bar.o. If bar.o refers to functions in z, those
functions may not be loaded.
It worked for me. It seems, needs to specify the library after the source file so that symbols are searched in the library.

clang-linux: reporting CFI errors without crashing. ftrap-function and -O2

I'm trying to use -ftrap-function flag from clang manual to catch CFI (call frame information) errors in a custom handler.
Here is a basic example generating a CFI error:
#include <stdio.h>
#include <stdlib.h>
__attribute__((used)) extern "C" void CatchCfi() {
printf("catched\n");
}
struct Foo {
Foo(const char* s) : command(s) {}
virtual ~Foo() {}
void fooStuff() { printf("fooStuff\n"); }
const char* command;
};
struct Bar {
Bar(const char* s) : name(s) {}
virtual ~Bar() {}
void barStuff() { printf("barStuff\n"); }
const char* name;
};
enum class WhichObject { FooObject, BarObject };
static void* allocator(WhichObject w, const char* arg) {
switch (w) {
case WhichObject::FooObject:
return new Foo(arg);
case WhichObject::BarObject:
return new Bar(arg);
}
}
int main(int argc, const char* argv[]) {
void* ptr = nullptr;
(void)(argc);
(void)(argv);
ptr = allocator(WhichObject::BarObject, "system(\"/bin/sh\")");
Foo* fooptr = static_cast<Foo*>(ptr);
fooptr->fooStuff();
printf("not printed when compiled with -O2\n");
return 0;
}
I build it with these CFI related clang options:
-ftrap-function=CatchCfi -fsanitize=cfi-vcall -fvisibility=hidden -fsanitize=cfi-derived-cast -fsanitize=cfi-unrelated-cast -flto=thin
When this example is built without optimization it works as I want. Output:
catched
fooStuff
not printed when compiled with -O2
The problem appear when I build it with -O2 option:
catched
Trace/breakpoint trap (core dumped)
GDB shows that the program is receiving SIGTRAP just after CatchCfi returns:
(gdb) r
Starting program: /home/romex/browser/src/out/debug/hello_cfi
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
catched
Program received signal SIGTRAP, Trace/breakpoint trap.
0x000000000020118a in ?? ()
(gdb) bt
#0 0x000000000020118a in ?? ()
#1 0x00000000002010f0 in frame_dummy ()
#2 0x00007ffff748e830 in __libc_start_main (main=0x201180 <main(int, char const**)>, argc=1, argv=0x7fffffffde18, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>,
stack_end=0x7fffffffde08) at ../csu/libc-start.c:291
#3 0x0000000000201029 in _start ()
Warning: the current language does not match this frame.
(gdb)
How to fix that?
I'm wondering if somebody has a success story dealing with ftrap-function flag? May be there is some specific optimization flag fixing this error?
Thanks.
I've updated your code so it works as expected. My environment does not raise SIGTRAP, thus I inserted __builtin_trap() call. As mentioned #YSC it is UB. The program can not continue after your trap function returns, you must restore the program to well known good state before SIGTRAP raised.
#include <setjmp.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
jmp_buf env;
__attribute__((used)) extern "C" void CatchCfi() {
printf("catched\n");
longjmp(env, 1);
}
struct Foo {
Foo(const char* s) : command(s) {}
virtual ~Foo() {}
void fooStuff() { printf("fooStuff\n"); }
const char* command;
};
struct Bar {
Bar(const char* s) : name(s) {}
virtual ~Bar() {}
void barStuff() { printf("barStuff\n"); }
const char* name;
};
enum class WhichObject { FooObject, BarObject };
static void* allocator(WhichObject w, const char* arg) {
switch (w) {
case WhichObject::FooObject:
return new Foo(arg);
case WhichObject::BarObject:
return new Bar(arg);
}
}
int main(int argc, const char* argv[]) {
void* ptr = nullptr;
(void)(argc);
(void)(argv);
ptr = allocator(WhichObject::BarObject, "system(\"/bin/sh\")");
int val = setjmp(env);
if (!val) {
Foo* fooptr = static_cast<Foo*>(ptr);
fooptr->fooStuff();
__builtin_trap();
}
printf("not printed when compiled with -O2\n");
return 0;
}
Since ptr is a pointer to a Bar,
Foo* fooptr = static_cast<Foo*>(ptr);
fooptr->fooStuff();
is undefined behavior and the compiler is not compelled to work as you expect him to.

How can I avoid an exception thrown by <thread> in C++11?

I am trying to write multi-thread software using the thread library in C++11. Some basic tutorials found on the internet can compile and run as expected. But my own application separated into classes always throws an exception.
Could anyone kindly tell me which part of the code should be fixed, please?
$ clang++ -std=c++11 -stdlib=libc++ BaseInterface.cxx -c -o BaseInterface.o
$ clang++ -std=c++11 -stdlib=libc++ SocketReceiver.cxx -c -o SocketReceiver.o
$ clang++ -std=c++11 -stdlib=libc++ main.cxx -c -o main.o
$ clang++ -std=c++11 -stdlib=libc++ main.o BaseInterface.o SocketReceiver.o -o main
$ gdb main
(gdb) run
Starting program: /Users/oxon/test/main
Reading symbols for shared libraries ++............................ done
libc++abi.dylib: terminate called throwing an exception
Program received signal SIGABRT, Aborted.
[Switching to process 859 thread 0x40b]
0x00007fff88df8212 in __pthread_kill ()
(gdb) bt
#0 0x00007fff88df8212 in __pthread_kill ()
#1 0x00007fff8bc85af4 in pthread_kill ()
#2 0x00007fff8bcc9dce in abort ()
#3 0x00007fff894d3a17 in abort_message ()
#4 0x00007fff894d13c6 in default_terminate ()
#5 0x00007fff89874887 in _objc_terminate ()
#6 0x00007fff894d13f5 in safe_handler_caller ()
#7 0x00007fff894d1450 in std::terminate ()
#8 0x00007fff894d25b7 in __cxa_throw ()
#9 0x00007fff8a9ba3b9 in std::__1::thread::join ()
#10 0x0000000100000cf0 in SocketReceiver::Receive ()
#11 0x0000000100000c6d in SocketReceiver::DoReceive ()
#12 0x0000000100001593 in _ZNSt3__114__thread_proxyINS_5tupleIJPFPvS2_ES2_EEEEES2_S2_ ()
#13 0x00007fff8bc84742 in _pthread_start ()
#14 0x00007fff8bc71181 in thread_start ()
This is the result on OS X 10.8. Scientific Linux 6 with GCC 4.4 also gives a similar result.
= BaseInterface.h =
#ifndef BASE_INTERFACE_H
#define BASE_INTERFACE_H
#include "SocketReceiver.h"
class BaseInterface
{
private:
SocketReceiver* fReceiver;
public:
BaseInterface();
virtual ~BaseInterface();
virtual void Close();
virtual void Open();
;
#endif
= BaseInterface.cxx =
#include <iostream>
#include <string.h>
#include <unistd.h>
#include "BaseInterface.h"
BaseInterface::BaseInterface()
{
fReceiver = new SocketReceiver(this);
}
//______________________________________________________________________________
BaseInterface::~BaseInterface()
{
Close();
delete fReceiver;
fReceiver = 0;
}
//______________________________________________________________________________
void BaseInterface::Close()
{
fReceiver->Stop();
usleep(10000);
while(fReceiver->IsRunning()){
usleep(10000);
} // while
}
//______________________________________________________________________________
void BaseInterface::Open()
{
fReceiver->Start();
}
= SocketReceiver.h =
#ifndef SOCKET_RECEIVER_H
#define SOCKET_RECEIVER_H
#include <thread>
#include <mutex>
class BaseInterface;
class SocketReceiver
{
private:
BaseInterface* fInterface;
bool fIsRunning;
std::mutex fMutex;
bool fStop;
std::thread* fThread;
public:
SocketReceiver(BaseInterface* interface = 0);
virtual ~SocketReceiver();
bool IsRunning() const {return fThread ? true : false;}
static void* DoReceive(void* arg);
void Receive();
void Start();
void Stop();
};
#endif
= SocketReceiver.cxx =
#include <iostream>
#include <thread>
#include <unistd.h>
#include "BaseInterface.h"
#include "SocketReceiver.h"
SocketReceiver::SocketReceiver(BaseInterface* interface)
{
fInterface = interface;
fStop = true;
fThread = 0;
}
//______________________________________________________________________________
SocketReceiver::~SocketReceiver()
{
}
//______________________________________________________________________________
void* SocketReceiver::DoReceive(void* arg)
{
SocketReceiver* receiver = (SocketReceiver*)arg;
receiver->Receive();
return 0;
}
//______________________________________________________________________________
void SocketReceiver::Receive()
{
while(not fStop){
fMutex.lock();
usleep(10000);
fMutex.unlock();
} // while
fThread->join();
delete fThread;
fThread = 0;
}
//______________________________________________________________________________
void SocketReceiver::Start()
{
fStop = false;
fThread = new std::thread(DoReceive, (void*)this);
}
//______________________________________________________________________________
void SocketReceiver::Stop()
{
fStop = true;
}
= main.cxx =
#include "BaseInterface.h"
int main()
{
BaseInterface interface;
interface.Open();
interface.Close();
return 0;
}
You're joining the thread in itself. Call join in the parent thread, like in SocketReceiver::Stop.
When join is called, it cleans up underlying data. And if you call it in the thread you're running then that data will be removed while the thread still needs it.
If the function run by a std::thread exits via and exception then std::terminate will be called.
std::thread::join() is specified to throw std::system_error with an error code resource_deadlock_would_occur if join() is called in the same thread, i.e. a thread cannot join itself. So your attempt to make the thread join itself causes an exception which terminates the process. A thread cannot join itself, joining is defined as "wait for the thread to complete" so obviously cannot be done by the thread itself, it would block waiting for itself to finish, which can't happen until the call to join() finishes, which can't happen until the thread finishes, which can't happen until the call to join() finishes ... can you see where this is going?
Also why are you doing this?
fThread = new std::thread(DoReceive, (void*)this);
std::thread is not pthread_create, you don't need to pass it void*, just get rid of DoReceive and call:
fThread = new std::thread(&SocketReceiver::Receive, this);
And why is your std::thread allocated with new? That's not necessary either, you can use a std::thread member and use joinable() to check if it's active or not, instead of checking if the pointer is non-null.