Merge pull request #2863 from mbrubeck/2862-null-fun

Don't fail on invalid JS syntax in event handlers. r=Ms2ger
This commit is contained in:
Matt Brubeck 2014-07-18 15:40:10 -07:00
commit d43db3df30
3 changed files with 60 additions and 15 deletions

View file

@ -6,10 +6,12 @@ use dom::bindings::conversions::ToJSValConvertible;
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::domexception::DOMException; use dom::domexception::DOMException;
use js::jsapi::{JSContext, JSBool}; use js::jsapi::{JSContext, JSBool, JSObject};
use js::jsapi::{JS_IsExceptionPending, JS_SetPendingException}; use js::jsapi::{JS_IsExceptionPending, JS_SetPendingException, JS_ReportPendingException};
use js::jsapi::{JS_ReportErrorNumber, JSErrorFormatString, JSEXN_TYPEERR}; use js::jsapi::{JS_ReportErrorNumber, JSErrorFormatString, JSEXN_TYPEERR};
use js::jsapi::{JS_SaveFrameChain, JS_RestoreFrameChain};
use js::glue::{ReportError}; use js::glue::{ReportError};
use js::rust::with_compartment;
use libc; use libc;
use std::ptr; use std::ptr;
@ -46,6 +48,20 @@ pub fn throw_dom_exception(cx: *mut JSContext, global: &GlobalRef,
} }
} }
pub fn report_pending_exception(cx: *mut JSContext, obj: *mut JSObject) {
unsafe {
if JS_IsExceptionPending(cx) != 0 {
let saved = JS_SaveFrameChain(cx);
with_compartment(cx, obj, || {
JS_ReportPendingException(cx);
});
if saved != 0 {
JS_RestoreFrameChain(cx);
}
}
}
}
pub fn throw_not_in_union(cx: *mut JSContext, names: &'static str) -> JSBool { pub fn throw_not_in_union(cx: *mut JSContext, names: &'static str) -> JSBool {
assert!(unsafe { JS_IsExceptionPending(cx) } == 0); assert!(unsafe { JS_IsExceptionPending(cx) } == 0);
let message = format!("argument could not be converted to any of: {}", names); let message = format!("argument could not be converted to any of: {}", names);

View file

@ -5,7 +5,7 @@
use dom::bindings::callback::CallbackContainer; use dom::bindings::callback::CallbackContainer;
use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull; use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
use dom::bindings::codegen::Bindings::EventListenerBinding::EventListener; use dom::bindings::codegen::Bindings::EventListenerBinding::EventListener;
use dom::bindings::error::{Fallible, InvalidState}; use dom::bindings::error::{Fallible, InvalidState, report_pending_exception};
use dom::bindings::js::JSRef; use dom::bindings::js::JSRef;
use dom::bindings::trace::Traceable; use dom::bindings::trace::Traceable;
use dom::bindings::utils::{Reflectable, Reflector}; use dom::bindings::utils::{Reflectable, Reflector};
@ -181,19 +181,25 @@ impl<'a> EventTargetHelpers for JSRef<'a, EventTarget> {
static arg_names: [*c_char, ..1] = [&arg_name as *c_char]; static arg_names: [*c_char, ..1] = [&arg_name as *c_char];
let source = source.to_utf16(); let source = source.to_utf16();
let handler = let handler = name.with_ref(|name| {
name.with_ref(|name| { url.with_ref(|url| {
url.with_ref(|url| { unsafe { unsafe {
let fun = JS_CompileUCFunction(cx, ptr::mut_null(), name, JS_CompileUCFunction(cx, ptr::mut_null(), name,
nargs, &arg_names as **i8 as *mut *i8, source.as_ptr(), nargs, &arg_names as **i8 as *mut *i8,
source.len() as size_t, source.as_ptr(), source.len() as size_t, url, lineno)
url, lineno); }
assert!(fun.is_not_null()); })
JS_GetFunctionObject(fun) });
}})}); if handler.is_null() {
let funobj = unsafe { JS_CloneFunctionObject(cx, handler, scope) }; report_pending_exception(cx, self.reflector().get_jsobject());
return;
}
let funobj = unsafe {
JS_CloneFunctionObject(cx, JS_GetFunctionObject(handler), scope)
};
assert!(funobj.is_not_null()); assert!(funobj.is_not_null());
self.set_event_handler_common(ty, Some(EventHandlerNonNull::new(funobj))) self.set_event_handler_common(ty, Some(EventHandlerNonNull::new(funobj)));
} }
fn set_event_handler_common<T: CallbackContainer>( fn set_event_handler_common<T: CallbackContainer>(

View file

@ -0,0 +1,23 @@
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="UTF-8">
<script src="harness.js"></script>
</head>
<body>
<a id="a" onclick="{">link</a>
<script>
var a = document.getElementById("a");
is(a.onclick, null, "invalid onclick attribute");
document.body.setAttribute("onx", "{");
document.body.setAttribute("ony", "}");
is(document.body.getAttribute("onx"), "{");
is(document.body.getAttribute("ony"), "}");
finish();
</script>
</body>
</html>