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: 148 155 95.5 %
Date: 2019-07-27 22:37:30 Branches: 71 98 72.4 %

Line Branch Exec Source
1
#include "env-inl.h"
2
#include "node_errors.h"
3
#include "node_process.h"
4
5
#include <time.h>  // tzset(), _tzset()
6
7
#ifdef __APPLE__
8
#include <crt_externs.h>
9
#define environ (*_NSGetEnviron())
10
#elif !defined(_MSC_VER)
11
extern char** environ;
12
#endif
13
14
namespace node {
15
using v8::Array;
16
using v8::Boolean;
17
using v8::Context;
18
using v8::EscapableHandleScope;
19
using v8::HandleScope;
20
using v8::Integer;
21
using v8::Isolate;
22
using v8::Just;
23
using v8::Local;
24
using v8::Maybe;
25
using v8::MaybeLocal;
26
using v8::Name;
27
using v8::NamedPropertyHandlerConfiguration;
28
using v8::NewStringType;
29
using v8::Nothing;
30
using v8::Object;
31
using v8::ObjectTemplate;
32
using v8::PropertyCallbackInfo;
33
using v8::PropertyHandlerFlags;
34
using v8::String;
35
using v8::Value;
36
37
9269
class RealEnvStore final : public KVStore {
38
 public:
39
  Local<String> Get(Isolate* isolate, Local<String> key) const override;
40
  void Set(Isolate* isolate, Local<String> key, Local<String> value) override;
41
  int32_t Query(Isolate* isolate, Local<String> key) const override;
42
  void Delete(Isolate* isolate, Local<String> key) override;
43
  Local<Array> Enumerate(Isolate* isolate) const override;
44
};
45
46
204
class MapKVStore final : public KVStore {
47
 public:
48
  Local<String> Get(Isolate* isolate, Local<String> key) const override;
49
  void Set(Isolate* isolate, Local<String> key, Local<String> value) override;
50
  int32_t Query(Isolate* isolate, Local<String> key) const override;
51
  void Delete(Isolate* isolate, Local<String> key) override;
52
  Local<Array> Enumerate(Isolate* isolate) const override;
53
54
  std::shared_ptr<KVStore> Clone(Isolate* isolate) const override;
55
56
204
  MapKVStore() = default;
57
1
  MapKVStore(const MapKVStore& other) : map_(other.map_) {}
58
59
 private:
60
  mutable Mutex mutex_;
61
  std::unordered_map<std::string, std::string> map_;
62
};
63
64
namespace per_process {
65
4832
Mutex env_var_mutex;
66
4832
std::shared_ptr<KVStore> system_environment = std::make_shared<RealEnvStore>();
67
}  // namespace per_process
68
69
template <typename T>
70
13677
void DateTimeConfigurationChangeNotification(Isolate* isolate, const T& key) {
71


13677
  if (key.length() == 2 && key[0] == 'T' && key[1] == 'Z') {
72
#ifdef __POSIX__
73
4
    tzset();
74
#else
75
    _tzset();
76
#endif
77
4
    auto constexpr time_zone_detection = Isolate::TimeZoneDetection::kRedetect;
78
4
    isolate->DateTimeConfigurationChangeNotification(time_zone_detection);
79
  }
80
13677
}
81
82
871948
Local<String> RealEnvStore::Get(Isolate* isolate,
83
                                Local<String> property) const {
84
871948
  Mutex::ScopedLock lock(per_process::env_var_mutex);
85
#ifdef __POSIX__
86
1743896
  node::Utf8Value key(isolate, property);
87
871948
  const char* val = getenv(*key);
88
871948
  if (val) {
89
    return String::NewFromUtf8(isolate, val, NewStringType::kNormal)
90
1624464
        .ToLocalChecked();
91
  }
92
#else  // _WIN32
93
  node::TwoByteValue key(isolate, property);
94
  WCHAR buffer[32767];  // The maximum size allowed for environment variables.
95
  SetLastError(ERROR_SUCCESS);
96
  DWORD result = GetEnvironmentVariableW(
97
      reinterpret_cast<WCHAR*>(*key), buffer, arraysize(buffer));
98
  // If result >= sizeof buffer the buffer was too small. That should never
99
  // happen. If result == 0 and result != ERROR_SUCCESS the variable was not
100
  // found.
101
  if ((result > 0 || GetLastError() == ERROR_SUCCESS) &&
102
      result < arraysize(buffer)) {
103
    const uint16_t* two_byte_buffer = reinterpret_cast<const uint16_t*>(buffer);
104
    v8::MaybeLocal<String> rc = String::NewFromTwoByte(
105
        isolate, two_byte_buffer, NewStringType::kNormal);
106
    if (rc.IsEmpty()) {
107
      isolate->ThrowException(ERR_STRING_TOO_LONG(isolate));
108
      return Local<String>();
109
    }
110
    return rc.ToLocalChecked();
111
  }
112
#endif
113
931664
  return Local<String>();
114
}
115
116
12678
void RealEnvStore::Set(Isolate* isolate,
117
                       Local<String> property,
118
                       Local<String> value) {
119
12678
  Mutex::ScopedLock lock(per_process::env_var_mutex);
120
#ifdef __POSIX__
121
25356
  node::Utf8Value key(isolate, property);
122
25356
  node::Utf8Value val(isolate, value);
123
12678
  setenv(*key, *val, 1);
124
#else  // _WIN32
125
  node::TwoByteValue key(isolate, property);
126
  node::TwoByteValue val(isolate, value);
127
  WCHAR* key_ptr = reinterpret_cast<WCHAR*>(*key);
128
  // Environment variables that start with '=' are read-only.
129
  if (key_ptr[0] != L'=') {
130
    SetEnvironmentVariableW(key_ptr, reinterpret_cast<WCHAR*>(*val));
131
  }
132
#endif
133
25356
  DateTimeConfigurationChangeNotification(isolate, key);
134
12678
}
135
136
1275583
int32_t RealEnvStore::Query(Isolate* isolate, Local<String> property) const {
137
1275583
  Mutex::ScopedLock lock(per_process::env_var_mutex);
138
#ifdef __POSIX__
139
2551166
  node::Utf8Value key(isolate, property);
140
1275583
  if (getenv(*key)) return 0;
141
#else  // _WIN32
142
  node::TwoByteValue key(isolate, property);
143
  WCHAR* key_ptr = reinterpret_cast<WCHAR*>(*key);
144
  SetLastError(ERROR_SUCCESS);
145
  if (GetEnvironmentVariableW(key_ptr, nullptr, 0) > 0 ||
146
      GetLastError() == ERROR_SUCCESS) {
147
    if (key_ptr[0] == L'=') {
148
      // Environment variables that start with '=' are hidden and read-only.
149
      return static_cast<int32_t>(v8::ReadOnly) |
150
             static_cast<int32_t>(v8::DontDelete) |
151
             static_cast<int32_t>(v8::DontEnum);
152
    }
153
    return 0;
154
  }
155
#endif
156
1280936
  return -1;
157
}
158
159
999
void RealEnvStore::Delete(Isolate* isolate, Local<String> property) {
160
999
  Mutex::ScopedLock lock(per_process::env_var_mutex);
161
#ifdef __POSIX__
162
1998
  node::Utf8Value key(isolate, property);
163
999
  unsetenv(*key);
164
#else
165
  node::TwoByteValue key(isolate, property);
166
  WCHAR* key_ptr = reinterpret_cast<WCHAR*>(*key);
167
  SetEnvironmentVariableW(key_ptr, nullptr);
168
#endif
169
1998
  DateTimeConfigurationChangeNotification(isolate, key);
170
999
}
171
172
12484
Local<Array> RealEnvStore::Enumerate(Isolate* isolate) const {
173
12484
  Mutex::ScopedLock lock(per_process::env_var_mutex);
174
#ifdef __POSIX__
175
12484
  int env_size = 0;
176
821577
  while (environ[env_size]) {
177
796609
    env_size++;
178
  }
179
24968
  std::vector<Local<Value>> env_v(env_size);
180
181
809093
  for (int i = 0; i < env_size; ++i) {
182
796609
    const char* var = environ[i];
183
796609
    const char* s = strchr(var, '=');
184
796609
    const int length = s ? s - var : strlen(var);
185
796609
    env_v[i] = String::NewFromUtf8(isolate, var, NewStringType::kNormal, length)
186
1593218
                   .ToLocalChecked();
187
  }
188
#else  // _WIN32
189
  std::vector<Local<Value>> env_v;
190
  WCHAR* environment = GetEnvironmentStringsW();
191
  if (environment == nullptr)
192
    return Array::New(isolate);  // This should not happen.
193
  WCHAR* p = environment;
194
  while (*p) {
195
    WCHAR* s;
196
    if (*p == L'=') {
197
      // If the key starts with '=' it is a hidden environment variable.
198
      p += wcslen(p) + 1;
199
      continue;
200
    } else {
201
      s = wcschr(p, L'=');
202
    }
203
    if (!s) {
204
      s = p + wcslen(p);
205
    }
206
    const uint16_t* two_byte_buffer = reinterpret_cast<const uint16_t*>(p);
207
    const size_t two_byte_buffer_len = s - p;
208
    v8::MaybeLocal<String> rc = String::NewFromTwoByte(
209
        isolate, two_byte_buffer, NewStringType::kNormal, two_byte_buffer_len);
210
    if (rc.IsEmpty()) {
211
      isolate->ThrowException(ERR_STRING_TOO_LONG(isolate));
212
      FreeEnvironmentStringsW(environment);
213
      return Local<Array>();
214
    }
215
    env_v.push_back(rc.ToLocalChecked());
216
    p = s + wcslen(s) + 1;
217
  }
218
  FreeEnvironmentStringsW(environment);
219
#endif
220
221
24968
  return Array::New(isolate, env_v.data(), env_v.size());
222
}
223
224
203
std::shared_ptr<KVStore> KVStore::Clone(v8::Isolate* isolate) const {
225
203
  HandleScope handle_scope(isolate);
226
203
  Local<Context> context = isolate->GetCurrentContext();
227
228
203
  std::shared_ptr<KVStore> copy = KVStore::CreateMapKVStore();
229
203
  Local<Array> keys = Enumerate(isolate);
230
203
  uint32_t keys_length = keys->Length();
231
13031
  for (uint32_t i = 0; i < keys_length; i++) {
232
25656
    Local<Value> key = keys->Get(context, i).ToLocalChecked();
233
25656
    CHECK(key->IsString());
234
38484
    copy->Set(isolate, key.As<String>(), Get(isolate, key.As<String>()));
235
  }
236
203
  return copy;
237
}
238
239
25228
Local<String> MapKVStore::Get(Isolate* isolate, Local<String> key) const {
240
25228
  Mutex::ScopedLock lock(mutex_);
241
50456
  Utf8Value str(isolate, key);
242
25228
  auto it = map_.find(std::string(*str, str.length()));
243
26249
  if (it == map_.end()) return Local<String>();
244
24207
  return String::NewFromUtf8(isolate, it->second.data(),
245
48414
                             NewStringType::kNormal, it->second.size())
246
73642
      .ToLocalChecked();
247
}
248
249
12833
void MapKVStore::Set(Isolate* isolate, Local<String> key, Local<String> value) {
250
12833
  Mutex::ScopedLock lock(mutex_);
251
25666
  Utf8Value key_str(isolate, key);
252
25666
  Utf8Value value_str(isolate, value);
253

12833
  if (*key_str != nullptr && *value_str != nullptr) {
254
38499
    map_[std::string(*key_str, key_str.length())] =
255
25666
        std::string(*value_str, value_str.length());
256
12833
  }
257
12833
}
258
259
46832
int32_t MapKVStore::Query(Isolate* isolate, Local<String> key) const {
260
46832
  Mutex::ScopedLock lock(mutex_);
261
93664
  Utf8Value str(isolate, key);
262
46832
  auto it = map_.find(std::string(*str, str.length()));
263
93664
  return it == map_.end() ? -1 : 0;
264
}
265
266
void MapKVStore::Delete(Isolate* isolate, Local<String> key) {
267
  Mutex::ScopedLock lock(mutex_);
268
  Utf8Value str(isolate, key);
269
  map_.erase(std::string(*str, str.length()));
270
}
271
272
718
Local<Array> MapKVStore::Enumerate(Isolate* isolate) const {
273
718
  Mutex::ScopedLock lock(mutex_);
274
1436
  std::vector<Local<Value>> values;
275
718
  values.reserve(map_.size());
276
47123
  for (const auto& pair : map_) {
277
    values.emplace_back(
278
        String::NewFromUtf8(isolate, pair.first.data(),
279
46405
                            NewStringType::kNormal, pair.first.size())
280
92810
            .ToLocalChecked());
281
  }
282
1436
  return Array::New(isolate, values.data(), values.size());
283
}
284
285
1
std::shared_ptr<KVStore> MapKVStore::Clone(Isolate* isolate) const {
286
1
  return std::make_shared<MapKVStore>(*this);
287
}
288
289
204
std::shared_ptr<KVStore> KVStore::CreateMapKVStore() {
290
204
  return std::make_shared<MapKVStore>();
291
}
292
293
1
Maybe<bool> KVStore::AssignFromObject(Local<Context> context,
294
                                      Local<Object> entries) {
295
1
  Isolate* isolate = context->GetIsolate();
296
1
  HandleScope handle_scope(isolate);
297
  Local<Array> keys;
298
2
  if (!entries->GetOwnPropertyNames(context).ToLocal(&keys))
299
    return Nothing<bool>();
300
1
  uint32_t keys_length = keys->Length();
301
2
  for (uint32_t i = 0; i < keys_length; i++) {
302
    Local<Value> key;
303
2
    if (!keys->Get(context, i).ToLocal(&key))
304
      return Nothing<bool>();
305
2
    if (!key->IsString()) continue;
306
307
    Local<Value> value;
308
    Local<String> value_string;
309


7
    if (!entries->Get(context, key.As<String>()).ToLocal(&value) ||
310
3
        !value->ToString(context).ToLocal(&value_string)) {
311
      return Nothing<bool>();
312
    }
313
314
2
    Set(isolate, key.As<String>(), value_string);
315
  }
316
1
  return Just(true);
317
}
318
319
870908
static void EnvGetter(Local<Name> property,
320
                      const PropertyCallbackInfo<Value>& info) {
321
870908
  Environment* env = Environment::GetCurrent(info);
322
870908
  if (property->IsSymbol()) {
323
883868
    return info.GetReturnValue().SetUndefined();
324
  }
325
1728856
  CHECK(property->IsString());
326
  info.GetReturnValue().Set(
327
3457712
      env->env_vars()->Get(env->isolate(), property.As<String>()));
328
}
329
330
12684
static void EnvSetter(Local<Name> property,
331
                      Local<Value> value,
332
                      const PropertyCallbackInfo<Value>& info) {
333
12684
  Environment* env = Environment::GetCurrent(info);
334
  // calling env->EmitProcessEnvWarning() sets a variable indicating that
335
  // warnings have been emitted. It should be called last after other
336
  // conditions leading to a warning have been met.
337


38083
  if (env->options()->pending_deprecation && !value->IsString() &&
338

38055
      !value->IsNumber() && !value->IsBoolean() &&
339
1
      env->EmitProcessEnvWarning()) {
340
2
    if (ProcessEmitDeprecationWarning(
341
            env,
342
            "Assigning any value other than a string, number, or boolean to a "
343
            "process.env property is deprecated. Please make sure to convert "
344
            "the "
345
            "value to a string before setting process.env with it.",
346
            "DEP0104")
347
2
            .IsNothing())
348
2
      return;
349
  }
350
351
  Local<String> key;
352
  Local<String> value_string;
353


76102
  if (!property->ToString(env->context()).ToLocal(&key) ||
354
50733
      !value->ToString(env->context()).ToLocal(&value_string)) {
355
2
    return;
356
  }
357
358
12682
  env->env_vars()->Set(env->isolate(), key, value_string);
359
360
  // Whether it worked or not, always return value.
361
25364
  info.GetReturnValue().Set(value);
362
}
363
364
1322416
static void EnvQuery(Local<Name> property,
365
                     const PropertyCallbackInfo<Integer>& info) {
366
1322416
  Environment* env = Environment::GetCurrent(info);
367
2644832
  if (property->IsString()) {
368
2644830
    int32_t rc = env->env_vars()->Query(env->isolate(), property.As<String>());
369
3955817
    if (rc != -1) info.GetReturnValue().Set(rc);
370
  }
371
1322416
}
372
373
1000
static void EnvDeleter(Local<Name> property,
374
                       const PropertyCallbackInfo<Boolean>& info) {
375
1000
  Environment* env = Environment::GetCurrent(info);
376
2000
  if (property->IsString()) {
377
1998
    env->env_vars()->Delete(env->isolate(), property.As<String>());
378
  }
379
380
  // process.env never has non-configurable properties, so always
381
  // return true like the tc39 delete operator.
382
2000
  info.GetReturnValue().Set(true);
383
1000
}
384
385
12999
static void EnvEnumerator(const PropertyCallbackInfo<Array>& info) {
386
12999
  Environment* env = Environment::GetCurrent(info);
387
388
  info.GetReturnValue().Set(
389
38997
      env->env_vars()->Enumerate(env->isolate()));
390
12999
}
391
392
4966
MaybeLocal<Object> CreateEnvVarProxy(Local<Context> context,
393
                                     Isolate* isolate,
394
                                     Local<Object> data) {
395
4966
  EscapableHandleScope scope(isolate);
396
4966
  Local<ObjectTemplate> env_proxy_template = ObjectTemplate::New(isolate);
397
  env_proxy_template->SetHandler(NamedPropertyHandlerConfiguration(
398
      EnvGetter, EnvSetter, EnvQuery, EnvDeleter, EnvEnumerator, data,
399
9932
      PropertyHandlerFlags::kHasNoSideEffect));
400
9932
  return scope.EscapeMaybe(env_proxy_template->NewInstance(context));
401
}
402

14496
}  // namespace node