Safely reading string from Lua stack - c++

How is it possible to safely read string value from Lua stack? The functions lua_tostring and lua_tolstring both can raise a Lua error (longjmp / exception of a strange type). Therefore the functions should be called in protected mode using lua_pcall probably. But I am not able to find a nice solution how to do that and get the string value from Lua stack to C++. Is it really needed to call lua_tolstring in protected mode using lua_pcall?
Actually using lua_pcall seems bad, because the string I want to read from Lua stack is an error message stored by lua_pcall.

Use lua_type before lua_tostring: If lua_type returns LUA_TSTRING, then you can safely call lua_tostring to get the string and no memory will be allocated.
lua_tostring only allocates memory when it needs to convert a number to a string.

Ok, When you call lua_pcall failed, it will return an error code. When you call lua_pcall successfully, you will get zero. So, first you should see the returned value by lua_pcall, then use the lua_type to get the type, at last, use the lua_to* functions the get the right value.
int iRet = lua_pcall(L, 0, 0, 0);
if (iRet)
{
const char *pErrorMsg = lua_tostring(L, -1); // error message
cout<<pErrorMsg<<endl;
lua_close(L);
return 0;
}
int iType = lua_type(L, -1);
switch (iType)
{
//...
case LUA_TSTRING:
{
const char *pValue = lua_tostring(L, -1);
// ...
}
}
It's all.
Good luck.

You can use the lua_isstring function to check if the value can be converted to a string without an error.

Here's how it's done in OpenTibia servers:
std::string LuaState::popString()
{
size_t len;
const char* cstr = lua_tolstring(state, -1, &len);
std::string str(cstr, len);
pop();
return str;
}
Source: https://github.com/opentibia/server/blob/master/src/lua_manager.cpp

Related

Init std::string with single copy

I have the following code in C++ on Win32. It's simply a C++ warp on some Win32 API that returns a CHAR *:
wstring expandEnvironmentVariables(const wstring & str)
{
DWORD neededSize = ExpandEnvironmentStrings(str.c_str(), nullptr, 0);
vector<WCHAR> expandedStr(neededSize);
if (0 == ExpandEnvironmentStrings(str.c_str(), expandedStr.data(), static_cast<DWORD>(expandedStr.size()))) {
return wstring(str);
}
return wstring(expandedStr.data());
}
What bothers me about this code, is the double copy of the result.
by the API into a vector of WCHARs.
from the vector into std::wstring.
Is there a way to implement this code with just a single copy, and without a major change to the signature of the function.
This is a specific example, but I'm more interested in the general solution and the right way to work with std::wstring/std::string, because this pattern shows itself in many places in the code.
Regarding the C++ side you can just use a wstring directly as a result variable.
To get a pointer to the buffer of a wstring of non-zero size, just use &s[0].
Just like std::vector, std::basic_string has a guaranteed contiguous buffer.
For the return it will probably get Return Value Optimization (RVO), and if not then it will be moved.
Disclaimer: I haven't checked the documentation of the API functions. I do not know if this code correct or even meaningful. I'm just assuming that.
wstring expandEnvironmentVariables(const wstring & str)
{
wstring expandedStr;
DWORD neededSize = ExpandEnvironmentStrings(str.c_str(),
nullptr, 0);
if (neededSize)
{
expandedStr.resize(neededSize);
if (0 == ExpandEnvironmentStrings(str.c_str(),
&expandedStr[0],
neededSize))
{
// pathological case requires a copy
expandedStr = str;
}
}
// RVO here
return expandedStr;
}
EDIT:
On reflection, since we're using c++ let's go the whole hog and put in proper error detection and report errors with an informative nested exception chain:
DWORD check_not_zero(DWORD retval, const char* context)
{
if(!retval)
throw std::system_error(GetLastError(),
std::system_category(),
context);
return retval;
}
std::wstring expandEnvironmentVariables(const std::wstring & str)
try
{
DWORD neededSize = check_not_zero(ExpandEnvironmentStrings(str.c_str(),
nullptr,
0),
"ExpandEnvironmentStrings1");
std::wstring expandedStr(neededSize, 0);
check_not_zero(ExpandEnvironmentStrings(str.c_str(),
&expandedStr[0],
neededSize),
"ExpandEnvironmentStrings2");
// RVO here
return expandedStr;
}
catch(...)
{
std::throw_with_nested(std::runtime_error("expandEnvironmentVariables() failed"));
}

c++ how to deal with method returning either NULL or std::string?

I am a bit stuck with some code. I have to use the return type of the method getToto() which usually returns a std::string, but in one case it returns false (It is part of a library I have to use, I cannot modify it). I understand that is equivalent to a null pointer. But I cannot find a proper way to catch it!
Test.cpp
static std::string getToto(){
char buffer[1024];
if ( CTX_Get_Env(buffer, "Toto", 1024) )
return false;
return buffer;
}
If I try
const char* returned = Test::getToto().c_str();
if (returned==NULL){
std::cout<< "null pointer"<<std::endl;
}
I get an error whilst running
terminate called after throwing an instance of 'std::logic_error'
what(): basic_string::_S_construct NULL not valid
Sorry, I have a rather low level in C++.
It depends. Is returning an empty string part of the logic, or is it an exceptional condition.
If it's not supposed to happen, you should throw an error.
If it's okay for the string to be empty, you should just return an empty string:
return std::string();
The reason it compiles as-is is that false is interpreted as 0, which is NULL, which can be a char*, so a string is attempted to be constructed from it. However, constructing an std::string from a NULL pointer is invalid, that's why you're getting the exception.
Here's how I'd code it:
static std::string getToto(){
char buffer[1024];
if ( CTX_Get_Env(buffer, "Toto", 1024) )
throw InvalidDataInBufferException();
return buffer;
}
if the string isn't supposed to be empty, or
static std::string getToto(){
char buffer[1024];
if ( CTX_Get_Env(buffer, "Toto", 1024) )
return std::string();
return buffer;
}
if it's okay for the string to be empty.
The implicit std::string(const char*) constructor is being initialized with false, which is being interpreted as the null pointer. Constructing an std::string from a null pointer is disallowed by the standard. On your platform, this results in an exception being thrown. If you cannot modify the function, you can place the function call inside of a try block, but note that this is by no means guaranteed to work on other platforms.
try {
std::string returned = Test::getToto().c_str();
const char* c = returned.c_str();
} catch(...) {
// handle the error
}
Note 1: Since implementations are not required to raise an exception if an std::string is initialized from a null pointer, calling the getToto() function can result in undefined behaviour. The try-catch blocks only help if your implementation throws an exception, and is therefore not a portable solution. This also means that the library function getToto(), by invoking undefined behaviour, should be avoided.
Note2: The exception was hiding another error, here:
const char* returned = Test::getToto().c_str();
Test::getToto() returns a temporary string, which you do not assign. Your returned pointer is left dangling. In my code example, I assign the return to an std::string, then get the pointer to its internal char data.
You should understand that you got an exception BEFORE even getToto() really returns. There is no way to do 'return false' from the function returning string and do not get an exception. It's just a bug.
You can override it with try/catch block like this:
const char* returned = NULL;
try{
returned = Test::getToto().c_str();
}catch(std::exception& e){
std::cout << "null pointer" << std::endl;
}
but it is still a BAD thing to do.

char* losing data

I'm writing a C++ code with returns some data, the problem is: my const char is losing it value each time I call it from another file. I don't have idea what's happening.
My code on ProcClient.h
virtual void reportWorkflowError(unsigned int workflow,
const dp::String& errorCode) {
char message[1000];
snprintf(message, 1000, "Workflow: %s ERROR: %s", workflowToString(
workflow).utf8(), errorCode.utf8());
printf("[%s]", message);
errorInfo = message;
}
virtual const char * getErrorInfo() {
return errorInfo;
}
[Workflow: DW_FULFILL ERROR: E_ADEPT_NO_TOKEN]
[Workflow: ERROR: E_ADEPT_NOT_READY]
//two errors was thrown, and the errorInfo should has the last
On Services.cpp I start a "workflow", and if it throws an error the listener above is called, and after that I should get tha lastError pointer.
//g_drmClient is the ProcClient
bool RMServices::startFullfilment(dp::String acsm) {
//Do things
g_drmClient->getProcessor()->startWorkflows(dpdrm::DW_FULFILL);
size_t count = g_drmClient->getProcessor()->getFulfillmentItems();
printf("Number of items fulfilled: %d\n", count);
bool returnValue = !g_drmClient->hasError();
if (!returnValue)
lastError = g_drmClient->getErrorInfo());
printf("[%s]", lastError);
return returnValue;
}
Here it prints:
[\æ¾°Ô¯£ ¯|æ¾\æ¾er of items fulfer of ite]
What's happening?
char message[1000];
is a local variable residing on stack and goes out of scope on return of reportWorkflowError. So,
errorInfo = message; // errorInfo is simply pointing to garbage on method return.
Do some thing on these lines -
void className::foo()
{
char stackVariable[] = "abcdef" ;
classVariableCharPointer = new char[ sizeof(stackVariable) + 1 ] ;
strcpy( classVariableCharPointer, stackVariable ) ;
}
Also remember to deallocate the classVariableCharPointer in the destructor using delete[].
Yikes, you can't do that.
As soon as reportWorkflowError returns, all local variables are destroyed. This includes message, which returnValue points to.
A better approach would include making returnValue a character array, and calling srtrcpy() to copy the local data to the member variable. This way, the copy would still exist after message is destroyed.
You're putting message on the stack. Maybe you want it to be static, or better an instance variable.

Function to mangle/demangle functions

I have previously, here, been shown that C++ functions aren't easily represented in assembly. Now I am interested in reading them one way or another because Callgrind, part of Valgrind, show them demangled while in assembly they are shown mangled.
So I would like to either mangle the Valgrind function output or demangle the assembly names of functions. Anyone ever tried something like that? I was looking at a website and found out the following:
Code to implement demangling is part of the GNU Binutils package;
see libiberty/cplus-dem.c and include/demangle.h.
Has anyone ever tried something like that? I want to demangle/mangle in C.
My compiler is gcc 4.x.
Use the c++filt command line tool to demangle the name.
Here is my C++11 implementation, derived from the following page:
http://gcc.gnu.org/onlinedocs/libstdc++/manual/ext_demangling.html
#include <cxxabi.h> // needed for abi::__cxa_demangle
std::shared_ptr<char> cppDemangle(const char *abiName)
{
int status;
char *ret = abi::__cxa_demangle(abiName, 0, 0, &status);
/* NOTE: must free() the returned char when done with it! */
std::shared_ptr<char> retval;
retval.reset( (char *)ret, [](char *mem) { if (mem) free((void*)mem); } );
return retval;
}
To make the memory management easy on the returned (char *), I'm using a std::shared_ptr with a custom lambda 'deleter' function that calls free() on the returned memory. Because of this, I don't ever have to worry about deleting the memory on my own, I just use it as needed, and when the shared_ptr goes out of scope, the memory will be free'd.
Here's the macro I use to access the demangled type name as a (const char *). Note that you must have RTTI turned on to have access to 'typeid'
#define CLASS_NAME(somePointer) ((const char *) cppDemangle(typeid(*somePointer).name()).get() )
So, from within a C++ class I can say:
printf("I am inside of a %s\n",CLASS_NAME(this));
This is a slight variation on Dave's version above. This is a unique_ptr version with a little bit of checking on the return type, though it looks like you could just ignore that, but somehow that just seems unclean.
auto cppDemangle (const char *abiName)
{
//
// This function allocates and returns storage in ret
//
int status;
char *ret = abi::__cxa_demangle(abiName, 0 /* output buffer */, 0 /* length */, &status);
auto deallocator = ( [](char *mem) { if (mem) free((void*)mem); } );
if (status) {
// 0: The demangling operation succeeded.
// -1: A memory allocation failure occurred.
// -2: mangled_name is not a valid name under the C++ ABI mangling rules.
// -3: One of the arguments is invalid.
std::unique_ptr<char, decltype(deallocator) > retval(nullptr, deallocator);
return retval;
}
//
// Create a unique pointer to take ownership of the returned string so it
// is freed when that pointers goes out of scope
//
std::unique_ptr<char, decltype(deallocator) > retval(ret, deallocator);
return retval;
}

Can I use a static var to "cache" the result? C++

I am using a function that returns a char*, and right now I am getting the compiler warning "returning address of local variable or temporary", so I guess I will have to use a static var for the return, my question is can I make something like if(var already set) return var else do function and return var?
This is my function:
char * GetUID()
{
TCHAR buf[20];
StringCchPrintf(buf, 20*sizeof(char), TEXT("%s"),
someFunction());
return buf;
}
And this is what I want to do:
char * GetUID()
{
static TCHAR buf[20];
if(strlen(buf)!=0) return buf;
StringCchPrintf(buf, 20*sizeof(char), TEXT("%s"),
someFunction());
return buf;
}
Is this a well use of static vars? And should I use ZeroMemory(&buf, 20*sizeof(char))? I removed it because if I use it above the if(strlen...) my TCHAR length is never 0, should I use it below?
The reason you're getting a warning is because the memory allocated within your function for buf is going to be popped off the stack once the function exits. If you return a pointer to that memory address, you have a pointer to undefined memory. It may work, it may not - it's not safe regardless.
Typically the pattern in C/C++ is to allocate a block of memory and pass a pointer to that block into your function. e.g.
void GetUID( char* buf )
{
if(strlen(buf)!=0) return;
StringCchPrintf(buf, 20*sizeof(char), TEXT("%s"), someFunction());
}
If you want the function (GetUID) itself to handle caching the result, then you can use a static, a singleton (OOP), or consider thread local storage.
(e.g. in Visual C++)
__declspec(thread) TCHAR buf[20];
It's OK if your code is single threaded. The buffer will be set to contain all zeros when the function is entered for the very first time, so there is no need to explicitly set its contents to zero. But these days all code eventually tends to become multi-threaded, so I would not do this, if I were you.
What you should do instead is allocate buf dynamically using new, and then return it. But be aware that the caller would be responsible for deallocating the memory.
Better yet, use std::string instead of char *.
You could do that, but it won't be thread-safe. You should also be careful with what you do with the result, since you can not store it between subsequent calls to the function (without copying it, of course).
You should also initialize the static variable to the empty string.
This is how I would do it.
It caches; it does not rely on the buffer being 0.
It does have the implicit assumption that 'buf' will be identical from thread to thread, which is not (to my knowledge) correct. I would use a global for that purpose.
//returns a newly allocated buffer, every time. remember to delete [] it.
char * GetUID()
{
static TCHAR buf[20];
static bool run = false;
TCHAR ret_mem = new TCHAR[20];
if(run)
{ return ret_mem; }
//do stuff to the buf
//assuming - dst, src, size.
memcpy(ret_mem, buf, 20);
run = true;
return ret_mem;
}