Alternative `harden` implementation approach
See original GitHub issueWhat is the Problem Being Solved?
The current implementation of harden
uses membership in a WeakSet
to determine whether various objects, functions, etc. have already been hardened. This prevents infinite recursion and improves performance by preventing walking already-frozen object graphs. The algorithm cannot just use isFrozen
for the test because a user could manually freeze
objects that reference still-mutable state.
That hardened
WeakSet
can get very large, whereas in both typical JavaScript programs and in Agoric’s model using harden
, Object.freeze
is rarely used. Can we eliminate the need for the large hardened
set?
Description of the Design
This alternative implementation approach is inspired by the assumption that we harden many more objects than we just freeze. So we record the usages of freeze
instead.
- change the
hardened
WeakSet to aonlyFrozen
WeakSet. - shim
Object.freeze
to both freeze the object and add it to theonlyFrozen
set isFrozen
is unchangedharden
just recursively freezes. If it finds a frozen object, it checks whether it’s in theonlyFrozen
set. If so, it removes it from the set and recurs on it- if
freeze
cannot be shimmed early enough, thenlockdown
may use ahardened
set to recur into frozen things it has not seen before.
As a result, isHardened(o)
is isFrozen(o) && !onlyFrozen.has(o)
Security Considerations
3 potential concerns:
- objects frozen before
lockdown
is called - freezing things without using
Object.freeze
- things that get frozen by the execution semantics
Re #2, @erights had some insight:
Need to also patch
Object.preventExtensions
,{Object,Reflect}.{defineProperty,defineProperties}
since those can make an object frozen. Actually, once an object is non-extensible, it is too easy to make it accidentally frozen, such a property deletion. I think you should mark everything made non-extensible, since that’s a narrower funnel. IIUC, it does not hurt to take a non-extensible but non-frozen object and put it intoonlyFrozen
just in case. [I agree]
Issue Analytics
- State:
- Created 2 years ago
- Comments:12 (11 by maintainers)
Also, Dean found a third case that I forgot: The ThrowTypeError object. But it is already included in our primordials and hardened on
lockdown
, so not a problem.Unless they’re empty, in which case, like the templates array, they’re transitively immutable anyway, and so not a threat.