This is an automated email from the ASF dual-hosted git repository. jan pushed a commit to branch fix-js-sealing in repository https://gitbox.apache.org/repos/asf/couchdb.git
commit b97b3ff056f7067e6115fb4aa67f99bd619b9077 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) {
