From a7dfa43dc7f9d101e45fbc796f3fc6138726d2c9 Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Mon, 6 Dec 2021 18:38:26 +0100 Subject: [PATCH] assert: use stricter stack frame detection in .ifError() This makes sure arbitrary stack traces are not handled as stack frames. Signed-off-by: Ruben Bridgewater PR-URL: https://github.com/nodejs/node/pull/41006 Reviewed-By: James M Snell --- lib/assert.js | 32 ++++++++++++++++----------- test/parallel/test-assert-if-error.js | 12 ++++++++++ 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/lib/assert.js b/lib/assert.js index 89949c01614fd4..46d6102381a450 100644 --- a/lib/assert.js +++ b/lib/assert.js @@ -966,21 +966,27 @@ assert.ifError = function ifError(err) { // This will remove any duplicated frames from the error frames taken // from within `ifError` and add the original error frames to the newly // created ones. - const tmp2 = StringPrototypeSplit(origStack, '\n'); - ArrayPrototypeShift(tmp2); - // Filter all frames existing in err.stack. - let tmp1 = StringPrototypeSplit(newErr.stack, '\n'); - for (const errFrame of tmp2) { - // Find the first occurrence of the frame. - const pos = ArrayPrototypeIndexOf(tmp1, errFrame); - if (pos !== -1) { - // Only keep new frames. - tmp1 = ArrayPrototypeSlice(tmp1, 0, pos); - break; + const origStackStart = origStack.indexOf('\n at'); + if (origStackStart !== -1) { + const originalFrames = StringPrototypeSplit( + origStack.slice(origStackStart + 1), + '\n' + ); + // Filter all frames existing in err.stack. + let newFrames = StringPrototypeSplit(newErr.stack, '\n'); + for (const errFrame of originalFrames) { + // Find the first occurrence of the frame. + const pos = ArrayPrototypeIndexOf(newFrames, errFrame); + if (pos !== -1) { + // Only keep new frames. + newFrames = ArrayPrototypeSlice(newFrames, 0, pos); + break; + } } + const stackStart = ArrayPrototypeJoin(newFrames, '\n'); + const stackEnd = ArrayPrototypeJoin(originalFrames, '\n'); + newErr.stack = `${stackStart}\n${stackEnd}`; } - newErr.stack = - `${ArrayPrototypeJoin(tmp1, '\n')}\n${ArrayPrototypeJoin(tmp2, '\n')}`; } throw newErr; diff --git a/test/parallel/test-assert-if-error.js b/test/parallel/test-assert-if-error.js index 76539bb69b44f0..9bc58cd73825a6 100644 --- a/test/parallel/test-assert-if-error.js +++ b/test/parallel/test-assert-if-error.js @@ -39,6 +39,18 @@ const stack = err.stack; })(); })(); +assert.throws( + () => { + const error = new Error(); + error.stack = 'Error: containing weird stack\nYes!\nI am part of a stack.'; + assert.ifError(error); + }, + (error) => { + assert(!error.stack.includes('Yes!')); + return true; + } +); + assert.throws( () => assert.ifError(new TypeError()), {