Crashes when calling `lua_getfield()` after overriding the require - c++

This question is related to #Henri_Menke's answer from this question : How to get preloaded module name in C++
I'm trying to override the require function with my own version so I can get the preloaded module name inside Lua script.
Here's my code:
#include "lua.hpp"
void main()
{
lua_State *L = luaL_newstate();
luaL_openlibs(L);
lua_settop(L, 0);
luaL_dostring(L, "local require_original = require\n"
"function require(name, ...)\n"
"current_module = name\n"
"require_original(name, ...)\n"
"current_module = nil\n"
"end\n"); //if I comment out this chunk, it works fine
luaL_dostring(L, "package.preload['test'] = function ()\n"
"local test = {}\n"
"print('While loading:', current_module)\n"
"function test.update() print('Updated!') end\n"
"return test\n"
"end\n");
lua_getglobal(L, "require");
lua_pushstring(L, "test");
if (lua_pcall(L, 1, LUA_MULTRET, 0))
{
std::cout << "Error: " << lua_tostring(L, -1) << std::endl;
lua_pop(L, 1);
}
int top = lua_gettop(L);
lua_getfield(L, -1, "update"); //crashes here
if (lua_isfunction(L, -1))
{
lua_pushnil(L);
if (lua_pcall(L, 1, LUA_MULTRET, 0))
{
std::cout << "Error: " << lua_tostring(L, -1) << std::endl;
lua_pop(L, 1);
}
}
lua_close(L);
}
However, it crashes when calling lua_getfield(L, -1, "update");.
And it no longer crashes when I comment out the first chunk of Lua script(first luaL_dostring).
I don't understand why it crashes if I use my own version of require.
How can I fix this?

I forgot to return the module table from overridden require function. Sorry about that.
#include <iostream>
#include "lua.hpp"
int main() {
lua_State *L = luaL_newstate();
luaL_openlibs(L);
lua_settop(L, 0);
luaL_dostring(L, "local require_original = require\n"
"function require(name, ...)\n"
"current_module = name\n"
"local val = table.pack(require_original(name, ...))\n"
"current_module = nil\n"
"return table.unpack(val,1,val.n)\n"
"end\n"); //if I comment out this chunk, it works fine
luaL_dostring(L, "package.preload['test'] = function ()\n"
"local test = {}\n"
"print('While loading:', current_module)\n"
"function test.update() print('Updated!') end\n"
"return test\n"
"end\n");
lua_getglobal(L, "require");
lua_pushstring(L, "test");
if (lua_pcall(L, 1, LUA_MULTRET, 0))
{
std::cout << "Error: " << lua_tostring(L, -1) << std::endl;
lua_pop(L, 1);
}
int top = lua_gettop(L);
lua_getfield(L, -1, "update"); //crashes here
if (lua_isfunction(L, -1))
{
lua_pushnil(L);
if (lua_pcall(L, 1, LUA_MULTRET, 0))
{
std::cout << "Error: " << lua_tostring(L, -1) << std::endl;
lua_pop(L, 1);
}
}
lua_close(L);
}
$ clang++ -Wall -Wextra -Wpedantic -I /usr/include/lua5.2 test.cpp -llua5.2
test.cpp:28:9: warning: unused variable 'top' [-Wunused-variable]
int top = lua_gettop(L);
^
1 warning generated.
$ ./a.out
While loading: test
Updated!

Related

SQLite3 - Taking function parameters as values

I'm trying to make a class using sqlite3 database with a method that should insert the data in the table when the user adds the files to the application, but it is not working as intended,
void Database::InsertSample(int Favorite, std::string Filename,
std::string SamplePack, int Channels, int Length,
int SampleRate, int Bitrate, std::string Comment,
std::string Path)
{
try
{
rc = sqlite3_open("Samples.db", &DB);
sql = "INSERT INTO SAMPLES (FAVORITE, FILENAME, SAMPLEPACK, CHANNELS, \
LENGTH, SAMPLERATE, BITRATE, BITSPERSAMPLE, PATH) \
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?);";
rc = sqlite3_prepare_v2(DB, sql.c_str(), 0, &stmt, 0); // create the prepared statement
rc = sqlite3_bind_int(stmt, 1, Favorite);
rc = sqlite3_bind_text(stmt, 2, Filename.c_str(), Filename.size(), SQLITE_STATIC);
rc = sqlite3_bind_text(stmt, 3, SamplePack.c_str(), SamplePack.size(), SQLITE_STATIC);
rc = sqlite3_bind_int(stmt, 4, Channels);
rc = sqlite3_bind_text(stmt, 5, Filename.c_str(), Filename.size(), SQLITE_STATIC);
rc = sqlite3_bind_int(stmt, 6, Length);
rc = sqlite3_bind_int(stmt, 7, SampleRate);
rc = sqlite3_bind_int(stmt, 8, Bitrate);
rc = sqlite3_bind_text(stmt, 9, Comment.c_str(), Comment.size(), SQLITE_STATIC);
rc = sqlite3_bind_text(stmt, 10, Path.c_str(), Path.size(), SQLITE_STATIC);
rc = sqlite3_step(stmt);
rc = sqlite3_exec(DB, Sample.c_str(), NULL, 0, &ErrorMessage);
if (rc != SQLITE_OK)
{
std::cerr << "Error! Cannot insert data into table." << std::endl;
sqlite3_free(ErrorMessage);
}
else
{
std::cout << "Data inserted successfully." << std::endl;
}
sqlite3_close(DB);
}
catch (const std::exception &exception)
{
std::cerr << exception.what();
}
}
But this fails, throwing the error statement "Error! Cannot insert data into table.". Am I doing something wrong here.
I'm using this function in another class as,
void Browser::OnClickDirCtrl(wxCommandEvent& event)
{
TagLib::FileRef File (DirCtrl->GetFilePath());
TagLib::String Artist = File.tag()->artist();
TagLib::String Album = File.tag()->album();
TagLib::String Genre = File.tag()->genre();
TagLib::String Title = File.tag()->title();
TagLib::String Comment = File.tag()->comment();
int Bitrate = File.audioProperties()->bitrate();
int Channels = File.audioProperties()->channels();
int Length = File.audioProperties()->lengthInMilliseconds();
int LengthSec = File.audioProperties()->lengthInSeconds();
int SampleRate = File.audioProperties()->sampleRate();
wxVector<wxVariant> Data;
Data.clear();
Data.push_back(false);
Data.push_back(TagLibTowx(Title));
Data.push_back(TagLibTowx(Artist));
Data.push_back(wxString::Format("%d",Channels));
Data.push_back(wxString::Format("%d",LengthSec));
Data.push_back(wxString::Format("%d",SampleRate));
Data.push_back(wxString::Format("%d",Bitrate));
Data.push_back(TagLibTowx(Comment));
SampleListView->AppendItem(Data);
db.InsertSample(0, Title.to8Bit(), Artist.to8Bit(), Channels, Length, SampleRate, Bitrate, Comment.to8Bit(), DirCtrl->GetFilePath().ToStdString());
}
This just a part of the function that should add the files to the database. As you can see, I am storing the path of the files in the database which is important data that I need for the project.
/---------/
EDIT: Adding a short sample,
main.cpp
#include "testdb.hpp"
int main()
{
Database db;
db.InsertData("Hello, World!");
return 0;
}
testdb.hpp
#include <sqlite3.h>
#include <string>
class Database
{
public:
Database();
~Database();
public:
sqlite3* DB;
int rc;
char* ErrorMessage;
std::string Test;
std::string sql;
sqlite3_stmt* stmt;
public:
void InsertData(std::string Path);
};
testdb.cpp
#include <exception>
#include <iostream>
#include <string>
#include "testdb.hpp"
Database::Database()
{
/* Create SQL statement */
Test = "CREATE TABLE TEST("
"TEST TEXT NOT NULL);";
try
{
rc = sqlite3_open("Test.db", &DB);
rc = sqlite3_exec(DB, Test.c_str(), NULL, 0, &ErrorMessage);
if (rc != SQLITE_OK)
{
std::cerr << "Error! Cannot create table." << std::endl;
sqlite3_free(ErrorMessage);
}
else
{
std::cout << "Table created successfuly." << std::endl;
}
sqlite3_close(DB);
}
catch (const std::exception &exception)
{
std::cerr << exception.what();
}
}
void Database::InsertData(std::string Test)
{
try
{
rc = sqlite3_open("Test.db", &DB);
sql = "INSERT INTO TEST (PATH) VALUES (?);";
rc = sqlite3_prepare_v2(DB, sql.c_str(), 10, &stmt, 0); // create the prepared statement
// error handling goes here
rc = sqlite3_bind_text(stmt, 10, Test.c_str(), Test.size(), SQLITE_STATIC);
// error handling goes here
rc = sqlite3_step(stmt);
// error handling goes here
rc = sqlite3_finalize(stmt);
if (rc != SQLITE_OK)
{
std::cerr << "Error! Cannot insert data into table." << std::endl;
sqlite3_free(ErrorMessage);
}
else if (rc == SQLITE_BUSY)
{
std::cout << "BUSY" << std::endl;
}
else if (rc == SQLITE_DONE)
{
std::cout << "DONE" << std::endl;
}
else if (rc == SQLITE_ERROR)
{
std::cout << "ERROR" << std::endl;
}
else if (rc == SQLITE_MISUSE)
{
std::cout << "MISUSE" << std::endl;
}
else
{
std::cout << "Data inserted successfully." << ErrorMessage << std::endl;
}
sqlite3_close(DB);
}
catch (const std::exception &exception)
{
std::cerr << exception.what();
}
}
Database::~Database(){}
Compile using g++ main.cpp testdb.cpp -l sqlite3 -o db.
Same thing happening here, it says data inserted but database shows empty in sqlitebrowser.
You have a sqlite3_step followed by sqlite3_exec, which is probably not what you intended. It's certainly not good. You must call sqlite3_reset or sqlite3_finalize to complete the prepared statement. It will also provide a specific error code that better describes the error if you get one from sqlite3_step.
See this explanation of `sqlite3_step'

Binding LuaJIT to C++ with LuaBridge results in "PANIC: unprotected error"

Windows 10 x64, MSVC 2017, LuaJIT 2.0.5.
I searched the web, but answers didn't help.
Basically I'm trying to follow this manual, except that I had to place #include <LuaBridge.h> after Lua includes, because otherwise it doesn't work saying that the LuaBridge should go after Lua includes.
Hovewher, I get following error: PANIC: unprotected error in call to Lua API (attempt to call a nil value).
I have no idea why. If you need more info - just say what.
#include "stdafx.h"
#include <iostream>
#include <lua.hpp>
#include <LuaBridge/LuaBridge.h>
using namespace luabridge;
using namespace std;
int main()
{
lua_State* L = luaL_newstate();
luaL_dofile(L, "script.lua");
luaL_openlibs(L);
lua_pcall(L, 0, 0, 0);
LuaRef s = getGlobal(L, "testString");
LuaRef n = getGlobal(L, "number");
string luaString = s.cast<string>();
int answer = n.cast<int>();
cout << luaString << endl;
cout << "And here's our number:" << answer << endl;
system("pause");
return 0;
}
script.lua:
testString = "LuaBridge works!"
number = 42
The code in the tutorial is faulty. lua_pcall has nothing to call because luaL_dofile and luaL_openlibs don't push a function onto the stack, so it tries to call nil and returns 2 (the value of the macro LUA_ERRRUN).
I verified this by changing the code from the tutorial thus and compiling with g++. I didn't get a PANIC error, for whatever reason; maybe because it was using Lua 5.3:
#include <iostream>
extern "C" {
# include "lua.h"
# include "lauxlib.h"
# include "lualib.h"
}
#include <LuaBridge/LuaBridge.h>
using namespace luabridge;
int main() {
lua_State* L = luaL_newstate();
luaL_dofile(L, "script.lua");
std::cout << "type of value at top of stack: " << luaL_typename(L, -1) << std::endl;
luaL_openlibs(L);
std::cout << "type of value at top of stack: " << luaL_typename(L, -1) << std::endl;
std::cout << "result of pcall: " << lua_pcall(L, 0, 0, 0) << std::endl; // Print return value of lua_pcall. This prints 2.
LuaRef s = getGlobal(L, "testString");
LuaRef n = getGlobal(L, "number");
std::string luaString = s.cast<std::string>();
int answer = n.cast<int>();
std::cout << luaString << std::endl;
std::cout << "And here's our number: " << answer << std::endl;
}
As you noticed, the code is also faulty because the Lua headers have to be included before the LuaBridge header!

How to check if preloaded module exists in Lua using C++

I would like to know how to check if a preloaded module exists or not in Lua using C++.
My Code :
#include "lua.hpp"
bool isModuleAvailable(lua_State *L, std::string name)
{
//what should be here?
return false;
}
int main()
{
lua_State *L = luaL_newstate();
luaL_openlibs(L);
lua_settop(L, 0);
luaL_dostring(L, "package.preload['A'] = function()\n"
"local a = {}\n"
"return a\n"
"end\n");
luaL_dostring(L, "package.preload['B'] = function()\n"
"local b = {}\n"
"return b\n"
"end\n");
if (isModuleAvailable(L, "A"))
std::cout << "Module Available" << '\n';
else
std::cout << "Module Not Available" << '\n';
if (isModuleAvailable(L, "B"))
std::cout << "Module Available" << '\n';
else
std::cout << "Module Not Available" << '\n';
if (isModuleAvailable(L, "C"))
std::cout << "Module Available" << '\n';
else
std::cout << "Module Not Available" << '\n';
lua_close(L);
}
The Result I get :
Module Not Available
Module Not Available
Module Not Available
The Result I want :
Module Available
Module Available
Module Not Available
How can I create isModuleAvailable() function so my code can work as expected?
Just check whether the field package.preload[name] is nil. I also renamed the function to isModulePreloaded because that's what is checks.
bool isModulePreloaded(lua_State *L, std::string const &name) {
lua_getglobal(L, "package");
lua_getfield(L, -1, "preload");
lua_getfield(L, -1, name.c_str());
bool is_preloaded = !lua_isnil(L, -1);
lua_pop(L, 3);
return is_preloaded;
}

C++ passing string to lua error

I'm trying to use a lua state within C++ and i need to pass it a str from C++, how ever when i try to call my function i wrote in lua, i get the error
attempted to call nil value. It compiles straight into the lua environment, but when i type the expression in i get the error.
int main(int argc, char** argv){
lua_State *L;
L = luaL_newstate();
string buff;
const char* finalString;
luaL_openlibs(L);
luaL_dofile(L,argv[1]);
getline(cin, buff);
lua_getglobal(L, "InfixToPostfix");
lua_pushstring (L, buff.c_str());
lua_pcall(L, 1, 1, 0);
finalString = lua_tostring(L, -1);
printf("%s\n", finalString);
lua_close(L);
}
from lua file:
function InfixToPostfix(str)
print("before for loop")
for i in string.gmatch(str, "%S+") do
it wont reach the print out before displaying error
The following works for me just fine:
#include <iostream>
#include <string>
#include <lua.hpp>
int main(int argc, char** argv)
{
lua_State *L;
L = luaL_newstate();
luaL_openlibs(L);
if (argc != 2)
{
std::cerr << "Usage: " << argv[0] << " script.lua\n";
return 1;
}
if ( luaL_dofile(L,argv[1]) != 0 )
{
std::cerr << lua_tostring(L, -1) << '\n';
return 1;
}
std::string buff;
std::getline(std::cin, buff);
lua_getglobal(L, "InfixToPostfix");
lua_pushstring (L, buff.c_str());
if ( lua_pcall(L, 1, 1, 0) != 0)
{
std::cerr << lua_tostring(L, -1) << '\n';
return 1;
}
if ( !lua_isstring(L, -1) )
{
std::cerr << "Error: Return value cannot be converted to string!\n";
return 1;
}
const char * finalString = lua_tostring(L, -1);
std::cout << finalString << '\n';
lua_close(L);
}
function InfixToPostfix(str)
print("before for loop")
for i in string.gmatch(str, "%S+") do
print(i)
end
return "Something"
end
For the C++ part you could also use the Selene library. This considerably reduces the amount of code needed, also no manual error checking is needed.
#include <iostream>
#include <string>
#include <selene.h>
int main(int argc, char** argv)
{
sel::State L{true};
if (argc != 2)
{
std::cerr << "Usage: " << argv[0] << " script.lua\n";
return 1;
}
L.Load(argv[1]);
std::string buff;
std::getline(std::cin, buff);
std::string finalString = L["InfixToPostfix"](buff);
std::cout << finalString << '\n';
}

error: ‘BadDevice’ was not declared in this scope

any idea why I would be getting this error?:
error: ‘BadDevice’ was not declared in this scope
I have included:
#include <X11/Xlib.h>
and
#include <X11/extensions/XInput2.h>
in my class header file.
I am using it like this:
int ret = XIGrabDevice(display_, 2, LinuxInputManager::getWindow(),
CurrentTime, None, GrabModeAsync,
GrabModeAsync, False, &eventMask_);
if (ret == BadValue)
std::cout << "bad value" << std::endl;
else if (ret == BadDevice)
std::cout << "BadDevice" << std::endl;
if (ret == BadMatch)
std::cout << "BadMatch" << std::endl;
if (ret == BadWindow)
std::cout << "BadWindow" << std::endl;
if (ret) {
std::cout << "not available 3" << std::endl;
}
Cheers
Jarrett
This is how you use it
int rc;
if ((rc = XIGrabDevice(dpy, 2, win, CurrentTime, None, GrabModeAsync,
GrabModeAsync, False, &mask)) != GrabSuccess)
{
fprintf(stderr, "Grab failed with %d\n", rc);
return;
}
or try (also try with your functions)
int rc;
if (!(rc = XIGrabDevice(dpy, 2, win, CurrentTime, None, GrabModeAsync,
GrabModeAsync, False, &mask)))
{
fprintf(stderr, "Grab failed with %d\n", rc);
return;
}
It appears that either BadValue, BadDevice, BadMatch... will be an int value, and they might not be defined in the header files so I would check to make sure they are there somewhere. So, try to cout the ret variable. Your error codes might be something like 1, 2, 3, 4 or they could be 1 or 0. You make have to define the error codes yourself.
Here is an example program of how someone else used XIGrabDevice: http://people.freedesktop.org/~whot/xi2-recipes/part5.c