-
Notifications
You must be signed in to change notification settings - Fork 29.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
vm: add code generation options #19016
Conversation
35f2f7c
to
ade9c38
Compare
src/node_contextify.cc
Outdated
@@ -184,6 +184,32 @@ Local<Context> ContextifyContext::CreateV8Context( | |||
CHECK(name->IsString()); | |||
Utf8Value name_val(env->isolate(), name); | |||
|
|||
Local<Value> codegen = options_obj->Get(env->context(), | |||
FIXED_ONE_BYTE_STRING(env->isolate(), "codeGeneration")) | |||
.ToLocalChecked(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you use 4 spaces indentation for these lines as well, like other statement continuations?
src/node_contextify.cc
Outdated
.ToLocalChecked(); | ||
if (!allowwcg->IsUndefined()) { | ||
CHECK(allowwcg->IsBoolean()); | ||
if(allowwcg.As<Boolean>()->Value() == false) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Style nit: space after if
src/node_contextify.cc
Outdated
if (!allowwcg->IsUndefined()) { | ||
CHECK(allowwcg->IsBoolean()); | ||
if(allowwcg.As<Boolean>()->Value() == false) | ||
ctx->SetEmbedderData(kAllowWasmCodeGeneration, True(env->isolate())); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Am I missing something? Shouldn’t this be true? (Or you could probably set the field directly to allowwcg
)
test/parallel/test-vm-codegen.js
Outdated
{ | ||
const ctx = createContext({}, { codeGeneration: { | ||
strings: false, | ||
} }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Style nit: Can you make codeGeneration
have its own three lines?
test/parallel/test-vm-codegen.js
Outdated
|
||
const ctx = createContext({ bytes }, { codeGeneration: { | ||
wasm: false, | ||
} }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
src/node.cc
Outdated
CHECK(wcg->IsBoolean()); | ||
return wcg.As<Boolean>()->Value(); | ||
} | ||
return true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could be just return wcg->IsTrue();
(also below.)
src/node_contextify.cc
Outdated
CHECK(allowwcg->IsBoolean()); | ||
if(allowwcg.As<Boolean>()->Value() == false) | ||
ctx->SetEmbedderData(kAllowWasmCodeGeneration, True(env->isolate())); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Apropos the variable names, allow_wasm_code_generation
is clearer than allowwcg
.
src/node_contextify.cc
Outdated
CHECK(codegen->IsObject()); | ||
Local<Object> codegen_obj = codegen.As<Object>(); | ||
|
||
Local<Value> allowcgfs = codegen_obj->Get(env->context(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Naming: allow_code_generation_from_strings
src/node_contextify.cc
Outdated
ctx->AllowCodeGenerationFromStrings(allowcgfs.As<Boolean>()->Value()); | ||
} | ||
|
||
Local<Value> allowwcg = codegen_obj->Get(env->context(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Likewise: allow_wasm_code_generation
src/node.cc
Outdated
@@ -4417,6 +4418,16 @@ inline int Start(uv_loop_t* event_loop, | |||
isolate->SetAbortOnUncaughtExceptionCallback(ShouldAbortOnUncaughtException); | |||
isolate->SetMicrotasksPolicy(v8::MicrotasksPolicy::kExplicit); | |||
isolate->SetFatalErrorHandler(OnFatalError); | |||
isolate->SetAllowWasmCodeGenerationCallback( | |||
[](Local<Context> context, Local<String>) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make this a static member of ContextifyContext?
ade9c38
to
afa8677
Compare
CI also i'm working on some docs now |
83d67bf
to
b52b2e9
Compare
CI failures unrelated @bnoordhuis comments addressed |
src/node_contextify.cc
Outdated
CHECK(wcg->IsBoolean()); | ||
return wcg.As<Boolean>()->Value(); | ||
} | ||
return true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just return wcg->IsUndefined() || wcg->IsTrue();
?
Aside: wasm_code_generation
, or wasm_code_gen
if you think that's too verbose, but no abbrevs.
src/node_contextify.cc
Outdated
if (!allow_code_generation_from_strings->IsUndefined()) { | ||
CHECK(allow_code_generation_from_strings->IsBoolean()); | ||
ctx->AllowCodeGenerationFromStrings( | ||
allow_code_generation_from_strings.As<Boolean>()->Value()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Likewise. You don't even need the if
.
src/node_contextify.cc
Outdated
.ToLocalChecked(); | ||
if (!allow_wasm_code_generation->IsUndefined()) { | ||
CHECK(allow_wasm_code_generation->IsBoolean()); | ||
ctx->SetEmbedderData(kAllowWasmCodeGeneration, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Better set it unconditionally because calling GetEmbedderData() on an undefined index is undefined behavior.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A better idea seems to be setting the slot to false unconditionally in NewContext()
and then override the value in contextity, since the wasm callback is called on the main context as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i'll do tgu's approach
sidenote @nodejs/v8 is there any reason why we don't have Context::AllowWasmCodeGeneration
/can it be added? it seems like the current approach here cause issues for people making native modules and creating a new context under node's isolate? what if someone takes over the callback without realizing that node uses it, etc.
b52b2e9
to
f765a8f
Compare
test/parallel/test-vm-codegen.js
Outdated
fn(); | ||
assert.fail('expected fn to error'); | ||
} catch (err) { | ||
console.log(err); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the console.log()
is an intended part of the test, can you add a comment. Otherwise, please remove it.
@@ -0,0 +1,70 @@ | |||
'use strict'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This also needs tests for unexpected types of contextCodeGeneration
and its properties.
b9f0737
to
c616b4a
Compare
lib/vm.js
Outdated
origin: options.contextOrigin, | ||
codeGeneration: | ||
validateObject(options.contextCodeGeneration, | ||
'options.contextCodeGeneration') ? { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The logic doesn’t currently work when options.contextCodeGeneration
is undefined.
c616b4a
to
7327c16
Compare
lib/vm.js
Outdated
function getContextOptions(options) { | ||
if (options) { | ||
const contextOptions = { | ||
name: options.contextName, | ||
origin: options.contextOrigin | ||
origin: options.contextOrigin, | ||
codeGeneration: options.contextCodeGeneration ? { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The typeof options.contextCodeGeneration === 'object'
check should be kept though.
7327c16
to
83d5ebd
Compare
lib/vm.js
Outdated
} | ||
|
||
function validateObject(prop, propName) { | ||
if (prop !== undefined && prop !== null && typeof prop !== 'object') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for keeping going back and forth on this, but we don’t want to allow null
here right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yea that seems right. I think I accidentally inverted the standard object type check in my head which is why the null is there, I'll fix it
83d5ebd
to
cbccf6c
Compare
lib/vm.js
Outdated
function validateObject(prop, propName) { | ||
if (prop !== undefined && (prop === null || typeof prop !== 'object')) | ||
throw new errors.TypeError('ERR_INVALID_ARG_TYPE', propName, | ||
'object', prop); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should be 'Object'
. I would also rather combine these validation functions instead of having one for each type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how would i combine them
cbccf6c
to
486ead3
Compare
lib/vm.js
Outdated
function validate(type, prop, propName) { | ||
if (prop !== undefined && | ||
((type === 'Object' && prop === null) || | ||
typeof prop !== type.toLowerCase())) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This logic is overly complicated, and would disallow V8 from inlining the typeof check. How it was (one validation function per type) was just fine.
src/node.cc
Outdated
@@ -4442,6 +4445,8 @@ inline int Start(uv_loop_t* event_loop, | |||
isolate->SetAbortOnUncaughtExceptionCallback(ShouldAbortOnUncaughtException); | |||
isolate->SetMicrotasksPolicy(v8::MicrotasksPolicy::kExplicit); | |||
isolate->SetFatalErrorHandler(OnFatalError); | |||
isolate->SetAllowWasmCodeGenerationCallback( | |||
contextify::ContextifyContext::AllowWasmCodeGeneration); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Node.js core shouldn't have to depend on contextify
. Please move AllowWasmCodeGeneration
to node.cc
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@TimothyGu I think this was done by an explicit suggestion from @bnoordhuis … is there any specific reason not to do it this way?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Conceptually, AllowWasmCodeGeneration
is used for all contexts, not just contexts created by contextify
. It feels natural to move this function (which itself doesn't use any contextify-specific machinery) to node.cc.
Sorry for going back and forth on this, I didn't realize @bnoordhuis suggested this way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i agree with timothy, but i'm going to wait for my other context pr to get merged before i work on this more
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IIRC, when I made that suggestion, it was only setting it for ContextifyContext objects. It makes sense to move it back now.
src/node.cc
Outdated
@@ -4347,6 +4348,8 @@ Local<Context> NewContext(Isolate* isolate, | |||
HandleScope handle_scope(isolate); | |||
auto intl_key = FIXED_ONE_BYTE_STRING(isolate, "Intl"); | |||
auto break_iter_key = FIXED_ONE_BYTE_STRING(isolate, "v8BreakIterator"); | |||
context->SetEmbedderData( | |||
contextify::ContextifyContext::kAllowWasmCodeGeneration, True(isolate)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: move this to before intl_key
declaration.
src/node_contextify.h
Outdated
Environment* const env_; | ||
Persistent<v8::Context> context_; | ||
|
||
public: | ||
// V8 reserves the first field in context objects for the debugger. We use the | ||
// second field to hold a reference to the sandbox object. | ||
enum { kSandboxObjectIndex = 1, kAllowWasmCodeGeneration = 2 }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having the indices this way would make non-VM contexts have a hole at index 1, which doesn't sound too desirable. Also, ditto on the "core should not depend on contextify" comment here.
In other words:
- Move
kAllowWasmCodeGeneration
tonode_internals.h
, and set it to 1. KeepkSandboxObjectIndex
here however. - Make
kSandboxObjectIndex
equal tokAllowWasmCodeGeneration + 1
.
You don't have to fix it now (though you certainly could), but "V8 reserves the first field in context objects for the debugger" is no longer true since v8/v8@5f90a6eb067. This means that kAllowWasmCodeGeneration
could just be 0.
Oops, meant to click the "comment" button rather than "approve."
Can you please add a few paragraph to the commit message that explain this change. Thanks! |
.ToLocalChecked(); | ||
|
||
if (!codegen->IsUndefined()) { | ||
CHECK(codegen->IsObject()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could leave a comment here, that the js part already ensured that we have undefined
or an object. Looking only at the C++ part, my first response was that this CHECK
would fail a lot.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this pattern it used a lot with stuff that is validated js-side and we don't leave usually comments, are you worried about something specific not being construed?
throw new ERR_INVALID_ARG_TYPE(propName, 'boolean', prop); | ||
} | ||
|
||
function validateObject(prop, propName) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we rather name this function validateObjectOrUndefined
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
none of the others are named like that, and it seems fairly self-explanatory
Adds options to a VM Context to disable code generation from strings (such as eval or new Function) and WASM code generation (WebAssembly.compile).
43b83d8
to
ecc0e20
Compare
landed in cb5f358 |
Adds options to a VM Context to disable code generation from strings (such as eval or new Function) and WASM code generation (WebAssembly.compile). PR-URL: #19016 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com>
Is there a feature request for this or a usage scenario? |
@jdalton i just have a general agenda of adding as much goodness to vm as possible; i really like vm :D i also am using this in an eval bot i have in a discord support guild for javascript |
This is semver-minor, right? |
Should this be backported to |
looks like 9.x doesn't have v8::Isolate::SetAllowWasmCodeGenerationCallback, maybe it can be cherry picked in? |
Add changes entries for vm.createContext codeGeneration option and script.runInNewContext contextCodeGeneration option. fixes: nodejs#19419 refs: nodejs#19016
Should be backported with #19440 |
Add changes entries for vm.createContext codeGeneration option and script.runInNewContext contextCodeGeneration option. PR-URL: #19440 Fixes: #19419 Refs: #19016 Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: Gus Caplan <me@gus.host> Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
Adds options to a VM Context to disable code generation from strings (such as eval or new Function) and WASM code generation (WebAssembly.compile). PR-URL: nodejs#19016 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com>
Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passesAffected core subsystem(s)
vm, src