Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

JavaScriptCore: Fixed exception object so sourceURL (file name), line…

… (number), and message can be recovered.

The current implementation only returns an error string. But this is insufficient for debugging (what file and line number did it fail at?).

As documented here:
http://parmanoir.com/Taming_JavascriptCore_within_and_without_WebView
converting the JSValueRef of string to an JSObjectRef (via JSValueToObject) will trigger JSCore into filling the "sourceURL" and "line" properties into the object so they can be inspected by the caller.

Additionally, JavaScriptCore has a "message" property which contains the message string. JSCore doesn't seem to be filling this in for us automatically, unlike "sourceURL" and "line". So this patch also fills that property in too.

Thanks to Brian Barnes for the detailed information about "sourceURL", "line", and "message".

Below is an example (derived from Brian Barnes's information) on how you typically use/extract these exception details.

void script_exception_to_string(JSContextRef js_context,JSValueRef exception_value_ref,char* return_error_string, int return_error_string_max_length)
{
	JSObjectRef exception_object;
	JSValueRef value_ref;
	JSStringRef jsstring_property_name = NULL;
	JSValueRef temporary_exception = NULL;
	JSStringRef js_return_string = NULL;
	size_t bytes_needed;
	char* c_result_string = NULL;
	exception_object = JSValueToObject(js_context, exception_value_ref, NULL);
	// source and line numbers

	strcpy(return_error_string,"[");

	jsstring_property_name = JSStringCreateWithUTF8CString("sourceURL");
	value_ref = JSObjectGetProperty(js_context, exception_object, jsstring_property_name, &temporary_exception);
	JSStringRelease(jsstring_property_name);
	js_return_string = JSValueToStringCopy(js_context, value_ref, NULL);
	bytes_needed = JSStringGetMaximumUTF8CStringSize(js_return_string);
	c_result_string = (char*)calloc(bytes_needed, sizeof(char));
	JSStringGetUTF8CString(js_return_string, c_result_string, bytes_needed);
	SDL_Log("c_result_string: %s\n", c_result_string);
	JSStringRelease(js_return_string);
	strncat(return_error_string, c_result_string, return_error_string_max_length-1);
	free(c_result_string);

	strncat(return_error_string, ":", return_error_string_max_length-1);

	jsstring_property_name = JSStringCreateWithUTF8CString("line");
	value_ref = JSObjectGetProperty(js_context, exception_object, jsstring_property_name, &temporary_exception);
	JSStringRelease(jsstring_property_name);
	js_return_string = JSValueToStringCopy(js_context, value_ref, NULL);
	bytes_needed = JSStringGetMaximumUTF8CStringSize(js_return_string);
	c_result_string = (char*)calloc(bytes_needed, sizeof(char));
	JSStringGetUTF8CString(js_return_string, c_result_string, bytes_needed);
	SDL_Log("c_result_string: %s\n", c_result_string);
	JSStringRelease(js_return_string);
	strncat(return_error_string, c_result_string, return_error_string_max_length-1);
	//SDL_Log("c_result_string: %s\n", c_result_string);
	free(c_result_string);

	strncat(return_error_string, "]", return_error_string_max_length-1);

	/* get message */
	jsstring_property_name = JSStringCreateWithUTF8CString("message");
	value_ref = JSObjectGetProperty(js_context, exception_object, jsstring_property_name, &temporary_exception);
	JSStringRelease(jsstring_property_name);
	if(NULL == value_ref)
	{
		strncat(return_error_string, "Unknown Error", return_error_string_max_length-1);
	}
	else
	{
		js_return_string = JSValueToStringCopy(js_context, value_ref, NULL);
		bytes_needed = JSStringGetMaximumUTF8CStringSize(js_return_string);
		c_result_string = (char*)calloc(bytes_needed, sizeof(char));
		JSStringGetUTF8CString(js_return_string, c_result_string, bytes_needed);
		SDL_Log("c_result_string: %s\n", c_result_string);
		JSStringRelease(js_return_string);
		strncat(return_error_string, c_result_string, return_error_string_max_length-1);
		//SDL_Log("c_result_string: %s\n", c_result_string);
		free(c_result_string);
	}
}

To use:
if(js_exception)
{
	char return_error_string[256];
	script_exception_to_string(js_context, js_exception, return_error_string, 256);
	SDL_Log("Compile error is %s", return_error_string);
}
  • Loading branch information...
commit 6f69555225d818530e60cc50a7cd57f8bafd46f1 1 parent 01f8253
Eric Wing authored oliver---- committed
Showing with 23 additions and 2 deletions.
  1. +23 −2 Lib/javascript/jsc/javascriptrun.swg
View
25 Lib/javascript/jsc/javascriptrun.swg
@@ -9,8 +9,29 @@
SWIGRUNTIME void SWIG_Javascript_Raise(JSContextRef context, JSValueRef *exception, const char* type) {
JSStringRef message = JSStringCreateWithUTF8CString(type);
- *exception = JSValueMakeString(context, message);
- JSStringRelease(message);
+ JSStringRef message_property_key;
+ JSObjectRef exception_object;
+ JSValueRef exception_value;
+ JSValueRef message_value;
+ exception_value = JSValueMakeString(context, message);
+ /* Converting the result to an object will let JavascriptCore add "sourceURL" (file) and "line" (number) to the exception,
+ instead of just returning a raw string. This is extremely important for debugging your errors.
+ */
+ exception_object = JSValueToObject(context, exception_value, NULL);
+
+ /* Additionally, JSCore uses "message" which contains the error description.
+ But it seems that unlike "sourceURL" and "line", converting to an object is not automatically doing this.
+ So we can add it ourselves.
+ */
+ message_property_key = JSStringCreateWithUTF8CString("message");
+ message_value = JSValueMakeString(context, message);
+ JSObjectSetProperty(context, exception_object, message_property_key, message_value, kJSClassAttributeNone, NULL);
+
+ /* Return the exception_object */
+ *exception = exception_object;
+
+ JSStringRelease(message_property_key);
+ JSStringRelease(message);
}
SWIGRUNTIME void SWIG_JSC_exception(JSContextRef context, JSValueRef *exception, int code, const char* msg) {
Please sign in to comment.
Something went wrong with that request. Please try again.