New issue
Advanced search Search tips
Note: Color blocks (like or ) mean that a user may not be available. Tooltip shows the reason.

Issue 754976 link

Starred by 7 users

Issue metadata

Status: Assigned
Owner:
Cc:
Components:
EstimatedDays: ----
NextAction: ----
OS: Linux , Windows , Mac
Pri: 1
Type: Bug-Regression



Sign in to add a comment

"debugger" statement in extension page postpones chrome API init and breaks its functionality

Reported by woxxom@gmail.com, Aug 12 2017

Issue description

UserAgent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36

Steps to reproduce the problem:
1. unpack and install the attached extension
2. follow the displayed instruction:
   2.1. Open devtools and reload the page.
   2.2. Hover the mouse cursor on "runtime" next to the highlighted line in debugger
   2.3. Press F8 or "play" button in devtools to continue

What is the expected behavior?
* Actual contents of the chrome.runtime is displayed
* No errors in the console afterwards

What went wrong?
* chrome.runtime is "undefined"

* These errors are displayed after continuing:
	(BLESSED_EXTENSION context for .........) Lazy require of runtime.binding did not set the binding field
	Previous API instantiation failed.
	Uncaught TypeError: Cannot read property 'getManifest' of undefined
	(BLESSED_EXTENSION context for .........) extensions::messaging:9: Uncaught Natives disabled{<stack trace unavailable>}
	Uncaught Natives disabled

* In the old Chrome the extension even crashes, but not in the current builds.
  Callstack of extension crash in r423559 revealing SuspendableScriptExecutor is attached.

Did this work before? Yes 54

Chrome version: 60.0.3112.90  Channel: n/a
OS Version: 6.1 (Windows 7, Windows Server 2008 R2)
Flash Version: Shockwave Flash 26.0 r0

========================================================================
Bisect info: 423547 (good) - 423558 (bad)
https://chromium.googlesource.com/chromium/src/+log/2bb40ba6..d3e0e665?pretty=fuller
Suspecting: r423548 "[Blink] Modify SuspendableScriptExecutor to take a v8::Function"
Landed in 55.0.2883.0
========================================================================

P.S. While using "debugger;" statement is an outdated and backwards method of setting breakpoints but supposedly many developers still use it and can't figure out why chrome extension API doesn't work at all.
 
good.png
15.0 KB View Download
bad.png
12.9 KB View Download
crash-callstack.txt
3.6 KB View Download

Comment 1 by woxxom@gmail.com, Aug 12 2017

Correction: even proper breakpoints set in devtools UI disrupt API initialization when debugging with devtools open.

Comment 2 by woxxom@gmail.com, Aug 12 2017

The extension is attached below.
test-debugger.zip
1.0 KB Download
Cc: mmanchala@chromium.org
Labels: -Pri-2 hasbisect-per-revision Needs-Triage-M61 OS-Linux OS-Mac Pri-1
Owner: rdevlin....@chromium.org
Status: Assigned (was: Unconfirmed)
Able to reproduce the issue on Windows-7,Windows-10,Mac-10.12.4 and Linux Ubuntu-14.04 using chrome stable version # 60.0.3112.90  and canary 62.0.3182.0 with the steps mentioned in comment#0

As per comment #0 
Good Build Revision: 423547 
Bad Build Revision : 423558

CHANGE-LOG URL:
---------------
https://chromium.googlesource.com/chromium/src/+/a9bc8ccd2becc952e4cea2d8a053247a481dd483

Suspecting https://codereview.chromium.org/2339683006 from changelog

@rdevlin.cronin: Could you please take a look into this issue and reassign if this issue is not related to your change.

Thanks..!!
Labels: -Needs-Triage-M61 Needs-Triage-M60 M-62
 Issue 756096  has been merged into this issue.
Cc: haraken@chromium.org jbroman@chromium.org dcheng@chromium.org
Nifty.

So, what's happening here:
Extension bindings are (currently) constructed in JavaScript with lazy getters (i.e., a stub property is added which is replaced with a real value on an as-needed basis; and that real value is created in JS).  While debugging, JS is "suspended".  So when you pause JS in a debugger and then try to examine a new property for the first time, it will try to perform the lazy getter, which will then try to execute JS, and subsequently fail (because JS is suspended).

Why this worked before is because extension bindings didn't execute JS suspension.  This led to other bugs.

Looking farther ahead, the right answer to this is that extension bindings will be entirely native, and this will just work naturally, because it won't execute any script.  Unfortunately, while the core of the bindings system is pretty much ready, converting each of the <n> custom bindings we have from JS to C++ will take time.

So, what can we do here?  It seems like these are a bit fundamentally at odds - we need to respect script suspension, but also execute script to return a value while suspended.  I'm not sure if there would be a way of detecting whether the getter was activated for devtools, and, if so, allowing nested script execution in that case (or if that would be something we'd want to do).

Plus some folks for thoughts.
I think it would make more sense to allow running extension bindings because it is not an author script. (For example, scripts typed in DevTools are running while the document is suspended but it makes sense. Extension bindings are sort of the scripts.)

> Why this worked before is because extension bindings didn't execute JS suspension.  This led to other bugs.

What were the bugs?





> I think it would make more sense to allow running extension bindings because it is not an author script. (For example, scripts typed in DevTools are running while the document is suspended but it makes sense. Extension bindings are sort of the scripts.)

hmm... this makes me a bit nervous because extension bindings are often, in some way, potentially visible to author script (we've had a ton of bugs around this where author script was executed when it shouldn't be, such as issue 628942).  This seems like it opens the door to those.  We could say that only the bindings-instantiation code is allowed to run during these times, but we'd still be at risk of having author script tampering with it.  Maybe that's an acceptable risk, since we should be striving to lock down that code anyway?

> What were the bugs?
 issue 629431  is one of the main ones that tracks the effort to respect script suspension, but there were others that were similar.
Thanks for the clarification!

Would it be a terrible idea to leave this bug as is until we convert all JS extension bindings to C++?

If it's not acceptable, would it be an option to allow running the extension bindings only when the document is suspended by DevTool's breakpoint? (i.e., forbid running the extension bindings when the document is suspended in other ways; e.g., page load deferrer)

> Would it be a terrible idea to leave this bug as is until we convert all JS extension bindings to C++?

I'm not entirely opposed to it - this has been broken since M55.  If there's a reasonable fix, that would obviously be preferable, but I don't think leaving things in this state for a bit longer is inviable.

> would it be an option to allow running the extension bindings only when the document is suspended by DevTool's breakpoint? (i.e., forbid running the extension bindings when the document is suspended in other ways; e.g., page load deferrer)

I'd be supportive of that, but I don't know if we have that info from the extensions layer.  Do you know how we determine that?
>> would it be an option to allow running the extension bindings only when the document is suspended by DevTool's breakpoint? (i.e., forbid running the extension bindings when the document is suspended in other ways; e.g., page load deferrer)
>
> I'd be supportive of that, but I don't know if we have that info from the extensions layer.  Do you know how we determine that?

I think we need to introduce Page::SetPausedByDevTools (in addition to the existing Page::SetPaused) to distinguish the two cases (i.e., paused by DevTools or paused by other things). Then expose that info to SuspendableScriptExecutor.

This is technically doable but adds some complexity to the architecture.

I'd be supportive of that approach, and happy to tackle the extensions side, but I'd probably want someone more familiar with the blink half to handle that portion.  I don't have a good estimation of how much work it would be for if you consider it worthwhile (the extensions side is probably doable in a single moderate size CL).  Otherwise, we can add this to the list of things that will be fixed with native bindings.
Yeah, I'd prefer fixing this by implementing native bindings unless there's an urgent need to fix this :)

Comment 14 by woxxom@gmail.com, Aug 17 2017

As a temporary solution in case you choose to wait for C++ rewrite, can devtools simply inform that bindings/value/whatever is unavailable in paused state and will be initialized on continuing? That's for the hover tooltip and other places the user may access in paused state like maybe watches, console. 
Cc: kozyatinskiy@chromium.org
>> it will try to perform the lazy getter, which will then try to execute JS, and subsequently fail (because JS is suspended)

Could you elaborate on this bit / point to the source? I would think that suspending should take place on the higher level / call site. If we are reaching lazy getter, js is already being executed, so there is no point in suspending anything...

Comment 16 by woxxom@gmail.com, Aug 17 2017

Regarding the tab/extension crash in the merged  issue 756096 , will it be solved by the work done here?
I've bisected that one to r445814 "DevTools: introduce object previews experiment" 
(the corresponding info added in that report).
@15: It's rather roundabout, but the basic flow is as follows:

The lazy getter is set on the chrome object through ModuleSystem::SetLazyField:
https://chromium.googlesource.com/chromium/src/+/955c32907a2c9921065fa628e0b8b5b28a7afe6c/extensions/renderer/module_system.cc#501

DevTools then tries to evaluate the lazy field, which leads eventually to ModuleSystem::LazyFieldGetterInner and then to ModuleSystem::Require.  ModuleSystem::Require calls ModuleSystem::RequireForJSInner, which calls ModuleSystem::LoadModule:

https://chromium.googlesource.com/chromium/src/+/955c32907a2c9921065fa628e0b8b5b28a7afe6c/extensions/renderer/module_system.cc#706

ModuleSystem::LoadModule wraps a JS resource in a function, and then calls that through the ScriptContext, which uses blink::WebFrame::RequestExecuteV8Function:
https://chromium.googlesource.com/chromium/src/+/955c32907a2c9921065fa628e0b8b5b28a7afe6c/extensions/renderer/script_context.cc#205

This respects suspended JS, and thus won't execute while dev tools is open.

Comment 18 Deleted

Components: -Platform>DevTools Platform>Extensions

Sign in to add a comment