I'm in the process of rewriting legacy code based on an old Framework with C++11 using thread and chrono libraries.
To summarize the library spawns a thread and waits either an event or a delay.
My problem is that when I strip the binary removing the .gnu.version section, the program segfaults.
I am wondering what's the purpose of this section and how does stripping it from a binary may lead to a different behavior and cause a segfault ?
I've written a code sample that works well until I strip the .gnu.version section.
1. Compilation
g++ -std=c++11 test.cpp -o test -pthread -lpthread
2. Execution before strip
$ ./test
>>run()
run() - before wait()
>>wait()
< wait()
run() - after wait()
run() - before wait_until()
run() - after wait_until()
run() - before wait()
run() - after wait()
< run()
3. Strip .gnu.version section
strip -R .gnu.version test
4. Execution after strip
./test
>>run()
run() - before wait()
>>wait()
< wait()
run() - after wait()
run() - before wait_until()
Segmentation fault (core dumped)
From what I was able to investigate the segfault occurs in std::condition_variable::.wait_until() when calling the undelaying pthread library.
Here is the code sample :
#include <thread>
#include <iostream>
#include <condition_variable>
#include <unistd.h>
class Task
{
private:
std::mutex _mutex;
std::condition_variable _cv;
std::thread _thread;
bool _bStop;
bool _bWait;
void run()
{
std::unique_lock<std::mutex> lock(_mutex);
std::cout << ">>run()" << std::endl;
while (!_bStop)
{
if ( !_bWait )
{
std::cout << " run() - before wait()" << std::endl;
_cv.wait(lock);
std::cout << " run() - after wait()" << std::endl;
}
else
{
_bWait = false;
std::chrono::steady_clock::time_point ts = std::chrono::steady_clock::now()
+ std::chrono::seconds(1);
std::cout << " run() - before wait_until()" << std::endl;
_cv.wait_until(lock,ts);
std::cout << " run() - after wait_until()" << std::endl;
}
}
std::cout << "< run()" << std::endl;
}
public:
Task():_bStop(false),_bWait(false)
{
}
void start()
{
_thread = std::thread(&Task::run,this);
}
void wait()
{
std::cout << ">>wait()" << std::endl;
std::unique_lock<std::mutex> lock(_mutex);
_bWait = true;
_cv.notify_one();
std::cout << "< wait()" << std::endl;
}
void cancel()
{
std::unique_lock<std::mutex> lock(_mutex);
_bStop = true;
_cv.notify_one();
}
void join()
{
_thread.join();
}
};
int main()
{
Task t;
// Start Task thread
t.start();
// Sleeping here seems to help produce the error
usleep(10000);
t.wait();
// Wait for Task to process delay
sleep(5);
// Stop Task and wait for thread termination
t.cancel();
t.join();
return 0;
}
Related
I picked up the code from the conditional_variable::wait reference. The reference states that :
wait causes the current thread to block until the condition variable
is notified or a spurious wakeup occurs, optionally looping until some
predicate is satisfied.
The link also states that the wait is equivalent to :
while (!pred()) {
wait(lock); }
If that is the case, is there a reason why the following code does not work as the original code?
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>
std::condition_variable cv;
std::mutex cv_m; // This mutex is used for three purposes:
// 1) to synchronize accesses to i
// 2) to synchronize accesses to std::cerr
// 3) for the condition variable cv
int i = 0;
void waits()
{
std::unique_lock<std::mutex> lk(cv_m);
std::cerr << "Waiting... \n";
cv.wait(lk, [] {std::cout << "Check Done!" << std::endl; return i == 1; });
std::cerr << "...finished waiting. i == 1\n";
}
void signals()
{
std::this_thread::sleep_for(std::chrono::seconds(1));
{
std::lock_guard<std::mutex> lk(cv_m);
std::cerr << "Notifying...\n";
}
cv.notify_all();
std::this_thread::sleep_for(std::chrono::seconds(1));
{
std::lock_guard<std::mutex> lk(cv_m);
i = 1;
std::cerr << "Notifying again...\n";
}
//cv.notify_all();
}
int main()
{
std::thread t1(waits), t2(waits), t3(waits), t4(signals);
t1.join();
t2.join();
t3.join();
t4.join();
}
I'm trying to download this link using an C++ apllication. But the it encountered exception:
terminate called after throwing an instance of 'boost::wrapexcept'
what(): body limit exceeded
This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.
I found out the problem is in http::write.
What on earth is going wrong? Does that mean I was just trying to download the whole file into the memory? If yes, can I continue using ssl::stream anymore? Or there's any alternative?
#ifndef __kernel_entry
#define __kernel_entry
#endif
#include <boost/asio.hpp>
#include <windows.h>
#include <boost/asio/ssl.hpp>
#include <boost/beast.hpp>
#include <boost/beast/http.hpp>
#include <boost/process.hpp>
#include <boost/process/async.hpp>
#include <iomanip>
#include <iostream>
void handle_batch(std::vector<size_t> params) {
std::mutex s_mx;
if (!params.empty()) {
// emulate some work, because I'm lazy
auto sum = std::accumulate(begin(params), end(params), 0ull);
// then wait some 100..200ms
{
using namespace std::chrono_literals;
std::mt19937 prng(std::random_device{}());
std::this_thread::sleep_for(
std::uniform_real_distribution<>(100,200)(prng)*1ms);
}
// simple thread id (thread::id displays ugly)
auto tid = std::hash<std::thread::id>{}(std::this_thread::get_id()) % 100;
// report results to stdout
std::lock_guard lk(s_mx); // make sure the output doesn't intermix
std::cout
<< "Thread #" << std::setw(2) << std::setfill('0') << tid
<< " Batch n:" << params.size()
<< "\tRange [" << params.front() << ".." << params.back() << "]"
<< "\tSum:" << sum
<< std::endl;
}
}
namespace net = boost::asio;
namespace ssl = net::ssl;
namespace beast = boost::beast;
namespace http = beast::http;
namespace process = boost::process;
using boost::system::error_code;
using boost::system::system_error;
using net::ip::tcp;
using stream = ssl::stream<tcp::socket>;
auto ssl_context() {
ssl::context ctx{ssl::context::sslv23};
return ctx;
}
void connect_https(stream& s, std::string const& host, tcp::resolver::iterator eps) {
net::connect(s.lowest_layer(), eps);
s.lowest_layer().set_option(tcp::no_delay(true));//dealt here
if (!SSL_set_tlsext_host_name(s.native_handle(), host.c_str())) {
throw system_error{ { (int)::ERR_get_error(), net::error::get_ssl_category() } };
}
s.handshake(stream::handshake_type::client);
}
auto get_request(std::string const& host, std::string const& path) {
using namespace http;
using std::cerr;
request<string_body> req;
req.version(11);cerr<<"__ver";
req.method(verb::get);cerr<<"__met";
req.target("https://" + host + path);cerr<<"__tar";
//req.set(field::user_agent, "test");
req.set(field::host, host);cerr<<"__set";
std::cerr << req << std::endl;
Sleep(1000);
return req;
}
int main() {
net::io_context io; // main thread does all io
net::thread_pool pool(6); // worker threads
// outside for lifetime
http::response_parser<http::buffer_body> response_reader;
beast::flat_buffer lookahead; // for the response_reader
std::array<char,512> buf{0}; // for download content
auto ctx = ssl_context();
ssl::stream<tcp::socket> s(io, ctx);
{ // synchronously write request
std::string host = "www.sfml-dev.org";
try{
connect_https(s, host, tcp::resolver{io}.resolve(host, "https"));
}catch(std::exception& e){std::cerr<<e.what()<<std::endl;}
http::write(s, get_request(host, "/files/SFML-2.5.1-windows-gcc-7.3.0-mingw-32-bit.zip"));
http::read_header(s, lookahead, response_reader);
std::cerr << "Headers: " << response_reader.get().base() << std::endl;
}//https://www.sfml-dev.org/files/SFML-2.5.1-windows-gcc-7.3.0-mingw-32-bit.zip
// now, asynchoronusly read contents
process::async_pipe pipe_to_zcat(io);
std::function<void(error_code, size_t)> receive_zip;
receive_zip = [&s, &response_reader, &pipe_to_zcat, &buf, &lookahead, &receive_zip](error_code ec, size_t /*ignore_this*/) {
auto& res = response_reader.get();
auto& body = res.body();
if (body.data) {
auto n = sizeof(buf) - body.size;
net::write(pipe_to_zcat, net::buffer(buf, n));
}
bool done = ec && !(ec == http::error::need_buffer);
done += response_reader.is_done();
if (done) {
std::cerr << "receive_zip: " << ec.message() << std::endl;
pipe_to_zcat.close();
} else {
body.data = buf.data();
body.size = buf.size();
http::async_read(s, lookahead, response_reader, receive_zip);
}
};
// kick off receive loop
receive_zip(error_code{}, 0);
process::async_pipe zcat_output(io);
process::child zcat(
process::search_path("zcat"),
process::std_in < pipe_to_zcat,
process::std_out > zcat_output,
process::on_exit([](int exitcode, std::error_code ec) {
std::cerr << "Child process exited with " << exitcode << " (" << ec.message() << ")\n";
}), io);
std::function<void(error_code, size_t)> receive_primes;
net::streambuf sb;
receive_primes = [&zcat_output, &sb, &receive_primes, &pool](error_code ec, size_t /*transferred*/) {
{
std::istream is(&sb);
size_t n = std::count(net::buffers_begin(sb.data()), net::buffers_end(sb.data()), '\n');
std::vector<size_t> batch(n);
std::copy_n(std::istream_iterator<size_t>(is), n, batch.begin());
is.ignore(1, '\n'); // we know a newline is pending, eat it to keep invariant
post(pool, std::bind(handle_batch, std::move(batch)));
}
if (ec) {
std::cerr << "receive_primes: " << ec.message() << std::endl;
zcat_output.close();
} else {
net::async_read_until(zcat_output, sb, "\n", receive_primes);
}
};
// kick off handler loop as well:
receive_primes(error_code{}, 0);
io.run();
pool.join();
}
I'm trying to refactor a rather complicated piece of code and run into segfaults during loading the library. This is a minimal example of what I could single out to be the source of the segfault:
#include <iostream>
#include <string>
#include <map>
class Manager {
public:
class Action{
};
static bool registerAction(const Action* a, const char* name);
};
namespace Actions {
class ExampleAction : public Manager::Action {
};
namespace {
static bool available = Manager::registerAction(new ExampleAction(),"ExampleAction");
}
}
namespace {
typedef std::map<const std::string,const Manager::Action*> ActionList;
static ActionList sActions;
}
bool Manager::registerAction(const Action* a, const char* name){
std::cout << "attempting to register action " << a << " as " << name << std::endl;
sActions[name] = a;
std::cout << "done" << std::endl;
return true;
}
int main(){
std::cout << "hello!" << std::endl;
for(auto it:sActions){
std::cout << it.first << std::endl;
}
std::cout << "world!" << std::endl;
return 0;
}
It compiles fine with g++ 4.8.4 using the --std=c++11 flag, but upon execution, this happens:
attempting to register action 0x1ebe010 as ExampleAction
Segmentation fault (core dumped)
The line attempting to register comes first, which is of course expected, but the line assigning the value to the static map instance causes the crash, and I don't understand the reason. I'm probably being stupid here, but still - any suggestions on how to fix this?
I'm trying to run an example of websocket++ that consists in receive messages from websocket clients and broadcast to all connected clients, but i having problems with thread synchronization.
In the code example the method process_messages waits for message on a std:queue
boost::unique_lock<boost::mutex> lock(m_action_lock);
while(m_actions.empty()) {
m_action_cond.wait(lock);
}
And the on_message handler locks the queue before to push a new message received from client, but when it try to notify_one(), the program fail with an Segmentation fault 11.
void on_message(connection_hdl hdl, server::message_ptr msg) {
// queue message up for sending by processing thread
{
boost::unique_lock<boost::mutex> lock(m_action_lock);
m_actions.push(action(MESSAGE,msg));
lock.unlock();
}
m_action_cond.notify_one();
}
The only way that the program works is commenting the wait(lock) but i not sure if this is safe.
Some body could help me to find de segmentation fault cause?
The complete code is:
#include <websocketpp/config/asio_no_tls.hpp>
#include <websocketpp/server.hpp>
#include <iostream>
#include <boost/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition_variable.hpp>
typedef websocketpp::server<websocketpp::config::asio> server;
using websocketpp::connection_hdl;
using websocketpp::lib::placeholders::_1;
using websocketpp::lib::placeholders::_2;
using websocketpp::lib::bind;
/* on_open insert connection_hdl into channel
* on_close remove connection_hdl from channel
* on_message queue send to all channels
*/
enum action_type {
SUBSCRIBE,
UNSUBSCRIBE,
MESSAGE
};
struct action {
action(action_type t, connection_hdl h) : type(t), hdl(h) {}
action(action_type t, server::message_ptr m) : type(t), msg(m) {}
action_type type;
websocketpp::connection_hdl hdl;
server::message_ptr msg;
};
class broadcast_server {
public:
broadcast_server() {
// Initialize Asio Transport
m_server.init_asio();
// Register handler callbacks
m_server.set_open_handler(bind(&broadcast_server::on_open,this,::_1));
m_server.set_close_handler(bind(&broadcast_server::on_close,this,::_1));
m_server.set_message_handler(bind(&broadcast_server::on_message,this,::_1,::_2));
}
void run(uint16_t port) {
// listen on specified port
m_server.listen(port);
// Start the server accept loop
m_server.start_accept();
// Start the ASIO io_service run loop
try {
m_server.run();
} catch (const std::exception & e) {
std::cout << e.what() << std::endl;
} catch (websocketpp::lib::error_code e) {
std::cout << e.message() << std::endl;
} catch (...) {
std::cout << "other exception" << std::endl;
}
}
void on_open(connection_hdl hdl) {
boost::unique_lock<boost::mutex> lock(m_action_lock);
//std::cout << "on_open" << std::endl;
m_actions.push(action(SUBSCRIBE,hdl));
lock.unlock();
m_action_cond.notify_one();
}
void on_close(connection_hdl hdl) {
boost::unique_lock<boost::mutex> lock(m_action_lock);
//std::cout << "on_close" << std::endl;
m_actions.push(action(UNSUBSCRIBE,hdl));
lock.unlock();
m_action_cond.notify_one();
}
void on_message(connection_hdl hdl, server::message_ptr msg) {
// queue message up for sending by processing thread
boost::unique_lock<boost::mutex> lock(m_action_lock);
//std::cout << "on_message" << std::endl;
m_actions.push(action(MESSAGE,msg));
lock.unlock();
m_action_cond.notify_one();
}
void process_messages() {
while(1) {
boost::unique_lock<boost::mutex> lock(m_action_lock);
while(m_actions.empty()) {
m_action_cond.wait(lock);
}
action a = m_actions.front();
m_actions.pop();
lock.unlock();
if (a.type == SUBSCRIBE) {
boost::unique_lock<boost::mutex> lock(m_connection_lock);
m_connections.insert(a.hdl);
} else if (a.type == UNSUBSCRIBE) {
boost::unique_lock<boost::mutex> lock(m_connection_lock);
m_connections.erase(a.hdl);
} else if (a.type == MESSAGE) {
boost::unique_lock<boost::mutex> lock(m_connection_lock);
con_list::iterator it;
for (it = m_connections.begin(); it != m_connections.end(); ++it) {
m_server.send(*it,a.msg);
}
} else {
// undefined.
}
}
}
private:
typedef std::set<connection_hdl,std::owner_less<connection_hdl>> con_list;
server m_server;
con_list m_connections;
std::queue<action> m_actions;
boost::mutex m_action_lock;
boost::mutex m_connection_lock;
boost::condition_variable m_action_cond;
};
int main() {
broadcast_server server;
// Start a thread to run the processing loop
boost::thread(bind(&broadcast_server::process_messages,&server));
// Run the asio loop with the main thread
server.run(9002);
}
I can reproduce this behavior when Boost is compiled using g++ and libstdc++ but the program linking to it is compiled using clang and libc++. The libstdc++ and libc++ standard libraries are not ABI compatible, so you will need to build everything with one or everything with the other.
Details on how to compile Boost in C++11 mode with clang/libc++:
How to compile/link Boost with clang++/libc++?
After porting a code segment from Windows to Mac OS X, I found it to consume a whole CPU core while running; the responsible call for the CPU consumption is boost::interprocess::interprocess_semaphore::timed_wait.
Here follows the code portion which reproduces this behaviour.
#include <boost/interprocess/sync/interprocess_semaphore.hpp>
#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/mapped_region.hpp>
#include <boost/thread/thread_time.hpp>
#include <iostream>
static bool gStopRequested(false);
struct ShmObj
{
boost::interprocess::interprocess_semaphore mSemaphore;
ShmObj() : mSemaphore(0) {};
~ShmObj() {};
};
int main(char* argc, const char** argv)
{
boost::interprocess::shared_memory_object* lShmObj = NULL;
std::string lShmObjName("My_Boost_Interprocess_Test");
boost::interprocess::mapped_region* lRegion;
ShmObj* lObj;
//Create shared segment
try
{
lShmObj = new boost::interprocess::shared_memory_object(boost::interprocess::create_only, lShmObjName.c_str(), boost::interprocess::read_write);
}
catch (boost::interprocess::interprocess_exception &ex)
{
if (ex.get_error_code() != boost::interprocess::already_exists_error)
{
std::cerr << "Some error" << std::endl;
exit(1);
}
else
{
std::cerr << "Already exists, just taking it back." << std::endl;
try
{
lShmObj = new boost::interprocess::shared_memory_object(boost::interprocess::open_only, lShmObjName.c_str(), boost::interprocess::read_write);
}
catch (boost::interprocess::interprocess_exception &ex2)
{
std::cerr << "D'oh !" << std::endl;
exit(1);
}
}
}
if (!lShmObj)
{
exit(1);
}
lShmObj->truncate(sizeof(ShmObj));
lRegion = new boost::interprocess::mapped_region(*lShmObj, boost::interprocess::read_write);
lObj = new (lRegion->get_address()) ShmObj;
// The loop
while (!gStopRequested)
{
boost::system_time lDeadlineAbsoluteTime = boost::get_system_time() + boost::posix_time::milliseconds(500);
if (lObj->mSemaphore.timed_wait(lDeadlineAbsoluteTime))
{
std::cout << "acquired !" << std::endl;
}
else
{
std::cout << "tick" << std::endl;
}
}
}
Then, I read that unnamed semaphores were not available under Mac OS X, so I thought it could be because unnamed semaphores were not efficiently emulated... I then tried the following, unsucessfully:
#include <boost/interprocess/sync/named_semaphore.hpp>
#include <boost/thread/thread_time.hpp>
#include <iostream>
static bool gStopRequested(false);
int main(char* argc, const char** argv)
{
boost::interprocess::named_semaphore::remove("My_Boost_Interprocess_Test");
boost::interprocess::named_semaphore lMySemaphore(boost::interprocess::open_or_create, "My_Boost_Interprocess_Test", 1);
// The loop
while (!gStopRequested)
{
boost::system_time lDeadlineAbsoluteTime = boost::get_system_time() + boost::posix_time::milliseconds(500);
if (lMySemaphore.timed_wait(lDeadlineAbsoluteTime))
{
std::cout << "acquired !" << std::endl;
}
else
{
std::cout << "tick" << std::endl;
}
}
}
I was actually expecting a better behaviour of boost::interprocess on Mac OS X because of the available Posix primitives, but it is actually not. Any idea for a resolution? Thanks a lot.
I successfully Used Mach semaphores instead of the ones of boost::interprocess... see http://pkaudio.blogspot.com/2010/05/mac-os-x-no-timed-semaphore-waits.html