diff --git a/include/boost/stacktrace/detail/backend_linux.hpp b/include/boost/stacktrace/detail/backend_linux.hpp index 46bdef2..4c763fd 100644 --- a/include/boost/stacktrace/detail/backend_linux.hpp +++ b/include/boost/stacktrace/detail/backend_linux.hpp @@ -22,6 +22,8 @@ #include #include +#include +#include namespace boost { namespace stacktrace { namespace detail { @@ -44,26 +46,67 @@ struct backtrace_holder { #pragma GCC diagnostic pop -class pipe_holder { +class addr2line_pipe { FILE* p; + pid_t pid; public: - explicit pipe_holder(const char* command) BOOST_NOEXCEPT - : p(popen(command,"r")) - {} + explicit addr2line_pipe(const char *flag, const char* exec_path, const char* addr) BOOST_NOEXCEPT + : p(0) + , pid(0) + { + int pdes[2]; + char prog_name[] = "addr2line"; + char* argp[] = { + prog_name, + const_cast(flag), + const_cast(exec_path), + const_cast(addr), + 0 + }; + + if (pipe(pdes) < 0) { + return; + } + + pid = fork(); + switch (pid) { + case -1: + // failed + close(pdes[0]); + close(pdes[1]); + return; + + case 0: + // we are the child + close(STDERR_FILENO); + close(pdes[0]); + if (pdes[1] != STDOUT_FILENO) { + dup2(pdes[1], STDOUT_FILENO); + } + execvp(prog_name, argp); + _exit(127); + } + + p = fdopen(pdes[0], "r"); + close(pdes[1]); + } operator FILE*() const BOOST_NOEXCEPT { return p; } - ~pipe_holder() BOOST_NOEXCEPT { + ~addr2line_pipe() BOOST_NOEXCEPT { if (p) { - pclose(p); + fclose(p); + int pstat = 0; + kill(pid, SIGKILL); + waitpid(pid, &pstat, 0); } } }; -static inline std::string addr2line(const char* command, void* addr) { +static inline std::string addr2line(const char* flag, void* addr) { std::string res; Dl_info dli; @@ -83,10 +126,7 @@ static inline std::string addr2line(const char* command, void* addr) { res.resize(rlin_size); } - // TODO: redirect STDERR - pipe_holder p( - (command + res + " " + to_hex_array(addr).data()).c_str() - ); + addr2line_pipe p(flag, res.c_str(), to_hex_array(addr).data()); res.clear(); if (!p) { @@ -149,7 +189,7 @@ std::string backend::get_name(std::size_t frame) const { if (!!dladdr(impl().buffer[frame], &dli) && dli.dli_sname) { res = try_demangle(dli.dli_sname); } else { - res = addr2line("addr2line -fe ", impl().buffer[frame]); + res = addr2line("-fe", impl().buffer[frame]); res = res.substr(0, res.find_last_of('\n')); res = try_demangle(res.c_str()); } @@ -162,13 +202,13 @@ const void* backend::get_address(std::size_t frame) const BOOST_NOEXCEPT { } std::string backend::get_source_file(std::size_t frame) const { - std::string res = addr2line("addr2line -e ", impl().buffer[frame]); + std::string res = addr2line("-e", impl().buffer[frame]); res = res.substr(0, res.find_last_of(':')); return res; } std::size_t backend::get_source_line(std::size_t frame) const BOOST_NOEXCEPT { - std::string res = addr2line("addr2line -e ", impl().buffer[frame]); + std::string res = addr2line("-e", impl().buffer[frame]); const std::size_t last = res.find_last_of(':'); if (last == std::string::npos) { return 0; diff --git a/test/test.cpp b/test/test.cpp index abd5947..4cbbc2f 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -65,7 +65,7 @@ void test_nested() { BOOST_TEST(ss2.str().find("foo1") != std::string::npos); BOOST_TEST(ss2.str().find("foo2") != std::string::npos); #endif - //BOOST_TEST(false); + BOOST_TEST(false); } void test_comparisons() {