process: make process.config read only

Fixes: https://github.com/nodejs/node/issues/43581
PR-URL: https://github.com/nodejs/node/pull/43627
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Tobias Nießen <tniessen@tnie.de>
This commit is contained in:
Sergey Petushkov 2022-09-11 00:00:23 +02:00 committed by GitHub
parent 22b9a0c4ba
commit e0ab8dd637
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 24 additions and 81 deletions

View File

@ -2889,12 +2889,15 @@ Prefer [`message.socket`][] over [`message.connection`][].
<!-- YAML
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/43627
description: End-of-Life.
- version: v16.0.0
pr-url: https://github.com/nodejs/node/pull/36902
description: Runtime deprecation.
-->
Type: Runtime
Type: End-of-Life
The `process.config` property provides access to Node.js compile-time settings.
However, the property is mutable and therefore subject to tampering. The ability

View File

@ -1041,6 +1041,9 @@ This feature is not available in [`Worker`][] threads.
<!-- YAML
added: v0.7.7
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/43627
description: The `process.config` object is now frozen.
- version: v16.0.0
pr-url: https://github.com/nodejs/node/pull/36902
description: Modifying process.config has been deprecated.
@ -1048,10 +1051,10 @@ changes:
* {Object}
The `process.config` property returns an `Object` containing the JavaScript
representation of the configure options used to compile the current Node.js
executable. This is the same as the `config.gypi` file that was produced when
running the `./configure` script.
The `process.config` property returns a frozen `Object` containing the
JavaScript representation of the configure options used to compile the current
Node.js executable. This is the same as the `config.gypi` file that was produced
when running the `./configure` script.
An example of the possible output looks like:
@ -1084,14 +1087,6 @@ An example of the possible output looks like:
}
```
The `process.config` property is **not** read-only and there are existing
modules in the ecosystem that are known to extend, modify, or entirely replace
the value of `process.config`.
Modifying the `process.config` property, or any child-property of the
`process.config` object has been deprecated. The `process.config` will be made
read-only in a future release.
## `process.connected`
<!-- YAML

View File

@ -46,10 +46,8 @@ const {
JSONParse,
ObjectDefineProperty,
ObjectGetPrototypeOf,
ObjectPreventExtensions,
ObjectSetPrototypeOf,
ReflectGet,
ReflectSet,
ObjectFreeze,
SymbolToStringTag,
globalThis,
} = primordials;
@ -91,75 +89,18 @@ process._exiting = false;
// process.config is serialized config.gypi
const nativeModule = internalBinding('builtins');
// TODO(@jasnell): Once this has gone through one full major
// release cycle, remove the Proxy and setter and update the
// getter to either return a read-only object or always return
// a freshly parsed version of nativeModule.config.
const deprecationHandler = {
warned: false,
message: 'Setting process.config is deprecated. ' +
'In the future the property will be read-only.',
code: 'DEP0150',
maybeWarn() {
if (!this.warned) {
process.emitWarning(this.message, {
type: 'DeprecationWarning',
code: this.code
});
this.warned = true;
}
},
defineProperty(target, key, descriptor) {
this.maybeWarn();
return ObjectDefineProperty(target, key, descriptor);
},
deleteProperty(target, key) {
this.maybeWarn();
delete target[key];
},
preventExtensions(target) {
this.maybeWarn();
return ObjectPreventExtensions(target);
},
set(target, key, value) {
this.maybeWarn();
return ReflectSet(target, key, value);
},
get(target, key, receiver) {
const val = ReflectGet(target, key, receiver);
if (val != null && typeof val === 'object') {
// eslint-disable-next-line node-core/prefer-primordials
return new Proxy(val, deprecationHandler);
}
return val;
},
setPrototypeOf(target, proto) {
this.maybeWarn();
return ObjectSetPrototypeOf(target, proto);
}
};
// eslint-disable-next-line node-core/prefer-primordials
let processConfig = new Proxy(
JSONParse(nativeModule.config),
deprecationHandler);
const processConfig = JSONParse(nativeModule.config, (_key, value) => {
// The `reviver` argument of the JSONParse method will visit all the values of
// the parsed config, including the "root" object, so there is no need to
// explicitly freeze the config outside of this method
return ObjectFreeze(value);
});
ObjectDefineProperty(process, 'config', {
__proto__: null,
enumerable: true,
configurable: true,
get() { return processConfig; },
set(value) {
deprecationHandler.maybeWarn();
processConfig = value;
}
value: processConfig,
});
require('internal/worker/js_transferable').setup();

View File

@ -28,7 +28,7 @@ const assert = require('assert');
const exec = require('child_process').exec;
let cmdline = `ulimit -c 0; ${process.execPath}`;
cmdline += ' --max-old-space-size=4 --max-semi-space-size=1';
cmdline += ' --max-old-space-size=16 --max-semi-space-size=4';
cmdline += ' -e "a = []; for (i = 0; i < 1e9; i++) { a.push({}) }"';
exec(cmdline, function(err, stdout, stderr) {

View File

@ -2,4 +2,5 @@
const common = require('../common');
common.skipIfInspectorDisabled();
delete process.config;
process.config = {};

View File

@ -36,6 +36,9 @@ assert(Object.hasOwn(process, 'config'));
// Ensure that `process.config` is an Object.
assert.strictEqual(Object(process.config), process.config);
// Ensure that you can't change config values
assert.throws(() => { process.config.variables = 42; }, TypeError);
const configPath = path.resolve(__dirname, '..', '..', 'config.gypi');
if (!fs.existsSync(configPath)) {