Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Undefined symbol error using Electron >= 12 when receiving/deserializing arrays #864

Closed
n0wis opened this issue Jul 16, 2022 · 14 comments · Fixed by #921
Closed

Undefined symbol error using Electron >= 12 when receiving/deserializing arrays #864

n0wis opened this issue Jul 16, 2022 · 14 comments · Fixed by #921
Labels

Comments

@n0wis
Copy link

n0wis commented Jul 16, 2022

Description
When using any Electron version >= 12 (which include Node >= 14), receiving a message that includes a non-empty array causes a symbol lookup error:
rclnodejs.node: undefined symbol: _ZN2v811ArrayBuffer3NewEPNS_7IsolateESt10shared_ptrINS_12BackingStoreEE

  • Library Version: 0.21.2
  • ROS Version: humble
  • Platform / OS: Ubuntu 22.04 LTS
  • Electron version: 19.0.8

Also tested on Ubuntu 20.04.3 LTS with galactic

Steps To Reproduce

  • npx create-react-app electron_app
  • npm i rclnodejs
  • Replace src/index.js with the following:
const { app, BrowserWindow } = require("electron");
const path = require("path");

const rclnodejs = require("rclnodejs");

const createWindow = () => {
  const mainWindow = new BrowserWindow();
  mainWindow.loadFile(path.join(__dirname, "index.html"));

  rclnodejs.init().then(() => {
    const node = new rclnodejs.Node("node_name");
    node.createSubscription(
      "sensor_msgs/msg/CompressedImage",
      "/image_raw/compressed",
      {},
      (msg) => {
        console.log(msg.header);
      }
    );
    node.spin();
  });
};
app.on("ready", createWindow);
  • npm start

Publish a suitable message that includes an array to the subscriber (in this example, it is a CompressedImage published via ros2 run image_publisher image_publisher_node image.jpg, but is reproducible with other kinds of arrays as well).

With Electron <= 11.5.3 everything works as expected.
Also, empty arrays and raw messages do not cause the crash so I guess it is the deserialization.

Expected Behavior
No crash / successful deserialization of the message.

Actual Behavior
Crash with symbol lookup error: /tmp/electron_app/node_modules/rclnodejs/build/Release/rclnodejs.node: undefined symbol: _ZN2v811ArrayBuffer3NewEPNS_7IsolateESt10shared_ptrINS_12BackingStoreEE

@n0wis n0wis added the bug label Jul 16, 2022
@wayneparrott
Copy link
Collaborator

Thx for reporting this issue. The backingstore info looks somewhat familiar. Will investigate asap.

@minggangw
Copy link
Member

We use the following #if, when nodejs > 12, we will use v8::BackingStore. From the crash log, it seems that the symbol is not found during runtime. @n0wis can you please double-check if it can reproduce on nodejs >= 14? I think we should have the unit test to cover this kind of case.

rclnodejs/src/rcl_bindings.cpp

Lines 1320 to 1330 in 4c23b0b

#if NODE_MAJOR_VERSION <= 12
v8::Local<v8::ArrayBuffer> array_buffer =
v8::ArrayBuffer::New(v8::Isolate::GetCurrent(), addr, length,
v8::ArrayBufferCreationMode::kInternalized);
#else
std::unique_ptr<v8::BackingStore> backing =
v8::ArrayBuffer::NewBackingStore(v8::Isolate::GetCurrent(), length);
memcpy(backing->Data(), addr, length);
auto array_buffer =
v8::ArrayBuffer::New(v8::Isolate::GetCurrent(), std::move(backing));
#endif

@n0wis
Copy link
Author

n0wis commented Jul 18, 2022

I probably should have emphasized that the error indeed does not occur when using "regular" Node >= 12, only the versions bundled with Electron crash. Unfortunately I know far too less about native Node.js modules to identify the cause of the error. It might be Electron after all?

I can file a bug report there if that is the more appropriate place.

Nonetheless, maybe the error can be prevented in this great package either way?

@minggangw
Copy link
Member

Yes, I have noticed that you mentioned the env is Electron, but just to double-check it on pure nodejs. From our side, we can fall back to the non-BackingStore code when detecting it's a Electron env. @n0wis do you have any idea that the nodejs integrated into the Electron has any difference compared with a normal nodejs release?

@n0wis
Copy link
Author

n0wis commented Jul 19, 2022

It does differ. Per the docs:

Native Node.js modules are supported by Electron, but since Electron has a different application binary interface (ABI) from a given Node.js binary (due to differences such as using Chromium's BoringSSL instead of OpenSSL), the native modules you use will need to be recompiled for Electron.

I followed the suggested steps to rebuild for the correct ABI version (which worked fine all along) but I could not resolve the missing symbol issue.

Unlike the my binary of pure nodejs, Electron is missing the mentioned symbol:
nm -D node_modules/electron/dist/electron | grep _ZN2v811ArrayBuffer3NewEPNS_7IsolateESt10shared_ptrINS_12BackingStoreEE returns nothing.

However, nm -D node_modules/electron/dist/electron | grep _ZN2v811ArrayBuffer3NewEPNS yields:

0000000003233290 T _ZN2v811ArrayBuffer3NewEPNS_7IsolateEm
00000000032332e0 T _ZN2v811ArrayBuffer3NewEPNS_7IsolateENSt3__110shared_ptrINS_12BackingStoreEEE

If that's useful, following up with nm -C node_modules/electron/dist/electron | grep 00000000032332e0 leads to:

00000000032332e0 T v8::ArrayBuffer::New(v8::Isolate*, std::__1::shared_ptr<v8::BackingStore>)

The most similar function signature in the rebuild rclnodejs module I can find is:
nm -C node_modules/rclnodejs/bin/linux-x64-106/rclnodejs.node | grep "ArrayBuffer::New("

U v8::ArrayBuffer::New(v8::Isolate*, std::shared_ptr<v8::BackingStore>)

I hope this is helpful and am happy to provide further information if required.

@minggangw
Copy link
Member

I did some investigation about why there is ::__1 namespace, and it seems that you must depend on libstdc++, below is ldd result dumping the shared library dependencies for a normal nodejs binary. So would you check if your Electron version nodejs also depends on libstdc++?

~/proj/rclnodejs/build/Release$ ldd /home/minggang/.nvm/versions/node/v16.13.2/bin/node
        linux-vdso.so.1 (0x00007ffe96f77000)
        libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f0c7dbac000)
        libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f0c7d9ca000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f0c7d87b000)
        libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f0c7d860000)
        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f0c7d83d000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f0c7d64b000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f0c7dbd6000)

@n0wis
Copy link
Author

n0wis commented Jul 19, 2022

It does depend on libstdc++ as well. For completeness, here is the whole ldd output:

linux-vdso.so.1 (0x00007ffebc162000)
libffmpeg.so => /home/simon/code/autosens/electron/node_modules/electron/dist/libffmpeg.so (0x00007fc28cb80000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fc28cb4f000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fc28cb4a000)
librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007fc28cb45000)
libgobject-2.0.so.0 => /lib/x86_64-linux-gnu/libgobject-2.0.so.0 (0x00007fc28cae3000)
libglib-2.0.so.0 => /lib/x86_64-linux-gnu/libglib-2.0.so.0 (0x00007fc28c9a9000)
libgio-2.0.so.0 => /lib/x86_64-linux-gnu/libgio-2.0.so.0 (0x00007fc28c7d1000)
libnss3.so => /lib/x86_64-linux-gnu/libnss3.so (0x00007fc28c6a4000)
libnssutil3.so => /lib/x86_64-linux-gnu/libnssutil3.so (0x00007fc28c672000)
libsmime3.so => /lib/x86_64-linux-gnu/libsmime3.so (0x00007fc28c648000)
libnspr4.so => /lib/x86_64-linux-gnu/libnspr4.so (0x00007fc28c606000)
libatk-1.0.so.0 => /lib/x86_64-linux-gnu/libatk-1.0.so.0 (0x00007fc28c5dc000)
libatk-bridge-2.0.so.0 => /lib/x86_64-linux-gnu/libatk-bridge-2.0.so.0 (0x00007fc28c5a4000)
libX11.so.6 => /lib/x86_64-linux-gnu/libX11.so.6 (0x00007fc28c464000)
libX11-xcb.so.1 => /lib/x86_64-linux-gnu/libX11-xcb.so.1 (0x00007fc28c45f000)
libxcb.so.1 => /lib/x86_64-linux-gnu/libxcb.so.1 (0x00007fc28c435000)
libdbus-1.so.3 => /lib/x86_64-linux-gnu/libdbus-1.so.3 (0x00007fc28c3e5000)
libgdk_pixbuf-2.0.so.0 => /lib/x86_64-linux-gnu/libgdk_pixbuf-2.0.so.0 (0x00007fc28c3b5000)
libgtk-3.so.0 => /lib/x86_64-linux-gnu/libgtk-3.so.0 (0x00007fc28bb8c000)
libgdk-3.so.0 => /lib/x86_64-linux-gnu/libgdk-3.so.0 (0x00007fc28ba85000)
libpangocairo-1.0.so.0 => /lib/x86_64-linux-gnu/libpangocairo-1.0.so.0 (0x00007fc28ba73000)
libpango-1.0.so.0 => /lib/x86_64-linux-gnu/libpango-1.0.so.0 (0x00007fc28ba0c000)
libcairo.so.2 => /lib/x86_64-linux-gnu/libcairo.so.2 (0x00007fc28b8e2000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fc28b7fb000)
libXcomposite.so.1 => /lib/x86_64-linux-gnu/libXcomposite.so.1 (0x00007fc28b7f6000)
libXdamage.so.1 => /lib/x86_64-linux-gnu/libXdamage.so.1 (0x00007fc28b7f1000)
libXext.so.6 => /lib/x86_64-linux-gnu/libXext.so.6 (0x00007fc28b7dc000)
libXfixes.so.3 => /lib/x86_64-linux-gnu/libXfixes.so.3 (0x00007fc28b7d4000)
libXrandr.so.2 => /lib/x86_64-linux-gnu/libXrandr.so.2 (0x00007fc28b7c5000)
libexpat.so.1 => /lib/x86_64-linux-gnu/libexpat.so.1 (0x00007fc28b794000)
libdrm.so.2 => /lib/x86_64-linux-gnu/libdrm.so.2 (0x00007fc28b77e000)
libxkbcommon.so.0 => /lib/x86_64-linux-gnu/libxkbcommon.so.0 (0x00007fc28b737000)
libgbm.so.1 => /lib/x86_64-linux-gnu/libgbm.so.1 (0x00007fc28b726000)
libasound.so.2 => /lib/x86_64-linux-gnu/libasound.so.2 (0x00007fc28b623000)
libcups.so.2 => /lib/x86_64-linux-gnu/libcups.so.2 (0x00007fc28b583000)
libatspi.so.0 => /lib/x86_64-linux-gnu/libatspi.so.0 (0x00007fc28b549000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fc28b529000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fc28b301000)
/lib64/ld-linux-x86-64.so.2 (0x00007fc29513a000)
libffi.so.8 => /lib/x86_64-linux-gnu/libffi.so.8 (0x00007fc28b2f4000)
libpcre.so.3 => /lib/x86_64-linux-gnu/libpcre.so.3 (0x00007fc28b27e000)
libgmodule-2.0.so.0 => /lib/x86_64-linux-gnu/libgmodule-2.0.so.0 (0x00007fc28b275000)
libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007fc28b259000)
libmount.so.1 => /lib/x86_64-linux-gnu/libmount.so.1 (0x00007fc28b215000)
libselinux.so.1 => /lib/x86_64-linux-gnu/libselinux.so.1 (0x00007fc28b1e9000)
libplc4.so => /lib/x86_64-linux-gnu/libplc4.so (0x00007fc28b1e2000)
libplds4.so => /lib/x86_64-linux-gnu/libplds4.so (0x00007fc28b1dd000)
libXau.so.6 => /lib/x86_64-linux-gnu/libXau.so.6 (0x00007fc28b1d5000)
libXdmcp.so.6 => /lib/x86_64-linux-gnu/libXdmcp.so.6 (0x00007fc28b1cd000)
libsystemd.so.0 => /lib/x86_64-linux-gnu/libsystemd.so.0 (0x00007fc28b106000)
libpng16.so.16 => /lib/x86_64-linux-gnu/libpng16.so.16 (0x00007fc28b0cb000)
libjpeg.so.8 => /lib/x86_64-linux-gnu/libjpeg.so.8 (0x00007fc28b04a000)
libXi.so.6 => /lib/x86_64-linux-gnu/libXi.so.6 (0x00007fc28b034000)
libcairo-gobject.so.2 => /lib/x86_64-linux-gnu/libcairo-gobject.so.2 (0x00007fc28b028000)
libepoxy.so.0 => /lib/x86_64-linux-gnu/libepoxy.so.0 (0x00007fc28aef3000)
libfribidi.so.0 => /lib/x86_64-linux-gnu/libfribidi.so.0 (0x00007fc28aed7000)
libpangoft2-1.0.so.0 => /lib/x86_64-linux-gnu/libpangoft2-1.0.so.0 (0x00007fc28aebc000)
libharfbuzz.so.0 => /lib/x86_64-linux-gnu/libharfbuzz.so.0 (0x00007fc28aded000)
libfontconfig.so.1 => /lib/x86_64-linux-gnu/libfontconfig.so.1 (0x00007fc28ada1000)
libXinerama.so.1 => /lib/x86_64-linux-gnu/libXinerama.so.1 (0x00007fc28ad9c000)
libXcursor.so.1 => /lib/x86_64-linux-gnu/libXcursor.so.1 (0x00007fc28ad90000)
libwayland-cursor.so.0 => /lib/x86_64-linux-gnu/libwayland-cursor.so.0 (0x00007fc28ad86000)
libwayland-egl.so.1 => /lib/x86_64-linux-gnu/libwayland-egl.so.1 (0x00007fc28ad81000)
libwayland-client.so.0 => /lib/x86_64-linux-gnu/libwayland-client.so.0 (0x00007fc28ad6f000)
libthai.so.0 => /lib/x86_64-linux-gnu/libthai.so.0 (0x00007fc28ad64000)
libpixman-1.so.0 => /lib/x86_64-linux-gnu/libpixman-1.so.0 (0x00007fc28acb9000)
libfreetype.so.6 => /lib/x86_64-linux-gnu/libfreetype.so.6 (0x00007fc28abf1000)
libxcb-shm.so.0 => /lib/x86_64-linux-gnu/libxcb-shm.so.0 (0x00007fc28abec000)
libxcb-render.so.0 => /lib/x86_64-linux-gnu/libxcb-render.so.0 (0x00007fc28abdd000)
libXrender.so.1 => /lib/x86_64-linux-gnu/libXrender.so.1 (0x00007fc28abce000)
libwayland-server.so.0 => /lib/x86_64-linux-gnu/libwayland-server.so.0 (0x00007fc28abb8000)
libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fc28a98c000)
libgssapi_krb5.so.2 => /lib/x86_64-linux-gnu/libgssapi_krb5.so.2 (0x00007fc28a938000)
libavahi-common.so.3 => /lib/x86_64-linux-gnu/libavahi-common.so.3 (0x00007fc28a92a000)
libavahi-client.so.3 => /lib/x86_64-linux-gnu/libavahi-client.so.3 (0x00007fc28a914000)
libgnutls.so.30 => /lib/x86_64-linux-gnu/libgnutls.so.30 (0x00007fc28a729000)
libblkid.so.1 => /lib/x86_64-linux-gnu/libblkid.so.1 (0x00007fc28a6f2000)
libpcre2-8.so.0 => /lib/x86_64-linux-gnu/libpcre2-8.so.0 (0x00007fc28a65b000)
libbsd.so.0 => /lib/x86_64-linux-gnu/libbsd.so.0 (0x00007fc28a643000)
liblzma.so.5 => /lib/x86_64-linux-gnu/liblzma.so.5 (0x00007fc28a616000)
libzstd.so.1 => /opt/ros/humble/lib/libzstd.so.1 (0x00007fc28a587000)
liblz4.so.1 => /lib/x86_64-linux-gnu/liblz4.so.1 (0x00007fc28a567000)
libcap.so.2 => /lib/x86_64-linux-gnu/libcap.so.2 (0x00007fc28a55c000)
libgcrypt.so.20 => /lib/x86_64-linux-gnu/libgcrypt.so.20 (0x00007fc28a41e000)
libgraphite2.so.3 => /lib/x86_64-linux-gnu/libgraphite2.so.3 (0x00007fc28a3f5000)
libuuid.so.1 => /lib/x86_64-linux-gnu/libuuid.so.1 (0x00007fc28a3ec000)
libdatrie.so.1 => /lib/x86_64-linux-gnu/libdatrie.so.1 (0x00007fc28a3e3000)
libbrotlidec.so.1 => /lib/x86_64-linux-gnu/libbrotlidec.so.1 (0x00007fc28a3d5000)
libkrb5.so.3 => /lib/x86_64-linux-gnu/libkrb5.so.3 (0x00007fc28a30a000)
libk5crypto.so.3 => /lib/x86_64-linux-gnu/libk5crypto.so.3 (0x00007fc28a2d9000)
libcom_err.so.2 => /lib/x86_64-linux-gnu/libcom_err.so.2 (0x00007fc28a2d3000)
libkrb5support.so.0 => /lib/x86_64-linux-gnu/libkrb5support.so.0 (0x00007fc28a2c5000)
libp11-kit.so.0 => /lib/x86_64-linux-gnu/libp11-kit.so.0 (0x00007fc28a18a000)
libidn2.so.0 => /lib/x86_64-linux-gnu/libidn2.so.0 (0x00007fc28a169000)
libunistring.so.2 => /lib/x86_64-linux-gnu/libunistring.so.2 (0x00007fc289fbf000)
libtasn1.so.6 => /lib/x86_64-linux-gnu/libtasn1.so.6 (0x00007fc289fa5000)
libnettle.so.8 => /lib/x86_64-linux-gnu/libnettle.so.8 (0x00007fc289f5f000)
libhogweed.so.6 => /lib/x86_64-linux-gnu/libhogweed.so.6 (0x00007fc289f17000)
libgmp.so.10 => /lib/x86_64-linux-gnu/libgmp.so.10 (0x00007fc289e95000)
libmd.so.0 => /lib/x86_64-linux-gnu/libmd.so.0 (0x00007fc289e88000)
libgpg-error.so.0 => /lib/x86_64-linux-gnu/libgpg-error.so.0 (0x00007fc289e60000)
libbrotlicommon.so.1 => /lib/x86_64-linux-gnu/libbrotlicommon.so.1 (0x00007fc289e3d000)
libkeyutils.so.1 => /lib/x86_64-linux-gnu/libkeyutils.so.1 (0x00007fc289e36000)
libresolv.so.2 => /lib/x86_64-linux-gnu/libresolv.so.2 (0x00007fc289e22000)

@minggangw
Copy link
Member

Hmm... have no idea, but it's clear this is a linker issue

@n0wis
Copy link
Author

n0wis commented Dec 1, 2022

The issue still persists with rcjlnodjs 0.21.4 and the most recent versions of Electron/Node...does anyone have further insight into the problem? I would be happy to help getting this bug closed.

@wayneparrott
Copy link
Collaborator

wayneparrott commented Dec 1, 2022

@n0wis Agree the undefined backingstore symbol error is still present with the latest Electron v22 and electron-rebuild v3.2.
To get up to speed on this issue I ran a quick test with a super simple electron app on Ubuntu 22 with ROS2 Humble and rclnodejs 0.21.4. The app creates subscription to the sensor_msgs/msg/LaserScan message. ros2 run dummy_sensors dummy_laser is used to gen and publish laser messages. Boom! Same error :(

Electron v22 is based on nodejs 16.17.1.
I confirmed that my test app succeeds when run outside of electron on node 16.17.

@gmp-capgemini
Copy link

gmp-capgemini commented Mar 14, 2023

Hello everyone,
I am facing the same issue with Electron 23.0.0 and Node 18.12.0 . I followed the same steps as @n0wis. I also concur with @wayneparrott that this issue does not happen when using rclnodejs outside of an Electron project. Did anyone found a solution to this?

I tested with ROS2 Foxy.

@KhalilSelyan
Copy link

Has there been any update made on this ? I'm also facing the same problem when using electron 20.1 and node 16.20 with humble on ubuntu 22.04

@minggangw
Copy link
Member

@KhalilSelyan thanks for your feedback, I found a possible solution zeromq/zeromq.js#532, would you like to try it out?

minggangw added a commit to minggangw/rclnodejs-1 that referenced this issue Jun 6, 2023
Since Electron 21, the V8 sandboxed pointers was enabled, which disables
creating a new BackingStore and take over an external memory block.
Instead, we must copy the data into a newly-allocated memory that is
inside V8 memory cage.

See more details: https://www.electronjs.org/blog/v8-memory-cage

This patch fixed the crashing when running on Electron > 21.

Fix RobotWebTools#864
minggangw added a commit that referenced this issue Jun 6, 2023
Since Electron 21, the V8 sandboxed pointers was enabled, which disables
creating a new BackingStore and take over an external memory block.
Instead, we must copy the data into a newly-allocated memory that is
inside V8 memory cage.

See more details: https://www.electronjs.org/blog/v8-memory-cage

This patch fixed the crashing when running on Electron > 21.

Fix #864
@minggangw
Copy link
Member

@n0wis @gmp-capgemini @KhalilSelyan hope it's not toooo late, please try the latest 0.22.2 to see if this issue is gone, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants