From e80d36783af4185c34099918f4b40f61b9942362 Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Sat, 16 Aug 2025 13:14:56 -0400 Subject: [PATCH] script: Ensure JS->webdriver conversions have a non-empty settings stack (#38709) JS scripts that are evaluated already run with an [entry script](https://html.spec.whatwg.org/#entry) on the script settings stack. The codepaths that do something with the return value (eg. WebDriver and embedder JS evaluation) have the potential to run additional JS, since they can trigger getters for arbitrary properties of objects, so they also need an entry script present in case code like https://github.com/servo/servo/blob/e649b9b91d39b112e4ae7e1816438d296a24a341/components/script/dom/location.rs#L182 is executed. Testing: Added a regression unit test. Fixes: #38692 Signed-off-by: Josh Matthews --- components/script/webdriver_handlers.rs | 2 ++ components/servo/tests/webview.rs | 14 ++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/components/script/webdriver_handlers.rs b/components/script/webdriver_handlers.rs index 5be9ce33765..cbd0788cd18 100644 --- a/components/script/webdriver_handlers.rs +++ b/components/script/webdriver_handlers.rs @@ -59,6 +59,7 @@ use crate::dom::bindings::error::{Error, report_pending_exception, throw_dom_exc use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::reflector::{DomGlobal, DomObject}; use crate::dom::bindings::root::DomRoot; +use crate::dom::bindings::settings_stack::AutoEntryScript; use crate::dom::bindings::str::DOMString; use crate::dom::document::Document; use crate::dom::domrect::DOMRect; @@ -345,6 +346,7 @@ pub(crate) fn jsval_to_webdriver( realm: InRealm, can_gc: CanGc, ) -> WebDriverJSResult { + let _aes = AutoEntryScript::new(global_scope); let mut seen = HashSet::new(); let result = unsafe { jsval_to_webdriver_inner(*cx, global_scope, val, &mut seen) }; if result.is_err() { diff --git a/components/servo/tests/webview.rs b/components/servo/tests/webview.rs index dbcc4f9fcb5..ccaa05d3ca3 100644 --- a/components/servo/tests/webview.rs +++ b/components/servo/tests/webview.rs @@ -134,6 +134,19 @@ fn test_evaluate_javascript_basic(servo_test: &ServoTest) -> Result<(), anyhow:: Ok(()) } +fn test_evaluate_javascript_panic(servo_test: &ServoTest) -> Result<(), anyhow::Error> { + let delegate = Rc::new(WebViewDelegateImpl::default()); + let webview = WebViewBuilder::new(servo_test.servo()) + .delegate(delegate.clone()) + .build(); + + let input = "location"; + let result = evaluate_javascript(servo_test, webview.clone(), input); + ensure!(matches!(result, Ok(JSValue::Object(..)))); + + Ok(()) +} + fn test_create_webview_and_immediately_drop_webview_before_shutdown( servo_test: &ServoTest, ) -> Result<(), anyhow::Error> { @@ -174,6 +187,7 @@ fn main() { run_api_tests!( test_create_webview, test_evaluate_javascript_basic, + test_evaluate_javascript_panic, test_theme_change, // This test needs to be last, as it tests creating and dropping // a WebView right before shutdown.