Skip to content

Commit 56377d6

Browse files
ExE-Bosstargos
authored andcommitted
lib: support returning Safe collections from C++
Co-authored-by: Antoine du Hamel <duhamelantoine1995@gmail.com> PR-URL: #36989 Refs: #36652 Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent 0129a79 commit 56377d6

File tree

5 files changed

+59
-0
lines changed

5 files changed

+59
-0
lines changed

src/env.cc

+23
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,29 @@ void Environment::CreateProperties() {
277277
CHECK(primordials->IsObject());
278278
set_primordials(primordials.As<Object>());
279279

280+
Local<String> prototype_string =
281+
FIXED_ONE_BYTE_STRING(isolate(), "prototype");
282+
283+
#define V(EnvPropertyName, PrimordialsPropertyName) \
284+
{ \
285+
Local<Value> ctor = \
286+
primordials.As<Object>() \
287+
->Get(ctx, \
288+
FIXED_ONE_BYTE_STRING(isolate(), PrimordialsPropertyName)) \
289+
.ToLocalChecked(); \
290+
CHECK(ctor->IsObject()); \
291+
Local<Value> prototype = \
292+
ctor.As<Object>()->Get(ctx, prototype_string).ToLocalChecked(); \
293+
CHECK(prototype->IsObject()); \
294+
set_##EnvPropertyName(prototype.As<Object>()); \
295+
}
296+
297+
V(primordials_safe_map_prototype_object, "SafeMap");
298+
V(primordials_safe_set_prototype_object, "SafeSet");
299+
V(primordials_safe_weak_map_prototype_object, "SafeWeakMap");
300+
V(primordials_safe_weak_set_prototype_object, "SafeWeakSet");
301+
#undef V
302+
280303
Local<Object> process_object =
281304
node::CreateProcessObject(this).FromMaybe(Local<Object>());
282305
set_process_object(process_object);

src/env.h

+4
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,10 @@ constexpr size_t kFsStatsBufferLength =
550550
V(prepare_stack_trace_callback, v8::Function) \
551551
V(process_object, v8::Object) \
552552
V(primordials, v8::Object) \
553+
V(primordials_safe_map_prototype_object, v8::Object) \
554+
V(primordials_safe_set_prototype_object, v8::Object) \
555+
V(primordials_safe_weak_map_prototype_object, v8::Object) \
556+
V(primordials_safe_weak_set_prototype_object, v8::Object) \
553557
V(promise_hook_handler, v8::Function) \
554558
V(promise_reject_callback, v8::Function) \
555559
V(script_data_constructor_function, v8::Function) \

src/node_options.cc

+12
Original file line numberDiff line numberDiff line change
@@ -917,6 +917,12 @@ void GetOptions(const FunctionCallbackInfo<Value>& args) {
917917
});
918918

919919
Local<Map> options = Map::New(isolate);
920+
if (options
921+
->SetPrototype(context, env->primordials_safe_map_prototype_object())
922+
.IsNothing()) {
923+
return;
924+
}
925+
920926
for (const auto& item : _ppop_instance.options_) {
921927
Local<Value> value;
922928
const auto& option_info = item.second;
@@ -1005,6 +1011,12 @@ void GetOptions(const FunctionCallbackInfo<Value>& args) {
10051011
Local<Value> aliases;
10061012
if (!ToV8Value(context, _ppop_instance.aliases_).ToLocal(&aliases)) return;
10071013

1014+
if (aliases.As<Object>()
1015+
->SetPrototype(context, env->primordials_safe_map_prototype_object())
1016+
.IsNothing()) {
1017+
return;
1018+
}
1019+
10081020
Local<Object> ret = Object::New(isolate);
10091021
if (ret->Set(context, env->options_string(), options).IsNothing() ||
10101022
ret->Set(context, env->aliases_string(), aliases).IsNothing()) {

src/uv.cc

+2
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@ void GetErrMap(const FunctionCallbackInfo<Value>& args) {
8181
Isolate* isolate = env->isolate();
8282
Local<Context> context = env->context();
8383

84+
// This can't return a SafeMap, because the uv binding can be referenced
85+
// by user code by using `process.binding('uv').getErrorMap()`:
8486
Local<Map> err_map = Map::New(isolate);
8587

8688
size_t errors_len = arraysize(per_process::uv_errors_map);

test/parallel/test-options-binding.js

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Flags: --expose-internals
2+
'use strict';
3+
4+
const common = require('../common');
5+
const { primordials: { SafeMap } } = require('internal/test/binding');
6+
7+
const { options, aliases, getOptionValue } = require('internal/options');
8+
const assert = require('assert');
9+
10+
assert(options instanceof SafeMap,
11+
"require('internal/options').options is a SafeMap");
12+
13+
assert(aliases instanceof SafeMap,
14+
"require('internal/options').aliases is a SafeMap");
15+
16+
Map.prototype.get =
17+
common.mustNotCall('`getOptionValue` must not call user-mutable method');
18+
assert.strictEqual(getOptionValue('--expose-internals'), true);

0 commit comments

Comments
 (0)