- Notifications
You must be signed in to change notification settings - Fork 8
Description
This code causes node to segfault on exit.
function run(){let vm = require('vm'); let ctx = vm.createContext(); let scr = new vm.Script('({})'); require('weak-napi')(ctx, () => console.log('freed')); scr.runInContext(ctx)} run(); ketchup% npm i weak-napi && node alpha.js zsh: segmentation fault (core dumped) node alpha.js Sometimes(:tm:) you can fix this by adding global.gc() before the script exits, but that's defeatable, e.g. with this, which segfaults again:
let vm = require('vm'); let ctx = vm.createContext(); let scr = new vm.Script('({"bar":function(require){require("https").get = () =>{}}})'); scr.runInContext(ctx).bar(require); require('weak-napi')(ctx, () => console.log('freed')) vm = null; ctx = null; scr = null; global.gc(); The backtrace is meaningless to me; it's trying to clean up the environment and it's trying a double-free. Ooh, I wonder if ASAN will catch this? Note that the backtrace is way worse on older nodes.
ketchup% gdb --args ~/clone/node/out/Debug/node alpha.js ... Thread 1 "node" received signal SIGSEGV, Segmentation fault. 0x000055837b4de4b2 in v8impl::(anonymous namespace)::RefBase::Delete (reference=0x558381065540) at ../src/js_native_api_v8.cc:248 248 delete reference; (gdb) bt #0 0x000055837b4de4b2 in v8impl::(anonymous namespace)::RefBase::Delete (reference=0x558381065540) at ../src/js_native_api_v8.cc:248 #1 v8impl::(anonymous namespace)::RefBase::Finalize (this=0x558381065540, is_env_teardown=<optimised out>) at ../src/js_native_api_v8.cc:281 #2 0x000055837b4feb4c in v8impl::RefTracker::FinalizeAll (list=0x558381109d08) at ../src/js_native_api_v8.h:43 #3 napi_env__::~napi_env__ (this=0x558381109cd0, __in_chrg=<optimised out>) at ../src/js_native_api_v8.h:66 #4 node_napi_env__::~node_napi_env__ (this=0x558381109cd0, __in_chrg=<optimised out>) at ../src/node_api.cc:17 #5 node_napi_env__::~node_napi_env__ (this=0x558381109cd0, __in_chrg=<optimised out>) at ../src/node_api.cc:17 #6 0x000055837b4fa0c2 in napi_env__::Unref (this=<optimised out>) at ../src/js_native_api_v8.h:77 #7 operator() (arg=<optimised out>, __closure=0x0) at ../src/node_api.cc:103 #8 _FUN () at ../src/node_api.cc:104 #9 0x000055837b4d18ec in node::Environment::RunCleanup (this=this@entry=0x558380ff2830) at ../src/env.cc:661 #10 0x000055837b4797ef in node::FreeEnvironment (env=0x558380ff2830) at ../src/api/environment.cc:371 #11 0x000055837b57deb1 in node::FunctionDeleter<node::Environment, &node::FreeEnvironment>::operator() (pointer=<optimised out>, this=0x7ffed4b26e30) at ../src/util.h:636 #12 std::unique_ptr<node::Environment, node::FunctionDeleter<node::Environment, &node::FreeEnvironment> >::~unique_ptr ( this=0x7ffed4b26e30, __in_chrg=<optimised out>) at /usr/include/c++/10/bits/unique_ptr.h:361 #13 node::NodeMainInstance::Run (this=this@entry=0x7ffed4b26f80, env_info=env_info@entry=0x55837fa57780 <node::env_info>) at ../src/node_main_instance.cc:135 #14 0x000055837b4f7908 in node::Start (argc=<optimised out>, argv=<optimised out>) at ../src/node.cc:1078 #15 0x000055837cb7cb63 in main (argc=2, argv=0x7ffed4b271b8) at ../src/node_main.cc:127 ketchup% node --version v12.20.0 Debug node built is from HEAD today (d90fa196c5540109bf9c5063f8c51673340ad9e3). Ubuntu 20.10, amd64.
I found this trying to diagnose jestjs/jest#10289 ; this createContext / runInContext dance is how Jest works. However, I assume Jest works for most people most of the time, so it can't always segfault. As far as I can see, Jest always use Script to load user code, with most core modules require'd like in the second bit of code.