Skip to content

Commit

Permalink
src: modified RealEnvStore methods to use libuv functions
Browse files Browse the repository at this point in the history
Modified RealEnvStore::Get, Set, Query and Delete methods
to use libuv methods environment variables operations instead
of using os specific logic and switches.

Fixes: #27211
Refs: http://docs.libuv.org/en/v1.x/misc.html

PR-URL: #27310
Reviewed-By: Gus Caplan <me@gus.host>
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
  • Loading branch information
devasci authored and targos committed Sep 20, 2019
1 parent 0c91bc0 commit 981ec7d
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 73 deletions.
4 changes: 2 additions & 2 deletions src/env.h
Original file line number Diff line number Diff line change
Expand Up @@ -611,8 +611,8 @@ class KVStore {
KVStore(KVStore&&) = delete;
KVStore& operator=(KVStore&&) = delete;

virtual v8::Local<v8::String> Get(v8::Isolate* isolate,
v8::Local<v8::String> key) const = 0;
virtual v8::MaybeLocal<v8::String> Get(v8::Isolate* isolate,
v8::Local<v8::String> key) const = 0;
virtual void Set(v8::Isolate* isolate,
v8::Local<v8::String> key,
v8::Local<v8::String> value) = 0;
Expand Down
3 changes: 2 additions & 1 deletion src/inspector_profiler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,8 @@ std::string GetCwd(Environment* env) {
void StartProfilers(Environment* env) {
Isolate* isolate = env->isolate();
Local<String> coverage_str = env->env_vars()->Get(
isolate, FIXED_ONE_BYTE_STRING(isolate, "NODE_V8_COVERAGE"));
isolate, FIXED_ONE_BYTE_STRING(isolate, "NODE_V8_COVERAGE"))
.FromMaybe(Local<String>());
if (!coverage_str.IsEmpty() && coverage_str->Length() > 0) {
CHECK_NULL(env->coverage_connection());
env->set_coverage_connection(std::make_unique<V8CoverageConnection>(env));
Expand Down
124 changes: 54 additions & 70 deletions src/node_env_var.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ using v8::Value;

class RealEnvStore final : public KVStore {
public:
Local<String> Get(Isolate* isolate, Local<String> key) const override;
MaybeLocal<String> Get(Isolate* isolate, Local<String> key) const override;
void Set(Isolate* isolate, Local<String> key, Local<String> value) override;
int32_t Query(Isolate* isolate, Local<String> key) const override;
void Delete(Isolate* isolate, Local<String> key) override;
Expand All @@ -43,7 +43,7 @@ class RealEnvStore final : public KVStore {

class MapKVStore final : public KVStore {
public:
Local<String> Get(Isolate* isolate, Local<String> key) const override;
MaybeLocal<String> Get(Isolate* isolate, Local<String> key) const override;
void Set(Isolate* isolate, Local<String> key, Local<String> value) override;
int32_t Query(Isolate* isolate, Local<String> key) const override;
void Delete(Isolate* isolate, Local<String> key) override;
Expand All @@ -64,92 +64,72 @@ Mutex env_var_mutex;
std::shared_ptr<KVStore> system_environment = std::make_shared<RealEnvStore>();
} // namespace per_process

Local<String> RealEnvStore::Get(Isolate* isolate,
Local<String> property) const {
MaybeLocal<String> RealEnvStore::Get(Isolate* isolate,
Local<String> property) const {
Mutex::ScopedLock lock(per_process::env_var_mutex);
#ifdef __POSIX__

node::Utf8Value key(isolate, property);
const char* val = getenv(*key);
if (val) {
return String::NewFromUtf8(isolate, val, NewStringType::kNormal)
.ToLocalChecked();
size_t init_sz = 256;
MaybeStackBuffer<char, 256> val;
int ret = uv_os_getenv(*key, *val, &init_sz);

if (ret == UV_ENOBUFS) {
// Buffer is not large enough, reallocate to the updated init_sz
// and fetch env value again.
val.AllocateSufficientStorage(init_sz);
ret = uv_os_getenv(*key, *val, &init_sz);
}
#else // _WIN32
node::TwoByteValue key(isolate, property);
WCHAR buffer[32767]; // The maximum size allowed for environment variables.
SetLastError(ERROR_SUCCESS);
DWORD result = GetEnvironmentVariableW(
reinterpret_cast<WCHAR*>(*key), buffer, arraysize(buffer));
// If result >= sizeof buffer the buffer was too small. That should never
// happen. If result == 0 and result != ERROR_SUCCESS the variable was not
// found.
if ((result > 0 || GetLastError() == ERROR_SUCCESS) &&
result < arraysize(buffer)) {
const uint16_t* two_byte_buffer = reinterpret_cast<const uint16_t*>(buffer);
v8::MaybeLocal<String> rc = String::NewFromTwoByte(
isolate, two_byte_buffer, NewStringType::kNormal);
if (rc.IsEmpty()) {
isolate->ThrowException(ERR_STRING_TOO_LONG(isolate));
return Local<String>();
}
return rc.ToLocalChecked();

if (ret >= 0) { // Env key value fetch success.
MaybeLocal<String> value_string =
String::NewFromUtf8(isolate, *val, NewStringType::kNormal, init_sz);
return value_string;
}
#endif
return Local<String>();

return MaybeLocal<String>();
}

void RealEnvStore::Set(Isolate* isolate,
Local<String> property,
Local<String> value) {
Mutex::ScopedLock lock(per_process::env_var_mutex);
#ifdef __POSIX__

node::Utf8Value key(isolate, property);
node::Utf8Value val(isolate, value);
setenv(*key, *val, 1);
#else // _WIN32
node::TwoByteValue key(isolate, property);
node::TwoByteValue val(isolate, value);
WCHAR* key_ptr = reinterpret_cast<WCHAR*>(*key);
// Environment variables that start with '=' are read-only.
if (key_ptr[0] != L'=') {
SetEnvironmentVariableW(key_ptr, reinterpret_cast<WCHAR*>(*val));
}

#ifdef _WIN32
if (key[0] == L'=') return;
#endif
uv_os_setenv(*key, *val);
}

int32_t RealEnvStore::Query(Isolate* isolate, Local<String> property) const {
Mutex::ScopedLock lock(per_process::env_var_mutex);
#ifdef __POSIX__

node::Utf8Value key(isolate, property);
if (getenv(*key)) return 0;
#else // _WIN32
node::TwoByteValue key(isolate, property);
WCHAR* key_ptr = reinterpret_cast<WCHAR*>(*key);
SetLastError(ERROR_SUCCESS);
if (GetEnvironmentVariableW(key_ptr, nullptr, 0) > 0 ||
GetLastError() == ERROR_SUCCESS) {
if (key_ptr[0] == L'=') {
// Environment variables that start with '=' are hidden and read-only.
return static_cast<int32_t>(v8::ReadOnly) |
static_cast<int32_t>(v8::DontDelete) |
static_cast<int32_t>(v8::DontEnum);
}
return 0;
}
#ifdef _WIN32
if (key[0] == L'=')
return static_cast<int32_t>(v8::ReadOnly) |
static_cast<int32_t>(v8::DontDelete) |
static_cast<int32_t>(v8::DontEnum);
#endif
return -1;

char val[2];
size_t init_sz = sizeof(val);
int ret = uv_os_getenv(*key, val, &init_sz);

if (ret == UV_ENOENT) {
return -1;
}

return 0;
}

void RealEnvStore::Delete(Isolate* isolate, Local<String> property) {
Mutex::ScopedLock lock(per_process::env_var_mutex);
#ifdef __POSIX__

node::Utf8Value key(isolate, property);
unsetenv(*key);
#else
node::TwoByteValue key(isolate, property);
WCHAR* key_ptr = reinterpret_cast<WCHAR*>(*key);
SetEnvironmentVariableW(key_ptr, nullptr);
#endif
uv_os_unsetenv(*key);
}

Local<Array> RealEnvStore::Enumerate(Isolate* isolate) const {
Expand Down Expand Up @@ -214,19 +194,20 @@ std::shared_ptr<KVStore> KVStore::Clone(v8::Isolate* isolate) const {
for (uint32_t i = 0; i < keys_length; i++) {
Local<Value> key = keys->Get(context, i).ToLocalChecked();
CHECK(key->IsString());
copy->Set(isolate, key.As<String>(), Get(isolate, key.As<String>()));
copy->Set(isolate,
key.As<String>(),
Get(isolate, key.As<String>()).ToLocalChecked());
}
return copy;
}

Local<String> MapKVStore::Get(Isolate* isolate, Local<String> key) const {
MaybeLocal<String> MapKVStore::Get(Isolate* isolate, Local<String> key) const {
Mutex::ScopedLock lock(mutex_);
Utf8Value str(isolate, key);
auto it = map_.find(std::string(*str, str.length()));
if (it == map_.end()) return Local<String>();
return String::NewFromUtf8(isolate, it->second.data(),
NewStringType::kNormal, it->second.size())
.ToLocalChecked();
NewStringType::kNormal, it->second.size());
}

void MapKVStore::Set(Isolate* isolate, Local<String> key, Local<String> value) {
Expand Down Expand Up @@ -306,8 +287,11 @@ static void EnvGetter(Local<Name> property,
return info.GetReturnValue().SetUndefined();
}
CHECK(property->IsString());
info.GetReturnValue().Set(
env->env_vars()->Get(env->isolate(), property.As<String>()));
MaybeLocal<String> value_string =
env->env_vars()->Get(env->isolate(), property.As<String>());
if (!value_string.IsEmpty()) {
info.GetReturnValue().Set(value_string.ToLocalChecked());
}
}

static void EnvSetter(Local<Name> property,
Expand Down

0 comments on commit 981ec7d

Please sign in to comment.