Don't commit to frozenSet until prototype checks have passed
refs
MODIFY
index.js
index.js
@@ -102,17 +102,9 @@ function makeHardener(initialRoots) {
toFreeze.forEach(freezeAndTraverse); // todo curried forEach
}
- function commit() {
- // todo curried forEach
- // we capture the real WeakSet.prototype.add above, in case someone
- // changes it. The two-argument form of forEach passes the second
- // argument as the 'this' binding, so we add to the correct set.
- toFreeze.forEach(rootSet.add, rootSet);
- }
-
function checkPrototypes() {
prototypes.forEach((path, p) => {
- if (!rootSet.has(p)) {
+ if (!(toFreeze.has(p) || rootSet.has(p))) {
// all reachable properties have already been frozen by this point
throw new TypeError(
`prototype ${p} of ${path} is not already in the rootSet`,
@@ -121,13 +113,21 @@ function makeHardener(initialRoots) {
});
}
+ function commit() {
+ // todo curried forEach
+ // we capture the real WeakSet.prototype.add above, in case someone
+ // changes it. The two-argument form of forEach passes the second
+ // argument as the 'this' binding, so we add to the correct set.
+ toFreeze.forEach(rootSet.add, rootSet);
+ }
+
enqueue(root);
dequeue();
// console.log("rootSet", rootSet);
// console.log("prototype set:", prototypes);
// console.log("toFreeze set:", toFreeze);
- commit();
checkPrototypes();
+ commit();
return root;
}

MODIFY
test/test.js
test/test.js
@@ -70,3 +70,33 @@ test('harden overlapping objects', t => {
t.ok(Object.isFrozen(o2));
t.end();
});
+
+test('do not commit early', t => {
+ // refs #4
+ const h = makeHardener([Object.prototype]);
+ const a = { a: 1 };
+ const b = { b: 1, __proto__: a };
+ const c = { c: 1, __proto__: b };
+
+ t.throws(() => h(b), TypeError);
+ // the bug is that 'b' is marked as hardened. If that happens, harden(c)
+ // will pass when it was supposed to throw.
+ t.throws(() => h(c), TypeError);
+
+ t.end();
+});
+
+test('can harden all objects in a single call', t => {
+ // refs #4
+ const h = makeHardener([Object.prototype, Object.getPrototypeOf([])]);
+ const a = { a: 1 };
+ const b = { b: 1, __proto__: a };
+ const c = { c: 1, __proto__: b };
+
+ h([a, b, c]);
+ t.ok(Object.isFrozen(a));
+ t.ok(Object.isFrozen(b));
+ t.ok(Object.isFrozen(c));
+
+ t.end();
+});

Don't commit to frozenSet until prototype checks have passed

refs #4