GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage/nodes/benchmark/out/../src/node_env_var.cc Lines: 60 60 100.0 %
Date: 2019-01-07 12:15:22 Branches: 31 38 81.6 %

Line Branch Exec Source
1
#include "node_internals.h"
2
#include "node_errors.h"
3
4
#ifdef __APPLE__
5
#include <crt_externs.h>
6
#define environ (*_NSGetEnviron())
7
#elif !defined(_MSC_VER)
8
extern char** environ;
9
#endif
10
11
namespace node {
12
using v8::Array;
13
using v8::Boolean;
14
using v8::Context;
15
using v8::EscapableHandleScope;
16
using v8::Integer;
17
using v8::Isolate;
18
using v8::Local;
19
using v8::Name;
20
using v8::NamedPropertyHandlerConfiguration;
21
using v8::NewStringType;
22
using v8::Object;
23
using v8::ObjectTemplate;
24
using v8::PropertyCallbackInfo;
25
using v8::String;
26
using v8::Value;
27
28
181994
static void EnvGetter(Local<Name> property,
29
                      const PropertyCallbackInfo<Value>& info) {
30
181994
  Isolate* isolate = info.GetIsolate();
31
181994
  if (property->IsSymbol()) {
32
146025
    return info.GetReturnValue().SetUndefined();
33
  }
34
181987
  Mutex::ScopedLock lock(environ_mutex);
35
#ifdef __POSIX__
36
217978
  node::Utf8Value key(isolate, property);
37
181988
  const char* val = getenv(*key);
38
181988
  if (val) {
39
    return info.GetReturnValue().Set(
40
        String::NewFromUtf8(isolate, val, NewStringType::kNormal)
41
437994
            .ToLocalChecked());
42
35990
  }
43
#else  // _WIN32
44
  node::TwoByteValue key(isolate, property);
45
  WCHAR buffer[32767];  // The maximum size allowed for environment variables.
46
  SetLastError(ERROR_SUCCESS);
47
  DWORD result = GetEnvironmentVariableW(
48
      reinterpret_cast<WCHAR*>(*key), buffer, arraysize(buffer));
49
  // If result >= sizeof buffer the buffer was too small. That should never
50
  // happen. If result == 0 and result != ERROR_SUCCESS the variable was not
51
  // found.
52
  if ((result > 0 || GetLastError() == ERROR_SUCCESS) &&
53
      result < arraysize(buffer)) {
54
    const uint16_t* two_byte_buffer = reinterpret_cast<const uint16_t*>(buffer);
55
    v8::MaybeLocal<String> rc = String::NewFromTwoByte(
56
        isolate, two_byte_buffer, NewStringType::kNormal);
57
    if (rc.IsEmpty()) {
58
      isolate->ThrowException(ERR_STRING_TOO_LONG(isolate));
59
      return;
60
    }
61
    return info.GetReturnValue().Set(rc.ToLocalChecked());
62
  }
63
#endif
64
}
65
66
245
static void EnvSetter(Local<Name> property,
67
                      Local<Value> value,
68
                      const PropertyCallbackInfo<Value>& info) {
69
245
  Environment* env = Environment::GetCurrent(info);
70


737
  if (env->options()->pending_deprecation && env->EmitProcessEnvWarning() &&
71

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