From b8bdaf86c4f8ad89eef3148c2c78b75ee3c6d920 Mon Sep 17 00:00:00 2001 From: James M Snell Date: Sat, 15 Apr 2023 20:21:16 +0200 Subject: [PATCH] lib: disallow file-backed blob cloning Disallow cloning of file-backed Blobs. If necessary, we can enable this later but for now we disable it. The reason is because the underlying FdEntry ends up bound to the Environment/Realm under which is was created and transfering across worker threads ends up failing. Fixes: https://github.com/nodejs/node/issues/47334 PR-URL: https://github.com/nodejs/node/pull/47574 Reviewed-By: Debadree Chatterjee Reviewed-By: Antoine du Hamel --- lib/internal/blob.js | 11 ++++++++++- test/parallel/test-blob-file-backed.js | 12 ++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/lib/internal/blob.js b/lib/internal/blob.js index 9c6be6981f5b88..ee8e1c75819ab9 100644 --- a/lib/internal/blob.js +++ b/lib/internal/blob.js @@ -56,6 +56,7 @@ const { ERR_INVALID_ARG_TYPE, ERR_INVALID_ARG_VALUE, ERR_INVALID_THIS, + ERR_INVALID_STATE, ERR_BUFFER_TOO_LARGE, }, } = require('internal/errors'); @@ -74,6 +75,7 @@ const { queueMicrotask } = require('internal/process/task_queues'); const kHandle = Symbol('kHandle'); const kType = Symbol('kType'); const kLength = Symbol('kLength'); +const kNotCloneable = Symbol('kNotCloneable'); const disallowedTypeCharacters = /[^\u{0020}-\u{007E}]/u; @@ -186,6 +188,11 @@ class Blob { } [kClone]() { + if (this[kNotCloneable]) { + // We do not currently allow file-backed Blobs to be cloned or passed across + // worker threads. + throw new ERR_INVALID_STATE.TypeError('File-backed Blobs are not cloneable'); + } const handle = this[kHandle]; const type = this[kType]; const length = this[kLength]; @@ -438,7 +445,9 @@ function createBlobFromFilePath(path, options) { return lazyDOMException('The blob could not be read', 'NotReadableError'); } const { 0: blob, 1: length } = maybeBlob; - return createBlob(blob, length, options?.type); + const res = createBlob(blob, length, options?.type); + res[kNotCloneable] = true; + return res; } module.exports = { diff --git a/test/parallel/test-blob-file-backed.js b/test/parallel/test-blob-file-backed.js index 225b660c7bbdb3..b25137a34c3d01 100644 --- a/test/parallel/test-blob-file-backed.js +++ b/test/parallel/test-blob-file-backed.js @@ -4,6 +4,7 @@ const common = require('../common'); const { strictEqual, rejects, + throws, } = require('assert'); const { TextDecoder } = require('util'); const { @@ -99,3 +100,14 @@ writeFileSync(testfile3, ''); const reader = stream.getReader(); await rejects(() => reader.read(), { name: 'NotReadableError' }); })().then(common.mustCall()); + +(async () => { + // We currently do not allow File-backed blobs to be cloned or transfered + // across worker threads. This is largely because the underlying FdEntry + // is bound to the Environment/Realm under which is was created. + const blob = await openAsBlob(__filename); + throws(() => structuredClone(blob), { + code: 'ERR_INVALID_STATE', + message: 'Invalid state: File-backed Blobs are not cloneable' + }); +})().then(common.mustCall());