Skip to content

Commit 90f90ae

Browse files
BridgeARjuanarbol
authored andcommitted
assert,util: fix stale nested cycle memo entries
Temporary nested cycle-tracking entries could remain in the memory set after a successful comparison. If a later sibling comparison reused one of those objects, deepStrictEqual could incorrectly fail for equivalent structures. This cleans up the temporary nested entries after the nested comparison returns. Fixes: #62422 PR-URL: #62509Fixes: #62422 Reviewed-By: Jordan Harband <ljharb@gmail.com>
1 parent dae9644 commit 90f90ae

2 files changed

Lines changed: 42 additions & 0 deletions

File tree

‎lib/internal/util/comparisons.js‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,10 @@ function handleCycles(val1, val2, mode, keys1, keys2, memos, iterationType) {
520520
memos.deep=true;
521521
constresult=objEquiv(val1,val2,mode,keys1,keys2,memos,iterationType);
522522
memos.deep=false;
523+
if(memos.set!==undefined){
524+
memos.set.delete(memos.c);
525+
memos.set.delete(memos.d);
526+
}
523527
returnresult;
524528
}
525529
memos.set=newSafeSet();

‎test/parallel/test-assert-deep.js‎

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,14 @@ function assertOnlyDeepEqual(a, b, err) {
248248
);
249249
}
250250

251+
functionactivateMemoizedCycleDetection(){
252+
constcircA={};
253+
circA.self=circA;
254+
constcircB={};
255+
circB.self=circB;
256+
assert.deepStrictEqual(circA,circB);
257+
}
258+
251259
test('es6 Maps and Sets',()=>{
252260
assertDeepAndStrictEqual(newSet(),newSet());
253261
assertDeepAndStrictEqual(newMap(),newMap());
@@ -597,6 +605,36 @@ test('GH-14441. Circular structures should be consistent', () => {
597605
}
598606
});
599607

608+
test('deepStrictEqual handles shared expected array elements after cycle detection',()=>{
609+
constsharedExpected={outer: {inner: 0}};
610+
constactualValues=[{outer: {inner: 0}},{outer: {inner: 0}}];
611+
constexpectedValues=[sharedExpected,sharedExpected];
612+
613+
activateMemoizedCycleDetection();
614+
615+
assertDeepAndStrictEqual(actualValues[0],expectedValues[0]);
616+
assertDeepAndStrictEqual(actualValues[1],expectedValues[1]);
617+
assertDeepAndStrictEqual(actualValues,expectedValues);
618+
});
619+
620+
test('deepStrictEqual handles cross-root aliases after cycle detection',()=>{
621+
activateMemoizedCycleDetection();
622+
623+
constnestedExpected={};
624+
nestedExpected.loop=nestedExpected;
625+
nestedExpected.payload={value: 1};
626+
627+
constexpected={};
628+
expected.loop=nestedExpected;
629+
expected.payload={value: 1};
630+
631+
constactual={};
632+
actual.loop=expected;
633+
actual.payload={value: 1};
634+
635+
assertDeepAndStrictEqual(actual,expected);
636+
});
637+
600638
// https://github.com/nodejs/node-v0.x-archive/pull/7178
601639
test('Ensure reflexivity of deepEqual with `arguments` objects.',()=>{
602640
constargs=(function(){returnarguments;})();

0 commit comments

Comments
 (0)