Skip to content

Commit 06c88fb

Browse files
committed
fix(js): re-instate deepFreeze() for all object freezing duties
Prior to landing SpiderMonkey 102+ we relied on a global `seal()` function that we defined in our custom `couchjs` C/C++ code. SM 102+ no longer exposes the API needed to implement this, but the JS standard also includes a userspace `Object.freeze()` method we can use. Our initial implementation of SM 102+ support introduced[1] a global `deepFreeze()` function that relied on `Reflect .ownKeys()` which is not available in SpiderMonkey 1.8.5, but all later ones we support. To fix the build for SM 1.8.5, we partly reverted[2] the use of `deepFreeze()`, but we missed a few spots in `main.js` where we seal our own new globals like `Couch`[3]. This commit reinstates the use of `deepFreeze()` everywhere and adds a safe fallback inside `deepFreeze()` to do the right thing for SM 1.8.5 and > 1.8.5. Tested on macOS with SM 128: ``` > ./src/couch/priv/couchjs -V couchjs - Apache CouchDB 3.4.2-70fc2cc-dirty (SpiderMonkey 128.6.0) [...] > ./src/couch/priv/couchjs share/server/main.js ["reset"] true ``` And Linux with SpiderMonkey 1.8.5: ``` > src/couch/priv/couchjs -V couchjs - Apache CouchDB 3.4.2-121ac7c-dirty (SpiderMonkey 1.8.5) [...] > src/couch/priv/couchjs share/server/main.js ["reset"] true ``` [1]: https://github.com/apache/couchdb/pull/5321/files#diff-71d0f32fee8a14f6a8d1775801cbb1851784c7050d844d2938d8fb8d71ecafe0R151 [2]: https://github.com/apache/couchdb/pull/5364/files#diff-71d0f32fee8a14f6a8d1775801cbb1851784c7050d844d2938d8fb8d71ecafe0R119 [3]: https://github.com/apache/couchdb/blob/main/share/server/loop.js#L180-L188
1 parent faa4fc8 commit 06c88fb

File tree

2 files changed

+15
-13
lines changed

2 files changed

+15
-13
lines changed

share/server/dispatch-quickjs.js

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,6 @@ function create_nouveau_sandbox() {
4444
return sandbox;
4545
};
4646

47-
function seal(obj, flag) {
48-
Object.freeze(obj);
49-
};
50-
5147
// This is a copy from loop.js
5248
var DDoc = (function() {
5349
var ddoc_dispatch = {

share/server/util.js

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -116,14 +116,7 @@ var Couch = {
116116
"Expression does not eval to a function. (" + source.toString() + ")"]);
117117
};
118118
},
119-
recursivelySeal: function (obj) {
120-
seal(obj);
121-
for (var propname in obj) {
122-
if (typeof obj[propname] == "object") {
123-
arguments.callee(obj[propname]);
124-
}
125-
}
126-
},
119+
recursivelySeal: deepFreeze,
127120
};
128121

129122
function errstr(e) {
@@ -155,13 +148,26 @@ function isArray(obj) {
155148
return toString.call(obj) === "[object Array]";
156149
}
157150

151+
function getPropNames(object) {
152+
if (typeof Reflect === 'undefined') {
153+
return Object.getOwnPropertyNames(object);
154+
} else {
155+
return Reflect.ownKeys(object);
156+
}
157+
}
158+
158159
function deepFreeze(object) {
159160
if (Object.isFrozen(object)) {
160161
return object;
161162
}
162163
Object.freeze(object);
163164
// Retrieve the property names defined on object
164-
const propNames = Reflect.ownKeys(object);
165+
// `Reflect.ownKeys()` gives us all own property name strings as well as
166+
// symbols, so it is a bit more complete, but it is a newer JS API, so we
167+
// fall back on `Object.getOwnPropertyNames()` in JS engines that don’t
168+
// understand symbols yet (SpiderMonkey 1.8.5). It is a safe fallback
169+
// because until then object keys can only be strings.
170+
const propNames = getPropNames(object);
165171

166172
// Freeze properties before freezing self
167173
for (var i in propNames) {

0 commit comments

Comments
 (0)