Commit 7ba3507e authored by Harald Alvestrand's avatar Harald Alvestrand Committed by Commit Bot

Check for executionContext returning null

This will happen if invoking functions on an object after its
context has been destroyed.

Added test.

Bug: chromium:1072412
Change-Id: Icc2e8a5ad47398acffb2d56a299a51b11386c9f2
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2160909
Commit-Queue: Harald Alvestrand <hta@chromium.org>
Reviewed-by: default avatarGuido Urdaneta <guidou@chromium.org>
Reviewed-by: default avatarKentaro Hara <haraken@chromium.org>
Cr-Commit-Position: refs/heads/master@{#763355}
parent 772aade4
...@@ -1324,6 +1324,7 @@ void RTCPeerConnection::ReportSetSdpUsage( ...@@ -1324,6 +1324,7 @@ void RTCPeerConnection::ReportSetSdpUsage(
ScriptPromise RTCPeerConnection::setLocalDescription( ScriptPromise RTCPeerConnection::setLocalDescription(
ScriptState* script_state) { ScriptState* script_state) {
DCHECK(script_state->ContextIsValid());
auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state); auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
ScriptPromise promise = resolver->Promise(); ScriptPromise promise = resolver->Promise();
auto* request = MakeGarbageCollected<RTCVoidRequestPromiseImpl>( auto* request = MakeGarbageCollected<RTCVoidRequestPromiseImpl>(
...@@ -1337,6 +1338,13 @@ ScriptPromise RTCPeerConnection::setLocalDescription( ...@@ -1337,6 +1338,13 @@ ScriptPromise RTCPeerConnection::setLocalDescription(
ScriptState* script_state, ScriptState* script_state,
const RTCSessionDescriptionInit* session_description_init, const RTCSessionDescriptionInit* session_description_init,
ExceptionState& exception_state) { ExceptionState& exception_state) {
if (closed_) {
exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
kSignalingStateClosedMessage);
return ScriptPromise();
}
DCHECK(script_state->ContextIsValid());
if (session_description_init->type().IsNull() && if (session_description_init->type().IsNull() &&
session_description_init->sdp().IsNull()) { session_description_init->sdp().IsNull()) {
return setLocalDescription(script_state); return setLocalDescription(script_state);
...@@ -1375,6 +1383,12 @@ ScriptPromise RTCPeerConnection::setLocalDescription( ...@@ -1375,6 +1383,12 @@ ScriptPromise RTCPeerConnection::setLocalDescription(
const RTCSessionDescriptionInit* session_description_init, const RTCSessionDescriptionInit* session_description_init,
V8VoidFunction* success_callback, V8VoidFunction* success_callback,
V8RTCPeerConnectionErrorCallback* error_callback) { V8RTCPeerConnectionErrorCallback* error_callback) {
if (CallErrorCallbackIfSignalingStateClosed(signaling_state_,
error_callback)) {
return ScriptPromise::CastUndefined(script_state);
}
DCHECK(script_state->ContextIsValid());
if (session_description_init->type() != "rollback") { if (session_description_init->type() != "rollback") {
MaybeWarnAboutUnsafeSdp(session_description_init); MaybeWarnAboutUnsafeSdp(session_description_init);
ReportSetSdpUsage(SetSdpOperationType::kSetLocalDescription, ReportSetSdpUsage(SetSdpOperationType::kSetLocalDescription,
...@@ -1449,6 +1463,13 @@ ScriptPromise RTCPeerConnection::setRemoteDescription( ...@@ -1449,6 +1463,13 @@ ScriptPromise RTCPeerConnection::setRemoteDescription(
ScriptState* script_state, ScriptState* script_state,
const RTCSessionDescriptionInit* session_description_init, const RTCSessionDescriptionInit* session_description_init,
ExceptionState& exception_state) { ExceptionState& exception_state) {
if (closed_) {
exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
kSignalingStateClosedMessage);
return ScriptPromise();
}
DCHECK(script_state->ContextIsValid());
if (session_description_init->type() != "rollback") { if (session_description_init->type() != "rollback") {
MaybeWarnAboutUnsafeSdp(session_description_init); MaybeWarnAboutUnsafeSdp(session_description_init);
ReportSetSdpUsage(SetSdpOperationType::kSetRemoteDescription, ReportSetSdpUsage(SetSdpOperationType::kSetRemoteDescription,
...@@ -1481,12 +1502,19 @@ ScriptPromise RTCPeerConnection::setRemoteDescription( ...@@ -1481,12 +1502,19 @@ ScriptPromise RTCPeerConnection::setRemoteDescription(
const RTCSessionDescriptionInit* session_description_init, const RTCSessionDescriptionInit* session_description_init,
V8VoidFunction* success_callback, V8VoidFunction* success_callback,
V8RTCPeerConnectionErrorCallback* error_callback) { V8RTCPeerConnectionErrorCallback* error_callback) {
if (CallErrorCallbackIfSignalingStateClosed(signaling_state_,
error_callback)) {
return ScriptPromise::CastUndefined(script_state);
}
DCHECK(script_state->ContextIsValid());
if (session_description_init->type() != "rollback") { if (session_description_init->type() != "rollback") {
MaybeWarnAboutUnsafeSdp(session_description_init); MaybeWarnAboutUnsafeSdp(session_description_init);
ReportSetSdpUsage(SetSdpOperationType::kSetRemoteDescription, ReportSetSdpUsage(SetSdpOperationType::kSetRemoteDescription,
session_description_init); session_description_init);
} }
ExecutionContext* context = ExecutionContext::From(script_state); ExecutionContext* context = ExecutionContext::From(script_state);
CHECK(context);
if (success_callback && error_callback) { if (success_callback && error_callback) {
UseCounter::Count( UseCounter::Count(
context, context,
...@@ -3214,6 +3242,9 @@ ExecutionContext* RTCPeerConnection::GetExecutionContext() const { ...@@ -3214,6 +3242,9 @@ ExecutionContext* RTCPeerConnection::GetExecutionContext() const {
} }
void RTCPeerConnection::ContextDestroyed() { void RTCPeerConnection::ContextDestroyed() {
if (!closed_) {
CloseInternal();
}
UnregisterPeerConnectionHandler(); UnregisterPeerConnectionHandler();
} }
......
...@@ -3207,12 +3207,6 @@ crbug.com/626703 [ Mac10.11 ] external/wpt/css/css-layout-api/edges/scrollbar.ht ...@@ -3207,12 +3207,6 @@ crbug.com/626703 [ Mac10.11 ] external/wpt/css/css-layout-api/edges/scrollbar.ht
crbug.com/626703 [ Linux ] external/wpt/webrtc/RTCPeerConnection-operations.https.html [ Timeout ] crbug.com/626703 [ Linux ] external/wpt/webrtc/RTCPeerConnection-operations.https.html [ Timeout ]
crbug.com/626703 [ Mac ] external/wpt/webrtc/RTCPeerConnection-operations.https.html [ Timeout ] crbug.com/626703 [ Mac ] external/wpt/webrtc/RTCPeerConnection-operations.https.html [ Timeout ]
crbug.com/626703 [ Win ] external/wpt/webrtc/RTCPeerConnection-operations.https.html [ Timeout ] crbug.com/626703 [ Win ] external/wpt/webrtc/RTCPeerConnection-operations.https.html [ Timeout ]
crbug.com/626703 [ Linux ] external/wpt/webrtc/RTCPeerConnection-setLocalDescription-parameterless.https.html [ Timeout ]
crbug.com/626703 [ Mac ] external/wpt/webrtc/RTCPeerConnection-setLocalDescription-parameterless.https.html [ Timeout ]
crbug.com/626703 [ Win ] external/wpt/webrtc/RTCPeerConnection-setLocalDescription-parameterless.https.html [ Timeout ]
crbug.com/626703 [ Linux ] virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-parameterless.https.html [ Timeout ]
crbug.com/626703 [ Mac ] virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-parameterless.https.html [ Timeout ]
crbug.com/626703 [ Win ] virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-parameterless.https.html [ Timeout ]
crbug.com/626703 [ Mac10.12 ] virtual/web-components-v0-disabled/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-mode.html [ Timeout ] crbug.com/626703 [ Mac10.12 ] virtual/web-components-v0-disabled/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-mode.html [ Timeout ]
crbug.com/626703 [ Linux ] external/wpt/content-dpr/content-dpr-various-elements.html [ Failure ] crbug.com/626703 [ Linux ] external/wpt/content-dpr/content-dpr-various-elements.html [ Failure ]
crbug.com/626703 [ Mac ] external/wpt/content-dpr/content-dpr-various-elements.html [ Failure ] crbug.com/626703 [ Mac ] external/wpt/content-dpr/content-dpr-various-elements.html [ Failure ]
......
...@@ -7,8 +7,10 @@ PASS Parameterless SLD() in 'have-remote-offer' sets currentLocalDescription ...@@ -7,8 +7,10 @@ PASS Parameterless SLD() in 'have-remote-offer' sets currentLocalDescription
PASS Parameterless SLD() in 'have-remote-offer' sets transceiver.currentDirection PASS Parameterless SLD() in 'have-remote-offer' sets transceiver.currentDirection
FAIL Parameterless SLD() uses [[LastCreatedOffer]] if it is still valid assert_true: offerer.pendingLocalDescription.sdp == offer.sdp expected true got false FAIL Parameterless SLD() uses [[LastCreatedOffer]] if it is still valid assert_true: offerer.pendingLocalDescription.sdp == offer.sdp expected true got false
FAIL Parameterless SLD() uses [[LastCreatedAnswer]] if it is still valid assert_true: answerer.currentLocalDescription.sdp == answer.sdp expected true got false FAIL Parameterless SLD() uses [[LastCreatedAnswer]] if it is still valid assert_true: answerer.currentLocalDescription.sdp == answer.sdp expected true got false
PASS Parameterless SLD() never resolves if already closed PASS Parameterless SLD() rejects with InvalidStateError if already closed
PASS Parameterless SLD() never resolves if closed while pending PASS Parameterless SLD() never settles if closed while pending
PASS Parameterless SLD() in a full O/A exchange succeeds PASS Parameterless SLD() in a full O/A exchange succeeds
PASS Parameterless SRD() rejects with TypeError.
FAIL RTCSessionDescription constructed without type throws TypeError assert_equals: expected "TypeError" but got "ReferenceError"
Harness: the test ran to completion. Harness: the test ran to completion.
<html>
<head>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script src="../../resources/gc.js"></script>
</head>
<body>
<script>
promise_test(async t => {
let iframe = document.createElement("iframe");
document.body.appendChild( iframe );
let iframe_pc = new iframe.contentWindow.RTCPeerConnection();
let iframe_exception_constructor = iframe.contentWindow.DOMException;
iframe.remove();
assert_equals(iframe_pc.signalingState, 'closed');
// Calling functions on the RTCPeerConnection should have no effect.
await promise_rejects_dom(t, 'InvalidStateError', iframe_exception_constructor,
iframe_pc.setLocalDescription({type:"answer", sdp:"v0"}));
await promise_rejects_dom(t, 'InvalidStateError', iframe_exception_constructor, iframe_pc.setRemoteDescription({type:"answer", sdp:"v0"}));
await promise_rejects_dom(t, 'InvalidStateError', iframe_exception_constructor, iframe_pc.createOffer());
await promise_rejects_dom(t, 'InvalidStateError', iframe_exception_constructor, iframe_pc.createAnswer());
// Verify equivalent (that error callback is called) for callback-based APIs.
await promise_rejects_dom(t, 'InvalidStateError',
new Promise((resolve, reject) => {
iframe_pc.setLocalDescription(
{type:"answer", sdp:"v0"},
() => { assert_unreached(); },
e => { reject(e); });
}));
await promise_rejects_dom(t, 'InvalidStateError',
new Promise((resolve, reject) => {
iframe_pc.setRemoteDescription(
{type:"answer", sdp:"v0"},
() => { assert_unreached(); },
e => { reject(e); });
}));
await promise_rejects_dom(t, 'InvalidStateError',
new Promise((resolve, reject) => {
iframe_pc.createOffer(
() => { assert_unreached(); },
e => { reject(e); });
}));
await promise_rejects_dom(t, 'InvalidStateError',
new Promise((resolve, reject) => {
iframe_pc.createAnswer(
() => { assert_unreached(); },
e => { reject(e); });
}));
}, 'PeerConnection in iframe closes properly when context is destroyed');
</script>
</body>
</html>
...@@ -5,9 +5,8 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE ...@@ -5,9 +5,8 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE
PASS gotStream was called. PASS gotStream was called.
PASS gotStream done. PASS gotStream done.
PASS onNegotiationNeeded was called. PASS onNegotiationNeeded was called.
PASS onNegotiationNeeded done.
PASS onStateChange was called.
PASS pc.signalingState is 'closed' PASS pc.signalingState is 'closed'
PASS onNegotiationNeeded done.
PASS successfullyParsed is true PASS successfullyParsed is true
TEST COMPLETE TEST COMPLETE
......
...@@ -25,17 +25,18 @@ function getUserMedia(dictionary, callback) { ...@@ -25,17 +25,18 @@ function getUserMedia(dictionary, callback) {
} }
function onStateChange(event) { function onStateChange(event) {
testPassed('onStateChange was called.'); testFailed('onStateChange was called on close.');
shouldBe("pc.signalingState", "'closed'");
finishJSTest();
} }
function onNegotiationNeeded(event) { function onNegotiationNeeded(event) {
testPassed('onNegotiationNeeded was called.'); testPassed('onNegotiationNeeded was called.');
pc.onsignalingstatechange = onStateChange; pc.onsignalingstatechange = onStateChange;
pc.onnegotiationneeded = onNegotiationNeededAgain; pc.onnegotiationneeded = onNegotiationNeededAgain;
// There should be no event fired from pc.close().
pc.close(); pc.close();
shouldBe("pc.signalingState", "'closed'");
testPassed('onNegotiationNeeded done.') testPassed('onNegotiationNeeded done.')
finishJSTest();
} }
function onNegotiationNeededAgain(event) { function onNegotiationNeededAgain(event) {
......
<!DOCTYPE html>
<html>
<head>
<title>RTCPeerConnection signalingState</title>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
</head>
<body>
<script>
async_test(function(test) {
var pc = new RTCPeerConnection();
assert_equals(pc.signalingState, 'stable');
pc.onsignalingstatechange = test.step_func(() => {
assert_equals(pc.signalingState, 'closed');
test.done();
});
pc.close();
}, 'Tests the RTCPeerConnection "stable" and "closed" signalingState strings.');
</script>
</body>
</html>
...@@ -7,8 +7,10 @@ PASS Parameterless SLD() in 'have-remote-offer' sets currentLocalDescription ...@@ -7,8 +7,10 @@ PASS Parameterless SLD() in 'have-remote-offer' sets currentLocalDescription
FAIL Parameterless SLD() in 'have-remote-offer' sets transceiver.currentDirection promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'." FAIL Parameterless SLD() in 'have-remote-offer' sets transceiver.currentDirection promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'."
FAIL Parameterless SLD() uses [[LastCreatedOffer]] if it is still valid assert_true: offerer.pendingLocalDescription.sdp == offer.sdp expected true got false FAIL Parameterless SLD() uses [[LastCreatedOffer]] if it is still valid assert_true: offerer.pendingLocalDescription.sdp == offer.sdp expected true got false
FAIL Parameterless SLD() uses [[LastCreatedAnswer]] if it is still valid assert_true: answerer.currentLocalDescription.sdp == answer.sdp expected true got false FAIL Parameterless SLD() uses [[LastCreatedAnswer]] if it is still valid assert_true: answerer.currentLocalDescription.sdp == answer.sdp expected true got false
PASS Parameterless SLD() never resolves if already closed PASS Parameterless SLD() rejects with InvalidStateError if already closed
PASS Parameterless SLD() never resolves if closed while pending PASS Parameterless SLD() never settles if closed while pending
PASS Parameterless SLD() in a full O/A exchange succeeds PASS Parameterless SLD() in a full O/A exchange succeeds
PASS Parameterless SRD() rejects with TypeError.
FAIL RTCSessionDescription constructed without type throws TypeError assert_equals: expected "TypeError" but got "ReferenceError"
Harness: the test ran to completion. Harness: the test ran to completion.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment