Dynamic library is created using some C files. This dynamic library is used by a C++ function. One of the C-functions calls a C++ function. Which in turn will invoke a Javascript Function Callback. I am getting segmentation fault in C++ function.
Here is the code,
In test.h,
#ifdef __cplusplus
extern "C" {
#endif
void cppFunc(void);
#ifdef __cplusplus
}
#endif
Here is the code in test.c
#include "test.h"
void cFunc(void){
/* some code */
cppFunc();
}
Here is the code in test.cpp
#include "test.h"
static Nan::Persistent<v8::Function> callback;
void storeFunc(const v8::FunctionCallbackInfo<v8::Value>& args){
if(args[0]->IsFunction()){
Local<Function> cb = Local<Function>::Cast(args[0]);
callback.Reset(cb);
}
}
void cppFunc(void){
Isolate *isolate = Isolate::GetCurrent();
Local<Function> c_back = Local<Function>::New(isolate, callback);
Nan::MakeCallback(Nan::GetCurrentContext()->Global(), c_back, 0, {});
}
void init(Handle<Object> exports, Handle<Object> module)
{
NODE_SET_METHOD(exports, "FuncStore", storeFunc);
}
NODE_MODULE(test, init)
test.node is created by using "node-gyp configure build" command. No errors or warnings are shown.
Following is my test.js file,
var sample = require("./build/Release/test.node");
sample.FuncStore(function(){
console.log("Callback has been called!!");
});
On executing test.js by "node test.js", a segmentation fault occurs when cFunc() calls cppFunc(). Segmentation fault is happening exactly at the line "Local c_back = Local::New(isolate, callback);" in cppFunc().
What could be the reason?
One possibility is that the pointer "isolate" is NULL. Accessing a pointer with no value or an invalid value can cause a segmentation fault. You should check for it's existence by performing:
Isolate *isolate = Isolate::GetCurrent();
if (isolate) {
//it is now safe to use isolate
Local<Function> c_back = Local<Function>::New(isolate, callback);
Nan::MakeCallback(Nan::GetCurrentContext()->Global(), c_back, 0, {});
}
else {
//possibly generate your own warning here
}
As a side note, it seems Isolate::GetCurrent is deprecated https://github.com/nodejs/node/commit/409d413363
Related
Calling on V8 experts. I am embedding V8 in a project of mine and I am running into issues modularizing my code. The simplest example of this is compiling and running a small script that prints "Hello World!" from a C++ function. The working version is as follows:
void testV8(const v8::FunctionCallbackInfo<v8::Value>& args) {
printf("Hello World!\n");
}
void working() {
v8::Isolate* isolate = nullptr;
std::string code = "testV8();";
{
// Basic initialization
std::unique_ptr<v8::Platform> platform = v8::platform::NewDefaultPlatform();
v8::V8::InitializePlatform(platform.get());
v8::V8::Initialize();
v8::Isolate::CreateParams initOptions;
initOptions.array_buffer_allocator = v8::ArrayBuffer::Allocator::NewDefaultAllocator();
isolate = v8::Isolate::New(initOptions);
isolate->Enter();
// Create context
v8::HandleScope handleScope(isolate);
auto global = v8::ObjectTemplate::New(isolate);
v8::Local<v8::Context> context = v8::Context::New(isolate, nullptr, global);
// Enter context
v8::Context::Scope contextScope(context);
// Bind function
v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New(isolate, &testV8);
auto name = v8::String::NewFromUtf8(isolate, "testV8").ToLocalChecked();
context->Global()->Set(context, name, ft->GetFunction(context).ToLocalChecked());
// Run script
auto execCode = v8::String::NewFromUtf8(isolate, code.c_str()).ToLocalChecked();
v8::Local<v8::Script> script;
if (v8::Script::Compile(context, execCode).ToLocal(&script)) {
v8::Local<v8::Value> result;
script->Run(context).ToLocal(&result);
}
}
}
When I try to split the code up into manageable scopes (mimicking wrapper classes I want to build later), I get a crash upon script compilation:
void testV8(const v8::FunctionCallbackInfo<v8::Value>& args) {
printf("Hello World!\n");
}
void failing() {
v8::Isolate* isolate = nullptr;
std::string code = "testV8();";
v8::Persistent<v8::Context> persistentContext;
{
// Basic initialization
std::unique_ptr<v8::Platform> platform = v8::platform::NewDefaultPlatform();
v8::V8::InitializePlatform(platform.get());
v8::V8::Initialize();
v8::Isolate::CreateParams initOptions;
initOptions.array_buffer_allocator = v8::ArrayBuffer::Allocator::NewDefaultAllocator();
isolate = v8::Isolate::New(initOptions);
isolate->Enter();
// Create context
v8::HandleScope handleScope(isolate);
auto global = v8::ObjectTemplate::New(isolate);
v8::Local<v8::Context> context = v8::Context::New(isolate, nullptr, global);
// Save context
persistentContext.Reset(isolate, context);
}
{
// Rebuild scopes and enter context
v8::Locker locker(isolate);
v8::HandleScope handleScope(isolate);
v8::Local<v8::Context> context = v8::Local<v8::Context>::New(isolate, persistentContext);
v8::Context::Scope contextScope(context);
// Bind function
v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New(isolate, &testV8);
auto name = v8::String::NewFromUtf8(isolate, "testV8").ToLocalChecked();
context->Global()->Set(context, name, ft->GetFunction(context).ToLocalChecked());
}
{
// Rebuild scopes and enter context
v8::Locker locker(isolate);
v8::HandleScope handleScope(isolate);
v8::Local<v8::Context> context = v8::Local<v8::Context>::New(isolate, persistentContext);
v8::Context::Scope contextScope(context);
// Run script
auto execCode = v8::String::NewFromUtf8(isolate, code.c_str()).ToLocalChecked();
v8::Local<v8::Script> script;
if (v8::Script::Compile(context, execCode).ToLocal(&script)) {
v8::Local<v8::Value> result;
script->Run(context).ToLocal(&result);
}
}
}
Building on xCode and running on this code on a Macbook. I can't tell if I'm doing anything wrong or if there is some bug with the contexts. Research online leads me to believe that using persistent contexts this way is fine to keep the same context alive between scopes. What's going wrong here?
The problem is that the unique_ptr for the platform is getting destroyed once the scope ends. Moving it into the parent scope fixes it.
I'm trying to embed an custom function to my project, that uses the V8 engine, and apparently I can't make it working. I've used code, that I've found, but it seems to be outdated, or I just do it wrong. My point is to include a custom javascript file. My current code (for testing) is this :
HandleScope handle_scope(isolate);
v8::Local<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate);
global->Set(v8::String::NewFromUtf8(isolate, "test", v8::NewStringType::kNormal).ToLocalChecked(),
v8::FunctionTemplate::New(isolate, test));
Handle<Context> context = Context::New(isolate);
Persistent<Context> persistent_context(isolate, context);
Context::Scope context_scope(context);
const char* data = "test";
Handle<String> source = String::NewFromUtf8(isolate, data);
Handle<Script> script = Script::Compile(source);
if (!script.IsEmpty())
Handle<Value> result = script->Run();
Test Code (obviously just for testing):
void test(const v8::FunctionCallbackInfo<v8::Value>& args) {
MessageBoxA(NULL,"test", "", 0);
}
But the engine returns this error :
Uncaught ReferenceError: test is not defined
So my question is if I even do it correct, I would be able to make the including myself I hope, but I just can't get the function to get executed.
Here's some code from a project that works:
Isolate::Scope iscope( isolate_ );
HandleScope hs( isolate_ );
Local<Object> test = Object::New(isolate_);
test->Set(String::NewFromUtf8(isolate_, "javaScriptFunctionName"), Function::New(isolate_, CPP_FN_CALLBACK));
global_template->Set(String::NewFromUtf8(isolate_, "test"), test);
That will result in an object for window.test with a function called window.test.javaScriptFunctionName()
Is it possible to call a JavaScript function (written over, say, node.js) from C?
(There are plenty of tutorials on calling C/C++ from node.js. But not the other way around.)
I've been working on the same problem recently, and found a tractable solution using QuickJS and esbuild. It's not the prettiest, but it works quite well!
To call JS from C, the general process is:
Get QuickJS and esbuild
esbuild your desired library/script into an ESM format using CommonJS. This will output one big script with all needed dependencies included.
output=/path/to/esbuild/output
npx esbuild --bundle /path/to/original/node-library --format=esm --outfile="$output"
Patch the output of esbuild to make it compatible with QuickJS:
sed -i 's/Function(\"return this\")()/globalThis/g' $output
sed -i 's#export default#//export default#g' $output
Load the script text into an object file using your linker:
ld -r -b binary my_obj_file.o $output
Depending on your compiler, this will automatically create 3 symbols in the object file:
- name_start
- name_end
- name_size
name in this context is automatically generated from the filename you provided as the last argument to ld. It replaces all non-alphanumeric characters with underscores, so my-cool-lib.mjs gives a name of my_cool_lib_mjs.
You can use ld_magic.h (here) for a cross platform way to access this data from your C code.
After the object file is generated, you should see the patched esbuild output if you run strings:
% strings foo_lib_js.o
var __getOwnPropNames = Object.getOwnPropertyNames;
var __commonJS = (cb, mod) => function __require() {
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
// src/foo.js
var require_foo = __commonJS({
"src/foo.js"(exports, module) {
function foo(bar, baz) {
return bar + baz;
}
module.exports = foo;
//export default require_foo();
_binary_my_foo_lib_mjs_end
_binary_my_foo_lib_mjs_start
_binary_my_foo_lib_mjs_size
.symtab
.strtab
.shstrtab
.data
Link the object file into your binary:
gcc my_obj_file.o <other object files> -o my_static_binary
You can also link the object file into a shared library, for use in other applications:
gcc -shared -o my_shared_library.so my_obj_file.o <other object files>
The source of this repo shows how to do this with a CMake project.
How to actually call the JS functions
Let's say you have a NodeJS library with a function you want to call from C:
// Let's say this lives in foo.js, and esbuild output goes in my-lib-foo.mjs
function foo(bar, baz) {
return bar + baz
}
module.exports = foo;
esbuild creates a series of require_thing() functions, which can be used to get the underlying thing(param1, param2...) function object which you can make calls with.
A simple loader in QuickJS looks like this:
JSValue commonjs_module_data_to_function(JSContext *ctx, const uint8_t *data, size_t data_length, const char *function_name)
{
JSValue result = JS_UNDEFINED;
char * module_function_name = NULL;
// Make sure you properly free all JSValues created from this procedure
if(data == NULL) {
goto done;
}
/**
* To pull the script objects, including require_thing() etc, into global scope,
* load the patched NodeJS script from the object file embedded in the binary
*/
result = JS_Eval(ctx, data, data_length, "<embed>", JS_EVAL_TYPE_GLOBAL);
if(JS_IsException(result)) {
printf("failed to parse module function '%s'\n", function_name);
goto cleanup_fail;
}
JSValue global = JS_GetGlobalObject(ctx);
/**
* Automatically create the require_thing() function name
*/
asprintf(&module_function_name, "require_%s", function_name);
JSValue module = JS_GetPropertyStr(ctx, global, module_function_name);
if(JS_IsException(module)) {
printf("failed to find %s module function\n", function_name);
goto cleanup_fail;
}
result = JS_Call(ctx, module, global, 0, NULL);
if(JS_IsException(result)) {
goto cleanup_fail;
}
/* don't lose the object we've built by passing over failure case */
goto done;
cleanup_fail:
/* nothing to do, cleanup context elsewhere */
result = JS_UNDEFINED;
done:
free(module_function_name);
return result;
}
If you wanted to, for example, get the foo(bar, baz) function mentioned above, you would write a function like this:
#include <stdio.h>
#include <inttypes.h>
// A simple helper for getting a JSContext
JSContext * easy_context(void)
{
JSRuntime *runtime = JS_NewRuntime();
if(runtime == NULL) {
puts("unable to create JS Runtime");
goto cleanup_content_fail;
}
JSContext *ctx = JS_NewContext(runtime);
if(ctx == NULL) {
puts("unable to create JS context");
goto cleanup_runtime_fail;
}
return ctx;
cleanup_runtime_fail:
free(runtime);
cleanup_content_fail:
return NULL;
}
int call_foo(int bar, int baz)
{
JSContext *ctx = easy_context();
JSValue global = JS_GetGlobalObject(ctx);
/**
* esbuild output was to my-foo-lib.mjs, so symbols will be named with my_foo_lib_mjs
*/
JSValue foo_fn = commonjs_module_data_to_function(
ctx
, _binary_my_foo_lib_mjs_start // gcc/Linux-specific naming
, _binary_my_foo_lib_mjs_size
, "foo"
);
/**
* To create more complex objects as arguments, use
* JS_ParseJSON(ctx, json_str, strlen(json_str), "<input>");
* You can also pass callback functions by loading them just like we loaded foo_fn
*/
JSValue args[] = {
JS_NewInt32(ctx, bar),
JS_NewInt32(ctx, baz)
};
JSValue js_result = JS_Call(ctx
, foo_fn
, global
, sizeof(args)/sizeof(*args)
, args
);
int32_t c_result = -1;
JS_ToInt32(ctx, &c_result, js_result);
return c_result;
}
Check out a minimal example project using CMake here: https://github.com/ijustlovemath/jescx/blob/master/README.md
You could use Emscripten.
Emscripten is an LLVM-to-JavaScript compiler.
It takes LLVM bitcode - which can be generated from C/C++, using llvm-gcc (DragonEgg) or clang, or any other language that can be converted into LLVM - and compiles that into JavaScript, which can be run on the web (or anywhere else JavaScript can run).
Also see this: How to execute Javascript function in C++
I have a C++ method (which role is killing some processes). She needs 2 parameters : a hostname and a port.
On the other hand, I am developing a web-application (using Nodejs and AngularJS), running on Google Chrome.
When I click on a button through the browser, I would like to be able to call the C++ function, through my app.js file.
I haven't found how to "bind" javascript with C++.
EDIT : I think this link could be very useful
How can I use a C++ library from node.js?
You can use Google's V8. V8 is Google's open source JavaScript engine.
V8 can run standalone, or can be embedded into any C++ application.
http://code.google.com/p/v8/
Following example from github demonstrates, binding a C++ class with Google V8.
v8_wrap_class.cpp - Author is nicholas
/*
* v8_wrap_class.cpp
*
* Created on: 14/01/2013
* Author: nicholas
* License: public domain
*/
#include <v8.h>
#include <cstdio>
#include <string>
#include <stdexcept>
#include <memory>
using namespace v8;
/*
var Simple = function(v)
{
this.value = v;
}
Simple.prototype.func = function()
{
alert(this.value);
}
var obj = new Simple(4);
obj.func();
*/
struct Simple
{
double value;
Simple(double v)
: value(v)
{
fprintf(stderr, "Simple::ctor\n");
}
void func()
{
fprintf(stderr, "Simple::func(%f)\n", value);
}
~Simple()
{
fprintf(stderr, "Simple::dtor\n");
}
};
namespace js
{
/*
* Retrieve the c++ object pointer from the js object
*/
template <typename T>
T* unwrap(const Arguments& args)
{
auto self = args.Holder();
auto wrap = Local<External>::Cast(self->GetInternalField(0));
return static_cast<T*>(wrap->Value());
}
/*
* Construct a new c++ object and wrap it in a js object
*/
template <typename T, typename... Args>
Persistent<Object> make_object(Handle<Object> object, Args&&... args)
{
auto x = new T(std::forward<Args>(args)...);
auto obj = Persistent<Object>::New(object);
obj->SetInternalField(0, External::New(x));
obj.MakeWeak(x, [](Persistent<Value> obj, void* data)
{
auto x = static_cast<T*>(data);
delete x;
obj.Dispose();
obj.Clear();
});
return obj;
}
}
void bind_Simple(Local<Object> global)
{
// Name the class in js
auto name = String::NewSymbol("Simple");
auto tpl = FunctionTemplate::New([&](const Arguments& args) -> Handle<Value>
{
if (!args.IsConstructCall())
return ThrowException(String::New("Cannot call constructor as function"));
HandleScope scope;
// Read and pass constructor arguments
js::make_object<Simple>(args.This(), args[0]->NumberValue());
return args.This();
});
tpl->SetClassName(name);
tpl->InstanceTemplate()->SetInternalFieldCount(1);
auto prototype = tpl->PrototypeTemplate();
// Add object properties to the prototype
// Methods, Properties, etc.
prototype->Set(String::New("func"), FunctionTemplate::New([](const Arguments& args) -> Handle<Value>
{
auto s = js::unwrap<Simple>(args);
s->func();
return {};
})->GetFunction());
auto constructor = Persistent<Function>::New(tpl->GetFunction());
global->Set(name, constructor);
}
int main()
{
std::string js_source = R"(
for(var i = 0; i < 1000; ++i)
{
var s = new Simple(4);
s.value = 5;
s.func();
}
)";
/*
* This code is mostly uninteresting.
* Just run the vm with the script provided.
*/
{
HandleScope handle_scope;
Handle<ObjectTemplate> global_template = ObjectTemplate::New();
Persistent<Context> context = Context::New(0, global_template);
Context::Scope context_scope(context);
auto global = context->Global();
// Wrap the class and bind to the global scope.
bind_Simple(global);
{
HandleScope handle_scope;
TryCatch trycatch;
Local<String> source = String::New(js_source.c_str(), js_source.size());
Local<Script> script = Script::Compile(source);
if (script.IsEmpty())
{
Handle<Value> exception = trycatch.Exception();
String::AsciiValue exception_str(exception);
throw std::runtime_error(*exception_str);
}
Local<Value> result = script->Run();
if (result.IsEmpty())
{
Local<Value> exception = trycatch.Exception();
String::AsciiValue exception_str(exception);
throw std::runtime_error(*exception_str);
}
}
context.Dispose();
context.Clear();
}
// Run the GC until there is nothing to reclaim.
while (!V8::IdleNotification())
;
return 0;
}
This answer gives four appraoches to using C++ in javascript. The methods shown try to keep the original C++ in a standard and simple C++ implementation.
Two methods using WASM and two using SWIG and JRPC are used to give examples and ideas on executing C++ in javascript. In detail, this answer gives one example for executing in the browser and one for executing in nodejs using WASM. The end of this answer also lists two other ways to execute C++ in javascript, one of which calls nodejs from the browser which is slightly more complex but possible using jrpc-oo.
If you want to execute in the browser or nodejs, then you can compile your C++ to WASM and load that module in the browser or nodejs, executing the C++ there. This WASM repo exemplifies how to do that. I will expand the key code in the WASM repo here.
Create some C++ code and declare your WASM binding, for example (from the files include/Test.H and src/Test.C) :
class Test {
public:
void sayHello(){
printf("Hi, my name is test\n");
}
};
#include <emscripten/bind.h>
EMSCRIPTEN_BINDINGS(Test_ex) {
emscripten::class_<Test>("Test")
.function("sayHello", &Test::sayHello)
;
}
Compile that down and you can now run that in nodejs (from the file nodejs/WASMTestNode.js) :
libWASM = require('./libwasmNode.js');
libWASM().then((mod)=>{
libWASM = mod;
let test = new libWASM.Test;
test.sayHello();
});
In the browser you can use the WASM code as well. To do that firs import the WASM library (from the file webcomponent/libWASM.js) :
import modProm from './libwasm.js';
The create your webcomponent and compile your WASM then execute the C++ method Test::sayHello (from the file webcomponent/libWASM.js) :
import { LitElement } from 'lit';
export class LibWASM extends LitElement {
constructor() {
super();
modProm().then((mod)=>{
this.libWASM = mod; // for rendered wasm that delay
this.WASMReady();
})
}
WASMReady(){
console.log('LibWASM.libWASM module compiled and ready to go.')
let test = new this.libWASM.Test;
test.sayHello();
}
}
This code example is implemented in the reference repo.
Alternatively a third way to do this is to only use C++, SWIG and nodejs from this reference repo.
If you want to execute nodejs from the browser or use a a different method of integrating C++ into nodejs, you can also look at this SWIG and jrpc-oo reference for doing the same thing, but not only in nodejs, also from the browser calling nodejs.
There are also other ways to execute C++ form javascript, however the methods demonstrated in this answer are reasonably straightforward and either rely on WASM binding or SWIG abstraction which leaves your original code as standard C++.
I have a piece of C++ code converted to JavaScript via Emscripten. I would like the converted C++ code to call back to the JavaScript code that calls it. Something like:
JavaScript:
function callback(message) {
alert(message);
}
ccall("my_c_function", ..., callback);
C++:
void my_c_function(whatever_type_t *callback) {
callback("Hello World!");
}
Is this possible somehow?
I believe the accepted answer is a bit outdated.
Please refer to this bullet point in the "Interacting with code" emscripten tutorial.
E.g.
C:
void invoke_function_pointer(void(*f)(void)) {
(*f)();
}
JS:
var pointer = Runtime.addFunction(function() {
console.log('I was called from C world!');
});
Module.ccall('invoke_function_pointer', 'number', ['number'], [pointer]);
Runtime.removeFunction(pointer);
This way the C-code does not need to be aware of that it is transpiled to JS and any bridges required can purely be controlled from JS.
(code hacked into message composer; may contain errors)
There is a new way of achieving your requirement which is via embind.
Consider the following piece of C++ code.
#include <emscripten/bind.h>
using namespace emscripten;
void cbTest(emscripten::val cb)
{
cb();
}
EMSCRIPTEN_BINDINGS(my_module) {
function("cbTest", &cbTest);
}
The cbTest C++ function takes in a emscripten::val. This can be an object of any kind. For us this is a function object.
This is how you will call it from JS
var cbFunc = function() {
console.log("Hi, this is a cb");
}
Module.cbTest(cbFunc);
P.S This api is still under construction.
A thing that is frequently done in Emscripten is to map strong types to simple ones.
JS:
function callback(message) {
alert(message);
}
var func_map = {
0: callback
};
// C/C++ functions get a _ prefix added
function _invoke_callback(callback_id, text_ptr) {
func_map[callback_id](Pointer_stringify(text_ptr));
}
ccall("my_c_function", ..., 0);
C++:
// In C/C++ you only need to declare the func signature and
// make sure C is used to prevent name mangling
extern "C" void invoke_callback(int callback_id, const char* text);
void my_c_function(int callback_id) {
invoke_callback( callback_id, "Hello World!" );
}
And of course, you can add some glue code, so this gets very seamless.
I needed to write something very similar to what is described in the question. My code ended up looking like this:
C:
void call(void (*back)(char*)){
back("Hello!");
}
JS:
function back(text){
alert(Pointer_stringify(text));
}
var pointer = Runtime.addFunction(back);
var call = Module.cwrap('call', 'void', ['pointer']);
call(pointer);
Runtime.removeFunction(pointer);
Note that the pointer returned to the callback has to be dereferenced with Pointer_stringify.
You can find example code like this on GitHub.
Here's what I have gathered from several posts and by looking at Emscripten bundled code:
In C++:
#include <iostream>
#include <functional>
extern "C" {
void registerCallback(void(*back)(const char*));
void triggerCallback(char* message); // for invoking it from JS, just for this example
}
// global
std::function<void(const char*)> gCallback;
void registerCallback(void(*back)(const char*)){
gCallback = back;
}
void triggerCallback(char* message){
if (gCallback) {
gCallback(message);
} else {
std::cerr << "Cannot pass '"<< message <<"' to undefined callback\n";
}
}
An important thing, which was missing in other posts, is to compile C++ with RESERVED_FUNCTION_POINTERS=... flag, e.g.:
em++ -std=c++11 -s RESERVED_FUNCTION_POINTERS=20 source.cpp -s EXPORTED_FUNCTIONS="['_registerCallback','_triggerCallback']" -o try.html
After loading try.html into a browser, you can execute the following JS code in its console:
// Register a callback function
function callback(text){ alert("In JS: "+Pointer_stringify(text)); }
var cb = Runtime.addFunction(callback);
_registerCallback(cb);
// Invoke it with some "C string"
var jsStr = "XOXOXO";
var cStr = allocate(intArrayFromString(jsStr), 'i8', ALLOC_NORMAL)
_triggerCallback(cStr);
// Free Emscripten heap and release the function pointer
_free(cStr);
Runtime.removeFunction(cb);
You should see an alert with "In JS: XOXOXO".