mirror of
https://github.com/servo/servo.git
synced 2025-07-23 07:13:52 +01:00
Stringify unknown JavaScript objects in global exception handlers
When turning DOM exceptions into `ErrorInfo` always try to stringify the JavaScript value, even if it's an object that isn't a `DOMException` or native exception. This means that exceptions that extend the `Error` prototype are now stringified. The result is that test output for WPT global assertion failures is more useful. For instance for the test include-frames-from-child-same-origin-grandchild.sub.html: Before: ``` uncaught exception: unknown (can't convert to string) ``` After: ``` uncaught exception: Error: assert_equals: expected 4 but got 3 ```
This commit is contained in:
parent
633f14df11
commit
e68ebd2617
3 changed files with 81 additions and 30 deletions
|
@ -29,8 +29,7 @@ use js::jsval::UndefinedValue;
|
|||
use js::rust::wrappers::JS_ErrorFromException;
|
||||
use js::rust::wrappers::JS_GetPendingException;
|
||||
use js::rust::wrappers::JS_SetPendingException;
|
||||
use js::rust::HandleObject;
|
||||
use js::rust::MutableHandleValue;
|
||||
use js::rust::{HandleObject, HandleValue, MutableHandleValue};
|
||||
use libc::c_uint;
|
||||
use std::slice::from_raw_parts;
|
||||
|
||||
|
@ -181,7 +180,7 @@ pub struct ErrorInfo {
|
|||
}
|
||||
|
||||
impl ErrorInfo {
|
||||
unsafe fn from_native_error(cx: *mut JSContext, object: HandleObject) -> Option<ErrorInfo> {
|
||||
unsafe fn from_native_error(object: HandleObject, cx: *mut JSContext) -> Option<ErrorInfo> {
|
||||
let report = JS_ErrorFromException(cx, object);
|
||||
if report.is_null() {
|
||||
return None;
|
||||
|
@ -209,10 +208,10 @@ impl ErrorInfo {
|
|||
};
|
||||
|
||||
Some(ErrorInfo {
|
||||
filename: filename,
|
||||
message: message,
|
||||
lineno: lineno,
|
||||
column: column,
|
||||
filename,
|
||||
message,
|
||||
lineno,
|
||||
column,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -229,6 +228,37 @@ impl ErrorInfo {
|
|||
column: 0,
|
||||
})
|
||||
}
|
||||
|
||||
unsafe fn from_object(object: HandleObject, cx: *mut JSContext) -> Option<ErrorInfo> {
|
||||
if let Some(info) = ErrorInfo::from_native_error(object, cx) {
|
||||
return Some(info);
|
||||
}
|
||||
if let Some(info) = ErrorInfo::from_dom_exception(object, cx) {
|
||||
return Some(info);
|
||||
}
|
||||
return None;
|
||||
}
|
||||
|
||||
unsafe fn from_value(value: HandleValue, cx: *mut JSContext) -> ErrorInfo {
|
||||
if value.is_object() {
|
||||
rooted!(in(cx) let object = value.to_object());
|
||||
if let Some(info) = ErrorInfo::from_object(object.handle(), cx) {
|
||||
return info;
|
||||
}
|
||||
}
|
||||
|
||||
match USVString::from_jsval(cx, value, ()) {
|
||||
Ok(ConversionResult::Success(USVString(string))) => ErrorInfo {
|
||||
message: format!("uncaught exception: {}", string),
|
||||
filename: String::new(),
|
||||
lineno: 0,
|
||||
column: 0,
|
||||
},
|
||||
_ => {
|
||||
panic!("uncaught exception: failed to stringify primitive");
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Report a pending exception, thereby clearing it.
|
||||
|
@ -248,29 +278,7 @@ pub unsafe fn report_pending_exception(cx: *mut JSContext, dispatch_event: bool,
|
|||
}
|
||||
|
||||
JS_ClearPendingException(cx);
|
||||
let error_info = if value.is_object() {
|
||||
rooted!(in(cx) let object = value.to_object());
|
||||
ErrorInfo::from_native_error(cx, object.handle())
|
||||
.or_else(|| ErrorInfo::from_dom_exception(object.handle(), cx))
|
||||
.unwrap_or_else(|| ErrorInfo {
|
||||
message: format!("uncaught exception: unknown (can't convert to string)"),
|
||||
filename: String::new(),
|
||||
lineno: 0,
|
||||
column: 0,
|
||||
})
|
||||
} else {
|
||||
match USVString::from_jsval(cx, value.handle(), ()) {
|
||||
Ok(ConversionResult::Success(USVString(string))) => ErrorInfo {
|
||||
message: format!("uncaught exception: {}", string),
|
||||
filename: String::new(),
|
||||
lineno: 0,
|
||||
column: 0,
|
||||
},
|
||||
_ => {
|
||||
panic!("Uncaught exception: failed to stringify primitive");
|
||||
},
|
||||
}
|
||||
};
|
||||
let error_info = ErrorInfo::from_value(value.handle(), cx);
|
||||
|
||||
error!(
|
||||
"Error at {}:{}:{} {}",
|
||||
|
|
|
@ -13746,6 +13746,13 @@
|
|||
{}
|
||||
]
|
||||
],
|
||||
"global_exception_stringification.html": [
|
||||
"b1c6cb6c390cca290085eea61ba4bf2f34aa4475",
|
||||
[
|
||||
null,
|
||||
{}
|
||||
]
|
||||
],
|
||||
"globals": {
|
||||
"entry.html": [
|
||||
"f963385342adbd92e4858a507c88155b4ed4371f",
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
<!-- doctype html -->
|
||||
<!DOCTYPE html>
|
||||
<meta charset=utf-8>
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
|
||||
<body>
|
||||
<div id="testOutput"></div>
|
||||
</body>
|
||||
|
||||
<script>
|
||||
setup({ 'allow_uncaught_exception': true });
|
||||
promise_test(async t => {
|
||||
function CustomError(message) {
|
||||
this.message = message;
|
||||
}
|
||||
CustomError.prototype = Object.create(Error.prototype);
|
||||
|
||||
let message = null;
|
||||
let waitForError = new Promise(resolve => {
|
||||
window.onerror = (errorMessage) => {
|
||||
message = errorMessage;
|
||||
resolve();
|
||||
};
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
throw new CustomError("An exceptional exception.");
|
||||
}, 0);
|
||||
|
||||
await waitForError;
|
||||
assert_equals(message, "uncaught exception: Error: An exceptional exception.");
|
||||
}, "Exception is stringified properly.");
|
||||
</script>
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue