Skip to content

Commit

Permalink
ignore anonymous scripts
Browse files Browse the repository at this point in the history
Summary:
Scripts coming from eval statements can be blackboxed the same way that named scripts can be ignored using regex patterns
https://developer.chrome.com/blog/new-in-devtools-131#ignore-list

Reviewed By: dannysu

Differential Revision: D66171797

fbshipit-source-id: e50a723c589217221b3960e47d8ca146090ab38e
  • Loading branch information
vzaidman authored and facebook-github-bot committed Dec 16, 2024
1 parent 2dd83b0 commit f708c3b
Show file tree
Hide file tree
Showing 6 changed files with 160 additions and 4 deletions.
6 changes: 6 additions & 0 deletions API/hermes/cdp/DebuggerDomainAgent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,8 @@ static inline bool blackboxRangeComparator(

void DebuggerDomainAgent::setBlackboxPatterns(
const m::debugger::SetBlackboxPatternsRequest &req) {
blackboxAnonymousScripts_ = req.skipAnonymous.value_or(false);

if (req.patterns.empty()) {
compiledBlackboxPatternRegex_ = std::nullopt;
sendResponseToClient(m::makeOkResponse(req.id));
Expand Down Expand Up @@ -391,6 +393,10 @@ bool DebuggerDomainAgent::isLocationBlackboxed(
std::string scriptName,
int lineNumber,
int columnNumber) {
if (blackboxAnonymousScripts_ && scriptName.empty()) {
return true;
}

if (compiledBlackboxPatternRegex_.has_value()) {
// We expect scriptName to be encoded as UTF-8 in accordance with RFC-8259
// See comment in CDPAgent::handleCommand
Expand Down
5 changes: 5 additions & 0 deletions API/hermes/cdp/DebuggerDomainAgent.h
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,11 @@ class DebuggerDomainAgent : public DomainAgent {
CDPBreakpoint &breakpoint,
debugger::ScriptID scriptID);

/// Holds a boolean that determines if scripts without a script url
/// (e.g. anonymous scripts) should be blackboxed.
/// Same as V8:
/// https://source.chromium.org/chromium/chromium/src/+/fef5d519bab86dbd712d76bfca5be90a6e03459c:v8/src/inspector/v8-debugger-agent-impl.cc;l=997-999
bool blackboxAnonymousScripts_ = false;
/// Optionally, holds a compiled regex pattern that is used to test if
/// script urls should be blackboxed.
/// See isLocationBlackboxed below for more details. Same as V8:
Expand Down
6 changes: 4 additions & 2 deletions API/hermes/cdp/MessageTypes.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright (c) Meta Platforms, Inc. and affiliates. All Rights Reserved.
// @generated SignedSource<<e0a836847da36fc0e86ce97f17f76caa>>
// @generated SignedSource<<310395f971015ee3431e0c8490405e5c>>

#include "MessageTypes.h"

Expand Down Expand Up @@ -910,13 +910,15 @@ debugger::SetBlackboxPatternsRequest::tryMake(const JSONObject *obj) {
}
auto *params = *convertResult;
TRY_ASSIGN(req->patterns, params, "patterns");
TRY_ASSIGN(req->skipAnonymous, params, "skipAnonymous");
return req;
}

JSONValue *debugger::SetBlackboxPatternsRequest::toJsonVal(
JSONFactory &factory) const {
llvh::SmallVector<JSONFactory::Prop, 1> paramsProps;
llvh::SmallVector<JSONFactory::Prop, 2> paramsProps;
put(paramsProps, "patterns", patterns, factory);
put(paramsProps, "skipAnonymous", skipAnonymous, factory);

llvh::SmallVector<JSONFactory::Prop, 1> props;
put(props, "id", id, factory);
Expand Down
3 changes: 2 additions & 1 deletion API/hermes/cdp/MessageTypes.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright (c) Meta Platforms, Inc. and affiliates. All Rights Reserved.
// @generated SignedSource<<8c4708c816bd7ab749ff48ba06986659>>
// @generated SignedSource<<7e121aac8a1883c75ff45194ba469176>>

#pragma once

Expand Down Expand Up @@ -664,6 +664,7 @@ struct debugger::SetBlackboxPatternsRequest : public Request {
void accept(RequestHandler &handler) const override;

std::vector<std::string> patterns;
std::optional<bool> skipAnonymous;
};

struct debugger::SetBlackboxedRangesRequest : public Request {
Expand Down
2 changes: 1 addition & 1 deletion API/hermes/cdp/tools/hermes-inspector-msggen/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"test": "jest"
},
"dependencies": {
"devtools-protocol": "0.0.1107588",
"devtools-protocol": "0.0.1383960",
"yargs": "^17.6.2"
},
"devDependencies": {
Expand Down
142 changes: 142 additions & 0 deletions unittests/API/CDPAgentTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1339,10 +1339,90 @@ TEST_F(CDPAgentTest, DebuggerSkipBlackboxedPatterns) {
// stays ignored
sendAndCheckResponse("Debugger.resume", msgId++);
ensureNotification(waitForMessage(), "Debugger.resumed");
waitForScheduledScripts();
}

TEST_F(CDPAgentTest, DebuggerSkipAnonymousScriptsExplicit) {
int msgId = 1;

sendAndCheckResponse("Debugger.enable", msgId++);

sendRequest(
"Debugger.setBlackboxPatterns", msgId, [](::hermes::JSONEmitter &json) {
json.emitKey("patterns");
json.openArray();
json.closeArray();
json.emitKeyValue("skipAnonymous", true);
});
ensureOkResponse(waitForMessage("setBlackboxPatterns"), msgId++);

auto emptyScriptNameMakingItAnonymous = "";

scheduleScript(
R"(// (line 0)
var a = 1 + 2;
debugger; // [1] (line 2) don't hit debugger statement since it is in a blackboxed script now
var b = a / 2;
debugger; // [2] (line 4) don't hit debugger statement since it is in a blackboxed script now
var c = b - 2;
)",
emptyScriptNameMakingItAnonymous);

expectNotification("Debugger.scriptParsed");

waitForScheduledScripts();
}

TEST_F(CDPAgentTest, DebuggerSkipAnonymousScriptsEval) {
int msgId = 1;

sendAndCheckResponse("Debugger.enable", msgId++);

scheduleScript(
R"( // (line 0)
var a = 1 + 2;
eval(` // (line 2 globally, line 0 in eval)
function aa() {
debugger; // [1] (line 4 globally, line 2 in eval) hit debugger statement, setBlackboxPatterns with skipAnonymous, resume
};
aa(); // [1] (line 5 globally, line 4 in eval)
`);
eval(`
function aa() {
debugger; // [2] (line 9 globally, line 2 in eval) don't hit debugger statement since evals are blackboxed now
};
aa();
`);
)");

expectNotification("Debugger.scriptParsed"); // global script parsed
expectNotification("Debugger.scriptParsed"); // eval script parsed

// [1] (line 2) hit debugger statement in eval
ensurePaused(
waitForMessage(),
"other",
{// line 2, and line 4 are relative to evaluated string
{"aa", 2, 3},
{"eval", 4, 2},
{"global", 2, 1}});
sendRequest(
"Debugger.setBlackboxPatterns", msgId, [](::hermes::JSONEmitter &json) {
json.emitKey("patterns");
json.openArray();
json.closeArray();
json.emitKeyValue("skipAnonymous", true);
});
ensureOkResponse(waitForMessage("setBlackboxPatterns"), msgId++);
sendAndCheckResponse("Debugger.resume", msgId++);
ensureNotification(waitForMessage(), "Debugger.resumed");

expectNotification("Debugger.scriptParsed"); // second eval script parsed

// [3] (line 9) don't hit debugger statement since evals are blackboxed now
waitForScheduledScripts();
}

TEST_F(CDPAgentTest, DebuggerSkipBlackboxedPatternsRegexEscaping) {
int msgId = 1;

Expand Down Expand Up @@ -1427,6 +1507,40 @@ TEST_F(CDPAgentTest, DebuggerSkipBlackboxedPatternsRegexEscaping) {
waitForScheduledScripts();
}

TEST_F(
CDPAgentTest,
DebuggerSkipAnonymousScriptsRuntimeEvaluateWithDebuggerStatement) {
int msgId = 1;

sendAndCheckResponse("Debugger.enable", msgId++);
sendAndCheckResponse("Runtime.enable", msgId++);

// setBlackboxPatterns with skipAnonymous = true
sendRequest(
"Debugger.setBlackboxPatterns", msgId, [](::hermes::JSONEmitter &json) {
json.emitKey("patterns");
json.openArray();
json.closeArray();
json.emitKeyValue("skipAnonymous", true);
});
ensureOkResponse(waitForMessage("setBlackboxPatterns"), msgId++);

// evaluate an expression containing a debugger statement
sendRequest("Runtime.evaluate", msgId, [](::hermes::JSONEmitter &params) {
params.emitKeyValue("expression", R"(
function aa() {
debugger; // (line 2)
return 12;
};
aa(); // (line 5)
)");
});
expectNotification("Debugger.scriptParsed");

// expect the eval to resolve without hitting the debugger statement
expectResponse(std::nullopt, msgId++);
}

TEST_F(CDPAgentTest, DebuggerFiltersNativeFrames) {
int msgId = 1;

Expand Down Expand Up @@ -3594,6 +3708,34 @@ TEST_F(CDPAgentTest, RuntimeEvaluateNested) {
EXPECT_EQ(jsonScope_.getNumber(resp1, {"result", "result", "value"}), 4);
}

TEST_F(CDPAgentTest, RuntimeEvaluateWithDebuggerStatement) {
int msgId = 1;

sendAndCheckResponse("Debugger.enable", msgId++);
sendAndCheckResponse("Runtime.enable", msgId++);

// evaluate an expression containing a debugger statement
int evalMsgId = msgId++;
sendRequest("Runtime.evaluate", evalMsgId, [](::hermes::JSONEmitter &params) {
params.emitKeyValue("expression", R"(
function aa() {
debugger; // (line 2)
return 12;
};
aa(); // (line 5)
)");
});
expectNotification("Debugger.scriptParsed");

// stopped at the debugger -> resume
ensurePaused(waitForMessage(), "other", {{"aa", 2, 2}, {"global", 5, 1}});
sendAndCheckResponse("Debugger.resume", msgId++);
ensureNotification(waitForMessage(), "Debugger.resumed");

// evaluation finished
expectResponse(std::nullopt, evalMsgId);
}

TEST_F(CDPAgentTest, RuntimeCallFunctionOnObject) {
int msgId = 1;

Expand Down

0 comments on commit f708c3b

Please sign in to comment.