diff --git a/README.md b/README.md index bd17bc29a4..937e45a73e 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Rusty V8 Binding -V8 Version: 14.9.207.2 +V8 Version: 15.0.245.2 [![ci](https://github.com/denoland/rusty_v8/workflows/ci/badge.svg?branch=main)](https://github.com/denoland/rusty_v8/actions) [![crates](https://img.shields.io/crates/v/v8.svg)](https://crates.io/crates/v8) diff --git a/build b/build index fffa45f2e9..2aeedfc1aa 160000 --- a/build +++ b/build @@ -1 +1 @@ -Subproject commit fffa45f2e9df48c0230a4c799b7d12e7f83d8219 +Subproject commit 2aeedfc1aae7eca3852cfe921657bc62330baaf9 diff --git a/buildtools b/buildtools index c9110ba715..17495e454a 160000 --- a/buildtools +++ b/buildtools @@ -1 +1 @@ -Subproject commit c9110ba7150d93134b1c85ea392033b4a82d28f7 +Subproject commit 17495e454aae81b581e8b3caccbb53054509b280 diff --git a/src/fast_api.rs b/src/fast_api.rs index 9849d33879..e4831b1a07 100644 --- a/src/fast_api.rs +++ b/src/fast_api.rs @@ -11,7 +11,35 @@ use std::ptr::NonNull; pub struct CFunction(v8__CFunction); impl CFunction { - pub const fn new(address: *const c_void, type_info: &CFunctionInfo) -> Self { + /// Construct a `CFunction` from a function address and its type info. + /// + /// `type_info` is borrowed for `'static` because the resulting `CFunction` + /// stores the raw `v8::CFunctionInfo*` pointer and, once handed to V8 via + /// [`FunctionBuilder::build_fast`], that pointer is retained for the + /// lifetime of the `FunctionTemplate` (and copied into each fast-call + /// dispatch site). Anything other than `'static` storage for the type info + /// would let the pointer dangle. + /// + /// In practice this is achieved by constructing the `CFunctionInfo` inside + /// a `const` initializer (where reference-to-temporary rvalues are promoted + /// to `'static`), exactly as the existing test/bench patterns do: + /// + /// ```ignore + /// const FAST_CALL: v8::fast_api::CFunction = v8::fast_api::CFunction::new( + /// my_fast_fn as _, + /// &v8::fast_api::CFunctionInfo::new( + /// v8::fast_api::Type::Void.as_info(), + /// &[v8::fast_api::Type::V8Value.as_info()], + /// v8::fast_api::Int64Representation::Number, + /// ), + /// ); + /// ``` + /// + /// [`FunctionBuilder::build_fast`]: crate::FunctionBuilder::build_fast + pub const fn new( + address: *const c_void, + type_info: &'static CFunctionInfo, + ) -> Self { Self(v8__CFunction { address_: address, type_info_: &type_info.0, @@ -38,9 +66,15 @@ impl CFunctionInfo { /// |arg_info| is an array of |arg_count| CTypeInfos describing the /// arguments. Only the last argument may be of the special type /// CTypeInfo::kCallbackOptionsType. + /// + /// `arg_info` is borrowed for `'static` because the resulting + /// `CFunctionInfo` stores the raw `arg_info.as_ptr()` pointer and V8 reads + /// it on every fast-call invocation through the `CFunction` chain. As with + /// [`CFunction::new`], `const` initializers make this trivial: rvalues + /// such as `&[Type::V8Value.as_info()]` are promoted to `'static` storage. pub const fn new( return_info: CTypeInfo, - arg_info: &[CTypeInfo], + arg_info: &'static [CTypeInfo], repr: Int64Representation, ) -> Self { Self(v8__CFunctionInfo { diff --git a/src/template.rs b/src/template.rs index 387bdcbb78..5e956af004 100644 --- a/src/template.rs +++ b/src/template.rs @@ -702,10 +702,31 @@ impl<'s> FunctionBuilder<'s, FunctionTemplate> { /// useful to pass them explicitly - eg. when you are snapshotting you'd provide /// the overloads and `CFunctionInfo` that would be placed in the external /// references array. + /// + /// # Lifetime invariant + /// + /// `overloads` is `&'static [CFunction]` because, since + /// [crrev.com/c/7828135], V8 stores the raw `v8::CFunction` pointers it + /// receives via `NewWithCFunctionOverloads` directly inside + /// `FunctionTemplateInfo` (rather than copying them into a managed heap + /// object). The pointed-to storage must therefore outlive every + /// `FunctionTemplate` that references it. A `FunctionTemplate` may live + /// until isolate disposal, so in practice this requires the slice (and its + /// elements, including the `CFunctionInfo`s they reference) to have + /// `'static` storage. Use a `const` slice such as + /// + /// ```ignore + /// const OVERLOADS: &[v8::fast_api::CFunction] = &[FAST_TEST]; + /// ``` + /// + /// or a `static` item; do **not** synthesize the slice from stack-local + /// data. + /// + /// [crrev.com/c/7828135]: https://chromium-review.googlesource.com/c/v8/v8/+/7828135 pub fn build_fast<'i>( self, scope: &PinScope<'s, 'i>, - overloads: &[CFunction], + overloads: &'static [CFunction], ) -> Local<'s, FunctionTemplate> { unsafe { scope.cast_local(|sd| { diff --git a/tests/compile_fail/build_fast_local_overloads.rs b/tests/compile_fail/build_fast_local_overloads.rs new file mode 100644 index 0000000000..808102bcfe --- /dev/null +++ b/tests/compile_fail/build_fast_local_overloads.rs @@ -0,0 +1,31 @@ +// Copyright 2019-2026 the Deno authors. All rights reserved. MIT license. +// +// Regression test for denoland/rusty_v8#1989 (Orchid #160). +// +// Since crrev.com/c/7828135, V8 stores the raw `v8::CFunction` pointers +// passed to `NewWithCFunctionOverloads` directly inside `FunctionTemplateInfo` +// instead of copying them into a managed heap object. The pointed-to storage +// must therefore outlive the resulting `FunctionTemplate`, which in practice +// means it must be `'static`. `FunctionBuilder::build_fast` enforces this at +// the type level by requiring `&'static [v8::fast_api::CFunction]`, so a +// stack-local `Vec` of overloads must be rejected. + +fn slow_fn( + _: &mut v8::PinScope, + _: v8::FunctionCallbackArguments, + _: v8::ReturnValue, +) { +} + +fn rejects_local_overloads(scope: &mut v8::PinScope<'_, '_>) { + let overloads: Vec = Vec::new(); + let _ = v8::FunctionTemplate::builder(slow_fn).build_fast(scope, &overloads); +} + +pub fn main() { + rejects_local_overloads(mock()); +} + +fn mock() -> T { + unimplemented!() +} diff --git a/tests/compile_fail/build_fast_local_overloads.stderr b/tests/compile_fail/build_fast_local_overloads.stderr new file mode 100644 index 0000000000..0ead906f29 --- /dev/null +++ b/tests/compile_fail/build_fast_local_overloads.stderr @@ -0,0 +1,12 @@ +error[E0597]: `overloads` does not live long enough + --> tests/compile_fail/build_fast_local_overloads.rs:22:68 + | +21 | let overloads: Vec = Vec::new(); + | --------- binding `overloads` declared here +22 | let _ = v8::FunctionTemplate::builder(slow_fn).build_fast(scope, &overloads); + | ---------------------------------------------------------^^^^^^^^^^- + | | | + | | borrowed value does not live long enough + | argument requires that `overloads` is borrowed for `'static` +23 | } + | - `overloads` dropped here while still borrowed diff --git a/tests/test_api.rs b/tests/test_api.rs index 55d2ce774c..252a40c3eb 100644 --- a/tests/test_api.rs +++ b/tests/test_api.rs @@ -4703,6 +4703,17 @@ fn security_token() { let global = v8::Local::new(scope, global); templ.set_named_property_handler( v8::NamedPropertyHandlerConfiguration::new() + // NON_MASKING so the interceptor only fires for properties that are + // absent on the global (here just `variable`). Without it the handler + // would also intercept lookups of built-in globals, including those + // V8 performs while bootstrapping the context: since V8 15 shipped + // `Atomics.pause`, `Genesis::InitializeGlobal_js_atomics_pause` does a + // `GetProperty(global, "Atomics")` during context creation. A masking + // handler answers that with the *parent's* `Atomics` (which already + // has `pause`), so V8 reinstalls `pause` and aborts with a duplicate + // descriptor CHECK. NON_MASKING skips already-present properties and + // avoids the collision while preserving what this test exercises. + .flags(v8::PropertyHandlerFlags::NON_MASKING) .getter( |scope: &mut v8::PinScope, key: v8::Local, diff --git a/third_party/abseil-cpp b/third_party/abseil-cpp index 5e42a36a85..d16e32215c 160000 --- a/third_party/abseil-cpp +++ b/third_party/abseil-cpp @@ -1 +1 @@ -Subproject commit 5e42a36a85a252d8cdee6c39661d2bfd9883fd5c +Subproject commit d16e32215c3ab90ba57c2e904a5344d85c7353e4 diff --git a/third_party/libc++/src b/third_party/libc++/src index 99457fa555..5abc7f8397 160000 --- a/third_party/libc++/src +++ b/third_party/libc++/src @@ -1 +1 @@ -Subproject commit 99457fa555797f8c5ac3c076ca288d8481d3b23a +Subproject commit 5abc7f839700f0f17338434e1c1c6a8c87c00c11 diff --git a/third_party/libunwind/src b/third_party/libunwind/src index a2530baf3d..d6c7a21e97 160000 --- a/third_party/libunwind/src +++ b/third_party/libunwind/src @@ -1 +1 @@ -Subproject commit a2530baf3d11013afd0f1c1941ab6bef5ba71d0a +Subproject commit d6c7a21e978f0adaa43accaad53bc64f0b64f6ec diff --git a/third_party/llvm-libc/src b/third_party/llvm-libc/src index cb952785cc..9309c117eb 160000 --- a/third_party/llvm-libc/src +++ b/third_party/llvm-libc/src @@ -1 +1 @@ -Subproject commit cb952785ccee13811f293f3c419958d1e3ddafbf +Subproject commit 9309c117ebae84dd2f9df1ef99de4782162527d5 diff --git a/third_party/partition_alloc b/third_party/partition_alloc index fafdd4c9f5..ff3b8b885b 160000 --- a/third_party/partition_alloc +++ b/third_party/partition_alloc @@ -1 +1 @@ -Subproject commit fafdd4c9f559c6d0cfdf2ed3170ce370b59bfdbf +Subproject commit ff3b8b885b8374cbd3902642d94dc737bda93d5d diff --git a/third_party/rust b/third_party/rust index 2b055f4eca..26e8ff47f1 160000 --- a/third_party/rust +++ b/third_party/rust @@ -1 +1 @@ -Subproject commit 2b055f4ecac78bbf34a0d34217c699b7b09b44dd +Subproject commit 26e8ff47f18a8d28d6187a04b6a16cb7332356f8 diff --git a/tools/auto_update_v8.ts b/tools/auto_update_v8.ts index 8627c4550e..11aef7486b 100644 --- a/tools/auto_update_v8.ts +++ b/tools/auto_update_v8.ts @@ -1,4 +1,4 @@ -const V8_TRACKING_BRANCH = "14.9-lkgr-denoland"; +const V8_TRACKING_BRANCH = "15.0-lkgr-denoland"; const AUTOROLL_BRANCH = "autoroll"; function extractVersion() { diff --git a/tools/clang b/tools/clang index 61150a5f1d..45f4b9e251 160000 --- a/tools/clang +++ b/tools/clang @@ -1 +1 @@ -Subproject commit 61150a5f1ddf6460bad3d896c1502c6a56e15311 +Subproject commit 45f4b9e25124809497a27a8ae0e63d603b0f9f1b diff --git a/tools/win b/tools/win index d16e6b55b2..faefd1b6fa 160000 --- a/tools/win +++ b/tools/win @@ -1 +1 @@ -Subproject commit d16e6b55b2bd699735919d8a13a55ff284086603 +Subproject commit faefd1b6fa9eeb033ad6fe60368ccb9bf908cbd0 diff --git a/v8 b/v8 index 73d1969899..ac1e239891 160000 --- a/v8 +++ b/v8 @@ -1 +1 @@ -Subproject commit 73d19698991616a34a00ca691a6e697dbb69e2ef +Subproject commit ac1e23989121713ca642f6650b34deff7b686896