防止资源比较循环递归溢出

为 sameResource 增加对象对访问跟踪,遇到循环结构时安全终止递归
This commit is contained in:
2026-09-03 13:15:49 +08:00
parent 6b332e8c12
commit 08caa1f29f
@@ -238,7 +238,11 @@ function cloneState(state: State): State {
return structuredClone(state);
}
function sameResource<T>(left: T, right: T): boolean {
function sameResource<T>(
left: T,
right: T,
seenPairs = new WeakMap<object, WeakSet<object>>(),
): boolean {
if (Object.is(left, right)) return true;
if (
typeof left !== 'object' ||
@@ -248,10 +252,22 @@ function sameResource<T>(left: T, right: T): boolean {
) {
return false;
}
const leftObject = left as object;
const rightObject = right as object;
let seenRightObjects = seenPairs.get(leftObject);
if (seenRightObjects?.has(rightObject)) return true;
if (!seenRightObjects) {
seenRightObjects = new WeakSet<object>();
seenPairs.set(leftObject, seenRightObjects);
}
seenRightObjects.add(rightObject);
if (Array.isArray(left) || Array.isArray(right)) {
if (!Array.isArray(left) || !Array.isArray(right)) return false;
if (left.length !== right.length) return false;
return left.every((value, index) => sameResource(value, right[index]));
return left.every((value, index) =>
sameResource(value, right[index], seenPairs),
);
}
const leftRecord = left as Record<string, unknown>;
const rightRecord = right as Record<string, unknown>;
@@ -261,7 +277,7 @@ function sameResource<T>(left: T, right: T): boolean {
return leftKeys.every(
(key) =>
Object.prototype.hasOwnProperty.call(rightRecord, key) &&
sameResource(leftRecord[key], rightRecord[key]),
sameResource(leftRecord[key], rightRecord[key], seenPairs),
);
}