Starting to use the googletest ASSERT_THROW clause, it seems that 'sometimes' the base type of the thrown exception is handled. I reduced the relevant code section to this:
// myexception.h
struct myexception : public std::logic_error {
myexception(const char* what):std::logic_error(what){}
};
void throwMy();
// myexception.cpp
void throwMy(){ throw myexception(NULL); }
This is my test code:
//
void localThrowMy(){ throw myexception(""); }
// test code, based upon the ASSERT_THROW macro
try {
throwMy(); // outputs "logic_error"
//localThrowMy(); // would output "what I expected"
}
catch( myexception & ) { cout << "what I expected"; }
catch( std::logic_error & ) { cout << "logic_error"; } // my addition
catch(...) { cout << "mmmh."; }
The strange thing is: if I declare the throwMy function in the same compilation unit as the test code, "what I expected" is output. If it's in another unit, the test outputs "logic_error.".
g++ --version: (Debian 4.4.5-8) 4.4.5
ld --version: (GNU Binutils for Debian) 2.20.1-system.20100303
Is this code correct? Could the linker be in error here?
std::logic_error constructor receives a std::string& as argument, not a const char *. So passing NULL is undefined behavior.
Consider using a std::string& too for myexception.
Mea Culpa.
Once again, select wasn't broken.
The logic_error was thrown within the std::string constructor: "basic_string::_S_construct NULL not valid". I falsely deduced that there was a problem with the inheritance; it was a plain case of pebkac.
Actually, I didn't know. But you can't pass a null pointer into the std::string constructor.
Related
I've seen several similar snippets of code that looked like this:
struct MyExcept : std::exception {
explicit MyExcept(const char* m) noexcept : message{m} {}
const char* what() const noexcept override {
return message;
}
const char* message;
};
void foo() {
std::string error;
error += "Some";
error += " Error";
throw MyExcept{error.c_str()};
}
int main() {
try {
foo();
} catch (const MyExcept& e) {
// Is this okay?
std::cout << e.message << std::endl;
}
}
In the line following the comment Is this okay?, we read the c-style string that was allocated in the foo function using std::string. Since the string is destructed with stack unwinding, is this undefined behavior?
If it's indeed undefined behavior, what if we replace the main function with this one?
int main() {
foo();
}
Since there is no catch, the compiler is not forced to unwind the stack, and yet output the result of what() in the console and abort the program. So is it still undefined behavior?
Yes, that's undefined behavior. You are working with a dangling pointer.
void foo() {
std::string error;
error += "Some";
error += " Error";
throw MyExcept{error.c_str()};
} // << error goes out of scope here and so does the pointer returned
// from c_str()
Since there is no catch, the compiler is not forced to unwind the stack, and yet output the result of what() in the console and abort the program. So is it still undefined behavior?
Since the default implementation will use std::terminate and in turn calling std::abort() this may be still undefined behavior because most of the standard handler implementations will try to dereference what().
You can install your own handlers though to avoid that.
Your first snippet has undefined behavior. [exception.ctor]/1:
As control passes from the point where an exception is thrown to a handler, destructors are invoked by a process, specified in this section, called stack unwinding.
Here, the destructor or error is called, causing the c_str() to become a dangling pointer. Later dereferencing it, when you use std::cout for instance, is undefined behavior.
Your second snippet is perfectly fine. There is no reason why it would be undefined behavior. You never actually call what, or do anything else that might result in undefined behavior. The only thing not defined by the Standard is if stack unwinding happens or not, [except.terminate]/2:
In the situation where no matching handler is found, it is implementation-defined whether or not the stack is unwound before std::terminate() is called.
As others stated, the code has undefined behavior, since the pointer assigned to message is left dangling.
std::runtime_error already provides a solution to this issue. Call its constructor that takes a std::string as input, and don't override what() at all:
struct MyExcept : std::runtime_error {
explicit MyExcept(const std::string & m) noexcept : std::runtime_error(m) {}
};
void foo() {
std::string error;
error += "Some";
error += " Error";
throw MyExcept(error);
}
int main() {
try {
foo();
}
catch (const MyExcept& e) {
std::cout << e.what() << std::endl;
}
}
std::runtime_error has an internal std::string whose data what() returns by default, thus avoiding the dangling issue.
I am learning C++ and I am experiencing when I try and create my own exception and throw them on Linux.
I've created a small test project to test my implementation and below is my exception class header file.
class TestClass : public std::runtime_error
{
public:
TestClass(char const* const message) throw();
virtual char const* what() const throw();
};
The source file for the exception class is
using namespace std;
TestClass::TestClass(char const* const message) throw()
: std::runtime_error(message)
{
}
char const * TestClass::what() const throw()
{
return exception::what();
}
In my main app, I am calling a function which throws my exception and catches it in a try/catch as follows:
void runAFunctionAndthrow();
/*
*
*/
int main(int argc, char** argv) {
try
{
cout << "About to call function" << endl;
runAFunctionAndthrow();
}
catch (TestClass ex)
{
cout << "Exception Caught: " << ex.what() << endl;
}
return 0;
}
void runAFunctionAndthrow()
{
cout << "going to run now. oh dear I need to throw an exception" << endl;
stringstream logstream;
logstream << "This is my exception error. :(";
throw TestClass(logstream.str().c_str());
}
When I run I'm expecting to get the following output:
About to call function
Going to run now. oh dear I need to throw an exception
Exception Caught: This is my exception error. :(
Instead what I am getting is
About to call function
going to run now. oh dear I need to throw an exception
Exception Caught: std::exception
Notice the last line it says std::exception instead of my actual exception message "This is my exception error".
Why is this, it works OK on Windows but on Linux it does this.
From what I've seen on various posts what I've done is correct so what am I missing.
Your what() returns:
return exception::what();
The return value from std::exception::what() is specified as follows:
Pointer to a null-terminated string with explanatory information.
That's it. Nothing more, nothing else. The text you're showing certainly qualifies as an "explanatory information". And this is the only requirement for the return value of what() (except for one other one which is not germane here).
In other words, C++ does not guarantee the exact contents of what you get with what(). what() you see is what() you get, as the saying goes.
If you want your exception to describe itself, in some way, it's up to you to implement that, as part of your what().
You need your own implementation of what() method or use std::runtime_error::what() as written in comments
Say:
class TestClass : public std::runtime_error
{
std::string what_message;
public:
const char* what() override
{
return what_message.c_str();
}
};
Also, better use noexcept instead of throw() and only after you read about them - link.
And in your try-catch:
catch (const TestClass& myException)
Instead of catch(TestClass myException) - otherwise you do an implicit copy which can potentially result in an exception throw. It also breaks the polymorphism: if you want to catch pure virtual interface implementation instance, you would need to use a reference.
You need a way to specify a custom error message to std::exception which afaik is not allowed. See this for a possible solution.
First of most of the info about the answer had been given by Sam Varshavchik
But I want to add one thing
When throwing and catching A good rule is
"Throw by value catch by reference "
So your throw was fine as:
void runAFunctionAndthrow()
{
cout << "going to run now. oh dear I need to throw an exception" << endl;
stringstream logstream;
logstream << "This is my exception error. :(";
throw **TestClass(logstream.str().c_str())**;
}
used an implicit conversion to TestClass and then it got passed by value.
the Key point in that rule is to minimize memory allocating handling between different stack frames
your catch on the other hand dosen't follow the rule (since you catch by value):
catch (TestClass ex)
{
cout << "Exception Caught: " << ex.what() << endl;
}
the catch should be (const TestClass& ex)
the key point in this rule is implicit conversion between base class and derived class.
I wrote a routine to store the backtrace and line no and file name etcetera. The purpose for this was to store such data for whenever an exception is thrown. However, the problem I am facing is that my routine will be called from the catch block and it will end up storing the backtrace up to the catch block. This is not good. I only must add the backtrace till the place where the exception is thrown. I cannot (obviously call it inside the try block since in that case I will end up storing a backtrace even in the cases where no exception is thrown). I could also always store the backtrace to the end of the try block and access it inside the catch block; but there is no way of knowing at which line of the try block the exception will be thrown. Thus the throw function seems to be a good place to add the routine call. But I dont know how to do it. Please help me.
If my strategy seems inherently wrong, please feel free to point me a better solution. If the problem itself is not clear, please leave a comment.
P.S. I wrote the custom exception class to inherit from std::runtime_error.
There is no 'throw function' defined by C++ that you can override. Throwing is handled by the C++ implementation and there's no standard way to insert any kind of code for every throw.
Instead what you can do is make your exception type store the current backtrace when it is constructed.
std::string get_backtrace() {
return "this is the backtrace...";
}
struct backtrace_exception : public std::exception {
std::string b;
backtrace_exception() : b(get_backtrace()) {}
};
int main() {
try {
throw backtrace_exception();
} catch(backtrace_exception &e) {
std::cout << e.b;
}
}
You cannot overload the throw operator. The more usual solution would be to define a macro that packages the exception with a backtrace record. For example this:
#include <string>
#include <iostream>
#include <sstream>
#include <exception>
#include <stdexcept>
#include <type_traits>
template <typename BaseException>
class backtraced_exception : public BaseException {
private:
std::string backtrace;
public:
template <typename... Args>
backtraced_exception(const char* aFilename, int aLineNum, Args&&... args) :
BaseException(std::forward<Args>(args)...) {
std::stringstream ss;
ss << "From '" << aFilename << "' at line " << aLineNum << ":\n"
<< BaseException::what();
backtrace = ss.str();
};
backtraced_exception(const std::exception& e, const char* aFilename, int aLineNum) :
BaseException(static_cast<const BaseException&>(e)) {
std::stringstream ss;
ss << "From '" << aFilename << "' at line " << aLineNum << ":\n"
<< e.what();
backtrace = ss.str();
};
virtual ~backtraced_exception() noexcept { };
virtual const char* what() const noexcept {
return backtrace.c_str();
};
};
#define THROW_WITH_BACKTRACE(EXCEPTION, ARG1) throw backtraced_exception< EXCEPTION >(__FILE__, __LINE__, ARG1)
// ... and you can create more macros for more arguments...
#define CATCH_WITH_BACKTRACE(EXCEPTION, EXCEPT_NAME) catch(backtraced_exception< EXCEPTION >& EXCEPT_NAME)
#define RETHROW_WITH_BACKTRACE(EXCEPT_NAME) throw backtraced_exception< std::decay< decltype(EXCEPT_NAME) >::type >(EXCEPT_NAME, __FILE__, __LINE__)
Use it like this:
int main() {
try {
try {
try {
THROW_WITH_BACKTRACE(std::runtime_error, "This is an example!");
} CATCH_WITH_BACKTRACE(std::runtime_error, e) {
std::cout << "First caught this exception:\n" << e.what() << std::endl;
RETHROW_WITH_BACKTRACE(e);
};
} catch(std::runtime_error& e) { // can also catch normally.
std::cout << "Got this exception:\n"
<< e.what() << std::endl;
// and even rethrow again, with backtrace:
RETHROW_WITH_BACKTRACE(e);
};
} catch(std::runtime_error& e) {
std::cout << "Finally, got this exception:\n"
<< e.what() << std::endl;
};
};
The output is as follows:
First caught this exception:
From 'logged_except.cpp' at line 50:
This is an example!
Got this exception:
From 'logged_except.cpp' at line 53:
From 'logged_except.cpp' at line 50:
This is an example!
Finally, got this exception:
From 'logged_except.cpp' at line 59:
From 'logged_except.cpp' at line 53:
From 'logged_except.cpp' at line 50:
This is an example!
Another good thing with this solution is that you can disable backtracing by simply conditionally defining the macros depending on whether you want backtracing or not (e.g. debug or release build).
The above example requires C++11 features, but you can probably come up with an equivalent solution without those features (i.e., variadic templates, decltype, type-traits, etc.).
And you could also use C++11 exception-pointers to make this scheme even more convenient.
Yeah you can override 'throw' under GCC by overriding this function :
extern "C"
void __cxa_throw (void *thrown_exception, void *pvtinfo, void (*dest)(void *))
After doing your stuff you should call the real 'throw' for that you should use 'dlsym()' under Unix to get its address or use function wrapping under 'mingw' by passing -WL,-wrap,symbole to the linker , like in here GNU gcc/ld - wrapping a call to symbol with caller and callee defined in the same object file , I worked with both methods
The following code works just fine:
#include <exception>
using namespace std;
class FileException : public exception { // error occurs here
int _error;
// string _error; <-- this would cause the error
public:
FileException(int error);
// FileException(string error);
const char* what() const throw();
};
But as soon as I change the type of _error to string, the following compile error occurs:
Exception specification of overriding function is more lax than base version
The destructor of std::string is not no-throw, which causes the implicit destructor of FileException not no-throw either. But the destructor of std::exception is no-throw, thus there's a compiler error.
You could declare an explicit no-throw destructor:
virtual ~FileException() throw() {}
or just inherit from std::runtime_error instead of std::exception, which has a constructor that takes std::string input.
Simplify with:
// Derive from std::runtime_error rather than std::exception
// std::runtime_error (unlike std::exception) accepts a string as an argument that will
// be used as the error message.
//
// Note: Some versions of MSVC have a non standard std::exception that accepts a string
// Do not rely on this.
class FileException : public std::runtime_error
{
public:
// Pass error msg by const reference.
FileException(std::string const& error)
// Pass the error to the standard exception
: std::runtime_error(error)
{}
// what() is defined in std::runtime_error to do what is correct
};
I approve of the above method,
but g++ seems to complain if
the default constructor is not present.
The following addition makes things work:
using namespace std;
class MyException : public runtime_error {
public:
/* add the following line: */
MyException() : runtime_error("MyException") { } // default constructor
MyException( string const& error ) : runtime_error(error) { } // ctor w/string
};
additionally, an exception list is easily created:
MyException FileNotFound ( "File Not Found" );
MyException ReadOnly ( "ReadOnly" );
MyException Unkown ( "Unknown" );
...
throw FileNotFound;
...
when catching these exceptions, if you don't need specificity catch them generically:
catch( runtime_error re) { cout << "Runtime Error: " << re.what() << endl; ... }
Since all MyExceptions decend from runtime_error this catches them all and
you won't miss any other runtime errors from the system either.
catch( exception e) { cout << "exception: " << e.what() << endl; ... }
catches them all.
In C++, you can also throw and catch any types (int, booleans,pointers, etc.) Its sometimes simpler
to just throw/catch a string or an int within a function block.
Multiple classes should only throw and catch code library standard exceptions and their subclasses, (and all in the same manner), however, mostly for consistency and maintenance, but also because c++ compilers know how to optimize the exception mechanisms and linkages for them, and can generate intelligent warnings and errors about them, easing debugging.
"Error: "0x137F" is for IBM guys, not "the third guy on the project this year" ...
Is there any way to get at least some information inside of here?
...
catch(...)
{
std::cerr << "Unhandled exception" << std::endl;
}
I have this as a last resort around all my code. Would it be better to let it crash, because then I at least could get a crash report?
No, there isn't any way. Try making all your exception classes derive from one single class, like std::exception, and then catch that one.
You could rethrow in a nested try, though, in an attempt to figure out the type. But then you could aswell use a previous catch clause (and ... only as fall-back).
You can do this using gdb or another debugger. Tell the debugger to stop when any exception is throw (in gdb the command is hilariously catch throw). Then you will see not only the type of the exception, but where exactly it is coming from.
Another idea is to comment out the catch (...) and let your runtime terminate your application and hopefully tell you more about the exception.
Once you figure out what the exception is, you should try to replace or augment it with something that does derive from std::exception. Having to catch (...) at all is not great.
If you use GCC or Clang you can also try __cxa_current_exception_type()->name() to get the name of the current exception type.
Yes there is, but how useful it is is open to debate:
#include <exception>
#include <iostream>
using namespace std;
int f() {
throw "message";
}
int main() {
try {
f();
}
catch ( ... ) {
try {
throw;
}
catch( const char * s ) {
cout << "caught " << s << endl;
}
}
}
And to actually to answer your question, IMHO you should always have a catch(...) at
the top level of your code, that terminates (or otherwise handles) when presented with an unexpected exception in your application, in a manner fully documented by your application's manual.
I believe you should catch (...), if you have a reasonable course of action at that point and want the application to keep running.
You don't have to crash in order to generate a crash report, mind you. There's API for generating a mini-dump and you can do it in your SEH handler.
here's an approach I used on one project. it involves rethrowing until an exception type is matched against a list of known exceptions and then dispatching some action upon a match (in this case just returning some string information, but it could also be calling a registered function object).
This idea can be extended into a dynamic registry of exception types if you wish, the thing you have to be careful of is to ensure that the list is in most-derived to least-derived order (requires a lot of rethrowing and catching during registration!)
#include <iostream>
#include <stdexcept>
#include <exception>
#include <typeinfo>
#include <system_error>
namespace detail {
// a function which compares the current exception against a list of exception types terminated
// with a void type
// if a match is made, return the exception (mangled) class name and the what() string.
// note that base classes will be caught if the actual class is not mentioned in the list
// and the list must be in the order of most-derived to least derived
//
template<class E, class...Rest>
std::string catcher_impl()
{
try
{
std::rethrow_exception(std::current_exception());
}
catch(const E& e)
{
bool is_exact = typeid(E) == typeid(e);
return std::string(typeid(E).name()) + (is_exact ? "(exact)" : "(base class)") + " : " + e.what();
}
catch(...)
{
return catcher_impl<Rest...>();
}
return "unknown";
}
// specialise for end of list condition
template<> std::string catcher_impl<void>()
{
return "unknown exception";
}
}
// catcher interface
template<class...Es>
std::string catcher()
{
return detail::catcher_impl<Es..., void>();
}
// throw some exception type
// and then attempt to identify it using the type list available
//
template<class E>
void test(E&& ex)
{
try
{
throw std::forward<E>(ex);
}
catch(...)
{
std::cout << "exception is: "
<< catcher<std::invalid_argument, std::system_error, std::runtime_error, std::logic_error>()
<< std::endl;
}
}
int main()
{
test(std::runtime_error("hello world"));
test(std::logic_error("my logic error"));
test(std::system_error(std::make_error_code(std::errc::filename_too_long)));
test(std::invalid_argument("i don't like arguments"));
struct my_runtime_error : std::runtime_error
{
using std::runtime_error::runtime_error;
};
test(my_runtime_error("an unlisted error"));
}
example output:
exception is: St13runtime_error(exact) : hello world
exception is: St11logic_error(exact) : my logic error
exception is: NSt3__112system_errorE(exact) : File name too long
exception is: St16invalid_argument(exact) : i don't like arguments
exception is: St13runtime_error(base class) : an unlisted error