For the purpose of creating a custom exception class, I need to convert a QString to a const char*. Here's the main code of the aforementioned class:
// File "Exception.cpp"
const auto MESSAGE_PREFIX = QStringLiteral("Exception ");
Exception::Exception(const char* file, int line, const QString& cause)
: m_Message{MESSAGE_PREFIX + file + ':' + QString::number(line) + ": " + cause}
{
}
const char* Exception::what() const noexcept
{
// QString -> const char*
const auto ba = m_Message.toLocal8Bit();
return ba.constData();
}
So, the conversion happens in the overriden method Exception::what and the returned C-string indicates, among others, the file which throws the exception.
In addition, I've defined a macro THROW_EXCEPTION_IF() which helps throwing exception:
// File "exception_macros.h"
#include "Exception.h"
#ifdef Q_OS_WINDOWS
#define __FILENAME__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
#else
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
#endif
#define THROW_EXCEPTION_IF(condition, cause)
if (condition) {
auto str = QString{};
QTextStream stream{&str};
stream << cause;
throw Exception{__FILENAME__, __LINE__, str};
}
Finally, I test the above macro with the following code:
void TestException::testMacro()
{
try {
THROW_EXCEPTION_IF(true, "Test")
QVERIFY(false);
}
catch (const std::exception& e) {
QVERIFY(true);
QCOMPARE(QString{e.what()}, QStringLiteral("Exception TestException.cpp:36: Test"));
}
}
And here's the problem: when I run this test on Linux (Qt 5.7.1, GCC 6.3), it fails with this message:
FAIL!: TestException::testMacro() Compared values are not the same
Actual (QString{e.what()}): "Exception TestExn\u0000\u0000T\u0000e\u0000s\u0000t\u0000E\u0000x\u0000n\u0000\u0000\u0000"
Expected (QStringLiteral("Exception TestException.cpp:36: Test")): "Exception TestException.cpp:36: Test"
And it's the same problem on Windows (Qt 5.15) with MSVC 2019 but it works with MinGW 8.1. Moreover, on Linux, when I replace m_Message.toLocal8bit() with m_Message.toLatin1(), the test passed successfully. I think there's a problem with Unicode characters but I don't understand where's the problem in my code. Thank yout very much for your help.
Your problem is that you are returning an invalid pointer:
const auto ba = m_Message.toLocal8Bit(); // here you create a bytearray
return ba.constData();//here you take the pointer to the data of the bytearray
//then you destroy the array, hence the pointer.
//then you return an invalid pointer
You have different behaviors in the different platforms because it is not warrantied when the pointer will not be longer available. It depends on the platform, the compiler, the compilation flags, etc.
Why it doesn't work
I agree with Pablo Yaggi that you are trying to access destroyed data, see QByteArray::constData:
The [const char *] pointer remains valid as long as the byte array isn't reallocated
or destroyed.
Solution
You should store the QByteArray (returned by toLocal8Bit) in your exception class (instead of the QString). Note that you may want to return the string UTF-8 encoded (see toUtf8) to support all (special) characters. The behaviour of toLocal8Bit and toLatin1 are undefined if unsupported characters are encountered:
If this string contains any characters that cannot be encoded in the
locale, the returned byte array is undefined. Those characters may be
suppressed or replaced by another. [source]
Related
I am using Il2CppInspector to generate scaffolding for a Unity game. I am able to convert System.String (app::String in Il2CppInspector) to std::string using the functions provided below.
How would I reverse this process; how do I convert a std::string to System.String?
helpers.cpp
// Helper function to convert Il2CppString to std::string
std::string il2cppi_to_string(Il2CppString* str) {
std::u16string u16(reinterpret_cast<const char16_t*>(str->chars));
return std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}.to_bytes(u16);
}
// Helper function to convert System.String to std::string
std::string il2cppi_to_string(app::String* str) {
return il2cppi_to_string(reinterpret_cast<Il2CppString*>(str));
}
In short, I am looking for a function that takes in a std::string and returns an app::String
// Helper function to convert std::string to System.String
app::String string_to_il2cppi(std::string str) {
// Conversion code here
}
The accepted answer is actually wrong, there is no size parameter and copying stops at the first null byte (0x00) according to the MSDN documentation.
The following code fixes these problems and works correctly:
app::String* string_to_il2cppi(const std::string& string)
{
const auto encoding = (*app::Encoding__TypeInfo)->static_fields->utf8Encoding;
const auto managed_string = app::String_CreateStringFromEncoding((uint8_t*)&string.at(0), string.size(), encoding, nullptr);
return managed_string;
}
A quote from djkaty:
To create a string, you cannot use System.String‘s constructors –
these are redirected to icalls that throw exceptions. Instead, you
should use the internal Mono function String.CreateString. This
function has many overloads accepting various types of pointer and
array; an easy one to use accepts a uint16_t* to a Unicode string and
can be called as follows [...]
Export Il2CppInspector with all namespaces, which will give you access to Marshal_PtrToStringAnsi.
app::String* string_to_il2cppi(std::string str) {
return app::Marshal_PtrToStringAnsi((void*)&str, NULL);
}
Limitation: do not attempt to convert a string with null terminators inside of them example:
std::string test = "Hello\0world";
Use BullyWiiPlaza's solution if this is an issue for you.
I am attempting to pass a string from python to a c++ library. However, I have been crashing with variations of segfaults std::bad_alloc, and invalid type messages while I have been attempting to do so. Here is the code that I am attempting to use in c++:
#define DLLEXPORT extern "C"
DLLEXPORT std::string returnAString()
{
std::string ret = "Returning string from lib";
return ret;
}
DLLEXPORT char* returnACharArray()
{
return "Returning char* from lib";
}
DLLEXPORT void passInAString(std::string incomingString)
{
printf("Recieved message in passInAString\n");
printf("Recieved incoming message: %s", incomingString);
}
DLLEXPORT void passInACharArray(char* incomingString)
{
printf("Recieved message in passInACharArray\n");
printf("Recieved incoming message: %s", incomingString);
}
Realistically, with what I am doing I can work with either the char* or the std::string once it gets in my c++ code, and I don't really have a preference either way. Here is what I am doing in python:
from ctypes import *
import os
libPath = os.path.join(os.getcwd(), "mylib.so")
lib = cdll.LoadLibrary(libPath)
string = "hello from python"
lib.passInAString(string)
#lib.passInACharArray(string)
#ret = lib.returnAString()
#print("recieved string: " + string)
#ret = lib.returnACharArray()
#print("recieved char*: " + string)
here, I will uncomment whichever line I am attempting to test. When passing in a string, I will get my first printf statement, I will get std::bad_alloc. When I pass in a char*, I get a segfault. When I attempt to receive a message, I get back a number (I am assuming that this is the pointer), but I am unable to decode this message into an actual string message.
I have attempted to use c_char_p to convert my python string into a char* to pass to my library, but when I do that I get "invalid type". Trying to convert the returned message by doing c_char_p(lib.returnACharArray) and then print(str(string.value)) then gives me the hex value of 4 bytes... which is not what I am returning.
What am I missing to make this functionality work?
Your DLL has the wrong argument types.
Since you're passing a string from Python the function should take a char*. You can convert this to a std::string within the function if you want to.
There's a table in the Python docs showing the corresponding types in both C and Python here: https://docs.python.org/3.6/library/ctypes.html#fundamental-data-types
Edit: Just realized the string types differ for Python 3 meaning the function needs to be declared differently.
e.g.
// Python2, or Python3 passing bytes
DLLEXPORT void passInAString(char* incomingString)
{
printf("Received message in passInAString\n");
printf("Received incoming message: %s", incomingString);
std::string myStr = incomingString;
// and do stuff with myStr if needed
printf("Incoming message as std::string is %s", myStr.c_str());
}
// Python3 passing strings
DLLEXPORT void passStringPy3(wchar_t* wideString)
{
printf("Message >>%ls<<\n", wideString);
}
I have this public function inside a class and what I am doing is appending a string to another string char by char (because I'm also making some checking on the characters). So, it basically looks like this:
void mystring::copy(wstring oldtext) {
wstring newtext;
for (unsigned int i=0; i<oldtext.length(); ++i) {
// Doing some checking ...
// I also used newtext.append(1, oldtext[i]);
newtext += oldtext[i];
// Just testing
wprintf_s(L"String: %s\n", newtext);
}
}
So, if I comment the wprintf_s line the program doesn't crash, but if I want to test and see what is added to newtext by using it, it crashes. I tried to add "\0\n" but it doesn't work either and it smells like some pointer problem. What could it be?
I guess you should use newtext.c_str() to convert it to a normal C string when using it with %s type specifier inside a printf.
I've created a function that will convert all the event notification codes to strings. Pretty simple stuff really.
I've got a bunch of consts like
const _bstr_t DIRECTSHOW_MSG_EC_ACTIVATE("A video window is being activated or deactivated.");
const _bstr_t DIRECTSHOW_MSG_EC_BUFFERING_DATA("The graph is buffering data, or has stopped buffering data.");
const _bstr_t DIRECTSHOW_MSG_EC_BUILT("Send by the Video Control when a graph has been built. Not forwarded to applications.");
.... etc....
and my function
TCHAR* GetDirectShowMessageDisplayText( int messageNumber )
{
switch( messageNumber )
{
case EC_ACTIVATE: return DIRECTSHOW_MSG_EC_ACTIVATE;
case EC_BUFFERING_DATA: return DIRECTSHOW_MSG_EC_BUFFERING_DATA;
case EC_BUILT: return DIRECTSHOW_MSG_EC_BUILT;
... etc ...
No big deal. Took me 5 minutes to throw together.
... but I simply don't trust that I've got all the possible values, so I want to have a default to return something like "Unexpected notification code (7410)" if no matches are found.
Unfortunately, I can't think of anyway to return a valid pointer, without forcing the caller to delete the string's memory ... which is not only nasty, but also conflicts with the simplicity of the other return values.
So I can't think of any way to do this without changing the return value to a parameter where the user passes in a buffer and a string length. Which would make my function look like
BOOL GetDirectShowMessageDisplayText( int messageNumber, TCHAR* outBuffer, int bufferLength )
{
... etc ...
I really don't want to do that. There must be a better way.
Is there?
I'm coming back to C++ after a 10 year hiatus, so if it's something obvious, don't discount that I've overlooked it for a reason.
C++? std::string. It's not going to destroy the performance on any modern computer.
However if you have some need to over-optimize this, you have three options:
Go with the buffer your example has.
Have the users delete the string afterwards. Many APIs like this provide their own delete function for deleting each kind of dynamically allocated return data.
Return a pointer to a static buffer which you fill in with the return string on each call. This does have some drawbacks, though, in that it's not thread safe, and it can be confusing because the returned pointer's value will change the next time someone calls the function. If non-thread-safety is acceptable and you document the limitations, it should be all right though.
If you are returning a point to a string constant, the caller will not have to delete the string - they'll only have to if you are new-ing the memory used by the string every time. If you're just returning a pointer to a string entry in a table of error messages, I would change the return type to TCHAR const * const and you should be OK.
Of course this will not prevent users of your code to attempt to delete the memory referenced by the pointer but there is only so much you can do to prevent abuse.
Just declare use a static string as a default result:
TCHAR* GetDirectShowMessageDisplayText( int messageNumber )
{
switch( messageNumber )
{
// ...
default:
static TCHAR[] default_value = "This is a default result...";
return default_value;
}
}
You may also declare "default_value" outside of the function.
UPDATE:
If you want to insert a message number in that string then it won't be thread-safe (if you are using multiple threads). However, the solution for that problem is to use thread-specific string. Here is an example using Boost.Thread:
#include <cstdio>
#include <boost/thread/tss.hpp>
#define TCHAR char // This is just because I don't have TCHAR...
static void errorMessageCleanup (TCHAR *msg)
{
delete []msg;
}
static boost::thread_specific_ptr<TCHAR> errorMsg (errorMessageCleanup);
static TCHAR *
formatErrorMessage (int number)
{
static const size_t MSG_MAX_SIZE = 256;
if (errorMsg.get () == NULL)
errorMsg.reset (new TCHAR [MSG_MAX_SIZE]);
snprintf (errorMsg.get (), MSG_MAX_SIZE, "Unexpected notification code (%d)", number);
return errorMsg.get ();
}
int
main ()
{
printf ("Message: %s\n", formatErrorMessage (1));
}
The only limitation of this solution is that returned string cannot be passed by the client to the other thread.
Perhaps have a static string buffer you return a pointer to:
std::ostringstream ss;
ss << "Unexpected notification code (" << messageNumber << ")";
static string temp = ss.str(); // static string always has a buffer
return temp.c_str(); // return pointer to buffer
This is not thread safe, and if you persistently hold the returned pointer and call it twice with different messageNumbers, they all point to the same buffer in temp - so both pointers now point to the same message. The solution? Return a std::string from the function - that's modern C++ style, try to avoid C style pointers and buffers. (It looks like you might want to invent a tstring which would be std::string in ANSI and std::wstring in unicode, although I'd recommend just going unicode-only... do you really have any reason to support non-unicode builds?)
You return some sort of self-releasing smart pointer or your own custom string class. You should follow the interface as it's defined in std::string for easiest use.
class bstr_string {
_bstr_t contents;
public:
bool operator==(const bstr_string& eq);
...
~bstr_string() {
// free _bstr_t
}
};
In C++, you never deal with raw pointers unless you have an important reason, you always use self-managing classes. Usually, Microsoft use raw pointers because they want their interfaces to be C-compatible, but if you don't care, then don't use raw pointers.
The simple solution does seem to be to just return a std::string. It does imply one dynamic memory allocation, but you'd probably get that in any case (as either the user or your function would have to make the allocation explicitly)
An alternative might be to allow the user to pass in an output iterator which you write the string into. Then the user is given complete control over how and when to allocate and store the string.
On the first go-round I missed that this was a C++ question rather than a plain C question. Having C++ to hand opens up another possibility: a self-managing pointer class that can be told whether or not to delete.
class MsgText : public boost::noncopyable
{
const char* msg;
bool shouldDelete;
public:
MsgText(const char *msg, bool shouldDelete = false)
: msg(msg), shouldDelete(shouldDelete)
{}
~MsgText()
{
if (shouldDelete)
free(msg);
}
operator const char*() const
{
return msg;
}
};
const MsgText GetDirectShowMessageDisplayText(int messageNumber)
{
switch(messageNumber)
{
case EC_ACTIVATE:
return MsgText("A video window is being activated or deactivated.");
// etc
default: {
char *msg = asprintf("Undocumented message (%u)", messageNumber);
return MsgText(msg, true);
}
}
}
(I don't remember if Windows CRT has asprintf, but it's easy enough to rewrite the above on top of std::string if it doesn't.)
Note the use of boost::noncopyable, though - if you copy this kind of object you risk double frees. Unfortunately, that may cause problems with returning it from your message-pretty-printer function. I'm not sure what the right way to deal with that is, I'm not actually much of a C++ guru.
You already use _bstr_t, so if you can just return those directly:
_bstr_t GetDirectShowMessageDisplayText(int messageNumber);
If you need to build a different message at runtime you can pack it into a _bstr_t too. Now the ownership is clear and the use is still simple thanks to RAII.
The overhead is negligible (_bstr_t uses ref-counting) and the calling code can still use _bstr_ts conversion to wchar_t* and char* if needed.
There's no good answer here, but this kludge might suffice.
const char *GetDirectShowMessageDisplayText(int messageNumber)
{
switch(messageNumber)
{
// ...
default: {
static char defaultMessage[] = "Unexpected notification code #4294967296";
char *pos = defaultMessage + sizeof "Unexpected notification code #" - 1;
snprintf(pos, sizeof "4294967296" - 1, "%u", messageNumber);
return defaultMessage;
}
}
}
If you do this, callers must be aware that the string they get back from GetDirectShowMessageText might be clobbered by a subsequent call to the function. And it's not thread safe, obviously. But those might be acceptable limitations for your application.
I have a Visual Studio 2008 C++ project that uses a Win32Exception class in cases where there is an exceptional error. The Win32Exception class looks like this:
/// defines an exception based on Win32 error codes. The what() function will
/// return a formatted string returned from FormatMessage()
class Win32Exception : public std::runtime_error
{
public:
Win32Exception() : std::runtime_error( ErrorMessage( &error_code_ ) )
{
};
virtual ~Win32Exception() { };
/// return the actual error code
DWORD ErrorCode() const throw() { return error_code_; };
private:
static std::string ErrorMessage( DWORD* error_code )
{
*error_code = ::GetLastError();
std::string error_messageA;
wchar_t* error_messageW = NULL;
DWORD len = ::FormatMessageW( FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
*error_code,
MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
reinterpret_cast< LPWSTR >( &error_messageW ),
0,
NULL );
if( NULL != error_messageW )
{
// this may generate a C4244 warning. It is safe to ignore.
std::copy( error_messageW,
error_messageW + len,
std::back_inserter( error_messageA ) );
::LocalFree( error_messageW );
}
return error_messageA;
};
/// error code returned by GetLastError()
DWORD error_code_;
}; // class Win32Exception
The class works well in the situations it has been used in. What I would like to know is if there are any obvious cases where this will fail that I should be aware of. Any other gotchas, caveats, or general suggestions on improvements are welcome.
Please note that the boost library is not an option for this code.
This has already done by several people, including yours truly
https://github.com/BillyONeal/Instalog/blob/master/LogCommon/Win32Exception.hpp
https://github.com/BillyONeal/Instalog/blob/master/LogCommon/Win32Exception.cpp
Ironically, your code is not exception safe.
if( NULL != error_messageW )
{
// this may generate a C4244 warning. It is safe to ignore.
std::copy( error_messageW,
error_messageW + len,
std::back_inserter( error_messageA ) );
::LocalFree( error_messageW );
}
Note that if the back_inserter causes std::bad_alloc to be thrown, the memory allocated inside FormatMessage is leaked.
What a coincidence! I use a similar code in all my projects! It is actually a good idea.
This code is problematic:
// this may generate a C4244 warning. It is safe to ignore.
std::copy( error_messageW,
error_messageW + len,
std::back_inserter( error_messageA ) );
It just trancates WCHARs to chars. Your can either use FormatMessageA explicitly to get a message in the current code-page (ok, you can't as you said), or make convention that all your stings are UTF-8 encoded. I chose the later, see this why.
Error message by itself may be not useful. Capturing the stack trace may be a good idea.
Realize this is old, but at least with VC++ 2015 you can throw a system_error that will do all this with the system_category() function:
try
{
throw system_error(E_ACCESSDENIED, system_category(), "Failed to write file");
}
catch (exception& ex)
{
cout << ex.what();
}
This would print: "Failed to write file: Access is denied"
FormatMessage may itself fail. Some neutral "Unknown error with code %d" might be in order for such case.
Some error codes are not really errors (ERROR_ALREADY_EXISTS), depending on what user is expecting.
Some system functions return their own error codes (notable example being SHFileOperation) that you must handle separately. If you want them to be handled, that is.
Consider having additional information inside exception: where is exception being thrown from (source file and line), what system function caused exception, what were the parameters of the function (at least the identifying ones, like file name, handle value, or some such). Stack trace is also good.
What I would like to know is if there
are any obvious cases where this will
fail that I should be aware of. Any
other gotchas, caveats, or general
suggestions on improvements are
welcome.
The main I've problem I've had with such message retrieval has been ERROR_SUCCESS. It's rather perplexing when some operation fails, accompanied by error message "The operation succeeded". One wouldn't think that could happen, but it does.
I guess this is a special case of what Dialecticus noted, that "Some error codes are not really errors", but for most of those codes at least the message is generally acceptable.
The second problem is that most Windows system error message have a carriage return + linefeed at the end. It's problematic for insertion of messages into other text, and it breaks the convention for C++ exception messages. So, good idea to remove those chars.
Now, instead of repeating all that others have already noted, a few words about the design.
The ErrorMessage function would much more usable if was made public or moved out of the class, and took the error code by value, instead of taking pointer argument. This is the principle of keeping separate responsibilities separate. Promotes reuse.
The code in ErrorMessage would be more clear and safe and efficient if you used a destructor to deallocate the memory. Then you could also just construct the string directly in the return statement instead of using a copy loop with back inserter.
Cheers & hth.,
I was recently working on a very similar class and after reading this thread tried to make the copying part exception-safe. I introduced a little helper class that does nothing but hold the pointer to the string returned by ::FormatMessage and free it with ::LocalFree in its destructor. Copying, assigning and moving is not allowed, so one cannot get into trouble.
Here is what I came up with in total:
class windows_error {
public:
windows_error(wchar_t const* what);
// Getter functions
unsigned long errorCode() const { return _code; }
wchar_t const* description() const { return _what; }
std::wstring errorMessage() const { return _sys_err_msg; }
private:
unsigned long _code;
wchar_t const* _what;
std::wstring _sys_err_msg;
};
// This class outsources the problem of managing the string which
// was allocated with ::LocalAlloc by the ::FormatMessage function.
// This is necessary to make the constructor of windows_error exception-safe.
class LocalAllocHelper {
public:
LocalAllocHelper(wchar_t* string) : _string(string) { }
~LocalAllocHelper() {
::LocalFree(_string);
}
LocalAllocHelper(LocalAllocHelper const& other) = delete;
LocalAllocHelper(LocalAllocHelper && other) = delete;
LocalAllocHelper& operator=(LocalAllocHelper const& other) = delete;
LocalAllocHelper& operator=(LocalAllocHelper && other) = delete;
private:
wchar_t* _string;
};
windows_error::windows_error(wchar_t const* what)
: _code(::GetLastError()),
_what(what) {
// Create a temporary pointer to a wide string for the error message
LPWSTR _temp_msg = 0;
// Retrieve error message from error code and save the length
// of the buffer which is being returned. This is needed to
// implement the copy and assignment constructor.
DWORD _buffer_size = ::FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, _code, 0, _temp_msg, 0, NULL);
if(_buffer_size) {
// When calling _sys_err_msg.resize an exception could be thrown therefore
// the _temp_msg needs to be a managed resource.
LocalAllocHelper helper(_temp_msg);
_sys_err_msg.resize(_buffer_size + 1);
std::copy(_temp_msg, _temp_msg + _buffer_size, _sys_err_msg.begin());
}
else {
_sys_err_msg = std::wstring(L"Unknown error. (FormatMessage failed)");
}
}
Maybe this will be useful for some of you.