You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Segfault with unref on a worker with ArrayBuffer in transferList #33263
When communicating a Uint8 Array Buffer from a worker to the parent process with postMessage, which is included in the transferList argument and then calling unref on the worker, I get a Segfault: 'node index.js' terminated by signal SIGSEGV (Address boundary error).
So this is related to this issue: #33240 and this PR #33252
Specifically, you're attempting to transfer an ArrayBuffer instance that cannot be transferred. We need to implement better protections around this throughout core but the fundamental idea is that you should never transfer a Buffer or TypedArray unless you know for absolute certain that it is safe to do so -- and that's generally only when you are creating it yourself. The fix in this particular case would be to create your own Uint8Array copy of the buffer before sending it...
In your worker... something like:
constfs=require('fs')constcrypto=require('crypto')const{ parentPort }=require('worker_threads')parentPort.on('message',(message)=>{consthasher=crypto.createHash('sha256')fs.createReadStream('example.txt').pipe(hasher).on('finish',()=>{const{ buffer }=hasher.read()constbuf=newUint8Array(buffer);// Create a copyparentPort.postMessage({value: buf},[buf.buffer])})})
Alternatively, it's not clear from this example why you are using hasher.read() at all. The example is definitely not a typical case. What I would imagine would be a better approach in general is something like...
constfs=require('fs')constcrypto=require('crypto')const{ parentPort }=require('worker_threads')const{ pipeline }=require('stream')parentPort.on('message',(message)=>{constinput=fs.createReadStream('example.txt')consthasher=crypto.createHash('sha256')pipeline(input,hasher,(err)=>{if(err){// handle the error appropriatelyreturn;}// Pass a hex of the hash rather than the bufferparentPort.postMessage({value: hasher.digest().toString('hex')});});})
Now... all that said... just as a more general point that is independent of the segfault issue that we really need to make sure we look at... given that read stream and the hash operations here are already async, you're not likely to see any real benefit from using a worker thread in this way (see https://github.com/jasnell/piscina/tree/master/examples/server for an example perf analysis). Specifically, the performance of the worker thread in this specific example will never be faster than just doing the same operations on the main thread.
I'm now unable to reproduce this issue on 14.x and 15.x. I believe the issue has been resolved tho I'm not sure exactly which commit fixed it. Closing, can reopen if it's still an issue
Activity
Jolg42 commentedon May 6, 2020
I can also reproduce this when cloning the reproduction repository with Node 14.1.0
It works with Node 12 for me.
juanarbol commentedon May 6, 2020
Thank you so much for the report and code recreation.
juanarbol commentedon May 6, 2020
I'm not completely sure, but may be related with The new V8 ArrayBuffer API landed on Node v14.0.
juanarbol commentedon May 6, 2020
cc @nodejs/buffer
jasnell commentedon May 6, 2020
So this is related to this issue: #33240 and this PR #33252
Specifically, you're attempting to transfer an
ArrayBufferinstance that cannot be transferred. We need to implement better protections around this throughout core but the fundamental idea is that you should never transfer a Buffer or TypedArray unless you know for absolute certain that it is safe to do so -- and that's generally only when you are creating it yourself. The fix in this particular case would be to create your own Uint8Array copy of the buffer before sending it...In your worker... something like:
Alternatively, it's not clear from this example why you are using hasher.read() at all. The example is definitely not a typical case. What I would imagine would be a better approach in general is something like...
jasnell commentedon May 6, 2020
Now... all that said... just as a more general point that is independent of the segfault issue that we really need to make sure we look at... given that read stream and the hash operations here are already async, you're not likely to see any real benefit from using a worker thread in this way (see https://github.com/jasnell/piscina/tree/master/examples/server for an example perf analysis). Specifically, the performance of the worker thread in this specific example will never be faster than just doing the same operations on the main thread.
timsuchanek commentedon May 6, 2020
Thanks @jasnell for the insights! Sounds like a simplification can be done in the library
hashathen, where that pattern is used.jasnell commentedon May 6, 2020
Ah, yes... I'll open an issue there
jasnell commentedon Dec 15, 2020
I'm now unable to reproduce this issue on 14.x and 15.x. I believe the issue has been resolved tho I'm not sure exactly which commit fixed it. Closing, can reopen if it's still an issue