Changeset 239583 in webkit


Ignore:
Timestamp:
Jan 2, 2019 7:48:19 PM (5 years ago)
Author:
webkit@devinrousso.com
Message:

Web Inspector: Implement queryObjects Command Line API
https://bugs.webkit.org/show_bug.cgi?id=176766
<rdar://problem/34890689>

Reviewed by Joseph Pecoraro.

Source/JavaScriptCore:

Introduces a new Command Line function called queryObjects that will return an array of
object that have the given constructor/prototype argument in their prototype chain.

  • queryObjects(Promise) will return an array of all Promises.
  • queryObjects(Foo) will return all objects created with the constructor Foo.

Currently, an error is thrown if the first argument is one of the following:

  • Object
  • Object.prototype
  • Function
  • Function.prototype
  • Array
  • Array.prototype
  • Map
  • Map.prototype
  • Set
  • Set.prototype
  • Proxy

The reason for this is that we don't want to expose any internal/builtin objects, as some of
them are highly sensitive and undefined behaviour can occur if they are modified.

  • inspector/JSInjectedScriptHost.h:
  • inspector/JSInjectedScriptHost.cpp:

(Inspector::checkForbiddenPrototype): Added.
(Inspector::JSInjectedScriptHost::queryObjects): Added.
Does a GC and then iterates over all live JSCell in the heap to find these objects.

  • inspector/JSInjectedScriptHostPrototype.cpp:

(Inspector::JSInjectedScriptHostPrototype::finishCreation):
(Inspector::jsInjectedScriptHostPrototypeFunctionQueryObjects): Added.

  • inspector/InjectedScriptSource.js:

(queryObjects): Added.

  • runtime/JSGlobalObject.h:

(JSC::JSGlobalObject::promisePrototype): Added.

Source/WebCore:

Test: inspector/console/queryObjects.html

  • inspector/CommandLineAPIModuleSource.js:

(CommandLineAPI):
(CommandLineAPIImpl.prototype.queryObjects): Added.

Source/WebInspectorUI:

  • UserInterface/Controllers/JavaScriptRuntimeCompletionProvider.js:

(WI.JavaScriptRuntimeCompletionProvider.completionControllerCompletionsNeeded.receivedPropertyNames):
Add queryObjects to the list of command line functions.

LayoutTests:

  • inspector/console/queryObjects-expected.html: Added.
  • inspector/console/queryObjects.html: Added.
  • http/tests/inspector/console/cross-domain-inspected-node-access-expected.txt:
Location:
trunk
Files:
2 added
12 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r239579 r239583  
     12019-01-02  Devin Rousso  <webkit@devinrousso.com>
     2
     3        Web Inspector: Implement `queryObjects` Command Line API
     4        https://bugs.webkit.org/show_bug.cgi?id=176766
     5        <rdar://problem/34890689>
     6
     7        Reviewed by Joseph Pecoraro.
     8
     9        * inspector/console/queryObjects-expected.html: Added.
     10        * inspector/console/queryObjects.html: Added.
     11
     12        * http/tests/inspector/console/cross-domain-inspected-node-access-expected.txt:
     13
    1142019-01-02  Charles Vazac  <cvazac@gmail.com>
    215
  • trunk/LayoutTests/http/tests/inspector/dom/cross-domain-inspected-node-access-expected.txt

    r222486 r239583  
    1 CONSOLE MESSAGE: line 42: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
    2 CONSOLE MESSAGE: line 42: Blocked a frame with origin "http://localhost:8000" from accessing a frame with origin "http://127.0.0.1:8000". Protocols, domains, and ports must match.
     1CONSOLE MESSAGE: line 43: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
     2CONSOLE MESSAGE: line 43: Blocked a frame with origin "http://localhost:8000" from accessing a frame with origin "http://127.0.0.1:8000". Protocols, domains, and ports must match.
    33Test that code evaluated in the main frame cannot access $0 that resolves to a node in a frame from a different domain. Bug 105423.
    44
  • trunk/Source/JavaScriptCore/ChangeLog

    r239569 r239583  
     12019-01-02  Devin Rousso  <webkit@devinrousso.com>
     2
     3        Web Inspector: Implement `queryObjects` Command Line API
     4        https://bugs.webkit.org/show_bug.cgi?id=176766
     5        <rdar://problem/34890689>
     6
     7        Reviewed by Joseph Pecoraro.
     8
     9        Introduces a new Command Line function called `queryObjects` that will return an array of
     10        object that have the given constructor/prototype argument in their prototype chain.
     11         - `queryObjects(Promise)` will return an array of all Promises.
     12         - `queryObjects(Foo)` will return all objects created with the constructor `Foo`.
     13
     14        Currently, an error is thrown if the first argument is one of the following:
     15         - Object
     16         - Object.prototype
     17         - Function
     18         - Function.prototype
     19         - Array
     20         - Array.prototype
     21         - Map
     22         - Map.prototype
     23         - Set
     24         - Set.prototype
     25         - Proxy
     26
     27        The reason for this is that we don't want to expose any internal/builtin objects, as some of
     28        them are highly sensitive and undefined behaviour can occur if they are modified.
     29
     30        * inspector/JSInjectedScriptHost.h:
     31        * inspector/JSInjectedScriptHost.cpp:
     32        (Inspector::checkForbiddenPrototype): Added.
     33        (Inspector::JSInjectedScriptHost::queryObjects): Added.
     34        Does a GC and then iterates over all live JSCell in the heap to find these objects.
     35
     36        * inspector/JSInjectedScriptHostPrototype.cpp:
     37        (Inspector::JSInjectedScriptHostPrototype::finishCreation):
     38        (Inspector::jsInjectedScriptHostPrototypeFunctionQueryObjects): Added.
     39
     40        * inspector/InjectedScriptSource.js:
     41        (queryObjects): Added.
     42
     43        * runtime/JSGlobalObject.h:
     44        (JSC::JSGlobalObject::promisePrototype): Added.
     45
    1462018-12-31  Keith Miller  <keith_miller@apple.com>
    247
  • trunk/Source/JavaScriptCore/inspector/InjectedScriptSource.js

    r238850 r239583  
    14481448        return result;
    14491449    },
     1450
     1451    function queryObjects() {
     1452        return InjectedScriptHost.queryObjects(...arguments);
     1453    },
    14501454];
    14511455
  • trunk/Source/JavaScriptCore/inspector/JSInjectedScriptHost.cpp

    r233122 r239583  
    2828
    2929#include "ArrayIteratorPrototype.h"
     30#include "ArrayPrototype.h"
    3031#include "BuiltinNames.h"
    3132#include "Completion.h"
     
    3334#include "DirectArguments.h"
    3435#include "Error.h"
     36#include "FunctionPrototype.h"
     37#include "HeapIterationScope.h"
    3538#include "InjectedScriptHost.h"
    3639#include "IterationKind.h"
     
    4548#include "JSMap.h"
    4649#include "JSPromise.h"
     50#include "JSPromisePrototype.h"
    4751#include "JSSet.h"
    4852#include "JSStringIterator.h"
     
    5256#include "JSWithScope.h"
    5357#include "MapIteratorPrototype.h"
     58#include "MapPrototype.h"
     59#include "MarkedSpaceInlines.h"
    5460#include "ObjectConstructor.h"
     61#include "ObjectPrototype.h"
    5562#include "ProxyObject.h"
    5663#include "RegExpObject.h"
    5764#include "ScopedArguments.h"
    5865#include "SetIteratorPrototype.h"
     66#include "SetPrototype.h"
    5967#include "SourceCode.h"
    6068#include "TypedArrayInlines.h"
     
    622630}
    623631
     632static bool checkForbiddenPrototype(ExecState* exec, JSValue value, JSValue proto)
     633{
     634    if (value == proto)
     635        return true;
     636
     637    // Check that the prototype chain of proto hasn't been modified to include value.
     638    return JSObject::defaultHasInstance(exec, proto, value);
     639}
     640
     641JSValue JSInjectedScriptHost::queryObjects(ExecState* exec)
     642{
     643    if (exec->argumentCount() < 1)
     644        return jsUndefined();
     645
     646    VM& vm = exec->vm();
     647    auto scope = DECLARE_THROW_SCOPE(vm);
     648
     649    JSValue prototypeOrConstructor = exec->uncheckedArgument(0);
     650    if (!prototypeOrConstructor.isObject())
     651        return throwTypeError(exec, scope, "queryObjects first argument must be an object."_s);
     652
     653    JSObject* object = asObject(prototypeOrConstructor);
     654    if (object->inherits<ProxyObject>(vm))
     655        return throwTypeError(exec, scope, "queryObjects cannot be called with a Proxy."_s);
     656
     657    JSValue prototype = object;
     658
     659    PropertySlot prototypeSlot(object, PropertySlot::InternalMethodType::VMInquiry);
     660    if (object->getPropertySlot(exec, vm.propertyNames->prototype, prototypeSlot)) {
     661        RETURN_IF_EXCEPTION(scope, { });
     662        if (prototypeSlot.isValue()) {
     663            JSValue prototypeValue = prototypeSlot.getValue(exec, vm.propertyNames->prototype);
     664            if (prototypeValue.isObject()) {
     665                prototype = prototypeValue;
     666                object = asObject(prototype);
     667            }
     668        }
     669    }
     670
     671    if (object->inherits<ProxyObject>(vm) || prototype.inherits<ProxyObject>(vm))
     672        return throwTypeError(exec, scope, "queryObjects cannot be called with a Proxy."_s);
     673
     674    // FIXME: implement a way of distinguishing between internal and user-created objects.
     675    JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject();
     676    if (checkForbiddenPrototype(exec, object, lexicalGlobalObject->objectPrototype()))
     677        return throwTypeError(exec, scope, "queryObjects cannot be called with Object."_s);
     678    if (checkForbiddenPrototype(exec, object, lexicalGlobalObject->functionPrototype()))
     679        return throwTypeError(exec, scope, "queryObjects cannot be called with Function."_s);
     680    if (checkForbiddenPrototype(exec, object, lexicalGlobalObject->arrayPrototype()))
     681        return throwTypeError(exec, scope, "queryObjects cannot be called with Array."_s);
     682    if (checkForbiddenPrototype(exec, object, lexicalGlobalObject->mapPrototype()))
     683        return throwTypeError(exec, scope, "queryObjects cannot be called with Map."_s);
     684    if (checkForbiddenPrototype(exec, object, lexicalGlobalObject->jsSetPrototype()))
     685        return throwTypeError(exec, scope, "queryObjects cannot be called with Set."_s);
     686    if (checkForbiddenPrototype(exec, object, lexicalGlobalObject->promisePrototype()))
     687        return throwTypeError(exec, scope, "queryObjects cannot be called with Promise."_s);
     688
     689    sanitizeStackForVM(&vm);
     690    vm.heap.collectNow(Sync, CollectionScope::Full);
     691
     692    JSArray* array = constructEmptyArray(exec, nullptr);
     693    RETURN_IF_EXCEPTION(scope, { });
     694
     695    {
     696        HeapIterationScope iterationScope(vm.heap);
     697        vm.heap.objectSpace().forEachLiveCell(iterationScope, [&] (HeapCell* cell, HeapCell::Kind kind) {
     698            if (!isJSCellKind(kind))
     699                return IterationStatus::Continue;
     700
     701            JSValue value(static_cast<JSCell*>(cell));
     702            if (value.inherits<ProxyObject>(vm))
     703                return IterationStatus::Continue;
     704
     705            if (JSObject::defaultHasInstance(exec, value, prototype))
     706                array->putDirectIndex(exec, array->length(), value);
     707
     708            return IterationStatus::Continue;
     709        });
     710    }
     711
     712    return array;
     713}
     714
    624715} // namespace Inspector
  • trunk/Source/JavaScriptCore/inspector/JSInjectedScriptHost.h

    r229413 r239583  
    7272    JSC::JSValue weakSetEntries(JSC::ExecState*);
    7373    JSC::JSValue iteratorEntries(JSC::ExecState*);
     74    JSC::JSValue queryObjects(JSC::ExecState*);
    7475
    7576protected:
  • trunk/Source/JavaScriptCore/inspector/JSInjectedScriptHostPrototype.cpp

    r223027 r239583  
    5050static EncodedJSValue JSC_HOST_CALL jsInjectedScriptHostPrototypeFunctionWeakSetEntries(ExecState*);
    5151static EncodedJSValue JSC_HOST_CALL jsInjectedScriptHostPrototypeFunctionIteratorEntries(ExecState*);
     52static EncodedJSValue JSC_HOST_CALL jsInjectedScriptHostPrototypeFunctionQueryObjects(ExecState*);
    5253static EncodedJSValue JSC_HOST_CALL jsInjectedScriptHostPrototypeFunctionEvaluateWithScopeExtension(ExecState*);
    5354
     
    7374    JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("weakSetEntries", jsInjectedScriptHostPrototypeFunctionWeakSetEntries, static_cast<unsigned>(PropertyAttribute::DontEnum), 1);
    7475    JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("iteratorEntries", jsInjectedScriptHostPrototypeFunctionIteratorEntries, static_cast<unsigned>(PropertyAttribute::DontEnum), 1);
     76    JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("queryObjects", jsInjectedScriptHostPrototypeFunctionQueryObjects, static_cast<unsigned>(PropertyAttribute::DontEnum), 1);
    7577    JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("evaluateWithScopeExtension", jsInjectedScriptHostPrototypeFunctionEvaluateWithScopeExtension, static_cast<unsigned>(PropertyAttribute::DontEnum), 1);
    7678
     
    195197}
    196198
     199EncodedJSValue JSC_HOST_CALL jsInjectedScriptHostPrototypeFunctionQueryObjects(ExecState* exec)
     200{
     201    VM& vm = exec->vm();
     202    auto scope = DECLARE_THROW_SCOPE(vm);
     203
     204    JSValue thisValue = exec->thisValue();
     205    JSInjectedScriptHost* castedThis = jsDynamicCast<JSInjectedScriptHost*>(vm, thisValue);
     206    if (!castedThis)
     207        return throwVMTypeError(exec, scope);
     208
     209    return JSValue::encode(castedThis->queryObjects(exec));
     210}
     211
    197212EncodedJSValue JSC_HOST_CALL jsInjectedScriptHostPrototypeFunctionEvaluateWithScopeExtension(ExecState* exec)
    198213{
  • trunk/Source/JavaScriptCore/runtime/JSGlobalObject.h

    r237469 r239583  
    617617    // Workaround for the name conflict between JSCell::setPrototype.
    618618    SetPrototype* jsSetPrototype() const { return m_setPrototype.get(); }
     619    JSPromisePrototype* promisePrototype() const { return m_promisePrototype.get(); }
    619620    AsyncGeneratorPrototype* asyncGeneratorPrototype() const { return m_asyncGeneratorPrototype.get(); }
    620621    AsyncGeneratorFunctionPrototype* asyncGeneratorFunctionPrototype() const { return m_asyncGeneratorFunctionPrototype.get(); }
  • trunk/Source/WebCore/ChangeLog

    r239579 r239583  
     12019-01-02  Devin Rousso  <webkit@devinrousso.com>
     2
     3        Web Inspector: Implement `queryObjects` Command Line API
     4        https://bugs.webkit.org/show_bug.cgi?id=176766
     5        <rdar://problem/34890689>
     6
     7        Reviewed by Joseph Pecoraro.
     8
     9        Test: inspector/console/queryObjects.html
     10
     11        * inspector/CommandLineAPIModuleSource.js:
     12        (CommandLineAPI):
     13        (CommandLineAPIImpl.prototype.queryObjects): Added.
     14
    1152019-01-02  Charles Vazac  <cvazac@gmail.com>
    216
  • trunk/Source/WebCore/inspector/CommandLineAPIModuleSource.js

    r234563 r239583  
    5858
    5959    // Command Line API methods.
    60     for (let member of CommandLineAPI.members_) {
    61         this[member] = bind(commandLineAPIImpl[member], commandLineAPIImpl);
    62         this[member].toString = function() { return "function " + member + "() { [Command Line API] }" };
     60    for (let i = 0; i < CommandLineAPI.methods.length; ++i) {
     61        let method = CommandLineAPI.methods[i];
     62        this[method] = bind(commandLineAPIImpl[method], commandLineAPIImpl);
     63        this[method].toString = function() { return "function " + method + "() { [Command Line API] }" };
    6364    }
    6465}
     
    6869 * @const
    6970 */
    70 CommandLineAPI.members_ = [
    71     "$", "$$", "$x", "dir", "dirxml", "keys", "values", "profile", "profileEnd", "table",
    72     "monitorEvents", "unmonitorEvents", "inspect", "copy", "clear", "getEventListeners"
     71CommandLineAPI.methods = [
     72    "$",
     73    "$$",
     74    "$x",
     75    "clear",
     76    "copy",
     77    "dir",
     78    "dirxml",
     79    "getEventListeners",
     80    "inspect",
     81    "keys",
     82    "monitorEvents",
     83    "profile",
     84    "profileEnd",
     85    "queryObjects",
     86    "table",
     87    "unmonitorEvents",
     88    "values",
    7389];
    7490
     
    220236    {
    221237        return this._inspect(object);
     238    },
     239
     240    queryObjects()
     241    {
     242        return InjectedScriptHost.queryObjects(...arguments);
    222243    },
    223244
  • trunk/Source/WebInspectorUI/ChangeLog

    r239530 r239583  
     12019-01-02  Devin Rousso  <webkit@devinrousso.com>
     2
     3        Web Inspector: Implement `queryObjects` Command Line API
     4        https://bugs.webkit.org/show_bug.cgi?id=176766
     5        <rdar://problem/34890689>
     6
     7        Reviewed by Joseph Pecoraro.
     8
     9        * UserInterface/Controllers/JavaScriptRuntimeCompletionProvider.js:
     10        (WI.JavaScriptRuntimeCompletionProvider.completionControllerCompletionsNeeded.receivedPropertyNames):
     11        Add `queryObjects` to the list of command line functions.
     12
    1132018-12-21  Devin Rousso  <drousso@apple.com>
    214
  • trunk/Source/WebInspectorUI/UserInterface/Controllers/JavaScriptRuntimeCompletionProvider.js

    r226674 r239583  
    219219
    220220            if (!base) {
    221                 var commandLineAPI = ["$", "$$", "$x", "dir", "dirxml", "keys", "values", "profile", "profileEnd", "monitorEvents", "unmonitorEvents", "inspect", "copy", "clear", "getEventListeners", "$0", "$_"];
     221                let commandLineAPI = WI.JavaScriptRuntimeCompletionProvider._commandLineAPI.slice(0);
    222222                if (WI.debuggerManager.paused) {
    223223                    let targetData = WI.debuggerManager.dataForTarget(WI.runtimeManager.activeExecutionContext.target);
     
    225225                        commandLineAPI.push("$exception");
    226226                }
    227                 for (var i = 0; i < commandLineAPI.length; ++i)
    228                     propertyNames[commandLineAPI[i]] = true;
     227                for (let name of commandLineAPI)
     228                    propertyNames[name] = true;
    229229
    230230                // FIXME: Due to caching, sometimes old $n values show up as completion results even though they are not available. We should clear that proactively.
     
    302302    }
    303303};
     304
     305WI.JavaScriptRuntimeCompletionProvider._commandLineAPI = [
     306    "$",
     307    "$$",
     308    "$0",
     309    "$_",
     310    "$x",
     311    "clear",
     312    "copy",
     313    "dir",
     314    "dirxml",
     315    "getEventListeners",
     316    "inspect",
     317    "keys",
     318    "monitorEvents",
     319    "profile",
     320    "profileEnd",
     321    "queryObjects",
     322    "table",
     323    "unmonitorEvents",
     324    "values",
     325];
Note: See TracChangeset for help on using the changeset viewer.