Reputation: 517
I have a legacy C++ code that was written as a dll that can be called on Windows 10. A new requirement is to allow this dll to function properly on earlier Windows (7 Embedded, optionally XP as well). In short, the code is supposed to display body
of a REST response.
The problem is, when called on Windows 7 without any modifications, there are additional (sometimes invisible) characters, especially at the beginning of the displayed output.
The code below is an abbreviated version and I believe to_utf8string
is the root of the problem. What other function should I use in order for this dll to work on Windows 7 properly?
const char* foo(const char* param)
{
web::http::http_response resp = other_foo(param).get();
std::string utf8Response;
web::json::value json = resp.extract_json().get();
utf8Response = utility::conversions::to_utf8string(json.serialize());
return utf8Response.c_str();
}
Two example outputs on Windows 7:
Upvotes: 0
Views: 255
Reputation: 596672
The problem has nothing to do with character encoding, or OS used. The function is returning a dangling pointer to invalid memory!
The function is declaring a local std::string
variable that goes out of scope when the function exits. It is returning a pointer to the std::string
's internal character data, which is freed when the std::string
is destroyed.
To solve this, the function will have to return a pointer to dynamically allocated memory that the caller can then free (or pass back to the DLL to free) at a later time when it is done using the data. For example:
const char* foo(const char* param)
{
web::http::http_response resp = other_foo(param).get();
web::json::value json = resp.extract_json().get();
std::string utf8Response = utility::conversions::to_utf8string(json.serialize());
// the caller can use CoTaskMemFree() to free this returned memory...
size_t size = utf8Response.size() + 1; // +1 for null terminator
char *ptr = static_cast<char*>(CoTaskMemAlloc(size));
if (ptr)
std::memcpy(ptr, utf8Response.c_str(), size);
return ptr;
}
const char* response = foo(param);
if (response) {
...
CoTaskMemFree(response);
}
Or:
const char* foo(const char* param)
{
web::http::http_response resp = other_foo(param).get();
web::json::value json = resp.extract_json().get();
std::string utf8Response = utility::conversions::to_utf8string(json.serialize());
// the caller must call free_foo_result() to free this memory...
size_t size = utf8Response.size() + 1; // +1 for null terminator
char *ptr = new(std::nothrow) char[size];
if (ptr)
std::memcpy(ptr, utf8Response.c_str(), size);
return ptr;
}
void free_foo_result(const char *data)
{
delete[] data;
}
const char* response = foo(param);
if (response) {
...
free_foo_result(response);
}
If re-writing the EXE to make these extra function calls is not an option, then the DLL will have to cache the JSON data so it can survive past the return
, eg:
const char* foo(const char* param)
{
static thread_local std::string utf8Response;
web::http::http_response resp = other_foo(param).get();
web::json::value json = resp.extract_json().get();
utf8Response = utility::conversions::to_utf8string(json.serialize());
return utf8Response.c_str();
}
Upvotes: 3