1

I am working on an Electron project with node-api (for C++ addons). The app crashes, even after a full-build. The problem that I am facing occurs within the C++ template addon that I have made.

I have added extensive logging in order to figure out where the error occurs, and narrowed it down to the helloFunc = Napi::Function::New(env, HelloWorld); call within [addon.cpp] (because the "Creating helloFunc..." log appears in the terminal, but the "Created helloFunc." log doesn't).

However, the try/catch blocks that I added around this line aren't logging anything, so I assume some memory access error is occuring at the OS-level, and the Napi::Object Init function is abruptly ending at the relevant line, so all later lines containing the std::cout logs aren't running.

In regards to this, my question is: Why is the line `Napi::Function::New(env, HelloWorld)` even causing a memory access error?
Any answer that explains either (a) the detailed debugging steps for my case or (b) the origin of the error within the code suffices. I don't need both points to be delved into. The replier can decide which one he finds more useful to me - I myself just don't know, and I don't want to choose the wrong answer format and leave with useless information.

In a previous iteration of this question, it was suggested to me that I "use a debugger" to figure out what is going wrong. In regards to this suggestion, I must say: That's exactly what I tried to do using C++ logs! But since the error seems to not be handled by the C++, doing so tells me nothing about the error. And I have no clue how to debug at a lower level in this scenario, which ties into my question.

All relevant files in my project are below:

[addon.cpp]

#include <napi.h>
#include <iostream>

Napi::String HelloWorld(const Napi::CallbackInfo& info) {
  std::cout << "[C++] " << "Getting environment..." << std::endl; // Is not run
  Napi::Env env = info.Env();
  std::string helloWorld = "Hello from C++!";

  return Napi::String::New(env, helloWorld);
}

Napi::Object Init(Napi::Env env, Napi::Object exports) {
  Napi::Function helloFunc;

  try {
    std::cout << "[C++] " << "Creating helloFunc..." << std::endl;
    helloFunc = Napi::Function::New(env, HelloWorld);
    std::cout << "[C++] " << "Created helloFunc." << std::endl;
  } catch (...) {
  }

  exports.Set("hello", helloFunc);

  return exports;
}

NODE_API_MODULE(addon, Init)

[CMakeLists.txt]

cmake_minimum_required(VERSION 3.15)
project(my_native_addon)

execute_process(
    COMMAND node -p "require('path').dirname(require.resolve('node-addon-api'))"
    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
    OUTPUT_VARIABLE NODE_ADDON_API_DIR
    OUTPUT_STRIP_TRAILING_WHITESPACE
)

include_directories(${NODE_ADDON_API_DIR})
include_directories(${CMAKE_JS_INC})

# Enable C++ exceptions for node-addon-api
add_definitions(-DNAPI_CPP_EXCEPTIONS)

# Enable C++ exception handling
if(MSVC)
    add_compile_options(/EHsc)
else()
    add_compile_options(-fexceptions)
endif()

# Set source files
set(CMAKE_JS_SRC "native/addon.cpp")

# Build the library
add_library(${PROJECT_NAME} SHARED ${CMAKE_JS_SRC})
set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "" SUFFIX ".node")
target_link_libraries(${PROJECT_NAME} ${CMAKE_JS_LIB})

[package.json]

{
  "scripts": {
    "ng": "ng",
    "build": "ng build",

    "build-native": "cmake-js rebuild --runtime=electron --runtime-version=40.6.1",
    "build-angular": "ng build --base-href ./", 
    "start-electron": "electron electron/main.js",
    "full-build": "npm run build-native && npm run build-angular && npm run start-electron"
  },
  "packageManager": "[email protected]",
  "dependencies": {
    "node-addon-api": "^8.5.0",
  },
  "devDependencies": {
    "@electron/rebuild": "^4.0.3",
    "cmake-js": "^8.0.0",
    "electron": "40.6.1",
    "electron-builder": "^26.8.1",
  }
}

[main.js]

const { app, BrowserWindow, ipcMain } = require('electron');
const path = require('path');

console.log("Starting Electron App...");

let addon;

const addonPath = path.join(__dirname, '../build/Release/my_native_addon.node');
addon = require(addonPath);
console.log("Native addon loaded successfully!");

try {
  app.whenReady().then(() => {
    ipcMain.handle('get-hello-message', () => {
      if (addon) {
        return addon.hello();
      }
      return "Addon not loaded";
    });
  })
} catch (err) {
  console.error("Failed to start Electron app:", err);
}

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.