diff --git a/lib/protocol/crypto/src/binding.cc b/lib/protocol/crypto/src/binding.cc index 559d7682..574cbb75 100644 --- a/lib/protocol/crypto/src/binding.cc +++ b/lib/protocol/crypto/src/binding.cc @@ -84,11 +84,15 @@ class ChaChaPolyCipher : public ObjectWrap { SetPrototypeMethod(tpl, "encrypt", Encrypt); SetPrototypeMethod(tpl, "free", Free); - constructor().Reset(Nan::GetFunction(tpl).ToLocalChecked()); + Local func = Nan::GetFunction(tpl).ToLocalChecked(); + Local context = Nan::GetCurrentContext(); + v8::Isolate* isolate = context->GetIsolate(); + + constructor().Set(isolate, func); Nan::Set(target, Nan::New("ChaChaPolyCipher").ToLocalChecked(), - Nan::GetFunction(tpl).ToLocalChecked()); + func); } private: @@ -387,8 +391,8 @@ class ChaChaPolyCipher : public ObjectWrap { obj->clear(); } - static inline Nan::Persistent & constructor() { - static Nan::Persistent my_constructor; + static inline v8::Eternal & constructor() { + static v8::Eternal my_constructor; return my_constructor; } @@ -414,11 +418,15 @@ class AESGCMCipher : public ObjectWrap { SetPrototypeMethod(tpl, "encrypt", Encrypt); SetPrototypeMethod(tpl, "free", Free); - constructor().Reset(Nan::GetFunction(tpl).ToLocalChecked()); + Local func = Nan::GetFunction(tpl).ToLocalChecked(); + Local context = Nan::GetCurrentContext(); + v8::Isolate* isolate = context->GetIsolate(); + + constructor().Set(isolate, func); Nan::Set(target, Nan::New("AESGCMCipher").ToLocalChecked(), - Nan::GetFunction(tpl).ToLocalChecked()); + func); } private: @@ -633,8 +641,8 @@ class AESGCMCipher : public ObjectWrap { obj->clear(); } - static inline Nan::Persistent & constructor() { - static Nan::Persistent my_constructor; + static inline v8::Eternal & constructor() { + static v8::Eternal my_constructor; return my_constructor; } @@ -651,11 +659,15 @@ class GenericCipher : public ObjectWrap { SetPrototypeMethod(tpl, "encrypt", Encrypt); SetPrototypeMethod(tpl, "free", Free); - constructor().Reset(Nan::GetFunction(tpl).ToLocalChecked()); + Local func = Nan::GetFunction(tpl).ToLocalChecked(); + Local context = Nan::GetCurrentContext(); + v8::Isolate* isolate = context->GetIsolate(); + + constructor().Set(isolate, func); Nan::Set(target, Nan::New("GenericCipher").ToLocalChecked(), - Nan::GetFunction(tpl).ToLocalChecked()); + func); } private: @@ -1014,8 +1026,8 @@ class GenericCipher : public ObjectWrap { obj->clear(); } - static inline Nan::Persistent & constructor() { - static Nan::Persistent my_constructor; + static inline v8::Eternal & constructor() { + static v8::Eternal my_constructor; return my_constructor; } @@ -1044,11 +1056,15 @@ class ChaChaPolyDecipher : public ObjectWrap { SetPrototypeMethod(tpl, "decryptLen", DecryptLen); SetPrototypeMethod(tpl, "free", Free); - constructor().Reset(Nan::GetFunction(tpl).ToLocalChecked()); + Local func = Nan::GetFunction(tpl).ToLocalChecked(); + Local context = Nan::GetCurrentContext(); + v8::Isolate* isolate = context->GetIsolate(); + + constructor().Set(isolate, func); Nan::Set(target, Nan::New("ChaChaPolyDecipher").ToLocalChecked(), - Nan::GetFunction(tpl).ToLocalChecked()); + func); } private: @@ -1440,8 +1456,8 @@ class ChaChaPolyDecipher : public ObjectWrap { obj->clear(); } - static inline Nan::Persistent & constructor() { - static Nan::Persistent my_constructor; + static inline v8::Eternal & constructor() { + static v8::Eternal my_constructor; return my_constructor; } @@ -1468,11 +1484,15 @@ class AESGCMDecipher : public ObjectWrap { SetPrototypeMethod(tpl, "decrypt", Decrypt); SetPrototypeMethod(tpl, "free", Free); - constructor().Reset(Nan::GetFunction(tpl).ToLocalChecked()); + Local func = Nan::GetFunction(tpl).ToLocalChecked(); + Local context = Nan::GetCurrentContext(); + v8::Isolate* isolate = context->GetIsolate(); + + constructor().Set(isolate, func); Nan::Set(target, Nan::New("AESGCMDecipher").ToLocalChecked(), - Nan::GetFunction(tpl).ToLocalChecked()); + func); } private: @@ -1697,8 +1717,8 @@ class AESGCMDecipher : public ObjectWrap { obj->clear(); } - static inline Nan::Persistent & constructor() { - static Nan::Persistent my_constructor; + static inline v8::Eternal & constructor() { + static v8::Eternal my_constructor; return my_constructor; } @@ -1716,11 +1736,15 @@ class GenericDecipher : public ObjectWrap { SetPrototypeMethod(tpl, "decrypt", Decrypt); SetPrototypeMethod(tpl, "free", Free); - constructor().Reset(Nan::GetFunction(tpl).ToLocalChecked()); + Local func = Nan::GetFunction(tpl).ToLocalChecked(); + Local context = Nan::GetCurrentContext(); + v8::Isolate* isolate = context->GetIsolate(); + + constructor().Set(isolate, func); Nan::Set(target, Nan::New("GenericDecipher").ToLocalChecked(), - Nan::GetFunction(tpl).ToLocalChecked()); + func); } private: @@ -2183,8 +2207,8 @@ class GenericDecipher : public ObjectWrap { obj->clear(); } - static inline Nan::Persistent & constructor() { - static Nan::Persistent my_constructor; + static inline v8::Eternal & constructor() { + static v8::Eternal my_constructor; return my_constructor; } diff --git a/test/test-worker-imports.js b/test/test-worker-imports.js new file mode 100644 index 00000000..8152d9ec --- /dev/null +++ b/test/test-worker-imports.js @@ -0,0 +1,25 @@ +// Test for thread-safety issues caused by subsequent imports of the module +// in worker threads: https://github.com/mscdex/ssh2/issues/1393. +// Each subsequent worker increases probability of abnormal termination. +// The probability of a false pass due to zero response becomes negligible +// for 4 consecutive workers. +'use strict'; + +let Worker, isMainThread; +try { + ({ Worker, isMainThread } = require('worker_threads')); +} catch (e) { + if (e.code !== 'MODULE_NOT_FOUND') throw e; + process.exit(0); +} +require('../lib/index.js'); + +if (isMainThread) { + async function runWorker() { + return new Promise((r) => new Worker(__filename).on('exit', r)); + } + runWorker() + .then(runWorker) + .then(runWorker) + .then(runWorker); +}