I am working on updating node-mapserver that wraps the mapserver library in the class-refactor branch to a more maintainable code structure (basing my changes on the organization of node-ogr).
Up to now, I have refactored the main module interface and started on the first class to be wrapped, a mapserver C struct called errorObj that I am wrapping with class MSError. The extension builds but I am facing is a runtime assertion error in the extension the first time I trigger a new MSError object to wrap an errorObj.
Fatal error in ../deps/v8/src/api.h, line 297
CHECK(allow_empty_handle || that != __null) failed
With node 0.10 there is an extremely lengthy stack trace after this which can be seen in travis build 27.2. I couldn't find anything particularly useful in the stack trace.
The extension builds and some tests pass (symbols and methods exported from the library itself), but fails when the library tries to create an Object that wraps a C object.
In javascript, I call mapserver.getError(). In the extension, this invokes a mapserver method errorObj* err = msGetErrorObj();and returned with return scope.Close(MSError::New(err));. The New method of MSError does this:
Handle<Value> MSError::New(errorObj *err) {
HandleScope scope;
MSError *wrapped = new MSError(err);
Handle<Value> ext = External::New(wrapped);
Handle<Object> obj = MSError::constructor->GetFunction()->NewInstance(1, &ext);
return scope.Close(obj);
}
I have attempted to debug this using gdb, the best I can get out of it with my limited skills is that the error happens at this call:
Handle<Object> obj = MSError::constructor->GetFunction()->NewInstance(1, &ext);
What I can gather from this is that ext is null which means that the External::New(wrapped) call is not returning a valid value. I have confirmed that errorObj* err does point to a valid, properly initialized, errorObj structure. To clarify, there is no actual error, mapserver always returns a valid errorObj but with a code of 0 if there is no error at this time.
Here is, hopefully, the relevant code.
ms_error.hpp
#ifndef __NODE_MS_ERROR_H__
#define __NODE_MS_ERROR_H__
#include <v8.h>
#include <node.h>
#include <node_object_wrap.h>
#include <mapserver.h>
using namespace v8;
using namespace node;
class MSError: public node::ObjectWrap {
public:
static Persistent<FunctionTemplate> constructor;
static void Initialize(Handle<Object> target);
static Handle<Value> New(const Arguments &args);
static Handle<Value> New(errorObj *err);
MSError();
MSError(errorObj *err);
inline errorObj *get() { return this_; }
private:
~MSError();
errorObj *this_;
};
#endif
ms_error.cpp
#include "ms_error.hpp"
Persistent<FunctionTemplate> MSError::constructor;
void MSError::Initialize(Handle<Object> target) {
HandleScope scope;
constructor = Persistent<FunctionTemplate>::New(FunctionTemplate::New(MSError::New));
constructor->InstanceTemplate()->SetInternalFieldCount(1);
constructor->SetClassName(String::NewSymbol("MSError"));
// constructor->InstanceTemplate()->SetNamedPropertyHandler(MSError::NamedPropertyGetter, NULL, MSError::NamedPropertyQuery, NULL, MSError::NamedPropertyEnumerator);
target->Set(String::NewSymbol("MSError"), constructor->GetFunction());
}
MSError::MSError(errorObj *err) : ObjectWrap(), this_(err) { }
MSError::MSError() : ObjectWrap(), this_(0) { }
MSError::~MSError() { }
Handle<Value> MSError::New(const Arguments& args)
{
HandleScope scope;
if (!args.IsConstructCall())
return ThrowException(String::New("Cannot call constructor as function, you need to use 'new' keyword"));
if (args[0]->IsExternal()) {
Local<External> ext = Local<External>::Cast(args[0]);
void *ptr = ext->Value();
MSError *f = static_cast<MSError *>(ptr);
f->Wrap(args.This());
return args.This();
}
return args.This();
}
The answer to this is that the code above is fine. The actual error was that the MSError::constructor was not initialized because I neglected to call it from the main module code. The actual null object was MSError::constructor->GetFunction().
Thanks to Ben Noordhuis for pointing us in the right direction.
Related
I have been trying to figure out why this is happening and maybe it is just due to inexperience at this point but could really use some help.
When I run my code, which is compiled into a DLL using C++20, I get that a debug assertion has failed with the expression being __acrt_first_block == header.
I narrowed down where the code is failing, but the weird part is that it runs just fine when I change the Init(std::string filePath function signature to not contain the parameter. The code is below and hope someone can help.
Logger.h
#pragma once
#include "../Core.h"
#include <memory>
#include <string>
#include "spdlog/spdlog.h"
namespace Ruby
{
class RUBY_API Logger
{
public:
static void Init(std::string filePath);
inline static std::shared_ptr<spdlog::logger>& GetCoreLogger() { return coreLogger; }
inline static std::shared_ptr<spdlog::logger>& GetClientLogger() { return clientLogger; }
private:
static std::shared_ptr<spdlog::logger> coreLogger;
static std::shared_ptr<spdlog::logger> clientLogger;
};
}
Logger.cpp
namespace Ruby
{
std::shared_ptr<spdlog::logger> Logger::coreLogger;
std::shared_ptr<spdlog::logger> Logger::clientLogger;
void Logger::Init(std::string filePath)
{
std::string pattern{ "%^[%r][%n][%l]: %v%$" };
auto fileSink = std::make_shared<spdlog::sinks::basic_file_sink_mt>(filePath, true);
// Setup the console and file sinks
std::vector<spdlog::sink_ptr> coreSinks;
coreSinks.push_back(std::make_shared<spdlog::sinks::stdout_color_sink_mt>());
coreSinks.push_back(fileSink);
// Bind the sinks to the core logger.
coreLogger = std::make_shared<spdlog::logger>("RUBY", begin(coreSinks), end(coreSinks));
// Set the Patterns for the sinks
coreLogger->sinks()[0]->set_pattern(pattern);
coreLogger->sinks()[1]->set_pattern(pattern);
// Tell spdlog to flush the file loggers on trace or worse message (can be changed if necessary).
coreLogger->flush_on(spdlog::level::trace);
// Set the default level of the logger
coreLogger->set_level(spdlog::level::trace);
// Do the same for the client logger
std::vector<spdlog::sink_ptr> clientSinks;
clientSinks.push_back(std::make_shared<spdlog::sinks::stdout_color_sink_mt>());
clientSinks.push_back(fileSink);
clientLogger = std::make_shared<spdlog::logger>("APP", begin(clientSinks), end(clientSinks));
clientLogger->sinks()[0]->set_pattern(pattern);
clientLogger->sinks()[1]->set_pattern(pattern);
clientLogger->flush_on(spdlog::level::trace);
clientLogger->set_level(spdlog::level::trace);
}
}
Entrypoint.h
#pragma once
#ifdef RB_PLATFORM_WINDOWS
extern Ruby::Application* Ruby::CreateApplication();
int main(int argc, char** argv)
{
Ruby::Logger::Init("../Logs/Recent_Run.txt");
RB_CORE_INFO("Initialized the logger.");
auto app = Ruby::CreateApplication();
app->Run();
delete app;
return 0;
}
#else
#error Ruby only supports windows
#endif // RB_PLATFORM_WINDOWS
For anyone else who runs into a similar problem, here is how I fixed it.
Essentially the function signature for the Init() function was the problem. The std::string parameter was causing the debug assertion to fire, my best guess as of right now was because of move semantics but that part I am still not sure on. So there are a couple of ways that I found to fix this.
Method 1:
Make the parameter a const char*. I don't quite like this approach as it then relies on C style strings and if you are trying to write a program in modern C++, this is a huge step backwards.
Method 2:
Make the parameter a const std::string&. Making it a const reference to a string prevents the move semantics (again as far as I know) and the assertion no longer fires. I prefer this fix as it keeps the program in modern C++.
I hope this helps anyone who has similar issues, and be careful with statics and move semantics.
So I've got this interface class that I include, both in the dll and the client project
// InterfaceClass.h
#pragma once
class InterfaceClass
{
public:
virtual void Update() = 0;
};
This is the dll class that calls one of its own methods inside update
// DLLClassThatDoesSomething.cpp
#include "InterfaceClass.h"
#include <iostream>
#include <string>
class __declspec(dllexport) DLLClass : public InterfaceClass
{
public:
void Update()
{
std::cout << this->GetString();
}
std::string& GetString()
{
std::string thestring = "bruhmoment";
return thestring;
}
};
extern "C"
{
__declspec(dllexport) InterfaceClass* CreateInstance()
{
return new DLLClass();
}
}
And this is the "Client" project
// main.cpp
#include "InterfaceClass.h"
#include <Windows.h>
typedef InterfaceClass* (__cdecl *Class) ();
int main()
{
HINSTANCE dll = LoadLibrary(L"DLLClass.dll");
Class klass = (Class)GetProcAddress(dll, "CreateInstance");
InterfaceClass* IKlass = klass();
IKlass->Update();
FreeLibrary(dll);
return 0;
}
The moment I call IKlass->Update() I get an exception for Access Memory Violation because of the DLLClass calling its own method.
I haven't tried anything since I barely know how to load a DLL on runtime and I've used this nifty tutorial
How can I let it call the method and not get thrown an exception? I'm trying to let ppl that will create mods for my game create their own mods with their custom classes for bosses, mobs and etc. in DLLs.
EDIT:
Turns out it was a syntax mistake on my end. Instead of return new DLLClass;, it had to be return new DLLClass();. After fixing it, it works as intended.
You return a reference to a local variable thestring, and by the time you try to access it in
std::cout << this->GetString(), referenced data is already destroyed. In fact, it is destroyed right after the end of enclosing scope of compound statement where the variable was declared.
It may "appear" to work sometimes due to the stack not being overwritten yet, but eventually it will fail miserably like it did in your case. This triggers UB (undefined behavior).
I'm working on a plugin (GNU C++ 7.5.0/C++14/Ubuntu 18/amd64) that is being loaded through dynamic linking at runtime. When Test->run() gets called,
using namespace std;
class Test {
thread t;
void _run() {
this_thread::sleep_for(10ms);
}
void run() {
t = thread(&Test::_run, this);
t.join();
}
}
the shared object file (.so) stops getting unloaded from the main program.
This does not happen when calling a member method of a different class or a static function.
What's the issue and is there any fix besides restructuring things?
The plugin host in question is Reaper (https://www.reaper.fm/), so I can't really say what's going on on the dlclose/host side, but I know that the Test class does not get deconstructed. But that's always the case, even when the unloading works.
Update
Replaced this_thread::sleep_for with
this_thread::__sleep_for
and that somehow works. Here is the <thread> include file:
void
__sleep_for(chrono::seconds, chrono::nanoseconds);
/// sleep_for
template<typename _Rep, typename _Period>
inline void
sleep_for(const chrono::duration<_Rep, _Period>& __rtime)
{
if (__rtime <= __rtime.zero())
return;
auto __s = chrono::duration_cast<chrono::seconds>(__rtime);
auto __ns = chrono::duration_cast<chrono::nanoseconds>(__rtime - __s);
#ifdef _GLIBCXX_USE_NANOSLEEP
__gthread_time_t __ts =
{
static_cast<std::time_t>(__s.count()),
static_cast<long>(__ns.count())
};
while (::nanosleep(&__ts, &__ts) == -1 && errno == EINTR)
{ }
#else
__sleep_for(__s, __ns);
#endif
}
Somehow, that template code is producing an STB_GNU_UNIQUE it seems (see dlclose() doesn't work with factory function & complex static in function?). The --no-gnu-unique linker option seems not supported any more.
This has been driving me nuts for a long time now. I have followed every tutorial I could find on the internet (here are couple examples[ [1], [2] of the maybe half dozen good ones found via Google search), and still no clear explanation. Although it seems it must be something fairly simple as that lack of a documented explanation implies that it's something most people would take for granted.
How do I load a custom module into Lua?
On the advice of questions like this one, I have written a module that builds a shared library with the expectation that I would be able to load it through a require call. However, when I do that I get undefined symbol errors, despite those exact symbols appearing in the list from the command nm -g mylib.so.
Those two tutorials I linked before aim to create executables that look wrappers of the *.lua file. That is, the built *.exe file should be called to run the Lua program with the custom module.
I understand that these types questions are asked here fairly frequently (as noted in this answer), but I am still at a loss. I tried some of the binding packages (Luabind and OOLua), but those didn't work out great (e.g. my earlier question--which I did ultimately figure out, sort of).
I have implemented a class in C++
I have wrapped the constructors, destructors, and functions with thunks
I have built it errorless-ly as a shared library
Yet no matter what I get undefined symbol: ... errors when I try to load it as mod = require('mylib.so'). How do I do this?
Working Example of a Library of Functions
For the record, just registering a basic function works fine. The below code, when built as libluatest.so, can be run in Lua using the commands:
> require('libluatest')
> greet()
hello world!
libluatest.cpp
extern "C"
{
#include <lualib.h>
#include <lauxlib.h>
#include <lua.h>
}
#include <iostream>
static int greet(lua_State *L)
{
std::cout << "hello world!" << std::endl;
return 0;
}
static const luaL_reg funcs[] =
{
{ "greet", greet},
{ NULL, NULL }
};
extern "C" int luaopen_libluatest(lua_State* L)
{
luaL_register(L, "libluatest", funcs);
return 0;
}
Failing Example of a Class
This is what I am stuck on currently. It doesn't seem to want to work.
myObj.h
#include <string>
class MyObj
{
private:
std::string name_;
public:
MyObj();
~MyObj();
void rename(std::string name);
};
myObj.cpp
extern "C"
{
#include <lualib.h>
#include <lauxlib.h>
#include <lua.h>
}
#include <iostream>
#include "myObj.h"
void MyObj::rename(std::string name)
{
name_ = name;
std::cout << "New name: " << name_ << std::endl;
}
extern "C"
{
// Lua "constructor"
static int lmyobj_new(lua_State* L)
{
MyObj ** udata = (MyObj **)lua_newuserdata(L, sizeof(MyObj));
*udata = new MyObj();
luaL_getmetatable(L, "MyObj");
lua_setmetatable(L, -1);
return 1;
}
// Function to check the type of an argument
MyObj * lcheck_myobj(lua_State* L, int n)
{
return *(MyObj**)luaL_checkudata(L, n, "MyObj");
}
// Lua "destructor": Free instance for garbage collection
static int lmyobj_delete(lua_State* L)
{
MyObj * obj = lcheck_myobj(L, 1);
delete obj;
return 0;
}
static int lrename(lua_State* L)
{
MyObj * obj = lcheck_myobj(L, 1);
std::string new_name = luaL_checkstring(L, 2);
obj->rename(new_name);
return 0;
}
int luaopen_libmyObj(lua_State* L)
{
luaL_Reg funcs[] =
{
{ "new", lmyobj_new }, // Constructor
{ "__gc", lmyobj_delete }, // Destructor
{ "rename", lrename }, // Setter function
{ NULL, NULL } // Terminating flag
};
luaL_register(L, "MyObj", funcs);
return 0;
}
}
Compiled into libmyObj.so using a simple CMake build with C++11 standard flags on.
Error
> require('libmyObj')
error loading module 'libmyObj' from file './libmyObj.so':
./libmyObj.so: undefined symbol: _ZN5MyObjC1Ev stack traceback: [C]:
? [C]: in function 'require' stdin:1: in main chunk [C]: ?
I am dealing with Lua 5.1 on Ubuntu 14.04.
I am wondering if it has something to do with the mix of C and C++...
It seems that you do not implement:
MyObj() ; ~MyObj();
and be careful with luaopen_* function, since module name is myObj, function name should be luaopen_libmyObj.
I am writing a NodeJS addon where I use a C library that lets you register a callback at certain events. When the callback is fired I want to call a NodeJS callback function. The problem is that in my C callback function I get a segmentation fault when trying to do anything V8 related, like creating a HandleScope.
In test.js:
...
myaddon.register(function(data) {
console.log("data: " + JSON.stringify(data));
});
...
In test.c:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <node.h>
#include <v8.h>
using namespace v8;
void WINAPI myEvent(int num, void * context) {
HandleScope scope; // Segmentation fault here!
Local<Function> * cb = (Local<Function>*)(context);
Local<Object> obj = Object::New();
obj->Set(String::NewSymbol("id"), Number::New(num));
const int argc = 1;
Local<Value> argv[argc] = { obj };
(*cb)->Call(Context::GetCurrent()->Global(), argc, argv);
sleep(1);
}
Handle<Value> RegisterEvent(const Arguments& args) {
HandleScope scope;
Local<Function> cb = Local<Function>::Cast(args[0]);
int callbackId = registerEvent((Event)&myEvent, &cb );
printf("callback id: %i\n", callbackId);
init();
return scope.Close(Integer::New(callbackId));
}
void init(Handle<Object> exports) {
exports->Set(String::NewSymbol("register"),
FunctionTemplate::New(RegisterEvent)->GetFunction());
}
NODE_MODULE(test, init)
EDIT: Updated with real code.
EDIT: I just changed the title of this issue since the problem is probably that my callback function can't access the V8 Context. Since I get a segmentation fault when creating HandleScope instance I can't see what else it might be. In addition to this question I AM trying to find the answer in the V8 documentation, but it is huge and I don't have that much time to test and investigate.
Your handler function myEvent() must be called in V8 thread. If not, you have to post the event notification into the V8 thread:
https://stackoverflow.com/a/15701160/1355844
https://stackoverflow.com/a/22946062/1355844
It appears that you might have forgotten to create a HandleScope for your variable. This should work for you.
void callbackFunc() {
HandleScope scope;
Local<Object> obj = Object::New();
}