Skip to content

Commit

Permalink
src: make process.env work with symbols in/delete
Browse files Browse the repository at this point in the history
The getter for process.env already allows symbols to be used, and `in`
operator as a read-only operator can do the same.

`delete a[b]` operator in ES always returns `true` without doing
anything when `b in a === false`. Allow symbols in the deleter
accordingly.

PR-URL: #11709
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
  • Loading branch information
TimothyGu committed Mar 10, 2017
1 parent 7a4adb5 commit e2f151f
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 23 deletions.
42 changes: 23 additions & 19 deletions src/node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2787,39 +2787,43 @@ static void EnvSetter(Local<Name> property,
static void EnvQuery(Local<Name> property,
const PropertyCallbackInfo<Integer>& info) {
int32_t rc = -1; // Not found unless proven otherwise.
if (property->IsString()) {
#ifdef __POSIX__
node::Utf8Value key(info.GetIsolate(), property);
if (getenv(*key))
rc = 0;
node::Utf8Value key(info.GetIsolate(), property);
if (getenv(*key))
rc = 0;
#else // _WIN32
node::TwoByteValue key(info.GetIsolate(), property);
WCHAR* key_ptr = reinterpret_cast<WCHAR*>(*key);
if (GetEnvironmentVariableW(key_ptr, nullptr, 0) > 0 ||
GetLastError() == ERROR_SUCCESS) {
rc = 0;
if (key_ptr[0] == L'=') {
// Environment variables that start with '=' are hidden and read-only.
rc = static_cast<int32_t>(v8::ReadOnly) |
static_cast<int32_t>(v8::DontDelete) |
static_cast<int32_t>(v8::DontEnum);
node::TwoByteValue key(info.GetIsolate(), property);
WCHAR* key_ptr = reinterpret_cast<WCHAR*>(*key);
if (GetEnvironmentVariableW(key_ptr, nullptr, 0) > 0 ||
GetLastError() == ERROR_SUCCESS) {
rc = 0;
if (key_ptr[0] == L'=') {
// Environment variables that start with '=' are hidden and read-only.
rc = static_cast<int32_t>(v8::ReadOnly) |
static_cast<int32_t>(v8::DontDelete) |
static_cast<int32_t>(v8::DontEnum);
}
}
}
#endif
}
if (rc != -1)
info.GetReturnValue().Set(rc);
}


static void EnvDeleter(Local<Name> property,
const PropertyCallbackInfo<Boolean>& info) {
if (property->IsString()) {
#ifdef __POSIX__
node::Utf8Value key(info.GetIsolate(), property);
unsetenv(*key);
node::Utf8Value key(info.GetIsolate(), property);
unsetenv(*key);
#else
node::TwoByteValue key(info.GetIsolate(), property);
WCHAR* key_ptr = reinterpret_cast<WCHAR*>(*key);
SetEnvironmentVariableW(key_ptr, nullptr);
node::TwoByteValue key(info.GetIsolate(), property);
WCHAR* key_ptr = reinterpret_cast<WCHAR*>(*key);
SetEnvironmentVariableW(key_ptr, nullptr);
#endif
}

// process.env never has non-configurable properties, so always
// return true like the tc39 delete operator.
Expand Down
9 changes: 5 additions & 4 deletions test/parallel/test-process-env-symbols.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@ assert.throws(() => {
process.env.foo = symbol;
}, errRegExp);

// Verify that using a symbol with the in operator throws.
assert.throws(() => {
symbol in process.env;
}, errRegExp);
// Verify that using a symbol with the in operator returns false.
assert.strictEqual(symbol in process.env, false);

// Verify that deleting a symbol key returns true.
assert.strictEqual(delete process.env[symbol], true);

// Checks that well-known symbols like `Symbol.toStringTag` won’t throw.
assert.doesNotThrow(() => Object.prototype.toString.call(process.env));

0 comments on commit e2f151f

Please sign in to comment.