This is an automated email from the ASF dual-hosted git repository.
jan pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/couchdb.git
The following commit(s) were added to refs/heads/main by this push:
new 06c88fbe8 fix(js): re-instate `deepFreeze()` for all object freezing
duties
06c88fbe8 is described below
commit 06c88fbe8d10e88d4cd2b5011eceece57439e46a
Author: Jan Lehnardt <[email protected]>
AuthorDate: Fri Jan 24 12:29:07 2025 +0100
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
---
share/server/dispatch-quickjs.js | 4 ----
share/server/util.js | 24 +++++++++++++++---------
2 files changed, 15 insertions(+), 13 deletions(-)
diff --git a/share/server/dispatch-quickjs.js b/share/server/dispatch-quickjs.js
index 78ece8b59..5f69f6188 100644
--- a/share/server/dispatch-quickjs.js
+++ b/share/server/dispatch-quickjs.js
@@ -44,10 +44,6 @@ function create_nouveau_sandbox() {
return sandbox;
};
-function seal(obj, flag) {
- Object.freeze(obj);
-};
-
// This is a copy from loop.js
var DDoc = (function() {
var ddoc_dispatch = {
diff --git a/share/server/util.js b/share/server/util.js
index 2de3eb096..5508cc0e0 100644
--- a/share/server/util.js
+++ b/share/server/util.js
@@ -116,14 +116,7 @@ var Couch = {
"Expression does not eval to a function. (" + source.toString() +
")"]);
};
},
- recursivelySeal: function (obj) {
- seal(obj);
- for (var propname in obj) {
- if (typeof obj[propname] == "object") {
- arguments.callee(obj[propname]);
- }
- }
- },
+ recursivelySeal: deepFreeze,
};
function errstr(e) {
@@ -155,13 +148,26 @@ function isArray(obj) {
return toString.call(obj) === "[object Array]";
}
+function getPropNames(object) {
+ if (typeof Reflect === 'undefined') {
+ return Object.getOwnPropertyNames(object);
+ } else {
+ return Reflect.ownKeys(object);
+ }
+}
+
function deepFreeze(object) {
if (Object.isFrozen(object)) {
return object;
}
Object.freeze(object);
// Retrieve the property names defined on object
- const propNames = Reflect.ownKeys(object);
+ // `Reflect.ownKeys()` gives us all own property name strings as well as
+ // symbols, so it is a bit more complete, but it is a newer JS API, so we
+ // fall back on `Object.getOwnPropertyNames()` in JS engines that don’t
+ // understand symbols yet (SpiderMonkey 1.8.5). It is a safe fallback
+ // because until then object keys can only be strings.
+ const propNames = getPropNames(object);
// Freeze properties before freezing self
for (var i in propNames) {