Rethrowing new exception with same message causes garbage output. Why? - c++

I want to catch an exception to further specify the error message, then throw a new exception with that extended message. However, that causes garbage output. Why?
Here's an MWE:
#include <iostream>
#include <string>
#include <exception>
class myError : public std::exception
{
private:
std::string m_error;
public:
explicit myError( const std::string& error ) :
m_error { error }
{}
explicit myError( const char* error ) :
m_error { error }
{}
const char* what() const noexcept override
{
//return m_error.c_str();
return ("My error: " + m_error).c_str();
}
};
int main()
{
try{
try{
throw myError ( "Error message" );
} catch ( const std::exception& e ) {
throw myError( e.what() );
}
} catch ( const std::exception& e ) {
std::cout << e.what() << "\n";
}
return 0;
}
I would expect the output to be "My error: My error: Error message", but instead, it's a short sequence of random characters, presumably until a \0 is hit.
If I do not add a message inside myError::what() (i.e. the line that's commented out), then the output is simply "Error message", so everything works as expected.
Why is that happening?
I'm running gcc 8.1.0 on Windows, with x86_64-posix-seh-rev0 as the install options.
And I'm somewhat aware of nested_exception and that I'm losing some information on the trace etc.
EDIT: As a workaround, adding the message "My error" inside the constructor produces the expected output:
explicit myError( const std::string& error ) :
m_error { "My error: " + error }
{}
explicit myError( const char* error ) :
m_error { "My error: " + std::string{ error } }
{}
const char* what() const noexcept override
{
return m_error.c_str();
}
So something seems to be wrong with return ("My error: " + m_error).c_str();.

In:
return ("My error: " + m_error).c_str();
... c_str() returns a pointer to the internal buffer of the temporary string created by the concatenation. This string's lifetime ends immediately after the return statement, making the returned pointer dangling and its use undefined.

Related

C++ exception not propagating when non-empty function

I have the following function:
void filesys::create(char * pathname, char type) {
//char * msg;
//sprintf(msg, "create pathname: %s type: %c", pathname, type);
throw filesys::BadRequest();
}
When the first two lines are commented out as shown, the exception propagates and is caught by the calling function. When I uncomment these lines, I immediately get a propagation error:
libc++abi.dylib: terminating with uncaught exception of type filesys::BadRequest: bad req
Exception definition within filesys class:
struct BadRequest : public std::exception {
const char * what () const throw () {
return "bad req";
}
};
Catch block:
try {
char * response = serve_request(decrypted);
send_msg(connectionfd, response);
} catch (filesys::BadRequest& e) {
cout << "hello?";
}

C++ catch error and exit the function

I use try{} catch(){} to handle errors in a function which return a template type.
T get (int iOffset) const
{
try {
checkIndex(iOffset);
}
catch (char const* msg) {
std::cout << msg << std::endl;
}
int index = (m_iReadIdx + iOffset) % m_iBuffLength;
float a = m_ptBuff[index];
return a;
}
The function would first call checkIndex to check whether the input is out of range and throw an error if so.
However, I don't want the outside get return any value if checkIndex throws an error, because the returned value may be used by other functions or printed out incorrectly. If I put a return in the catch block, I don't know what to return since it's a template. If I don't, the codes following the catch block will still get executed and therefore return a value.
Is there any way to do that? I'm new to C++ and wondering how people usually do the error handling in this condition? THanks!
However, I don't want the outside get return any value if checkIndex throws an error, because the returned value may be used by other functions or printed out incorrectly.
You can always re-throw the exception after logging
T get (int iOffset) const
{
try {
checkIndex(iOffset);
}
catch (char const* msg) {
std::cout << msg << std::endl;
throw; // Just re-throw the exception
}
int index = (m_iReadIdx + iOffset) % m_iBuffLength;
float a = m_ptBuff[index];
return a;
}
You can also use optional for this situation. One of idea of this construct was to indicate that value cannot be set correctly because of some mistakes.
std::optional< T > get (int iOffset ) const
{
try {
checkIndex(iOffset);
}
catch (char const* msg) {
std::cout << msg << std::endl;
return std::optional< T >();
}
int index = (m_iReadIdx + iOffset) % m_iBuffLength;
float a = m_ptBuff[index];
return return std::optional< T >( a );
}
Using of such function can look like this:
auto result = get( someOffset );
if( result )
{
// correct, processing result
}
One of the easiest way is first to decide: What exactly should your get() return if it cannot return the 'proper' value?
In many cases it is just 0, or -1, or some other special value.
And then the code become very simple:
T get (int iOffset) const
{
T a;
try {
checkIndex(iOffset);
int index = (m_iReadIdx + iOffset) % m_iBuffLength;
a = m_ptBuff[index];
}
catch (char const* msg) {
a = special_value_for_errors;
std::cout << msg << std::endl;
}
return a;
}

printing the backtrace at the point an exception was thrown in the catch block

I want to print the backtrace of an exception (the state at the point is where was thrown), but in a catch block.
I am also just targetting gcc, but would like to keep unportable code to a minimum (I know the stack printing code I show in my examples is non-portable).
From what I understood so far, in the catch block the stack was already partially unwond, so it is no longer there to be read.
To be fair, it should still be there (in memory), if no local variables are created and no method calls are done, but I'm not sure how safe I would be trying to read it this way.
I also noticed that if I register a terminate method (via std::set_terminate) and have no catch block, then the full stack at the point where the unhandled exception was thrown is available to the handler. I'm guessing this is because it was unwound totally, but the original values in the stack was not overwritten (and most likely the terminate handler somehow has an indepentent call stack).
I tested this under gcc:
#include <cstdlib>
#include <iostream>
#include <stdexcept>
#include <execinfo.h>
using namespace std;
void handler()
{
void *trace_elems[20];
int trace_elem_count(backtrace(trace_elems, 20));
char **stack_syms(backtrace_symbols(trace_elems, trace_elem_count));
for(int i=0 ; i != trace_elem_count; ++i)
{
cout << stack_syms[i] << "\n";
}
free(stack_syms);
exit(1);
}
void level3() { throw std::runtime_error("oops"); }
void level2() { level3(); }
void level1() { level2(); }
If I use it like this, the exception backtrace is lost (only main and handler are in the call stack):
void main()
{
try { level1(); }
catch(...) { handler();}
}
But if I call it like this, the backtrace at the point the exception was thrown is printed:
void main()
{
std::set_terminate(handler);
level1();
}
Some context on my use case: I have two running processes, one produces requests and the other will process them. The execution of these requests can sometimes result in exceptions. At that point the backtrace is usefull to figure out why it failed (what() very often does not have enough information), but I cannot let the exception reach main, since both processes need to continue working. I just need to print the backtrace and return a message signalling failure to execute.
EDIT: A common solution, that is being suggested to this problem is having a base exception class that captures the call stack on construction, and has it available to print out later. This is certainly a possible solution (and one I might have to resort to, if no better solution is found).
I am avoiding it at the moment because:
It adds some (considerable) overhead to capture the call stack at the moment I throw the exception
I have a relatively high percentage of cases where I can actually handle the exception before having to give up and print the stack trace.
You could create a custom exception class, that would in its constructor, call backtrace and store the buffer within itself.
When caught, such exception would have the required data to print the trace. In fact, the handler could well be a member function of the exception. Note that the trace would include the extra call to the constructor of the exception.
This works as long as you only throw the custom exception or exceptions derived from it.
Best I can suggest is to collect the stack trace at the point of the throw.
This code may need a little refining, but it should give you an idea:
#include <cstdlib>
#include <iostream>
#include <stdexcept>
#include <vector>
#include <execinfo.h>
using namespace std;
inline
auto make_stack_trace(int depth = 20) {
auto trace_elems = std::vector<void *>(depth);
auto trace_elem_count = backtrace(trace_elems.data(), depth);
char **stack_syms = backtrace_symbols(trace_elems.data(), trace_elem_count);
std::vector<std::string> symbols;
symbols.reserve(trace_elem_count);
for (int i = 0; i < trace_elem_count; ++i) {
symbols.emplace_back(stack_syms[i]);
}
free(stack_syms);
return symbols;
}
struct tracer {
tracer(const std::vector<std::string> &trace)
: trace_(trace) {}
friend std::ostream &operator<<(std::ostream &os, const tracer &t) {
const char *sep = "";
for (const auto &line : t.trace_) {
os << sep << line;
sep = "\n";
}
return os;
}
const std::vector<std::string> &trace_;
};
struct has_stack_trace {
has_stack_trace(std::vector<std::string> trace) : trace_(std::move(trace)) {}
auto trace() const {
return tracer(trace_);
}
virtual const char* what() const noexcept = 0;
std::vector<std::string> trace_;
};
template<class Exception>
struct with_stack_trace : has_stack_trace, Exception {
template<class...Args>
with_stack_trace(Args &&...args)
: has_stack_trace(make_stack_trace()), Exception(std::forward<Args>(args)...) {
}
virtual const char* what() const noexcept override
{
return Exception::what();
}
};
void level3() { throw with_stack_trace<std::runtime_error>("oops"); }
void level2() { level3(); }
void level1() { level2(); }
int main() {
try {
level1();
}
catch (has_stack_trace const &e) {
std::cout << e.what() << std::endl;
std::cout << e.trace() << std::endl;
}
catch (std::exception const& e) {
std::cout << e.what() << std::endl;
}
}
Sample output:
oops
0 parallel-find 0x000000010bad09e9 _Z16make_stack_tracei + 105
1 parallel-find 0x000000010bad08ec _ZN16with_stack_traceISt13runtime_errorEC2IJRA5_KcEEEDpOT_ + 44
2 parallel-find 0x000000010bacf46d _ZN16with_stack_traceISt13runtime_errorEC1IJRA5_KcEEEDpOT_ + 29
3 parallel-find 0x000000010bacf40a _Z6level3v + 42
4 parallel-find 0x000000010bacf4a9 _Z6level2v + 9
5 parallel-find 0x000000010bacf4b9 _Z6level1v + 9
6 parallel-find 0x000000010bacf4d7 main + 23
7 libdyld.dylib 0x00007fffa6346255 start + 1
8 ??? 0x0000000000000001 0x0 + 1
Process finished with exit code 0

Error trying to use iterator returned from ptr_map::find

I am getting a compilation error on the code below. The error is:
/ ... /main.cpp:21:22: error: no member named 'name' in 'boost::ptr_container_detail::ref_pair<std::__1::basic_string<char>, repo *const>'
std::cout << it->name;
~~ ^
What am I doing wrong here? I've tried both it.name and it->name and neither works.
Regards, David.
#include <boost/ptr_container/ptr_map.hpp>
class repo {
public:
repo(const std::string & repo_name) : name(repo_name) {}
std::string name;
};
typedef boost::ptr_map<std::string, repo> repo_map;
repo_map repos;
int main() {
std::string repo_name("x");
repo_map::iterator it = repos.find(repo_name);
if (it == repos.end()) {
it = repos.insert(repo_name, new repo(repo_name)).first;
}
std::cout << it->name;
return 0;
}
As it is a ptr_map, it returns pair<key, ptr_value>. So you need:
it->second->name
I think this will do the work
it->second.name

Boost::file_system: Checking error codes

Although I'm using C++11, this question is boost-related, since I'm processing errors from boost::file_system.
In the following situation:
try {
// If p2 doesn't exists, canonical throws an exception
// of No_such_file_or_directory
path p = canonical(p2);
// Other code
} catch (filesystem_error& e) {
if (e is the no_such_file_or_directory exception)
custom_message(e);
} // other catchs
}
If I print the error value when the desired exception (no_such_file_or_directory) is thrown:
// ...
} catch (filesystem_error& e) {
cout << "Value: " << e.code().value() << endl;
}
I get the value 2. It is the same value of e.code().default_error_condition().value().
My questions is: could different error conditions from different error categories have same values? I mean, does I need to check both, error categories and error values, in order to ensure I'm getting a specific error? In such a case, what is the cleanest way to do it?
error_codes and error_conditions with different error_categories are allowed to have the same value(). The non-member comparison functions check both the the value and category:
bool operator==( const error_code & lhs, const error_code & rhs ) noexcept;
Returns: lhs.category() == rhs.category() && lhs.value() == rhs.value().
Hence, the exceptions's error_code could be checked against the return from make_error_code(), such as follows:
try {
// If p2 doesn't exists, canonical throws an exception
// of No_such_file_or_directory
path p = canonical(p2);
// ...
} catch (filesystem_error& e) {
if (e.code() ==
make_error_code(boost::system::errc::no_such_file_or_directory)) {
custom_message(e);
}
}
Here is a complete example demonstrating two error_codes that are not equivalent despite having the same value:
#include <boost/asio/error.hpp>
#include <boost/filesystem.hpp>
#include <boost/system/error_code.hpp>
int main()
{
// Two different error codes.
boost::system::error_code code1 = make_error_code(
boost::system::errc::no_such_file_or_directory);
boost::system::error_code code2 = make_error_code(
boost::asio::error::host_not_found_try_again);
// That have different error categories.
assert(code1.category() != code2.category());
assert(code1.default_error_condition().category() !=
code2.default_error_condition().category());
// Yet have the same value.
assert(code1.value() == code2.value());
assert(code1.default_error_condition().value() ==
code2.default_error_condition().value());
// Use the comparision operation to check both value
// and category.
assert(code1 != code2);
assert(code1.default_error_condition() !=
code2.default_error_condition());
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Test with Boost.Filesytem
try
{
boost::filesystem::canonical("bogus_file");
}
catch(boost::filesystem::filesystem_error& error)
{
if (error.code() ==
make_error_code(boost::system::errc::no_such_file_or_directory))
{
std::cout << "No file or directory" << std::endl;
}
if (error.code() ==
make_error_code(boost::asio::error::host_not_found_try_again))
{
std::cout << "Host not found" << std::endl;
}
}
}
Which produces the following output:
No file or directory