C++ Weird string/char* exception behaviour - c++

Well here is my exception code :
class OptionNotFoundError: public std::exception {
public:
OptionNotFoundError(std::string option, int position) throw()
: option(option), position(position) {}
OptionNotFoundError(char option_, int position) throw()
: position(position) { option.push_back(option_); }
virtual ~OptionNotFoundError() throw() {}
virtual const char* what() const throw() {
std::string what_str = "Option '" + option + "' not found in position " + std::to_string(position);
std::cout << what_str.c_str() << std::endl;
return what_str.c_str();;
}
std::string option;
int position;
};
When the exception is thrown, here is what I get in the terminal :
terminate called after throwing an instance of 'Args::OptionNotFoundError'
Option 'c' not found in position 1
what():
So the cout works fine, but… not the return. If I use return "smth" it works fine.
Weirder : if I replace what_str definition with
std::string what_str = "test";
I get
terminate called after throwing an instance of 'Args::OptionNotFoundError'
test
what(): x�zL�
Again, the cout<< works fine. But the return… Not so much. Is this some encoding error ?

return what_str.c_str();;
c_str() returns a pointer to the internal contents of the std::string.
This pointer remains valid only until either
The std::string object gets destroyed.
The std::string object gets modified.
The std::string object from which this c_str() pointer is obtained gets destroyed when your function returns.
This results in undefined behavior.
The const char * that your function returns is not valid. It's pointing to the internal contents of a destroyed object.

For the 1st case, note that what_str is a local variable inside what(), it'll be destroyed when get out of the function scope, then the pointer returned by it becomes dangled, dereference on it leads to UB.
For the 2nd case, returning "smth" works fine, because "smth" is a const char[5], which is a string literal,
String literals have static storage duration, and thus exist in memory for the life of the program.
For the 3rd case,
if i replace what_str definition with
std::string what_str = "test";
It doesn't work, because what_str is still a local std::string, the problem is same with the 1st case.

Related

C++ custom exception message not displaying

I am trying to create a custom exception class, throw it, and display the error message, but I am doing something wrong, causing the exception to not get thrown and the message to not get printed.
Here's the exception class:
class UnbalancedParenthesesException : public std::exception {
int line_number {0};
public:
UnbalancedParenthesesException(int line_number) :
line_number { line_number }
{}
virtual const char* what() const throw() {
std::string exception_message =
"Papentheses imbalance at line " + std::to_string(line_number) + "\n";
return exception_message.c_str();
}
};
I am trying totry/throw/catch as follows:
void handle_closed_paren(int line_number) {
try {
if (definitely_unbalanced()) {
throw UnbalancedParenthesesException(line_number);
}
} catch (const UnbalancedParenthesesException& e) {
std::out << e.what() << "\n";
}
There is nothing pertinent to this error in the console.
Thanks in advance.
Your what() method is creating a local std::string variable and then returning a pointer to its internal data, which will be left dangling when the std::string goes out of scope and is destroyed when what() exits.
You need to store your error message in a std::string that is a member of the class so it does not go out of scope prematurely. Fortunately, std::exception already has an internal std::string for that purpose. So, instead of formatting the error message in what() itself, you should format it in your derived constructor and pass it to the base class constructor, letting the base what() method return it as-is:
class UnbalancedParenthesesException : public std::exception
{
int mLineNumber;
public:
UnbalancedParenthesesException(int line_number) : std::exception("Parentheses imbalance at line " + std::to_string(line_number)), mLineNumber(line_number) {}
// optional, if the catcher needs access to the value
int lineNumber() const { return mLineNumber; }
};
Your program has undefined behaviour as you are returning the result of c_str() on a std::string that goes out of scope. Anything could happen.
Beyond that, if you're not seeing an exception then one was not thrown, probably because the result of definitely_unbalanced() is falsey.
Step through your program using your debugger.

Referencing non-static variables from a static variable makes non-static variables destruct before static variable

Simply put: I want to write to a file whenever my program exits, so I have an object that accepts a filename (char*) and a reference to a Google Protobuf Message (for these purposes, you can just pretend that it's a string&) in the constructor and then writes the message to the filename in the destructor. Then, in main(), I initialise one of these objects and declare it as static (so it will destruct when the program exits for any reason).
My code had been working perfectly for several revisions before I changed something (seemingly) unrelated, and now it doesn't work. Now, when the object destructs, the char* and reference both point to unintialised versions of char and Message. I have the related code below:
using namespace std;
class WriteOnShutdown {
private:
const char* filename;
public:
MathHelper::Log& message;
WriteOnShutdown(char* a, MathHelper::Log& b) : filename(a), message(b) {}
~WriteOnShutdown() {
cout << "debug\n";
//*filename is -52 (unitialised char)
//READ ACCESS VIOLATION - message is still valid, but message.DebugString tries to call a pointer which hasn't been initialised yet
cout << message.DebugString() << endl;
}
};
int main() {
char filename[100];
MathHelper::Log log;
//Initialise filename and log
static WriteOnShutdown write(filename, log);
//Do program stuff here
//Then, at the end of main(), printing write.message.DebugString() works like a charm
cout << endl << write.message.DebugString();
_getch();
}
The reason why you have a problem is following:
MathHelper::Log log is going to be destructed before your main returns, but destructor of WriteOnShutdown will be called after main returns.
Since WriteOnShutdown uses the reference to log in the destructor, you are accessing a 'dangling' reference, invoking undefined behavior and thus is seeing the problem.
And you have exactly the same problem with filename as well.
Obvious fix is to change write (which, by the way, is a terrible name for an object for several reasons) from being static to automatic variable.
This is called the static initialization order fiasco (which applies equally to destructors). It was always a problem, you just happened to get lucky earlier.
An easy way to fix that in your case is to change const char* filename; into std::string &filename; and MathHelper::Log& message; to MathHelper::Log message;. That way the memory will still be around by the time the destructor gets called.

Is qPrintable prone to access violations?

Definition of qPrintable:
# define qPrintable(string) QString(string).toLocal8Bit().constData()
toLocal8Bit returns a QByteArray. Documentation of QByteArray::constData():
The pointer remains valid as long as the byte array isn't reallocated or destroyed.
toLocal8Bit() creates a temporary QByteArray, which is destroyed just after constData() has been called. So the pointer returned by constData points to freed memory.
Am I missing something here?
Additional comments:
Documentation of qPrintable states this:
The char pointer will be invalid after the statement in which qPrintable() is used. This is because the array returned by QString::toLocal8Bit() will fall out of scope.
But what does this mean? For my understanding, this is identical to "The pointer is invalid from the moment it is returned by qPrintable"
Why I am asking:
I have seen code failing which can be simplified like this:
someFunction( stringA.toLatin1().constData(), stringB.toLatin1().constData())
Inside the called function, both parameters were pointers to the same address.
qPrintable macro is supposed to be used for debugging purposes:
qWarning("%s: %s", qPrintable(key), qPrintable(value));
or:
qDebug() << "My value is: " << qPrintable(value);
Here temporary QByteArray object created by QString::toLocal8Bit is destroyed after the whole statement finishes, which happens after QByteArray::constData() pointer is utilized.
And in this case we have a problem you have described:
QString s = "Hello";
const char *debug_string = s.toLocal8Bit().constData();
// Can't use debug_string here as the pointer is invalid:
// qDebug() << debug_string
For my understanding, this is identical to "The pointer is invalid from the moment it is returned by qPrintable"
No. Temporary objects are destroyed at the end of the full expression they're part of, unless their life is prolonged by taking a const reference. See this question for details. The pointer is invalid as soon as the full expression ends.
In a call like foo(obj1().method(), obj2().method()), the entire call is a full expression.
So, this will work:
#include <QtCore>
struct Test {
Test() { qDebug() << "created"; }
~Test() { qDebug() << "destroyed"; }
Test * fun() { return this; }
};
void f1(Test *, Test*) { qDebug() << "f1"; }
int main()
{
f1(Test().fun(), Test().fun());
}
Output:
created
created
f1
destroyed
destroyed
I have seen code failing which can be simplified like this: someFunction( stringA.toLatin1().constData(), stringB.toLatin1().constData()). Inside the called function, both parameters were pointers to the same address.
The "simplifications" do matter. As soon as you pull each qPrintable out of the full function call expression where they are used as arguments, things fail:
int main()
{
auto a1 = Test().fun();
// here a1 dangles
auto a2 = Test().fun();
// here both a1 and a2 dangle
f1(a1, a2); // undefined behavior
}
Output:
created
destroyed
created
destroyed
f1
Is qPrintable prone to access violations?
That depends on how aware one is of the semantics of C++. Given that it's an obsolete and unnecessary construct, I'd simply say: prone to undefined behavior or not, there's no reason to use it. If you need to pass a QString to something expecting const char *, be explicit about it in an adapter.
void foo(const char *); // we need to call this with a QString
void foo2(const char *, const char *);
inline void foo(const QString & arg1) { // now we can
auto a1 { arg1.toLocal8Bit() };
foo(a1.constData()); // a1's lifetime explicitly extends past the call
}
// or if you really like one-liners
inline void foo2(const QString & arg1, const QString & arg2) {
foo2(arg1.toLocal8Bit().constData(), arg2.toLocal8Bit().constData());
}
But what does this mean? For my understanding, this is identical to "The pointer is invalid from the moment it is returned by qPrintable"
I had the same question, but the key to understanding this is noticing that qPrintable is a macro, not a function:
#ifndef qPrintable
# define qPrintable(string) QtPrivate::asString(string).toLocal8Bit().constData()
#endif
(from here).
If it were a function, you'd be right. Being a macro, there is no return to speak of. The documentation says "returns", but that is just imprecise. Thus, the scope of the temporary is the scope where qPrintable is invoked.

How to properly create a custom exception with a message?

I'm new to C++ and I'm trying to create a custom exception that takes a message in its ctor.
What I have right now is this:
class LevelLoadException : public std::exception
{
public:
LevelLoadException(std::string msg) : m_message(msg) { }
const char * what () const throw ()
{
return m_message.c_str();
}
private:
std::string m_message;
};
In my calling code, I have this as part of a switch statements (c is a char, or more specifically, c = line[x]; where x is an int and line is a std::string);
default:
throw LevelLoadException("Invalid Character in Level: " + c);
The problem is that my Exception gets a completely unrelated string (that's part of the same method that throws: throw std::exception("There is more than 1 player start in the level.")).
I have excluded a logic bug - my program reaches the line where the correct exception with the correct string is thrown. So I'm pretty sure it's a lifetime/memory management problem.
To my understanding, C++ is copy-by-value by default. So I thought that calling the ctor of LevelLoadException would immediately copy the string. But it seems that there is some pointer stuff going on, since the string that I'm building seems like a C string (const char*).
I looked at the std::exception class, and this takes a const char* const& as the message and then does some C-like strcopy/malloc under the hood (MSVC / Visual Studio 2012 Update 4).
I'm not a hundred percent sure what I actually need. I think what I want is a string that's built in the caller, then moved/copied into the Exception (which now owns a copy of the string that's only owned by the exception) and then the one in the caller is destroyed when it's out of scope.
Can someone give me a pointer to what I should be doing differently to do this properly?
"Invalid Character in Level: " + c doesn't do what you think it does. It means "a char* pointer that is offset by N bytes from the beginning of the string literal", where N is the ASCII code of the character stored in c. Chances are high the literal is actually shorter than N characters, in which case this program contains a buffer overrun and exhibits undefined behavior.
Make it
throw LevelLoadException(std::string("Invalid Character in Level: ") + c);

std::exception using message from local object

Is the following code safely throwing an exception with custom message?
#include <exception>
#include <sstream>
#include <string>
#include <iostream>
int main() {
try {
std::ostringstream msg;
msg << "give me " << 5;
throw std::exception(msg.str().c_str());
} catch (std::exception& e) {
std::cout << "exception: " << e.what();
}
}
With VC++-2008 this gives:
exception: give me 5
But now I wonder why the message "give me 5" from the local object msg is still available in the catch-block? By the time the message is printed both the stream- and the temporary string-object should have been deleted? Btw: This way of generating a message for an exception seems also to work accross several functions and also if new memory is allocated in the catch-block before printing the exception.
Or is it necessary to define a custom exception class with a std::string member in order to safely keep the message until printing it.
It's perfectly safe. The constructor that takes a C string as a single parameter makes a copy of the string. The constructor that takes a C string and a length parameter allow you to specify no memory be allocated and stores a pointer to the string (the length parameter is ignored).
Note that these two constructors are extensions to the std::exception class and are not standard. Also be aware that the constructor that takes a C string as a single parameter is not marked as explicit.
It's OK.
Per §15.1/3:
Throwing an exception copy-initializes (8.5, 12.8) a temporary object,
called the exception object.
and §15.1/4:
The memory for the exception object is allocated in an unspecified
way, except as noted in 3.7.4.1. If a handler exits by rethrowing,
control is passed to another handler for the same exception. The
exception object is destroyed after either the last remaining active
handler for the exception exits by any means other than rethrowing...
so after throw expression:
the expression will be copied (new object will be created by copy constructor) and you shouldn't worry about the local object.
About the msg and const char* which you're worrying... here is Microsoft's implementation:
exception::exception(const char * const & _What)
: _Mywhat(NULL), _Mydofree(false)
{
_Copy_str(_What);
//^^^^^^^^^^^^^^^^^
}
void exception::_Copy_str(const char * _What)
{
if (_What != NULL)
{
const size_t _Buf_size = strlen(_What) + 1;
_Mywhat = static_cast<char *>(malloc(_Buf_size));
if (_Mywhat != NULL)
{
_CRT_SECURE_STRCPY(const_cast<char *>(_Mywhat), _Buf_size, _What);
//^^^^^^^^^^^^^^^^^^
_Mydofree = true;
}
}
}
It copies the _What not just storing the pointer.
No, it's not safe, because std::exception doesn't have a constructor taking a char* in the standard. You are using an MS extension. To make it portable and safe, use std::runtime_error instead, to which you can pass a std::string in the ctor.