Skip to content

Commit 4418140

Browse files
Web Inspector: JSContext inspection should report exceptions in the console
https://bugs.webkit.org/show_bug.cgi?id=128776 Source/JavaScriptCore: Reviewed by Timothy Hatcher. When JavaScript API functions have an exception, let the inspector know so it can log the JavaScript and Native backtrace that caused the exception. Include some clean up of ConsoleMessage and ScriptCallStack construction. * API/JSBase.cpp: (JSEvaluateScript): (JSCheckScriptSyntax): * API/JSObjectRef.cpp: (JSObjectMakeFunction): (JSObjectMakeArray): (JSObjectMakeDate): (JSObjectMakeError): (JSObjectMakeRegExp): (JSObjectGetProperty): (JSObjectSetProperty): (JSObjectGetPropertyAtIndex): (JSObjectSetPropertyAtIndex): (JSObjectDeleteProperty): (JSObjectCallAsFunction): (JSObjectCallAsConstructor): * API/JSValue.mm: (reportExceptionToInspector): (valueToArray): (valueToDictionary): * API/JSValueRef.cpp: (JSValueIsEqual): (JSValueIsInstanceOfConstructor): (JSValueCreateJSONString): (JSValueToNumber): (JSValueToStringCopy): (JSValueToObject): When seeing an exception, let the inspector know there was an exception. * inspector/JSGlobalObjectInspectorController.h: * inspector/JSGlobalObjectInspectorController.cpp: (Inspector::JSGlobalObjectInspectorController::JSGlobalObjectInspectorController): (Inspector::JSGlobalObjectInspectorController::appendAPIBacktrace): (Inspector::JSGlobalObjectInspectorController::reportAPIException): Log API exceptions by also grabbing the native backtrace. * inspector/ScriptCallStack.h: * inspector/ScriptCallStack.cpp: (Inspector::ScriptCallStack::firstNonNativeCallFrame): (Inspector::ScriptCallStack::append): Minor extensions to ScriptCallStack to make it easier to work with. * inspector/ConsoleMessage.cpp: (Inspector::ConsoleMessage::ConsoleMessage): (Inspector::ConsoleMessage::autogenerateMetadata): Provide better default information if the first call frame was native. * inspector/ScriptCallStackFactory.cpp: (Inspector::createScriptCallStack): (Inspector::extractSourceInformationFromException): (Inspector::createScriptCallStackFromException): Perform the handling here of inserting a fake call frame for exceptions if there was no call stack (e.g. a SyntaxError) or if the first call frame had no information. * inspector/ConsoleMessage.cpp: (Inspector::ConsoleMessage::ConsoleMessage): (Inspector::ConsoleMessage::autogenerateMetadata): * inspector/ConsoleMessage.h: * inspector/ScriptCallStackFactory.cpp: (Inspector::createScriptCallStack): (Inspector::createScriptCallStackForConsole): * inspector/ScriptCallStackFactory.h: * inspector/agents/InspectorConsoleAgent.cpp: (Inspector::InspectorConsoleAgent::enable): (Inspector::InspectorConsoleAgent::addMessageToConsole): (Inspector::InspectorConsoleAgent::count): * inspector/agents/JSGlobalObjectDebuggerAgent.cpp: (Inspector::JSGlobalObjectDebuggerAgent::breakpointActionLog): ConsoleMessage cleanup. Source/WebCore: Include some clean up of ConsoleMessage and ScriptCallStack construction. Covered by existing tests. * bindings/js/JSDOMBinding.cpp: (WebCore::reportException): Simplify code now that createStackTraceFromException handles it. * page/ContentSecurityPolicy.cpp: (WebCore::gatherSecurityPolicyViolationEventData): (WebCore::ContentSecurityPolicy::reportViolation): ScriptCallStack can give us the first non-native callframe. * inspector/InspectorResourceAgent.cpp: (WebCore::InspectorResourceAgent::buildInitiatorObject): * inspector/PageDebuggerAgent.cpp: (WebCore::PageDebuggerAgent::breakpointActionLog): * inspector/TimelineRecordFactory.cpp: (WebCore::TimelineRecordFactory::createGenericRecord): * page/Console.cpp: (WebCore::internalAddMessage): (WebCore::Console::profile): (WebCore::Console::profileEnd): (WebCore::Console::timeEnd): * page/ContentSecurityPolicy.cpp: (WebCore::gatherSecurityPolicyViolationEventData): (WebCore::ContentSecurityPolicy::reportViolation): * page/DOMWindow.cpp: (WebCore::DOMWindow::postMessage): Source/WebInspectorUI: Reviewed by Timothy Hatcher. * UserInterface/ConsoleMessageImpl.js: (WebInspector.ConsoleMessageImpl.prototype._formatMessage): (WebInspector.ConsoleMessageImpl.prototype._shouldHideURL): (WebInspector.ConsoleMessageImpl.prototype._firstNonNativeCallFrame): (WebInspector.ConsoleMessageImpl.prototype._populateStackTraceTreeElement): Provide better handling for "[native code]" and legacy "undefined" call frame URLs. Never linkify these. Also, when showing a link for an exception, always use the first non-native call frame as the link location. Canonical link: https://commits.webkit.org/147194@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@164486 268f45cc-cd09-0410-ab3c-d52691b4dbfc
1 parent 1d02086 commit 4418140

25 files changed

Lines changed: 489 additions & 160 deletions

‎Source/JavaScriptCore/API/JSBase.cpp‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@
4040
#include "SourceCode.h"
4141
#include <wtf/text/StringHash.h>
4242

43+
#if ENABLE(REMOTE_INSPECTOR)
44+
#include "JSGlobalObjectInspectorController.h"
45+
#endif
46+
4347
using namespace JSC;
4448

4549
JSValueRef JSEvaluateScript(JSContextRef ctx, JSStringRef script, JSObjectRef thisObject, JSStringRef sourceURL, int startingLineNumber, JSValueRef* exception)
@@ -65,6 +69,14 @@ JSValueRef JSEvaluateScript(JSContextRef ctx, JSStringRef script, JSObjectRef th
6569
if (evaluationException) {
6670
if (exception)
6771
*exception = toRef(exec, evaluationException);
72+
#if ENABLE(REMOTE_INSPECTOR)
73+
// FIXME: If we have a debugger attached we could learn about ParseError exceptions through
74+
// ScriptDebugServer::sourceParsed and this path could produce a duplicate warning. The
75+
// Debugger path is currently ignored by inspector.
76+
// NOTE: If we don't have a debugger, this SourceCode will be forever lost to the inspector.
77+
// We could stash it in the inspector in case an inspector is ever opened.
78+
globalObject->inspectorController().reportAPIException(exec, evaluationException);
79+
#endif
6880
return 0;
6981
}
7082

@@ -94,6 +106,9 @@ bool JSCheckScriptSyntax(JSContextRef ctx, JSStringRef script, JSStringRef sourc
94106
if (!isValidSyntax) {
95107
if (exception)
96108
*exception = toRef(exec, syntaxException);
109+
#if ENABLE(REMOTE_INSPECTOR)
110+
exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, syntaxException);
111+
#endif
97112
return false;
98113
}
99114

‎Source/JavaScriptCore/API/JSObjectRef.cpp‎

Lines changed: 64 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@
5555
#include "PropertyNameArray.h"
5656
#include "RegExpConstructor.h"
5757

58+
#if ENABLE(REMOTE_INSPECTOR)
59+
#include "JSGlobalObjectInspectorController.h"
60+
#endif
61+
5862
using namespace JSC;
5963

6064
JSClassRef JSClassCreate(const JSClassDefinition* definition)
@@ -145,9 +149,13 @@ JSObjectRef JSObjectMakeFunction(JSContextRef ctx, JSStringRef name, unsigned pa
145149

146150
JSObject* result = constructFunction(exec, exec->lexicalGlobalObject(), args, nameID, sourceURL->string(), TextPosition(OrdinalNumber::fromOneBasedInt(startingLineNumber), OrdinalNumber::first()));
147151
if (exec->hadException()) {
152+
JSValue exceptionValue = exec->exception();
148153
if (exception)
149-
*exception = toRef(exec, exec->exception());
154+
*exception = toRef(exec, exceptionValue);
150155
exec->clearException();
156+
#if ENABLE(REMOTE_INSPECTOR)
157+
exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue);
158+
#endif
151159
result = 0;
152160
}
153161
return toRef(result);
@@ -173,9 +181,13 @@ JSObjectRef JSObjectMakeArray(JSContextRef ctx, size_t argumentCount, const JSVa
173181
result = constructEmptyArray(exec, 0);
174182

175183
if (exec->hadException()) {
184+
JSValue exceptionValue = exec->exception();
176185
if (exception)
177-
*exception = toRef(exec, exec->exception());
186+
*exception = toRef(exec, exceptionValue);
178187
exec->clearException();
188+
#if ENABLE(REMOTE_INSPECTOR)
189+
exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue);
190+
#endif
179191
result = 0;
180192
}
181193

@@ -197,9 +209,13 @@ JSObjectRef JSObjectMakeDate(JSContextRef ctx, size_t argumentCount, const JSVal
197209

198210
JSObject* result = constructDate(exec, exec->lexicalGlobalObject(), argList);
199211
if (exec->hadException()) {
212+
JSValue exceptionValue = exec->exception();
200213
if (exception)
201-
*exception = toRef(exec, exec->exception());
214+
*exception = toRef(exec, exceptionValue);
202215
exec->clearException();
216+
#if ENABLE(REMOTE_INSPECTOR)
217+
exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue);
218+
#endif
203219
result = 0;
204220
}
205221

@@ -220,9 +236,13 @@ JSObjectRef JSObjectMakeError(JSContextRef ctx, size_t argumentCount, const JSVa
220236
JSObject* result = ErrorInstance::create(exec, errorStructure, message);
221237

222238
if (exec->hadException()) {
239+
JSValue exceptionValue = exec->exception();
223240
if (exception)
224-
*exception = toRef(exec, exec->exception());
241+
*exception = toRef(exec, exceptionValue);
225242
exec->clearException();
243+
#if ENABLE(REMOTE_INSPECTOR)
244+
exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue);
245+
#endif
226246
result = 0;
227247
}
228248

@@ -244,9 +264,13 @@ JSObjectRef JSObjectMakeRegExp(JSContextRef ctx, size_t argumentCount, const JSV
244264

245265
JSObject* result = constructRegExp(exec, exec->lexicalGlobalObject(), argList);
246266
if (exec->hadException()) {
267+
JSValue exceptionValue = exec->exception();
247268
if (exception)
248-
*exception = toRef(exec, exec->exception());
269+
*exception = toRef(exec, exceptionValue);
249270
exec->clearException();
271+
#if ENABLE(REMOTE_INSPECTOR)
272+
exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue);
273+
#endif
250274
result = 0;
251275
}
252276

@@ -308,9 +332,13 @@ JSValueRef JSObjectGetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef
308332

309333
JSValue jsValue = jsObject->get(exec, propertyName->identifier(&exec->vm()));
310334
if (exec->hadException()) {
335+
JSValue exceptionValue = exec->exception();
311336
if (exception)
312-
*exception = toRef(exec, exec->exception());
337+
*exception = toRef(exec, exceptionValue);
313338
exec->clearException();
339+
#if ENABLE(REMOTE_INSPECTOR)
340+
exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue);
341+
#endif
314342
}
315343
return toRef(exec, jsValue);
316344
}
@@ -337,9 +365,13 @@ void JSObjectSetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef prope
337365
}
338366

339367
if (exec->hadException()) {
368+
JSValue exceptionValue = exec->exception();
340369
if (exception)
341-
*exception = toRef(exec, exec->exception());
370+
*exception = toRef(exec, exceptionValue);
342371
exec->clearException();
372+
#if ENABLE(REMOTE_INSPECTOR)
373+
exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue);
374+
#endif
343375
}
344376
}
345377

@@ -356,9 +388,13 @@ JSValueRef JSObjectGetPropertyAtIndex(JSContextRef ctx, JSObjectRef object, unsi
356388

357389
JSValue jsValue = jsObject->get(exec, propertyIndex);
358390
if (exec->hadException()) {
391+
JSValue exceptionValue = exec->exception();
359392
if (exception)
360-
*exception = toRef(exec, exec->exception());
393+
*exception = toRef(exec, exceptionValue);
361394
exec->clearException();
395+
#if ENABLE(REMOTE_INSPECTOR)
396+
exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue);
397+
#endif
362398
}
363399
return toRef(exec, jsValue);
364400
}
@@ -378,9 +414,13 @@ void JSObjectSetPropertyAtIndex(JSContextRef ctx, JSObjectRef object, unsigned p
378414

379415
jsObject->methodTable()->putByIndex(jsObject, exec, propertyIndex, jsValue, false);
380416
if (exec->hadException()) {
417+
JSValue exceptionValue = exec->exception();
381418
if (exception)
382-
*exception = toRef(exec, exec->exception());
419+
*exception = toRef(exec, exceptionValue);
383420
exec->clearException();
421+
#if ENABLE(REMOTE_INSPECTOR)
422+
exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue);
423+
#endif
384424
}
385425
}
386426

@@ -397,9 +437,13 @@ bool JSObjectDeleteProperty(JSContextRef ctx, JSObjectRef object, JSStringRef pr
397437

398438
bool result = jsObject->methodTable()->deleteProperty(jsObject, exec, propertyName->identifier(&exec->vm()));
399439
if (exec->hadException()) {
440+
JSValue exceptionValue = exec->exception();
400441
if (exception)
401-
*exception = toRef(exec, exec->exception());
442+
*exception = toRef(exec, exceptionValue);
402443
exec->clearException();
444+
#if ENABLE(REMOTE_INSPECTOR)
445+
exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue);
446+
#endif
403447
}
404448
return result;
405449
}
@@ -541,9 +585,13 @@ JSValueRef JSObjectCallAsFunction(JSContextRef ctx, JSObjectRef object, JSObject
541585

542586
JSValueRef result = toRef(exec, call(exec, jsObject, callType, callData, jsThisObject, argList));
543587
if (exec->hadException()) {
588+
JSValue exceptionValue = exec->exception();
544589
if (exception)
545-
*exception = toRef(exec, exec->exception());
590+
*exception = toRef(exec, exceptionValue);
546591
exec->clearException();
592+
#if ENABLE(REMOTE_INSPECTOR)
593+
exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue);
594+
#endif
547595
result = 0;
548596
}
549597
return result;
@@ -578,9 +626,13 @@ JSObjectRef JSObjectCallAsConstructor(JSContextRef ctx, JSObjectRef object, size
578626
argList.append(toJS(exec, arguments[i]));
579627
JSObjectRef result = toRef(construct(exec, jsObject, constructType, constructData, argList));
580628
if (exec->hadException()) {
629+
JSValue exceptionValue = exec->exception();
581630
if (exception)
582-
*exception = toRef(exec, exec->exception());
631+
*exception = toRef(exec, exceptionValue);
583632
exec->clearException();
633+
#if ENABLE(REMOTE_INSPECTOR)
634+
exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue);
635+
#endif
584636
result = 0;
585637
}
586638
return result;

‎Source/JavaScriptCore/API/JSValue.mm‎

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
2121
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2222
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23-
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2424
*/
2525

2626
#include "config.h"
@@ -47,6 +47,12 @@
4747
#import <wtf/text/WTFString.h>
4848
#import <wtf/text/StringHash.h>
4949

50+
#if ENABLE(REMOTE_INSPECTOR)
51+
#import "CallFrame.h"
52+
#import "JSGlobalObject.h"
53+
#import "JSGlobalObjectInspectorController.h"
54+
#endif
55+
5056
#if JSC_OBJC_API_ENABLED
5157

5258
NSString * const JSPropertyDescriptorWritableKey = @"writable";
@@ -629,6 +635,14 @@ @implementation JSValue(Internal)
629635
return last;
630636
}
631637

638+
#if ENABLE(REMOTE_INSPECTOR)
639+
static void reportExceptionToInspector(JSGlobalContextRef context, JSC::JSValue exception)
640+
{
641+
JSC::ExecState* exec = toJS(context);
642+
exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exception);
643+
}
644+
#endif
645+
632646
static JSContainerConvertor::Task valueToObjectWithoutCopy(JSGlobalContextRef context, JSValueRef value)
633647
{
634648
if (!JSValueIsObject(context, value)) {
@@ -781,8 +795,13 @@ id valueToArray(JSGlobalContextRef context, JSValueRef value, JSValueRef* except
781795
return containerValueToObject(context, (JSContainerConvertor::Task){ value, [NSMutableArray array], ContainerArray});
782796

783797
JSC::APIEntryShim shim(toJS(context));
784-
if (!(JSValueIsNull(context, value) || JSValueIsUndefined(context, value)))
785-
*exception = toRef(JSC::createTypeError(toJS(context), ASCIILiteral("Cannot convert primitive to NSArray")));
798+
if (!(JSValueIsNull(context, value) || JSValueIsUndefined(context, value))) {
799+
JSC::JSObject* exceptionObject = JSC::createTypeError(toJS(context), ASCIILiteral("Cannot convert primitive to NSArray"));
800+
*exception = toRef(exceptionObject);
801+
#if ENABLE(REMOTE_INSPECTOR)
802+
reportExceptionToInspector(context, exceptionObject);
803+
#endif
804+
}
786805
return nil;
787806
}
788807

@@ -798,8 +817,13 @@ id valueToDictionary(JSGlobalContextRef context, JSValueRef value, JSValueRef* e
798817
return containerValueToObject(context, (JSContainerConvertor::Task){ value, [NSMutableDictionary dictionary], ContainerDictionary});
799818

800819
JSC::APIEntryShim shim(toJS(context));
801-
if (!(JSValueIsNull(context, value) || JSValueIsUndefined(context, value)))
802-
*exception = toRef(JSC::createTypeError(toJS(context), ASCIILiteral("Cannot convert primitive to NSDictionary")));
820+
if (!(JSValueIsNull(context, value) || JSValueIsUndefined(context, value))) {
821+
JSC::JSObject* exceptionObject = JSC::createTypeError(toJS(context), ASCIILiteral("Cannot convert primitive to NSDictionary"));
822+
*exception = toRef(exceptionObject);
823+
#if ENABLE(REMOTE_INSPECTOR)
824+
reportExceptionToInspector(context, exceptionObject);
825+
#endif
826+
}
803827
return nil;
804828
}
805829

0 commit comments

Comments
 (0)