RobotWebTools / rclnodejs

Node.js version of ROS 2.0 client
https://docs.ros.org/en/humble/Concepts/Basic/About-Client-Libraries.html?highlight=rclnodejs#community-maintained
Apache License 2.0
320 stars 70 forks source link

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

Closed n0wis closed 1 year ago

n0wis commented 2 years ago

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

Also tested on Ubuntu 20.04.3 LTS with galactic

Steps To Reproduce

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`
wayneparrott commented 2 years ago

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

minggangw commented 2 years ago

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. https://github.com/RobotWebTools/rclnodejs/blob/4c23b0b01493a19f424fb85e7c1491b6402f25ed/src/rcl_bindings.cpp#L1320-L1330

n0wis commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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

n0wis commented 1 year ago

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 commented 1 year ago

@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 commented 1 year ago

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 commented 1 year ago

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 commented 1 year ago

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

minggangw commented 1 year ago

@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!