Commit d4ce844b authored by Benedikt Meurer's avatar Benedikt Meurer Committed by V8 LUCI CQ

[inspector] Don't trigger window.onerror with side-effects disabled.

This was an oversight in https://crrev.com/c/3557234, which led to a
really weird developer experience: once a `window.onerror` handler was
installed, typing into the Console or other side-effect free debug
evaluations triggered this handler.

Fixed: chromium:1328008
Bug: chromium:1295750
Change-Id: I4029ff19ceb7cfe0a8eb6afff19c3ef9a4a82e25
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3660253
Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
Commit-Queue: Yang Guo <yangguo@chromium.org>
Reviewed-by: 's avatarYang Guo <yangguo@chromium.org>
Auto-Submit: Benedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/main@{#80696}
parent 1957427f
...@@ -73,7 +73,7 @@ class InjectedScript::ProtocolPromiseHandler { ...@@ -73,7 +73,7 @@ class InjectedScript::ProtocolPromiseHandler {
static bool add(V8InspectorSessionImpl* session, static bool add(V8InspectorSessionImpl* session,
v8::Local<v8::Context> context, v8::Local<v8::Value> value, v8::Local<v8::Context> context, v8::Local<v8::Value> value,
int executionContextId, const String16& objectGroup, int executionContextId, const String16& objectGroup,
WrapMode wrapMode, bool replMode, WrapMode wrapMode, bool replMode, bool throwOnSideEffect,
EvaluateCallback* callback) { EvaluateCallback* callback) {
v8::Local<v8::Promise::Resolver> resolver; v8::Local<v8::Promise::Resolver> resolver;
if (!v8::Promise::Resolver::New(context).ToLocal(&resolver)) { if (!v8::Promise::Resolver::New(context).ToLocal(&resolver)) {
...@@ -90,8 +90,8 @@ class InjectedScript::ProtocolPromiseHandler { ...@@ -90,8 +90,8 @@ class InjectedScript::ProtocolPromiseHandler {
: v8::MaybeLocal<v8::Promise>(); : v8::MaybeLocal<v8::Promise>();
V8InspectorImpl* inspector = session->inspector(); V8InspectorImpl* inspector = session->inspector();
ProtocolPromiseHandler* handler = new ProtocolPromiseHandler( ProtocolPromiseHandler* handler = new ProtocolPromiseHandler(
session, executionContextId, objectGroup, wrapMode, replMode, callback, session, executionContextId, objectGroup, wrapMode, replMode,
originalPromise); throwOnSideEffect, callback, originalPromise);
v8::Local<v8::Value> wrapper = handler->m_wrapper.Get(inspector->isolate()); v8::Local<v8::Value> wrapper = handler->m_wrapper.Get(inspector->isolate());
v8::Local<v8::Function> thenCallbackFunction = v8::Local<v8::Function> thenCallbackFunction =
v8::Function::New(context, thenCallback, wrapper, 0, v8::Function::New(context, thenCallback, wrapper, 0,
...@@ -143,7 +143,7 @@ class InjectedScript::ProtocolPromiseHandler { ...@@ -143,7 +143,7 @@ class InjectedScript::ProtocolPromiseHandler {
ProtocolPromiseHandler(V8InspectorSessionImpl* session, ProtocolPromiseHandler(V8InspectorSessionImpl* session,
int executionContextId, const String16& objectGroup, int executionContextId, const String16& objectGroup,
WrapMode wrapMode, bool replMode, WrapMode wrapMode, bool replMode,
EvaluateCallback* callback, bool throwOnSideEffect, EvaluateCallback* callback,
v8::MaybeLocal<v8::Promise> maybeEvaluationResult) v8::MaybeLocal<v8::Promise> maybeEvaluationResult)
: m_inspector(session->inspector()), : m_inspector(session->inspector()),
m_sessionId(session->sessionId()), m_sessionId(session->sessionId()),
...@@ -152,6 +152,7 @@ class InjectedScript::ProtocolPromiseHandler { ...@@ -152,6 +152,7 @@ class InjectedScript::ProtocolPromiseHandler {
m_objectGroup(objectGroup), m_objectGroup(objectGroup),
m_wrapMode(wrapMode), m_wrapMode(wrapMode),
m_replMode(replMode), m_replMode(replMode),
m_throwOnSideEffect(throwOnSideEffect),
m_callback(std::move(callback)), m_callback(std::move(callback)),
m_wrapper(m_inspector->isolate(), m_wrapper(m_inspector->isolate(),
v8::External::New(m_inspector->isolate(), this)) { v8::External::New(m_inspector->isolate(), this)) {
...@@ -249,8 +250,10 @@ class InjectedScript::ProtocolPromiseHandler { ...@@ -249,8 +250,10 @@ class InjectedScript::ProtocolPromiseHandler {
// we try to capture a fresh stack trace. // we try to capture a fresh stack trace.
if (maybeMessage.ToLocal(&message)) { if (maybeMessage.ToLocal(&message)) {
v8::Local<v8::Value> exception = result; v8::Local<v8::Value> exception = result;
session->inspector()->client()->dispatchError(scope.context(), message, if (!m_throwOnSideEffect) {
exception); session->inspector()->client()->dispatchError(scope.context(), message,
exception);
}
protocol::PtrMaybe<protocol::Runtime::ExceptionDetails> exceptionDetails; protocol::PtrMaybe<protocol::Runtime::ExceptionDetails> exceptionDetails;
response = scope.injectedScript()->createExceptionDetails( response = scope.injectedScript()->createExceptionDetails(
message, exception, m_objectGroup, &exceptionDetails); message, exception, m_objectGroup, &exceptionDetails);
...@@ -333,6 +336,7 @@ class InjectedScript::ProtocolPromiseHandler { ...@@ -333,6 +336,7 @@ class InjectedScript::ProtocolPromiseHandler {
String16 m_objectGroup; String16 m_objectGroup;
WrapMode m_wrapMode; WrapMode m_wrapMode;
bool m_replMode; bool m_replMode;
bool m_throwOnSideEffect;
EvaluateCallback* m_callback; EvaluateCallback* m_callback;
v8::Global<v8::External> m_wrapper; v8::Global<v8::External> m_wrapper;
v8::Global<v8::Promise> m_evaluationResult; v8::Global<v8::Promise> m_evaluationResult;
...@@ -651,17 +655,17 @@ std::unique_ptr<protocol::Runtime::RemoteObject> InjectedScript::wrapTable( ...@@ -651,17 +655,17 @@ std::unique_ptr<protocol::Runtime::RemoteObject> InjectedScript::wrapTable(
void InjectedScript::addPromiseCallback( void InjectedScript::addPromiseCallback(
V8InspectorSessionImpl* session, v8::MaybeLocal<v8::Value> value, V8InspectorSessionImpl* session, v8::MaybeLocal<v8::Value> value,
const String16& objectGroup, WrapMode wrapMode, bool replMode, const String16& objectGroup, WrapMode wrapMode, bool replMode,
std::unique_ptr<EvaluateCallback> callback) { bool throwOnSideEffect, std::unique_ptr<EvaluateCallback> callback) {
if (value.IsEmpty()) { if (value.IsEmpty()) {
callback->sendFailure(Response::InternalError()); callback->sendFailure(Response::InternalError());
return; return;
} }
v8::MicrotasksScope microtasksScope(m_context->isolate(), v8::MicrotasksScope microtasksScope(m_context->isolate(),
v8::MicrotasksScope::kRunMicrotasks); v8::MicrotasksScope::kRunMicrotasks);
if (ProtocolPromiseHandler::add(session, m_context->context(), if (ProtocolPromiseHandler::add(
value.ToLocalChecked(), session, m_context->context(), value.ToLocalChecked(),
m_context->contextId(), objectGroup, wrapMode, m_context->contextId(), objectGroup, wrapMode, replMode,
replMode, callback.get())) { throwOnSideEffect, callback.get())) {
m_evaluateCallbacks.insert(callback.release()); m_evaluateCallbacks.insert(callback.release());
} }
} }
...@@ -840,7 +844,7 @@ Response InjectedScript::createExceptionDetails( ...@@ -840,7 +844,7 @@ Response InjectedScript::createExceptionDetails(
Response InjectedScript::wrapEvaluateResult( Response InjectedScript::wrapEvaluateResult(
v8::MaybeLocal<v8::Value> maybeResultValue, const v8::TryCatch& tryCatch, v8::MaybeLocal<v8::Value> maybeResultValue, const v8::TryCatch& tryCatch,
const String16& objectGroup, WrapMode wrapMode, const String16& objectGroup, WrapMode wrapMode, bool throwOnSideEffect,
std::unique_ptr<protocol::Runtime::RemoteObject>* result, std::unique_ptr<protocol::Runtime::RemoteObject>* result,
Maybe<protocol::Runtime::ExceptionDetails>* exceptionDetails) { Maybe<protocol::Runtime::ExceptionDetails>* exceptionDetails) {
v8::Local<v8::Value> resultValue; v8::Local<v8::Value> resultValue;
...@@ -858,8 +862,10 @@ Response InjectedScript::wrapEvaluateResult( ...@@ -858,8 +862,10 @@ Response InjectedScript::wrapEvaluateResult(
return Response::ServerError("Execution was terminated"); return Response::ServerError("Execution was terminated");
} }
v8::Local<v8::Value> exception = tryCatch.Exception(); v8::Local<v8::Value> exception = tryCatch.Exception();
m_context->inspector()->client()->dispatchError( if (!throwOnSideEffect) {
m_context->context(), tryCatch.Message(), exception); m_context->inspector()->client()->dispatchError(
m_context->context(), tryCatch.Message(), exception);
}
Response response = Response response =
wrapObject(exception, objectGroup, wrapObject(exception, objectGroup,
exception->IsNativeError() ? WrapMode::kNoPreview exception->IsNativeError() ? WrapMode::kNoPreview
......
...@@ -113,7 +113,7 @@ class InjectedScript final { ...@@ -113,7 +113,7 @@ class InjectedScript final {
void addPromiseCallback(V8InspectorSessionImpl* session, void addPromiseCallback(V8InspectorSessionImpl* session,
v8::MaybeLocal<v8::Value> value, v8::MaybeLocal<v8::Value> value,
const String16& objectGroup, WrapMode wrapMode, const String16& objectGroup, WrapMode wrapMode,
bool replMode, bool replMode, bool throwOnSideEffect,
std::unique_ptr<EvaluateCallback> callback); std::unique_ptr<EvaluateCallback> callback);
Response findObject(const RemoteObjectId&, v8::Local<v8::Value>*) const; Response findObject(const RemoteObjectId&, v8::Local<v8::Value>*) const;
...@@ -133,7 +133,7 @@ class InjectedScript final { ...@@ -133,7 +133,7 @@ class InjectedScript final {
Response wrapEvaluateResult( Response wrapEvaluateResult(
v8::MaybeLocal<v8::Value> maybeResultValue, const v8::TryCatch&, v8::MaybeLocal<v8::Value> maybeResultValue, const v8::TryCatch&,
const String16& objectGroup, WrapMode wrapMode, const String16& objectGroup, WrapMode wrapMode, bool throwOnSideEffect,
std::unique_ptr<protocol::Runtime::RemoteObject>* result, std::unique_ptr<protocol::Runtime::RemoteObject>* result,
Maybe<protocol::Runtime::ExceptionDetails>*); Maybe<protocol::Runtime::ExceptionDetails>*);
v8::Local<v8::Value> lastEvaluationResult() const; v8::Local<v8::Value> lastEvaluationResult() const;
......
...@@ -1297,7 +1297,7 @@ Response V8DebuggerAgentImpl::evaluateOnCallFrame( ...@@ -1297,7 +1297,7 @@ Response V8DebuggerAgentImpl::evaluateOnCallFrame(
if (returnByValue.fromMaybe(false)) mode = WrapMode::kForceValue; if (returnByValue.fromMaybe(false)) mode = WrapMode::kForceValue;
return scope.injectedScript()->wrapEvaluateResult( return scope.injectedScript()->wrapEvaluateResult(
maybeResultValue, scope.tryCatch(), objectGroup.fromMaybe(""), mode, maybeResultValue, scope.tryCatch(), objectGroup.fromMaybe(""), mode,
result, exceptionDetails); throwOnSideEffect.fromMaybe(false), result, exceptionDetails);
} }
Response V8DebuggerAgentImpl::setVariableValue( Response V8DebuggerAgentImpl::setVariableValue(
......
...@@ -97,13 +97,14 @@ bool wrapEvaluateResultAsync(InjectedScript* injectedScript, ...@@ -97,13 +97,14 @@ bool wrapEvaluateResultAsync(InjectedScript* injectedScript,
v8::MaybeLocal<v8::Value> maybeResultValue, v8::MaybeLocal<v8::Value> maybeResultValue,
const v8::TryCatch& tryCatch, const v8::TryCatch& tryCatch,
const String16& objectGroup, WrapMode wrapMode, const String16& objectGroup, WrapMode wrapMode,
bool throwOnSideEffect,
ProtocolCallback* callback) { ProtocolCallback* callback) {
std::unique_ptr<RemoteObject> result; std::unique_ptr<RemoteObject> result;
Maybe<protocol::Runtime::ExceptionDetails> exceptionDetails; Maybe<protocol::Runtime::ExceptionDetails> exceptionDetails;
Response response = injectedScript->wrapEvaluateResult( Response response = injectedScript->wrapEvaluateResult(
maybeResultValue, tryCatch, objectGroup, wrapMode, &result, maybeResultValue, tryCatch, objectGroup, wrapMode, throwOnSideEffect,
&exceptionDetails); &result, &exceptionDetails);
if (response.IsSuccess()) { if (response.IsSuccess()) {
callback->sendSuccess(std::move(result), std::move(exceptionDetails)); callback->sendSuccess(std::move(result), std::move(exceptionDetails));
return true; return true;
...@@ -117,7 +118,7 @@ void innerCallFunctionOn( ...@@ -117,7 +118,7 @@ void innerCallFunctionOn(
v8::Local<v8::Value> recv, const String16& expression, v8::Local<v8::Value> recv, const String16& expression,
Maybe<protocol::Array<protocol::Runtime::CallArgument>> optionalArguments, Maybe<protocol::Array<protocol::Runtime::CallArgument>> optionalArguments,
bool silent, WrapMode wrapMode, bool userGesture, bool awaitPromise, bool silent, WrapMode wrapMode, bool userGesture, bool awaitPromise,
const String16& objectGroup, bool throw_on_side_effect, const String16& objectGroup, bool throwOnSideEffect,
std::unique_ptr<V8RuntimeAgentImpl::CallFunctionOnCallback> callback) { std::unique_ptr<V8RuntimeAgentImpl::CallFunctionOnCallback> callback) {
V8InspectorImpl* inspector = session->inspector(); V8InspectorImpl* inspector = session->inspector();
...@@ -166,7 +167,7 @@ void innerCallFunctionOn( ...@@ -166,7 +167,7 @@ void innerCallFunctionOn(
if (scope.tryCatch().HasCaught()) { if (scope.tryCatch().HasCaught()) {
wrapEvaluateResultAsync(scope.injectedScript(), maybeFunctionValue, wrapEvaluateResultAsync(scope.injectedScript(), maybeFunctionValue,
scope.tryCatch(), objectGroup, WrapMode::kNoPreview, scope.tryCatch(), objectGroup, WrapMode::kNoPreview,
callback.get()); throwOnSideEffect, callback.get());
return; return;
} }
...@@ -184,7 +185,7 @@ void innerCallFunctionOn( ...@@ -184,7 +185,7 @@ void innerCallFunctionOn(
v8::MicrotasksScope::kRunMicrotasks); v8::MicrotasksScope::kRunMicrotasks);
maybeResultValue = v8::debug::CallFunctionOn( maybeResultValue = v8::debug::CallFunctionOn(
scope.context(), functionValue.As<v8::Function>(), recv, argc, scope.context(), functionValue.As<v8::Function>(), recv, argc,
argv.get(), throw_on_side_effect); argv.get(), throwOnSideEffect);
} }
// Re-initialize after running client's code, as it could have destroyed // Re-initialize after running client's code, as it could have destroyed
// context or session. // context or session.
...@@ -197,12 +198,13 @@ void innerCallFunctionOn( ...@@ -197,12 +198,13 @@ void innerCallFunctionOn(
if (!awaitPromise || scope.tryCatch().HasCaught()) { if (!awaitPromise || scope.tryCatch().HasCaught()) {
wrapEvaluateResultAsync(scope.injectedScript(), maybeResultValue, wrapEvaluateResultAsync(scope.injectedScript(), maybeResultValue,
scope.tryCatch(), objectGroup, wrapMode, scope.tryCatch(), objectGroup, wrapMode,
callback.get()); throwOnSideEffect, callback.get());
return; return;
} }
scope.injectedScript()->addPromiseCallback( scope.injectedScript()->addPromiseCallback(
session, maybeResultValue, objectGroup, wrapMode, false /* replMode */, session, maybeResultValue, objectGroup, wrapMode, false /* replMode */,
throwOnSideEffect,
EvaluateCallbackWrapper<V8RuntimeAgentImpl::CallFunctionOnCallback>::wrap( EvaluateCallbackWrapper<V8RuntimeAgentImpl::CallFunctionOnCallback>::wrap(
std::move(callback))); std::move(callback)));
} }
...@@ -331,12 +333,13 @@ void V8RuntimeAgentImpl::evaluate( ...@@ -331,12 +333,13 @@ void V8RuntimeAgentImpl::evaluate(
if (!await || scope.tryCatch().HasCaught()) { if (!await || scope.tryCatch().HasCaught()) {
wrapEvaluateResultAsync(scope.injectedScript(), maybeResultValue, wrapEvaluateResultAsync(scope.injectedScript(), maybeResultValue,
scope.tryCatch(), objectGroup.fromMaybe(""), scope.tryCatch(), objectGroup.fromMaybe(""),
wrap_mode, callback.get()); wrap_mode, throwOnSideEffect.fromMaybe(false),
callback.get());
return; return;
} }
scope.injectedScript()->addPromiseCallback( scope.injectedScript()->addPromiseCallback(
m_session, maybeResultValue, objectGroup.fromMaybe(""), wrap_mode, m_session, maybeResultValue, objectGroup.fromMaybe(""), wrap_mode,
replMode, replMode, throwOnSideEffect.fromMaybe(false),
EvaluateCallbackWrapper<EvaluateCallback>::wrap(std::move(callback))); EvaluateCallbackWrapper<EvaluateCallback>::wrap(std::move(callback)));
} }
...@@ -360,7 +363,7 @@ void V8RuntimeAgentImpl::awaitPromise( ...@@ -360,7 +363,7 @@ void V8RuntimeAgentImpl::awaitPromise(
if (returnByValue.fromMaybe(false)) mode = WrapMode::kForceValue; if (returnByValue.fromMaybe(false)) mode = WrapMode::kForceValue;
scope.injectedScript()->addPromiseCallback( scope.injectedScript()->addPromiseCallback(
m_session, scope.object(), scope.objectGroupName(), mode, m_session, scope.object(), scope.objectGroupName(), mode,
false /* replMode */, false /* replMode */, false /* throwOnSideEffect */,
EvaluateCallbackWrapper<AwaitPromiseCallback>::wrap(std::move(callback))); EvaluateCallbackWrapper<AwaitPromiseCallback>::wrap(std::move(callback)));
} }
...@@ -631,12 +634,12 @@ void V8RuntimeAgentImpl::runScript( ...@@ -631,12 +634,12 @@ void V8RuntimeAgentImpl::runScript(
if (!awaitPromise.fromMaybe(false) || scope.tryCatch().HasCaught()) { if (!awaitPromise.fromMaybe(false) || scope.tryCatch().HasCaught()) {
wrapEvaluateResultAsync(scope.injectedScript(), maybeResultValue, wrapEvaluateResultAsync(scope.injectedScript(), maybeResultValue,
scope.tryCatch(), objectGroup.fromMaybe(""), mode, scope.tryCatch(), objectGroup.fromMaybe(""), mode,
callback.get()); false /* throwOnSideEffect */, callback.get());
return; return;
} }
scope.injectedScript()->addPromiseCallback( scope.injectedScript()->addPromiseCallback(
m_session, maybeResultValue.ToLocalChecked(), objectGroup.fromMaybe(""), m_session, maybeResultValue.ToLocalChecked(), objectGroup.fromMaybe(""),
mode, false /* replMode */, mode, false /* replMode */, false /* throwOnSideEffect */,
EvaluateCallbackWrapper<RunScriptCallback>::wrap(std::move(callback))); EvaluateCallbackWrapper<RunScriptCallback>::wrap(std::move(callback)));
} }
......
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