Bug 206110 - Web Inspector: unable to evaluate in the isolated world of content scripts injected by safari app extensions
Summary: Web Inspector: unable to evaluate in the isolated world of content scripts in...
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: Web Inspector (show other bugs)
Version: WebKit Local Build
Hardware: All All
: P2 Normal
Assignee: Devin Rousso
URL:
Keywords: InRadar
Depends on:
Blocks: 207232 208502
  Show dependency treegraph
 
Reported: 2020-01-10 16:35 PST by Devin Rousso
Modified: 2020-03-03 00:08 PST (History)
26 users (show)

See Also:


Attachments
Patch (104.52 KB, patch)
2020-01-10 17:08 PST, Devin Rousso
no flags Details | Formatted Diff | Diff
[Image] After Patch is applied (218.49 KB, image/png)
2020-01-10 17:09 PST, Devin Rousso
no flags Details
Patch (108.50 KB, patch)
2020-01-26 23:09 PST, Devin Rousso
no flags Details | Formatted Diff | Diff
[Patch] speculative win build fix (2.79 KB, patch)
2020-01-27 18:52 PST, Devin Rousso
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Devin Rousso 2020-01-10 16:35:25 PST
.
Comment 1 Devin Rousso 2020-01-10 16:35:40 PST
<rdar://problem/16945643>
Comment 2 Devin Rousso 2020-01-10 17:08:15 PST
Created attachment 387400 [details]
Patch
Comment 3 EWS Watchlist 2020-01-10 17:09:10 PST
Thanks for the patch. If this patch contains new public API please make sure it follows the guidelines for new WebKit2 GTK+ API. See http://trac.webkit.org/wiki/WebKitGTK/AddingNewWebKit2API

This patch modifies the inspector protocol. Please ensure that any frontend changes appropriately use feature checks for new protocol features.
Comment 4 Devin Rousso 2020-01-10 17:09:35 PST
Created attachment 387401 [details]
[Image] After Patch is applied

The checkbox is shown for _both_ "Auto - <...>" and the resolved execution context when "Auto - <...>" is selected so that if there are multiple execution contexts with the same display name, it's clear which one is currently active.
Comment 5 Joseph Pecoraro 2020-01-10 17:16:04 PST
Comment on attachment 387400 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=387400&action=review

> Source/WebKit/WebProcess/InjectedBundle/InjectedBundleScriptWorld.h:43
> +    static Ref<InjectedBundleScriptWorld> create(bool isInternal = true);
> +    static Ref<InjectedBundleScriptWorld> create(const String& name, bool isInternal = true);

An `enum` would reach so much better. `enum Type { User, Internal }`
Comment 6 Timothy Hatcher 2020-01-10 17:16:41 PST
Comment on attachment 387400 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=387400&action=review

> Source/WebCore/html/HTMLMediaElement.cpp:7209
> +        m_isolatedWorld = DOMWrapperWorld::create(commonVM(), DOMWrapperWorld::Type::Internal, makeString("Media Controls (", localName(), ')'));

Should you use ")" instead of ')'?
Comment 7 Joseph Pecoraro 2020-01-12 13:55:58 PST
(In reply to Timothy Hatcher from comment #6)
> Comment on attachment 387400 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=387400&action=review
> 
> > Source/WebCore/html/HTMLMediaElement.cpp:7209
> > +        m_isolatedWorld = DOMWrapperWorld::create(commonVM(), DOMWrapperWorld::Type::Internal, makeString("Media Controls (", localName(), ')'));
> 
> Should you use ")" instead of ')'?

This can be kept a character literal instead of a string. It is typically more efficient for string concatenation to deal with a `char` instead of a multi-character string literal `char*`. Though I'm not sure how much of this gets optimized by the compiler, since some of this goes through templated code and the strlen(...) of a literal like this can typically be done at compile time.
Comment 8 BJ Burg 2020-01-14 09:52:01 PST
Comment on attachment 387400 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=387400&action=review

r=me as well, but some EWS problems remain. Great work!

> Source/WebCore/bindings/js/WebCoreJSClientData.cpp:120
> +    clientData->m_normalWorld = DOMWrapperWorld::create(*vm, DOMWrapperWorld::Type::Normal);

Lovely!

> Source/WebCore/inspector/agents/InspectorPageAgent.cpp:774
> +void InspectorPageAgent::didClearWindowObjectInWorld(Frame& frame, DOMWrapperWorld& world)

Well that was an awkward method signature, but now it reads better.

>> Source/WebKit/WebProcess/InjectedBundle/InjectedBundleScriptWorld.h:43
>> +    static Ref<InjectedBundleScriptWorld> create(const String& name, bool isInternal = true);
> 
> An `enum` would reach so much better. `enum Type { User, Internal }`

enum class?
Comment 9 Devin Rousso 2020-01-26 23:09:46 PST
Created attachment 388830 [details]
Patch
Comment 10 WebKit Commit Bot 2020-01-27 15:49:17 PST
Comment on attachment 388830 [details]
Patch

Clearing flags on attachment: 388830

Committed r255191: <https://trac.webkit.org/changeset/255191>
Comment 11 WebKit Commit Bot 2020-01-27 15:49:19 PST
All reviewed patches have been landed.  Closing bug.
Comment 12 Devin Rousso 2020-01-27 17:49:27 PST
Unreviewed, speculative win build fix: <https://trac.webkit.org/r255212>
Comment 13 Devin Rousso 2020-01-27 18:52:38 PST
Created attachment 388959 [details]
[Patch] speculative win build fix
Comment 14 Devin Rousso 2020-01-27 19:02:32 PST
Unreviewed, speculative win build fix: <https://trac.webkit.org/r255221>
Comment 15 Pavel Feldman 2020-01-29 00:33:19 PST
Comment on attachment 388830 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=388830&action=review

> Source/WebCore/inspector/agents/page/PageRuntimeAgent.cpp:178
> +    auto injectedScript = injectedScriptManager().injectedScriptFor(globalObject);

I believe there is a subtle issue here - when didClearWindowObjectInWorld is called for the User world before it is called for the Normal world, subsequent call to clear the normal world will erase this injected script from the InjectedScriptManager through m_injectedScriptManager->discardInjectedScripts().

This can either be patched via the following change to the dispatchDidClearWindowObjectsInAllWorlds (that is somewhat hacky), or via going back to instrumenting only normal worlds and iterating over the remaining worlds within agents explicitly.

void FrameLoader::dispatchDidClearWindowObjectsInAllWorlds()
{
    Vector<Ref<DOMWrapperWorld>> worlds;
    ScriptController::getAllWorlds(worlds);
    // It is essential that the normal world is cleared first.
    // Various subsystem (InjectedScriptManager) will reset state upon normal
    // world initialization.
    Vector<DOMWrapperWorld*> nonNormalWorlds;
    for (auto& world : worlds) {
        if (world->type() == DOMWrapperWorld::Type::Normal)
            dispatchDidClearWindowObjectInWorld(world);
        else
            nonNormalWorlds.append(&world.get());
    }
    for (auto* world : nonNormalWorlds)
        dispatchDidClearWindowObjectInWorld(*world);
}
Comment 16 Devin Rousso 2020-02-03 11:00:49 PST
Comment on attachment 388830 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=388830&action=review

>> Source/WebCore/inspector/agents/page/PageRuntimeAgent.cpp:178
>> +    auto injectedScript = injectedScriptManager().injectedScriptFor(globalObject);
> 
> I believe there is a subtle issue here - when didClearWindowObjectInWorld is called for the User world before it is called for the Normal world, subsequent call to clear the normal world will erase this injected script from the InjectedScriptManager through m_injectedScriptManager->discardInjectedScripts().
> 
> This can either be patched via the following change to the dispatchDidClearWindowObjectsInAllWorlds (that is somewhat hacky), or via going back to instrumenting only normal worlds and iterating over the remaining worlds within agents explicitly.
> 
> void FrameLoader::dispatchDidClearWindowObjectsInAllWorlds()
> {
>     Vector<Ref<DOMWrapperWorld>> worlds;
>     ScriptController::getAllWorlds(worlds);
>     // It is essential that the normal world is cleared first.
>     // Various subsystem (InjectedScriptManager) will reset state upon normal
>     // world initialization.
>     Vector<DOMWrapperWorld*> nonNormalWorlds;
>     for (auto& world : worlds) {
>         if (world->type() == DOMWrapperWorld::Type::Normal)
>             dispatchDidClearWindowObjectInWorld(world);
>         else
>             nonNormalWorlds.append(&world.get());
>     }
>     for (auto* world : nonNormalWorlds)
>         dispatchDidClearWindowObjectInWorld(*world);
> }

Interesting!  That is super subtle :P

I think we'd ideally want to dispatch for the `mainThreadNormalWorld()` first (as that's really the "signpost" for resetting all the injected scripts and debugger state), then all other normal worlds, and then all other worlds.  IIUC, there should only ever be one normal world though (and the current code supports that), so I think we can just do as you suggest.

@Pavel Feldman, do you want to fix this, or should I?
Comment 17 Devin Rousso 2020-02-04 14:58:31 PST
Comment on attachment 388830 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=388830&action=review

>>> Source/WebCore/inspector/agents/page/PageRuntimeAgent.cpp:178
>>> +    auto injectedScript = injectedScriptManager().injectedScriptFor(globalObject);
>> 
>> I believe there is a subtle issue here - when didClearWindowObjectInWorld is called for the User world before it is called for the Normal world, subsequent call to clear the normal world will erase this injected script from the InjectedScriptManager through m_injectedScriptManager->discardInjectedScripts().
>> 
>> This can either be patched via the following change to the dispatchDidClearWindowObjectsInAllWorlds (that is somewhat hacky), or via going back to instrumenting only normal worlds and iterating over the remaining worlds within agents explicitly.
>> 
>> void FrameLoader::dispatchDidClearWindowObjectsInAllWorlds()
>> {
>>     Vector<Ref<DOMWrapperWorld>> worlds;
>>     ScriptController::getAllWorlds(worlds);
>>     // It is essential that the normal world is cleared first.
>>     // Various subsystem (InjectedScriptManager) will reset state upon normal
>>     // world initialization.
>>     Vector<DOMWrapperWorld*> nonNormalWorlds;
>>     for (auto& world : worlds) {
>>         if (world->type() == DOMWrapperWorld::Type::Normal)
>>             dispatchDidClearWindowObjectInWorld(world);
>>         else
>>             nonNormalWorlds.append(&world.get());
>>     }
>>     for (auto* world : nonNormalWorlds)
>>         dispatchDidClearWindowObjectInWorld(*world);
>> }
> 
> Interesting!  That is super subtle :P
> 
> I think we'd ideally want to dispatch for the `mainThreadNormalWorld()` first (as that's really the "signpost" for resetting all the injected scripts and debugger state), then all other normal worlds, and then all other worlds.  IIUC, there should only ever be one normal world though (and the current code supports that), so I think we can just do as you suggest.
> 
> @Pavel Feldman, do you want to fix this, or should I?

<https://webkit.org/b/207232> Web Inspector: ensure that `didClearWindowObjectInWorld` is dispatched for the main world first
Comment 18 Pavel Feldman 2020-02-07 14:08:51 PST
Happy to follow up and fix it!
Comment 19 Joseph Pecoraro 2020-02-07 14:26:16 PST
(In reply to Pavel Feldman from comment #18)
> Happy to follow up and fix it!

I think Devin just did in bug 207232. (Though no test)