Skip to content

Commit 20560e0

Browse files
committed
Expose ModifyCodeGenerationFromStrings callback
1 parent 3ffe0d7 commit 20560e0

File tree

4 files changed

+91
-0
lines changed

4 files changed

+91
-0
lines changed

src/binding.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,12 @@ void v8__Isolate__SetUseCounterCallback(
284284
isolate->SetUseCounterCallback(callback);
285285
}
286286

287+
void v8__Isolate__SetModifyCodeGenerationFromStringsCallback(
288+
v8::Isolate* isolate,
289+
v8::ModifyCodeGenerationFromStringsCallback2 callback) {
290+
isolate->SetModifyCodeGenerationFromStringsCallback(callback);
291+
}
292+
287293
bool v8__Isolate__AddMessageListener(v8::Isolate* isolate,
288294
v8::MessageCallback callback) {
289295
return isolate->AddMessageListener(callback);

src/isolate.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -554,6 +554,22 @@ pub struct OomDetails {
554554
pub type OomErrorCallback =
555555
unsafe extern "C" fn(location: *const char, details: &OomDetails);
556556

557+
#[repr(C)]
558+
pub struct ModifyCodeGenerationFromStringsResult<'s> {
559+
pub codegen_allowed: bool,
560+
pub modified_source: Option<Local<'s, String>>,
561+
}
562+
563+
// We use Option<NonNull<T>> which _is_ FFI-safe.
564+
// See https://doc.rust-lang.org/nomicon/other-reprs.html
565+
#[allow(improper_ctypes_definitions)]
566+
pub type ModifyCodeGenerationFromStringsCallback<'s> =
567+
extern "C" fn(
568+
context: Local<'s, Context>,
569+
source: Local<'s, Value>,
570+
is_code_like: bool,
571+
) -> ModifyCodeGenerationFromStringsResult<'s>;
572+
557573
// Windows x64 ABI: MaybeLocal<Value> returned on the stack.
558574
#[cfg(target_os = "windows")]
559575
pub type PrepareStackTraceCallback<'s> =
@@ -713,6 +729,13 @@ unsafe extern "C" {
713729
isolate: *mut Isolate,
714730
callback: UseCounterCallback,
715731
);
732+
// We use Option<NonNull<T>> which _is_ FFI-safe.
733+
// See https://doc.rust-lang.org/nomicon/other-reprs.html
734+
#[allow(improper_ctypes)]
735+
fn v8__Isolate__SetModifyCodeGenerationFromStringsCallback(
736+
isolate: *mut Isolate,
737+
callback: ModifyCodeGenerationFromStringsCallback,
738+
);
716739
fn v8__Isolate__RequestInterrupt(
717740
isolate: *const Isolate,
718741
callback: InterruptCallback,
@@ -1405,6 +1428,20 @@ impl Isolate {
14051428
unsafe { v8__Isolate__RemoveGCEpilogueCallback(self, callback, data) }
14061429
}
14071430

1431+
/// This specifies the callback called by v8 when JS is trying to dynamically execute
1432+
/// code using `eval` or the `Function` constructor.
1433+
///
1434+
/// The callback can decide whether to allow code generation and, if so, modify
1435+
/// the source code beforehand.
1436+
pub fn set_modify_code_generation_from_strings_callback(
1437+
&mut self,
1438+
callback: ModifyCodeGenerationFromStringsCallback,
1439+
) {
1440+
unsafe {
1441+
v8__Isolate__SetModifyCodeGenerationFromStringsCallback(self, callback)
1442+
}
1443+
}
1444+
14081445
/// Add a callback to invoke in case the heap size is close to the heap limit.
14091446
/// If multiple callbacks are added, only the most recently added callback is
14101447
/// invoked.

src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,8 @@ pub use isolate::MemoryPressureLevel;
116116
pub use isolate::MessageCallback;
117117
pub use isolate::MessageErrorLevel;
118118
pub use isolate::MicrotasksPolicy;
119+
pub use isolate::ModifyCodeGenerationFromStringsCallback;
120+
pub use isolate::ModifyCodeGenerationFromStringsResult;
119121
pub use isolate::ModuleImportPhase;
120122
pub use isolate::NearHeapLimitCallback;
121123
pub use isolate::OomDetails;

tests/test_api.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12018,6 +12018,52 @@ fn use_counter_callback() {
1201812018
assert_eq!(COUNT.load(Ordering::Relaxed), 1);
1201912019
}
1202012020

12021+
#[test]
12022+
fn code_generation_from_strings_callback() {
12023+
static CODEGEN_ALLOWED: AtomicBool = AtomicBool::new(false);
12024+
static COUNT: AtomicUsize = AtomicUsize::new(0);
12025+
12026+
#[allow(improper_ctypes_definitions)]
12027+
extern "C" fn callback<'s>(
12028+
_context: v8::Local<'s, v8::Context>,
12029+
_source: v8::Local<'s, v8::Value>,
12030+
_is_code_like: bool,
12031+
) -> v8::ModifyCodeGenerationFromStringsResult<'s> {
12032+
COUNT.fetch_add(1, Ordering::Relaxed);
12033+
v8::ModifyCodeGenerationFromStringsResult {
12034+
codegen_allowed: CODEGEN_ALLOWED.load(Ordering::Relaxed),
12035+
modified_source: None,
12036+
}
12037+
}
12038+
12039+
let _setup_guard = setup::parallel_test();
12040+
let mut isolate = v8::Isolate::new(Default::default());
12041+
isolate.set_modify_code_generation_from_strings_callback(callback);
12042+
let mut scope = v8::HandleScope::new(&mut isolate);
12043+
let context = v8::Context::new(&mut scope, Default::default());
12044+
// Must be set to false, otherwise code generation is unconditionally allowed and the callback is never used
12045+
context.set_allow_generation_from_strings(false);
12046+
12047+
let scope = &mut v8::ContextScope::new(&mut scope, context);
12048+
12049+
// Code generation should be disallowed
12050+
{
12051+
let tc = &mut v8::TryCatch::new(scope);
12052+
eval(tc, "eval('1 + 1')");
12053+
assert_eq!(
12054+
tc.message().unwrap().get(tc).to_rust_string_lossy(tc),
12055+
"Uncaught EvalError: Code generation from strings disallowed for this context"
12056+
);
12057+
assert_eq!(COUNT.load(Ordering::Relaxed), 1);
12058+
}
12059+
12060+
// Enable code generation
12061+
CODEGEN_ALLOWED.store(true, Ordering::Relaxed);
12062+
let result: Option<v8::Local<'_, v8::Value>> = eval(scope, "eval('1 + 1')");
12063+
assert_eq!(result.unwrap().number_value(scope).unwrap(), 2.0);
12064+
assert_eq!(COUNT.load(Ordering::Relaxed), 2);
12065+
}
12066+
1202112067
#[test]
1202212068
fn test_eternals() {
1202312069
let _setup_guard = setup::parallel_test();

0 commit comments

Comments
 (0)