GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/node_env_var.cc Lines: 140 147 95.2 %
Date: 2019-05-05 22:32:45 Branches: 63 86 73.3 %

Line Branch Exec Source
1
#include "node_errors.h"
2
#include "node_process.h"
3
#include "util.h"
4
5
#ifdef __APPLE__
6
#include <crt_externs.h>
7
#define environ (*_NSGetEnviron())
8
#elif !defined(_MSC_VER)
9
extern char** environ;
10
#endif
11
12
namespace node {
13
using v8::Array;
14
using v8::Boolean;
15
using v8::Context;
16
using v8::EscapableHandleScope;
17
using v8::HandleScope;
18
using v8::Integer;
19
using v8::Isolate;
20
using v8::Just;
21
using v8::Local;
22
using v8::Maybe;
23
using v8::MaybeLocal;
24
using v8::Name;
25
using v8::NamedPropertyHandlerConfiguration;
26
using v8::NewStringType;
27
using v8::Nothing;
28
using v8::Object;
29
using v8::ObjectTemplate;
30
using v8::PropertyCallbackInfo;
31
using v8::String;
32
using v8::Value;
33
34
4525
class RealEnvStore final : public KVStore {
35
 public:
36
  Local<String> Get(Isolate* isolate, Local<String> key) const override;
37
  void Set(Isolate* isolate, Local<String> key, Local<String> value) override;
38
  int32_t Query(Isolate* isolate, Local<String> key) const override;
39
  void Delete(Isolate* isolate, Local<String> key) override;
40
  Local<Array> Enumerate(Isolate* isolate) const override;
41
};
42
43
185
class MapKVStore final : public KVStore {
44
 public:
45
  Local<String> Get(Isolate* isolate, Local<String> key) const override;
46
  void Set(Isolate* isolate, Local<String> key, Local<String> value) override;
47
  int32_t Query(Isolate* isolate, Local<String> key) const override;
48
  void Delete(Isolate* isolate, Local<String> key) override;
49
  Local<Array> Enumerate(Isolate* isolate) const override;
50
51
  std::shared_ptr<KVStore> Clone(Isolate* isolate) const override;
52
53
184
  MapKVStore() = default;
54
1
  MapKVStore(const MapKVStore& other) : map_(other.map_) {}
55
56
 private:
57
  mutable Mutex mutex_;
58
  std::unordered_map<std::string, std::string> map_;
59
};
60
61
namespace per_process {
62
4525
Mutex env_var_mutex;
63
4525
std::shared_ptr<KVStore> system_environment = std::make_shared<RealEnvStore>();
64
}  // namespace per_process
65
66
558316
Local<String> RealEnvStore::Get(Isolate* isolate,
67
                                Local<String> property) const {
68
558316
  Mutex::ScopedLock lock(per_process::env_var_mutex);
69
#ifdef __POSIX__
70
1116632
  node::Utf8Value key(isolate, property);
71
558316
  const char* val = getenv(*key);
72
558316
  if (val) {
73
    return String::NewFromUtf8(isolate, val, NewStringType::kNormal)
74
1001748
        .ToLocalChecked();
75
  }
76
#else  // _WIN32
77
  node::TwoByteValue key(isolate, property);
78
  WCHAR buffer[32767];  // The maximum size allowed for environment variables.
79
  SetLastError(ERROR_SUCCESS);
80
  DWORD result = GetEnvironmentVariableW(
81
      reinterpret_cast<WCHAR*>(*key), buffer, arraysize(buffer));
82
  // If result >= sizeof buffer the buffer was too small. That should never
83
  // happen. If result == 0 and result != ERROR_SUCCESS the variable was not
84
  // found.
85
  if ((result > 0 || GetLastError() == ERROR_SUCCESS) &&
86
      result < arraysize(buffer)) {
87
    const uint16_t* two_byte_buffer = reinterpret_cast<const uint16_t*>(buffer);
88
    v8::MaybeLocal<String> rc = String::NewFromTwoByte(
89
        isolate, two_byte_buffer, NewStringType::kNormal);
90
    if (rc.IsEmpty()) {
91
      isolate->ThrowException(ERR_STRING_TOO_LONG(isolate));
92
      return Local<String>();
93
    }
94
    return rc.ToLocalChecked();
95
  }
96
#endif
97
615758
  return Local<String>();
98
}
99
100
9351
void RealEnvStore::Set(Isolate* isolate,
101
                       Local<String> property,
102
                       Local<String> value) {
103
9351
  Mutex::ScopedLock lock(per_process::env_var_mutex);
104
#ifdef __POSIX__
105
18702
  node::Utf8Value key(isolate, property);
106
18702
  node::Utf8Value val(isolate, value);
107
18702
  setenv(*key, *val, 1);
108
#else  // _WIN32
109
  node::TwoByteValue key(isolate, property);
110
  node::TwoByteValue val(isolate, value);
111
  WCHAR* key_ptr = reinterpret_cast<WCHAR*>(*key);
112
  // Environment variables that start with '=' are read-only.
113
  if (key_ptr[0] != L'=') {
114
    SetEnvironmentVariableW(key_ptr, reinterpret_cast<WCHAR*>(*val));
115
  }
116
#endif
117
9351
}
118
119
658813
int32_t RealEnvStore::Query(Isolate* isolate, Local<String> property) const {
120
658813
  Mutex::ScopedLock lock(per_process::env_var_mutex);
121
#ifdef __POSIX__
122
1317626
  node::Utf8Value key(isolate, property);
123
658813
  if (getenv(*key)) return 0;
124
#else  // _WIN32
125
  node::TwoByteValue key(isolate, property);
126
  WCHAR* key_ptr = reinterpret_cast<WCHAR*>(*key);
127
  SetLastError(ERROR_SUCCESS);
128
  if (GetEnvironmentVariableW(key_ptr, nullptr, 0) > 0 ||
129
      GetLastError() == ERROR_SUCCESS) {
130
    if (key_ptr[0] == L'=') {
131
      // Environment variables that start with '=' are hidden and read-only.
132
      return static_cast<int32_t>(v8::ReadOnly) |
133
             static_cast<int32_t>(v8::DontDelete) |
134
             static_cast<int32_t>(v8::DontEnum);
135
    }
136
    return 0;
137
  }
138
#endif
139
662397
  return -1;
140
}
141
142
997
void RealEnvStore::Delete(Isolate* isolate, Local<String> property) {
143
997
  Mutex::ScopedLock lock(per_process::env_var_mutex);
144
#ifdef __POSIX__
145
1994
  node::Utf8Value key(isolate, property);
146
1994
  unsetenv(*key);
147
#else
148
  node::TwoByteValue key(isolate, property);
149
  WCHAR* key_ptr = reinterpret_cast<WCHAR*>(*key);
150
  SetEnvironmentVariableW(key_ptr, nullptr);
151
#endif
152
997
}
153
154
5829
Local<Array> RealEnvStore::Enumerate(Isolate* isolate) const {
155
5829
  Mutex::ScopedLock lock(per_process::env_var_mutex);
156
#ifdef __POSIX__
157
5829
  int env_size = 0;
158
381781
  while (environ[env_size]) {
159
370123
    env_size++;
160
  }
161
11658
  std::vector<Local<Value>> env_v(env_size);
162
163
375952
  for (int i = 0; i < env_size; ++i) {
164
370123
    const char* var = environ[i];
165
370123
    const char* s = strchr(var, '=');
166
370123
    const int length = s ? s - var : strlen(var);
167
370123
    env_v[i] = String::NewFromUtf8(isolate, var, NewStringType::kNormal, length)
168
740246
                   .ToLocalChecked();
169
  }
170
#else  // _WIN32
171
  std::vector<Local<Value>> env_v;
172
  WCHAR* environment = GetEnvironmentStringsW();
173
  if (environment == nullptr)
174
    return Array::New(isolate);  // This should not happen.
175
  WCHAR* p = environment;
176
  while (*p) {
177
    WCHAR* s;
178
    if (*p == L'=') {
179
      // If the key starts with '=' it is a hidden environment variable.
180
      p += wcslen(p) + 1;
181
      continue;
182
    } else {
183
      s = wcschr(p, L'=');
184
    }
185
    if (!s) {
186
      s = p + wcslen(p);
187
    }
188
    const uint16_t* two_byte_buffer = reinterpret_cast<const uint16_t*>(p);
189
    const size_t two_byte_buffer_len = s - p;
190
    v8::MaybeLocal<String> rc = String::NewFromTwoByte(
191
        isolate, two_byte_buffer, NewStringType::kNormal, two_byte_buffer_len);
192
    if (rc.IsEmpty()) {
193
      isolate->ThrowException(ERR_STRING_TOO_LONG(isolate));
194
      FreeEnvironmentStringsW(environment);
195
      return Local<Array>();
196
    }
197
    env_v.push_back(rc.ToLocalChecked());
198
    p = s + wcslen(s) + 1;
199
  }
200
  FreeEnvironmentStringsW(environment);
201
#endif
202
203
11658
  return Array::New(isolate, env_v.data(), env_v.size());
204
}
205
206
183
std::shared_ptr<KVStore> KVStore::Clone(v8::Isolate* isolate) const {
207
183
  HandleScope handle_scope(isolate);
208
183
  Local<Context> context = isolate->GetCurrentContext();
209
210
183
  std::shared_ptr<KVStore> copy = KVStore::CreateMapKVStore();
211
183
  Local<Array> keys = Enumerate(isolate);
212
183
  uint32_t keys_length = keys->Length();
213
11748
  for (uint32_t i = 0; i < keys_length; i++) {
214
23130
    Local<Value> key = keys->Get(context, i).ToLocalChecked();
215
23130
    CHECK(key->IsString());
216
34695
    copy->Set(isolate, key.As<String>(), Get(isolate, key.As<String>()));
217
  }
218
183
  return copy;
219
}
220
221
1856
Local<String> MapKVStore::Get(Isolate* isolate, Local<String> key) const {
222
1856
  Mutex::ScopedLock lock(mutex_);
223
3712
  Utf8Value str(isolate, key);
224
1856
  auto it = map_.find(std::string(*str, str.length()));
225
2740
  if (it == map_.end()) return Local<String>();
226
972
  return String::NewFromUtf8(isolate, it->second.data(),
227
1944
                             NewStringType::kNormal, it->second.size())
228
3800
      .ToLocalChecked();
229
}
230
231
11570
void MapKVStore::Set(Isolate* isolate, Local<String> key, Local<String> value) {
232
11570
  Mutex::ScopedLock lock(mutex_);
233
23140
  Utf8Value key_str(isolate, key);
234
23140
  Utf8Value value_str(isolate, value);
235

11570
  if (*key_str != nullptr && *value_str != nullptr) {
236
34710
    map_[std::string(*key_str, key_str.length())] =
237
23140
        std::string(*value_str, value_str.length());
238
11570
  }
239
11570
}
240
241
136
int32_t MapKVStore::Query(Isolate* isolate, Local<String> key) const {
242
136
  Mutex::ScopedLock lock(mutex_);
243
272
  Utf8Value str(isolate, key);
244
136
  auto it = map_.find(std::string(*str, str.length()));
245
272
  return it == map_.end() ? -1 : 0;
246
}
247
248
void MapKVStore::Delete(Isolate* isolate, Local<String> key) {
249
  Mutex::ScopedLock lock(mutex_);
250
  Utf8Value str(isolate, key);
251
  map_.erase(std::string(*str, str.length()));
252
}
253
254
2
Local<Array> MapKVStore::Enumerate(Isolate* isolate) const {
255
2
  Mutex::ScopedLock lock(mutex_);
256
4
  std::vector<Local<Value>> values;
257
2
  values.reserve(map_.size());
258
69
  for (const auto& pair : map_) {
259
    values.emplace_back(
260
        String::NewFromUtf8(isolate, pair.first.data(),
261
67
                            NewStringType::kNormal, pair.first.size())
262
134
            .ToLocalChecked());
263
  }
264
4
  return Array::New(isolate, values.data(), values.size());
265
}
266
267
1
std::shared_ptr<KVStore> MapKVStore::Clone(Isolate* isolate) const {
268
1
  return std::make_shared<MapKVStore>(*this);
269
}
270
271
184
std::shared_ptr<KVStore> KVStore::CreateMapKVStore() {
272
184
  return std::make_shared<MapKVStore>();
273
}
274
275
1
Maybe<bool> KVStore::AssignFromObject(Local<Context> context,
276
                                      Local<Object> entries) {
277
1
  Isolate* isolate = context->GetIsolate();
278
1
  HandleScope handle_scope(isolate);
279
  Local<Array> keys;
280
2
  if (!entries->GetOwnPropertyNames(context).ToLocal(&keys))
281
    return Nothing<bool>();
282
1
  uint32_t keys_length = keys->Length();
283
2
  for (uint32_t i = 0; i < keys_length; i++) {
284
    Local<Value> key;
285
2
    if (!keys->Get(context, i).ToLocal(&key))
286
      return Nothing<bool>();
287
2
    if (!key->IsString()) continue;
288
289
    Local<Value> value;
290
    Local<String> value_string;
291


7
    if (!entries->Get(context, key.As<String>()).ToLocal(&value) ||
292
3
        !value->ToString(context).ToLocal(&value_string)) {
293
      return Nothing<bool>();
294
    }
295
296
2
    Set(isolate, key.As<String>(), value_string);
297
  }
298
1
  return Just(true);
299
}
300
301
529958
static void EnvGetter(Local<Name> property,
302
                      const PropertyCallbackInfo<Value>& info) {
303
529958
  Environment* env = Environment::GetCurrent(info);
304
529958
  if (property->IsSymbol()) {
305
529976
    return info.GetReturnValue().SetUndefined();
306
  }
307
1059898
  CHECK(property->IsString());
308
  info.GetReturnValue().Set(
309
2119796
      env->env_vars()->Get(env->isolate(), property.As<String>()));
310
}
311
312
9357
static void EnvSetter(Local<Name> property,
313
                      Local<Value> value,
314
                      const PropertyCallbackInfo<Value>& info) {
315
9357
  Environment* env = Environment::GetCurrent(info);
316
  // calling env->EmitProcessEnvWarning() sets a variable indicating that
317
  // warnings have been emitted. It should be called last after other
318
  // conditions leading to a warning have been met.
319


28102
  if (env->options()->pending_deprecation && !value->IsString() &&
320

28074
      !value->IsNumber() && !value->IsBoolean() &&
321
1
      env->EmitProcessEnvWarning()) {
322
2
    if (ProcessEmitDeprecationWarning(
323
            env,
324
            "Assigning any value other than a string, number, or boolean to a "
325
            "process.env property is deprecated. Please make sure to convert "
326
            "the "
327
            "value to a string before setting process.env with it.",
328
            "DEP0104")
329
2
            .IsNothing())
330
2
      return;
331
  }
332
333
  Local<String> key;
334
  Local<String> value_string;
335


56140
  if (!property->ToString(env->context()).ToLocal(&key) ||
336
37425
      !value->ToString(env->context()).ToLocal(&value_string)) {
337
2
    return;
338
  }
339
340
9355
  env->env_vars()->Set(env->isolate(), key, value_string);
341
342
  // Whether it worked or not, always return value.
343
18710
  info.GetReturnValue().Set(value);
344
}
345
346
658950
static void EnvQuery(Local<Name> property,
347
                     const PropertyCallbackInfo<Integer>& info) {
348
658950
  Environment* env = Environment::GetCurrent(info);
349
1317900
  if (property->IsString()) {
350
1317898
    int32_t rc = env->env_vars()->Query(env->isolate(), property.As<String>());
351
1969673
    if (rc != -1) info.GetReturnValue().Set(rc);
352
  }
353
658950
}
354
355
998
static void EnvDeleter(Local<Name> property,
356
                       const PropertyCallbackInfo<Boolean>& info) {
357
998
  Environment* env = Environment::GetCurrent(info);
358
1996
  if (property->IsString()) {
359
1994
    env->env_vars()->Delete(env->isolate(), property.As<String>());
360
  }
361
362
  // process.env never has non-configurable properties, so always
363
  // return true like the tc39 delete operator.
364
1996
  info.GetReturnValue().Set(true);
365
998
}
366
367
5648
static void EnvEnumerator(const PropertyCallbackInfo<Array>& info) {
368
5648
  Environment* env = Environment::GetCurrent(info);
369
370
  info.GetReturnValue().Set(
371
16944
      env->env_vars()->Enumerate(env->isolate()));
372
5648
}
373
374
4651
MaybeLocal<Object> CreateEnvVarProxy(Local<Context> context,
375
                                     Isolate* isolate,
376
                                     Local<Object> data) {
377
4651
  EscapableHandleScope scope(isolate);
378
4651
  Local<ObjectTemplate> env_proxy_template = ObjectTemplate::New(isolate);
379
  env_proxy_template->SetHandler(NamedPropertyHandlerConfiguration(
380
9302
      EnvGetter, EnvSetter, EnvQuery, EnvDeleter, EnvEnumerator, data));
381
9302
  return scope.EscapeMaybe(env_proxy_template->NewInstance(context));
382
}
383

13575
}  // namespace node