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: 62 62 100.0 %
Date: 2019-02-23 22:23:05 Branches: 34 42 81.0 %

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::Integer;
18
using v8::Isolate;
19
using v8::Local;
20
using v8::MaybeLocal;
21
using v8::Name;
22
using v8::NamedPropertyHandlerConfiguration;
23
using v8::NewStringType;
24
using v8::Object;
25
using v8::ObjectTemplate;
26
using v8::PropertyCallbackInfo;
27
using v8::String;
28
using v8::Value;
29
30
namespace per_process {
31
4288
Mutex env_var_mutex;
32
}  // namespace per_process
33
34
429609
static void EnvGetter(Local<Name> property,
35
                      const PropertyCallbackInfo<Value>& info) {
36
429609
  Isolate* isolate = info.GetIsolate();
37
429609
  if (property->IsSymbol()) {
38
389008
    return info.GetReturnValue().SetUndefined();
39
  }
40
429600
  Mutex::ScopedLock lock(per_process::env_var_mutex);
41
#ifdef __POSIX__
42
470219
  node::Utf8Value key(isolate, property);
43
429600
  const char* val = getenv(*key);
44
429600
  if (val) {
45
    return info.GetReturnValue().Set(
46
        String::NewFromUtf8(isolate, val, NewStringType::kNormal)
47
1166943
            .ToLocalChecked());
48
40619
  }
49
#else  // _WIN32
50
  node::TwoByteValue key(isolate, property);
51
  WCHAR buffer[32767];  // The maximum size allowed for environment variables.
52
  SetLastError(ERROR_SUCCESS);
53
  DWORD result = GetEnvironmentVariableW(
54
      reinterpret_cast<WCHAR*>(*key), buffer, arraysize(buffer));
55
  // If result >= sizeof buffer the buffer was too small. That should never
56
  // happen. If result == 0 and result != ERROR_SUCCESS the variable was not
57
  // found.
58
  if ((result > 0 || GetLastError() == ERROR_SUCCESS) &&
59
      result < arraysize(buffer)) {
60
    const uint16_t* two_byte_buffer = reinterpret_cast<const uint16_t*>(buffer);
61
    v8::MaybeLocal<String> rc = String::NewFromTwoByte(
62
        isolate, two_byte_buffer, NewStringType::kNormal);
63
    if (rc.IsEmpty()) {
64
      isolate->ThrowException(ERR_STRING_TOO_LONG(isolate));
65
      return;
66
    }
67
    return info.GetReturnValue().Set(rc.ToLocalChecked());
68
  }
69
#endif
70
}
71
72
7952
static void EnvSetter(Local<Name> property,
73
                      Local<Value> value,
74
                      const PropertyCallbackInfo<Value>& info) {
75
7952
  Environment* env = Environment::GetCurrent(info);
76
  // calling env->EmitProcessEnvWarning() sets a variable indicating that
77
  // warnings have been emitted. It should be called last after other
78
  // conditions leading to a warning have been met.
79


23877
  if (env->options()->pending_deprecation && !value->IsString() &&
80

23859
      !value->IsNumber() && !value->IsBoolean() &&
81
1
      env->EmitProcessEnvWarning()) {
82
2
    if (ProcessEmitDeprecationWarning(
83
            env,
84
            "Assigning any value other than a string, number, or boolean to a "
85
            "process.env property is deprecated. Please make sure to convert "
86
            "the "
87
            "value to a string before setting process.env with it.",
88
            "DEP0104")
89
2
            .IsNothing())
90
7952
      return;
91
  }
92
93
7952
  Mutex::ScopedLock lock(per_process::env_var_mutex);
94
#ifdef __POSIX__
95
15904
  node::Utf8Value key(info.GetIsolate(), property);
96
15904
  node::Utf8Value val(info.GetIsolate(), value);
97
7952
  setenv(*key, *val, 1);
98
#else  // _WIN32
99
  node::TwoByteValue key(info.GetIsolate(), property);
100
  node::TwoByteValue val(info.GetIsolate(), value);
101
  WCHAR* key_ptr = reinterpret_cast<WCHAR*>(*key);
102
  // Environment variables that start with '=' are read-only.
103
  if (key_ptr[0] != L'=') {
104
    SetEnvironmentVariableW(key_ptr, reinterpret_cast<WCHAR*>(*val));
105
  }
106
#endif
107
  // Whether it worked or not, always return value.
108
23856
  info.GetReturnValue().Set(value);
109
}
110
111
491253
static void EnvQuery(Local<Name> property,
112
                     const PropertyCallbackInfo<Integer>& info) {
113
491253
  Mutex::ScopedLock lock(per_process::env_var_mutex);
114
491253
  int32_t rc = -1;  // Not found unless proven otherwise.
115
982506
  if (property->IsString()) {
116
#ifdef __POSIX__
117
491252
    node::Utf8Value key(info.GetIsolate(), property);
118
491252
    if (getenv(*key)) rc = 0;
119
#else  // _WIN32
120
    node::TwoByteValue key(info.GetIsolate(), property);
121
    WCHAR* key_ptr = reinterpret_cast<WCHAR*>(*key);
122
    SetLastError(ERROR_SUCCESS);
123
    if (GetEnvironmentVariableW(key_ptr, nullptr, 0) > 0 ||
124
        GetLastError() == ERROR_SUCCESS) {
125
      rc = 0;
126
      if (key_ptr[0] == L'=') {
127
        // Environment variables that start with '=' are hidden and read-only.
128
        rc = static_cast<int32_t>(v8::ReadOnly) |
129
             static_cast<int32_t>(v8::DontDelete) |
130
             static_cast<int32_t>(v8::DontEnum);
131
      }
132
    }
133
#endif
134
  }
135
1467695
  if (rc != -1) info.GetReturnValue().Set(rc);
136
491253
}
137
138
977
static void EnvDeleter(Local<Name> property,
139
                       const PropertyCallbackInfo<Boolean>& info) {
140
977
  Mutex::ScopedLock lock(per_process::env_var_mutex);
141
1954
  if (property->IsString()) {
142
#ifdef __POSIX__
143
976
    node::Utf8Value key(info.GetIsolate(), property);
144
976
    unsetenv(*key);
145
#else
146
    node::TwoByteValue key(info.GetIsolate(), property);
147
    WCHAR* key_ptr = reinterpret_cast<WCHAR*>(*key);
148
    SetEnvironmentVariableW(key_ptr, nullptr);
149
#endif
150
  }
151
152
  // process.env never has non-configurable properties, so always
153
  // return true like the tc39 delete operator.
154
1954
  info.GetReturnValue().Set(true);
155
977
}
156
157
4303
static void EnvEnumerator(const PropertyCallbackInfo<Array>& info) {
158
4303
  Environment* env = Environment::GetCurrent(info);
159
4303
  Isolate* isolate = env->isolate();
160
161
4303
  Mutex::ScopedLock lock(per_process::env_var_mutex);
162
  Local<Array> envarr;
163
4303
  int env_size = 0;
164
#ifdef __POSIX__
165
282497
  while (environ[env_size]) {
166
273891
    env_size++;
167
  }
168
8606
  std::vector<Local<Value>> env_v(env_size);
169
170
278194
  for (int i = 0; i < env_size; ++i) {
171
273891
    const char* var = environ[i];
172
273891
    const char* s = strchr(var, '=');
173
273891
    const int length = s ? s - var : strlen(var);
174
273891
    env_v[i] = String::NewFromUtf8(isolate, var, NewStringType::kNormal, length)
175
547782
                   .ToLocalChecked();
176
  }
177
#else  // _WIN32
178
  std::vector<Local<Value>> env_v;
179
  WCHAR* environment = GetEnvironmentStringsW();
180
  if (environment == nullptr) return;  // This should not happen.
181
  WCHAR* p = environment;
182
  while (*p) {
183
    WCHAR* s;
184
    if (*p == L'=') {
185
      // If the key starts with '=' it is a hidden environment variable.
186
      p += wcslen(p) + 1;
187
      continue;
188
    } else {
189
      s = wcschr(p, L'=');
190
    }
191
    if (!s) {
192
      s = p + wcslen(p);
193
    }
194
    const uint16_t* two_byte_buffer = reinterpret_cast<const uint16_t*>(p);
195
    const size_t two_byte_buffer_len = s - p;
196
    v8::MaybeLocal<String> rc = String::NewFromTwoByte(
197
        isolate, two_byte_buffer, NewStringType::kNormal, two_byte_buffer_len);
198
    if (rc.IsEmpty()) {
199
      isolate->ThrowException(ERR_STRING_TOO_LONG(isolate));
200
      FreeEnvironmentStringsW(environment);
201
      return;
202
    }
203
    env_v.push_back(rc.ToLocalChecked());
204
    p = s + wcslen(s) + 1;
205
  }
206
  FreeEnvironmentStringsW(environment);
207
#endif
208
209
4303
  envarr = Array::New(isolate, env_v.data(), env_v.size());
210
12909
  info.GetReturnValue().Set(envarr);
211
4303
}
212
213
4405
MaybeLocal<Object> CreateEnvVarProxy(Local<Context> context,
214
                                     Isolate* isolate,
215
                                     Local<Value> data) {
216
4405
  EscapableHandleScope scope(isolate);
217
4405
  Local<ObjectTemplate> env_proxy_template = ObjectTemplate::New(isolate);
218
  env_proxy_template->SetHandler(NamedPropertyHandlerConfiguration(
219
8810
      EnvGetter, EnvSetter, EnvQuery, EnvDeleter, EnvEnumerator, data));
220
8810
  return scope.EscapeMaybe(env_proxy_template->NewInstance(context));
221
}
222

12864
}  // namespace node