diff options
author | Havoc Pennington <hp@pobox.com> | 2010-05-01 00:33:01 -0400 |
---|---|---|
committer | Havoc Pennington <hp@pobox.com> | 2010-05-01 01:19:21 -0400 |
commit | ccc6e7ce6cf9d2f42b2667d1998598f376c86f76 (patch) | |
tree | 99eed51691ecdde6ac7a80658358fc0e04f1c1dd | |
parent | 941791d4cbcf4a42ecac63d47ab2333613d847b8 (diff) | |
download | gjs-ccc6e7ce6cf9d2f42b2667d1998598f376c86f76.tar.gz |
add JS_BeginRequest/JS_EndRequest calls throughout the codebase.
This is one step toward thread safety. Remaining work includes at least:
* put locks on our own global state
* JS_SuspendRequest() when blocking in native code
* JS_SetContextThread() on load and call contexts
-rw-r--r-- | gi/closure.c | 12 | ||||
-rw-r--r-- | gi/function.c | 6 | ||||
-rw-r--r-- | gi/keep-alive.c | 34 | ||||
-rw-r--r-- | gi/ns.c | 6 | ||||
-rw-r--r-- | gi/repo.c | 30 | ||||
-rw-r--r-- | gi/value.c | 3 | ||||
-rw-r--r-- | gjs/context.c | 34 | ||||
-rw-r--r-- | gjs/importer.c | 23 | ||||
-rw-r--r-- | gjs/jsapi-util-array.c | 13 | ||||
-rw-r--r-- | gjs/jsapi-util-error.c | 9 | ||||
-rw-r--r-- | gjs/jsapi-util-string.c | 39 | ||||
-rw-r--r-- | gjs/jsapi-util.c | 125 | ||||
-rw-r--r-- | modules/dbus-exports.c | 14 | ||||
-rw-r--r-- | modules/dbus.c | 21 | ||||
-rw-r--r-- | modules/mainloop.c | 4 |
15 files changed, 340 insertions, 33 deletions
diff --git a/gi/closure.c b/gi/closure.c index 722279a9..7cf084cc 100644 --- a/gi/closure.c +++ b/gi/closure.c @@ -255,6 +255,8 @@ gjs_closure_invoke(GClosure *closure, return; } + JS_BeginRequest(context); + if (JS_IsExceptionPending(context)) { gjs_debug_closure("Exception was pending before invoking callback??? " "Not expected"); @@ -279,6 +281,8 @@ gjs_closure_invoke(GClosure *closure, if (gjs_log_exception(context, NULL)) { gjs_debug_closure("Closure invocation succeeded but an exception was set"); } + + JS_EndRequest(context); } gboolean @@ -294,6 +298,8 @@ gjs_closure_invoke_simple(JSContext *context, jsval *argv; int i; + JS_BeginRequest(context); + va_start(ap, format); argv = JS_PushArgumentsVA(context, &stack_space, format, ap); va_end(ap); @@ -313,6 +319,8 @@ gjs_closure_invoke_simple(JSContext *context, JS_PopArguments(context, stack_space); + JS_EndRequest(context); + return TRUE; } @@ -352,6 +360,8 @@ gjs_closure_new(JSContext *context, * is invoked (as long as the runtime lives) */ c->context = gjs_runtime_get_load_context(c->runtime); + JS_BeginRequest(c->context); + c->obj = callable; c->unref_on_global_object_finalized = FALSE; @@ -371,6 +381,8 @@ gjs_closure_new(JSContext *context, gjs_debug_closure("Create closure %p which calls object %p '%s'", c, c->obj, description); + JS_EndRequest(c->context); + return &c->base; } diff --git a/gi/function.c b/gi/function.c index 0bf57442..98343f5c 100644 --- a/gi/function.c +++ b/gi/function.c @@ -1033,10 +1033,13 @@ gjs_define_function(JSContext *context, JSContext *load_context; load_context = gjs_runtime_get_load_context(JS_GetRuntime(context)); + JS_BeginRequest(load_context); function = function_new(load_context, info); if (function == NULL) { gjs_move_exception(load_context, context); + + JS_EndRequest(load_context); return NULL; } @@ -1046,9 +1049,12 @@ gjs_define_function(JSContext *context, NULL, NULL, GJS_MODULE_PROP_FLAGS)) { gjs_debug(GJS_DEBUG_GFUNCTION, "Failed to define function"); + + JS_EndRequest(load_context); return NULL; } + JS_EndRequest(load_context); return function; } diff --git a/gi/keep-alive.c b/gi/keep-alive.c index 160a9caa..8e2c4ab3 100644 --- a/gi/keep-alive.c +++ b/gi/keep-alive.c @@ -217,6 +217,8 @@ gjs_keep_alive_new(JSContext *context) g_assert(context != NULL); + JS_BeginRequest(context); + /* put constructor in the global namespace */ global = JS_GetGlobalObject(context); @@ -277,6 +279,8 @@ gjs_keep_alive_new(JSContext *context) gjs_fatal("Failed to create keep_alive object"); } + JS_EndRequest(context); + return keep_alive; } @@ -292,7 +296,9 @@ gjs_keep_alive_add_child(JSContext *context, g_assert(keep_alive != NULL); + JS_BeginRequest(context); priv = priv_from_js(context, keep_alive); + JS_EndRequest(context); g_assert(priv != NULL); @@ -323,7 +329,9 @@ gjs_keep_alive_remove_child(JSContext *context, KeepAlive *priv; Child child; + JS_BeginRequest(context); priv = priv_from_js(context, keep_alive); + JS_EndRequest(context); g_assert(priv != NULL); @@ -345,15 +353,22 @@ gjs_keep_alive_get_global(JSContext *context) { jsval value; JSObject *global; + JSObject *result; + + JS_BeginRequest(context); global = JS_GetGlobalObject(context); gjs_object_get_property(context, global, GLOBAL_KEEP_ALIVE_NAME, &value); if (JSVAL_IS_OBJECT(value)) - return JSVAL_TO_OBJECT(value); + result = JSVAL_TO_OBJECT(value); + else + result = NULL; - return NULL; + JS_EndRequest(context); + + return result; } static JSObject* @@ -362,6 +377,8 @@ gjs_keep_alive_create_in_global(JSContext *context) JSObject *keep_alive; JSObject *global; + JS_BeginRequest(context); + global = JS_GetGlobalObject(context); keep_alive = gjs_keep_alive_new(context); @@ -376,6 +393,7 @@ gjs_keep_alive_create_in_global(JSContext *context) JSPROP_READONLY | JSPROP_PERMANENT)) gjs_fatal("no memory to define keep_alive property"); + JS_EndRequest(context); return keep_alive; } @@ -387,6 +405,8 @@ gjs_keep_alive_add_global_child(JSContext *context, { JSObject *keep_alive; + JS_BeginRequest(context); + keep_alive = gjs_keep_alive_get_global(context); if (!keep_alive) @@ -398,6 +418,8 @@ gjs_keep_alive_add_global_child(JSContext *context, gjs_keep_alive_add_child(context, keep_alive, notify, child, data); + + JS_EndRequest(context); } void @@ -408,6 +430,8 @@ gjs_keep_alive_remove_global_child(JSContext *context, { JSObject *keep_alive; + JS_BeginRequest(context); + keep_alive = gjs_keep_alive_get_global(context); if (!keep_alive) @@ -417,6 +441,8 @@ gjs_keep_alive_remove_global_child(JSContext *context, gjs_keep_alive_remove_child(context, gjs_keep_alive_get_global(context), notify, child, data); + + JS_EndRequest(context); } JSObject* @@ -429,6 +455,8 @@ gjs_keep_alive_get_for_load_context(JSRuntime *runtime) g_assert(context != NULL); + JS_BeginRequest(context); + keep_alive = gjs_keep_alive_get_global(context); if (!keep_alive) @@ -437,5 +465,7 @@ gjs_keep_alive_get_for_load_context(JSRuntime *runtime) if (!keep_alive) gjs_fatal("could not create keep_alive on global object, no memory?"); + JS_EndRequest(context); + return keep_alive; } @@ -89,6 +89,7 @@ ns_new_resolve(JSContext *context, return JS_TRUE; /* we are the prototype, or have the wrong class */ load_context = gjs_runtime_get_load_context(JS_GetRuntime(context)); + JS_BeginRequest(load_context); repo = g_irepository_get_default(); @@ -101,15 +102,18 @@ ns_new_resolve(JSContext *context, obj, NULL); if (gjs_move_exception(load_context, context)) { + JS_EndRequest(load_context); return JS_FALSE; } else { *objp = obj; /* we defined the property in this object */ + JS_EndRequest(load_context); return JS_TRUE; } } else { gjs_throw(context, "No symbol '%s' in namespace '%s'", name, priv->namespace); + JS_EndRequest(load_context); return JS_FALSE; } } @@ -123,6 +127,7 @@ ns_new_resolve(JSContext *context, if (gjs_define_info(load_context, obj, info)) { g_base_info_unref(info); *objp = obj; /* we defined the property in this object */ + JS_EndRequest(load_context); return JS_TRUE; } else { gjs_debug(GJS_DEBUG_GNAMESPACE, @@ -137,6 +142,7 @@ ns_new_resolve(JSContext *context, "Defining info failed but no exception set"); } + JS_EndRequest(load_context); return JS_FALSE; } } @@ -64,11 +64,16 @@ resolve_namespace_object(JSContext *context, JSObject *versions; jsval version_val; const char *version; + JSObject *result; load_context = gjs_runtime_get_load_context(JS_GetRuntime(context)); + JS_BeginRequest(load_context); + if (!gjs_object_require_property(load_context, repo_obj, "GI repository object", "versions", &versions_val) || !JSVAL_IS_OBJECT(versions_val)) { gjs_throw(context, "No 'versions' property in GI repository object"); + + JS_EndRequest(load_context); return NULL; } @@ -89,6 +94,7 @@ resolve_namespace_object(JSContext *context, "Requiring %s, version %s: %s", ns_name, version?version:"none", error->message); g_error_free(error); + JS_EndRequest(load_context); return JS_FALSE; } @@ -96,7 +102,9 @@ resolve_namespace_object(JSContext *context, * with the given namespace name, pointing to that namespace * in the repo. */ - return gjs_define_ns(context, repo_obj, ns_name, repo); + result = gjs_define_ns(context, repo_obj, ns_name, repo); + JS_EndRequest(load_context); + return result; } /* @@ -140,11 +148,14 @@ repo_new_resolve(JSContext *context, return JS_TRUE; /* we are the prototype, or have the wrong class */ load_context = gjs_runtime_get_load_context(JS_GetRuntime(context)); + JS_BeginRequest(load_context); resolve_namespace_object(load_context, obj, name); if (gjs_move_exception(load_context, context)) { + JS_EndRequest(load_context); return JS_FALSE; } else { *objp = obj; /* store the object we defined the prop in */ + JS_EndRequest(load_context); return JS_TRUE; } } @@ -507,6 +518,7 @@ gjs_lookup_namespace_object_by_name(JSContext *context, */ load_context = gjs_runtime_get_load_context(JS_GetRuntime(context)); + JS_BeginRequest(load_context); global = JS_GetGlobalObject(load_context); importer = JSVAL_VOID; @@ -514,7 +526,7 @@ gjs_lookup_namespace_object_by_name(JSContext *context, !JSVAL_IS_OBJECT(importer)) { gjs_log_exception(load_context, NULL); gjs_throw(context, "No imports property in global object"); - return NULL; + goto fail; } girepository = JSVAL_VOID; @@ -523,20 +535,26 @@ gjs_lookup_namespace_object_by_name(JSContext *context, !JSVAL_IS_OBJECT(girepository)) { gjs_log_exception(load_context, NULL); gjs_throw(context, "No gi property in importer"); - return NULL; + goto fail; } repo_obj = JSVAL_TO_OBJECT(girepository); - if (!gjs_object_require_property(context, repo_obj, "GI repository object", ns, &ns_obj)) - return NULL; + if (!gjs_object_require_property(context, repo_obj, "GI repository object", ns, &ns_obj)) { + goto fail; + } if (!JSVAL_IS_OBJECT(ns_obj)) { gjs_throw(context, "Namespace '%s' is not an object?", ns); - return NULL; + goto fail; } + JS_EndRequest(load_context); return JSVAL_TO_OBJECT(ns_obj); + + fail: + JS_EndRequest(load_context); + return NULL; } const char* @@ -66,6 +66,8 @@ closure_marshal(GClosure *closure, return; } + JS_BeginRequest(context); + argc = n_param_values; argv = g_newa(jsval, n_param_values); rval = JSVAL_VOID; @@ -133,6 +135,7 @@ closure_marshal(GClosure *closure, cleanup: gjs_unroot_value_locations(context, argv, argc); JS_RemoveRoot(context, &rval); + JS_EndRequest(context); } GClosure* diff --git a/gjs/context.c b/gjs/context.c index 035c8d3a..743bb1a3 100644 --- a/gjs/context.c +++ b/gjs/context.c @@ -107,6 +107,8 @@ gjs_log(JSContext *context, return JS_FALSE; } + JS_BeginRequest(context); + /* JS_ValueToString might throw, in which we will only *log that the value could be converted to string */ exc_state = JS_SaveExceptionState(context); @@ -117,15 +119,19 @@ gjs_log(JSContext *context, if (jstr == NULL) { gjs_debug(GJS_DEBUG_LOG, "<cannot convert value to string>"); + JS_EndRequest(context); return JS_TRUE; } - if (!gjs_string_to_utf8(context, STRING_TO_JSVAL(jstr), &s)) + if (!gjs_string_to_utf8(context, STRING_TO_JSVAL(jstr), &s)) { + JS_EndRequest(context); return JS_FALSE; + } gjs_debug(GJS_DEBUG_LOG, "%s", s); g_free(s); + JS_EndRequest(context); return JS_TRUE; } @@ -146,6 +152,8 @@ gjs_log_error(JSContext *context, return JS_FALSE; } + JS_BeginRequest(context); + exc = argv[0]; /* JS_ValueToString might throw, in which we will only @@ -159,16 +167,20 @@ gjs_log_error(JSContext *context, if (jstr == NULL) { gjs_debug(GJS_DEBUG_ERROR, "<cannot convert value to string>"); gjs_log_exception_props(context, exc); + JS_EndRequest(context); return JS_TRUE; } - if (!gjs_string_to_utf8(context, STRING_TO_JSVAL(jstr), &s)) + if (!gjs_string_to_utf8(context, STRING_TO_JSVAL(jstr), &s)) { + JS_EndRequest(context); return JS_FALSE; + } gjs_debug(GJS_DEBUG_ERROR, "%s", s); gjs_log_exception_props(context, exc); g_free(s); + JS_EndRequest(context); return JS_TRUE; } @@ -182,6 +194,8 @@ gjs_print_parse_args(JSContext *context, gchar *s; guint n; + JS_BeginRequest(context); + str = g_string_new(""); JS_EnterLocalRootScope(context); for (n = 0; n < argc; ++n) { @@ -201,6 +215,7 @@ gjs_print_parse_args(JSContext *context, if (jstr != NULL) { if (!gjs_string_to_utf8(context, STRING_TO_JSVAL(jstr), &s)) { JS_LeaveLocalRootScope(context); + JS_EndRequest(context); g_string_free(str, TRUE); return JS_FALSE; } @@ -211,6 +226,7 @@ gjs_print_parse_args(JSContext *context, g_string_append_c(str, ' '); } else { JS_LeaveLocalRootScope(context); + JS_EndRequest(context); *buffer = g_string_free(str, TRUE); if (!*buffer) *buffer = g_strdup("<invalid string>"); @@ -221,6 +237,7 @@ gjs_print_parse_args(JSContext *context, JS_LeaveLocalRootScope(context); *buffer = g_string_free(str, FALSE); + JS_EndRequest(context); return JS_TRUE; } @@ -330,7 +347,9 @@ gjs_context_dispose(GObject *object) } if (js_context->global != NULL) { + JS_BeginRequest(js_context->context); JS_RemoveRoot(js_context->context, &js_context->global); + JS_EndRequest(js_context->context); js_context->global = NULL; } @@ -537,6 +556,8 @@ gjs_context_constructor (GType type, if (js_context->context == NULL) gjs_fatal("Failed to create javascript context"); + JS_BeginRequest(js_context->context); + /* same as firefox, see discussion at * https://bugzilla.mozilla.org/show_bug.cgi?id=420869 */ JS_SetScriptStackQuota(js_context->context, 100*1024*1024); @@ -652,6 +673,8 @@ gjs_context_constructor (GType type, js_context->profiler = gjs_profiler_new(js_context->runtime); } + JS_EndRequest(js_context->context); + g_static_mutex_lock (&contexts_lock); all_contexts = g_list_prepend(all_contexts, object); g_static_mutex_unlock (&contexts_lock); @@ -805,6 +828,11 @@ gjs_context_eval(GjsContext *js_context, "Exception was set prior to JS_EvaluateScript()"); } + /* JS_EvaluateScript requires a request even though it sort of seems like + * it means we're always in a request? + */ + JS_BeginRequest(js_context->context); + retval = JSVAL_VOID; if (!JS_EvaluateScript(js_context->context, js_context->global, @@ -869,6 +897,8 @@ gjs_context_eval(GjsContext *js_context, g_object_unref(G_OBJECT(js_context)); + JS_EndRequest(js_context->context); + return success; } diff --git a/gjs/importer.c b/gjs/importer.c index 8d11e9d5..c7902f61 100644 --- a/gjs/importer.c +++ b/gjs/importer.c @@ -925,8 +925,10 @@ importer_new_resolve(JSContext *context, /* We always import in the special load context. */ load_context = gjs_runtime_get_load_context(JS_GetRuntime(context)); + JS_BeginRequest(load_context); if (do_import(load_context, obj, priv, name)) { *objp = obj; + JS_EndRequest(load_context); return JS_TRUE; } else { /* Move the exception to the calling context from load context. @@ -935,6 +937,7 @@ importer_new_resolve(JSContext *context, /* set an exception since none was set */ gjs_throw(context, "No exception was set, but import failed somehow"); } + JS_EndRequest(load_context); return JS_FALSE; } } @@ -1182,19 +1185,25 @@ gjs_create_root_importer(JSRuntime *runtime, context = gjs_runtime_get_load_context(runtime); + JS_BeginRequest(context); + if (!gjs_object_has_property(context, JS_GetGlobalObject(context), "imports")) { if (gjs_define_importer(context, JS_GetGlobalObject(context), "imports", - initial_search_path, add_standard_search_path) == NULL) + initial_search_path, add_standard_search_path) == NULL) { + JS_EndRequest(context); return JS_FALSE; + } } else { gjs_debug(GJS_DEBUG_IMPORTER, "Someone else already created root importer, ignoring second request"); + JS_EndRequest(context); return JS_TRUE; } + JS_EndRequest(context); return JS_TRUE; } @@ -1205,15 +1214,18 @@ gjs_define_root_importer(JSContext *context, { JSContext *load_context; jsval value; + JSBool success; + success = JS_FALSE; load_context = gjs_runtime_get_load_context(JS_GetRuntime(context)); + JS_BeginRequest(load_context); if (!gjs_object_require_property(load_context, JS_GetGlobalObject(load_context), "global object", "imports", &value) || !JSVAL_IS_OBJECT(value)) { gjs_debug(GJS_DEBUG_IMPORTER, "Root importer did not exist, couldn't get from load context; must create it"); - return JS_FALSE; + goto fail; } if (!JS_DefineProperty(context, in_object, @@ -1222,8 +1234,11 @@ gjs_define_root_importer(JSContext *context, GJS_MODULE_PROP_FLAGS)) { gjs_debug(GJS_DEBUG_IMPORTER, "DefineProperty %s on %p failed", importer_name, in_object); - return JS_FALSE; + goto fail; } - return JS_TRUE; + success = JS_TRUE; + fail: + JS_EndRequest(load_context); + return success; } diff --git a/gjs/jsapi-util-array.c b/gjs/jsapi-util-array.c index d3ce3f7a..b4c7360e 100644 --- a/gjs/jsapi-util-array.c +++ b/gjs/jsapi-util-array.c @@ -59,7 +59,9 @@ static void add_root_jsval(JSContext *context, jsval *value_p) { + JS_BeginRequest(context); JS_AddRoot(context, value_p); + JS_EndRequest(context); } /* typesafe wrapper */ @@ -67,7 +69,9 @@ static void remove_root_jsval(JSContext *context, jsval *value_p) { + JS_BeginRequest(context); JS_RemoveRoot(context, value_p); + JS_EndRequest(context); } /** @@ -190,9 +194,11 @@ gjs_root_value_locations(JSContext *context, g_return_if_fail(locations != NULL); g_return_if_fail(n_locations >= 0); + JS_BeginRequest(context); for (i = 0; i < n_locations; i++) { add_root_jsval(context, ((jsval*)locations) + i); } + JS_EndRequest(context); } /** @@ -215,9 +221,11 @@ gjs_unroot_value_locations(JSContext *context, g_return_if_fail(locations != NULL); g_return_if_fail(n_locations >= 0); + JS_BeginRequest(context); for (i = 0; i < n_locations; i++) { remove_root_jsval(context, ((jsval*)locations) + i); } + JS_EndRequest(context); } /** @@ -302,6 +310,9 @@ gjstest_test_func_gjs_jsapi_util_array(void) runtime = JS_NewRuntime(1024*1024 /* max bytes */); context = JS_NewContext(runtime, 8192); + + JS_BeginRequest(context); + global = JS_NewObject(context, NULL, NULL, NULL); JS_SetGlobalObject(context, global); JS_InitStandardClasses(context, global); @@ -332,6 +343,8 @@ gjstest_test_func_gjs_jsapi_util_array(void) gjs_rooted_array_free(context, array, TRUE); + JS_EndRequest(context); + JS_DestroyContext(context); JS_DestroyRuntime(runtime); JS_ShutDown(); diff --git a/gjs/jsapi-util-error.c b/gjs/jsapi-util-error.c index 2b867183..50d4449b 100644 --- a/gjs/jsapi-util-error.c +++ b/gjs/jsapi-util-error.c @@ -55,6 +55,8 @@ gjs_throw_valist(JSContext *context, s = g_strdup_vprintf(format, args); + JS_BeginRequest(context); + if (JS_IsExceptionPending(context)) { /* Often it's unclear whether a given jsapi.h function * will throw an exception, so we will throw ourselves @@ -138,6 +140,8 @@ gjs_throw_valist(JSContext *context, s); } g_free(s); + + JS_EndRequest(context); } /* Throws an exception, like "throw new Error(message)" @@ -212,6 +216,9 @@ gjstest_test_func_gjs_jsapi_util_error_throw(void) */ runtime = JS_NewRuntime(1024*1024 /* max bytes */); context = JS_NewContext(runtime, 8192); + + JS_BeginRequest(context); + global = JS_NewObject(context, NULL, NULL, NULL); JS_SetGlobalObject(context, global); JS_InitStandardClasses(context, global); @@ -266,6 +273,8 @@ gjstest_test_func_gjs_jsapi_util_error_throw(void) JS_RemoveRoot(context, &previous); + JS_EndRequest(context); + JS_DestroyContext(context); JS_DestroyRuntime(runtime); JS_ShutDown(); diff --git a/gjs/jsapi-util-string.c b/gjs/jsapi-util-string.c index fc669a02..4a571761 100644 --- a/gjs/jsapi-util-string.c +++ b/gjs/jsapi-util-string.c @@ -41,9 +41,12 @@ gjs_try_string_to_utf8 (JSContext *context, long utf8_length; GError *convert_error = NULL; + JS_BeginRequest(context); + if (!JSVAL_IS_STRING(string_val)) { g_set_error_literal(error, GJS_UTIL_ERROR, GJS_UTIL_ERROR_ARGUMENT_TYPE_MISMATCH, "Object is not a string, cannot convert to UTF-8"); + JS_EndRequest(context); return FALSE; } @@ -55,6 +58,9 @@ gjs_try_string_to_utf8 (JSContext *context, &read_items, &utf8_length, &convert_error); + /* ENDING REQUEST - no JSAPI after this point */ + JS_EndRequest(context); + if (!utf8_string) { g_set_error(error, GJS_UTIL_ERROR, GJS_UTIL_ERROR_ARGUMENT_INVALID, "Failed to convert JS string to UTF-8: %s", @@ -136,15 +142,20 @@ gjs_string_from_utf8(JSContext *context, return JS_FALSE; } + JS_BeginRequest(context); + s = JS_NewUCStringCopyN(context, (jschar*)u16_string, u16_string_length); g_free(u16_string); - if (!s) + if (!s) { + JS_EndRequest(context); return JS_FALSE; + } *value_p = STRING_TO_JSVAL(s); + JS_EndRequest(context); return JS_TRUE; } @@ -301,14 +312,18 @@ gjs_string_get_binary_data(JSContext *context, { char *js_data; + JS_BeginRequest(context); + if (!JSVAL_IS_STRING(value)) { gjs_throw(context, "Value is not a string, can't return binary data from it"); return JS_FALSE; } - if (throw_if_binary_strings_broken(context)) + if (throw_if_binary_strings_broken(context)) { + JS_EndRequest(context); return JS_FALSE; + } js_data = JS_GetStringBytes(JSVAL_TO_STRING(value)); /* GetStringLength returns number of 16-bit jschar; @@ -317,6 +332,8 @@ gjs_string_get_binary_data(JSContext *context, *len_p = JS_GetStringLength(JSVAL_TO_STRING(value)); *data_p = g_memdup(js_data, *len_p); + JS_EndRequest(context); + return JS_TRUE; } @@ -339,8 +356,12 @@ gjs_string_from_binary_data(JSContext *context, { JSString *s; - if (throw_if_binary_strings_broken(context)) + JS_BeginRequest(context); + + if (throw_if_binary_strings_broken(context)) { + JS_EndRequest(context); return JS_FALSE; + } /* store each byte in a 16-bit jschar so all high bytes are 0; * we can't put two bytes per jschar because then we'd lose @@ -350,10 +371,12 @@ gjs_string_from_binary_data(JSContext *context, if (s == NULL) { /* gjs_throw() does nothing if exception already set */ gjs_throw(context, "Failed to allocate binary string"); + JS_EndRequest(context); return JS_FALSE; } *value_p = STRING_TO_JSVAL(s); + JS_EndRequest(context); return JS_TRUE; } @@ -378,9 +401,12 @@ gjs_string_get_uint16_data(JSContext *context, { jschar *js_data; + JS_BeginRequest(context); + if (!JSVAL_IS_STRING(value)) { gjs_throw(context, "Value is not a string, can't return binary data from it"); + JS_EndRequest(context); return JS_FALSE; } @@ -388,6 +414,7 @@ gjs_string_get_uint16_data(JSContext *context, *len_p = JS_GetStringLength(JSVAL_TO_STRING(value)); *data_p = g_memdup(js_data, sizeof(*js_data)*(*len_p)); + JS_EndRequest(context); return JS_TRUE; } @@ -439,6 +466,7 @@ gjstest_test_func_gjs_jsapi_util_string_js_string_utf8(void) runtime = JS_NewRuntime(1024*1024 /* max bytes */); context = JS_NewContext(runtime, 8192); + JS_BeginRequest(context); global = JS_NewObject(context, NULL, NULL, NULL); JS_SetGlobalObject(context, global); JS_InitStandardClasses(context, global); @@ -450,6 +478,7 @@ gjstest_test_func_gjs_jsapi_util_string_js_string_utf8(void) g_assert(JSVAL_IS_STRING(js_string)); g_assert(gjs_string_to_utf8(context, js_string, &utf8_result) == JS_TRUE); + JS_EndRequest(context); JS_DestroyContext(context); JS_DestroyRuntime(runtime); @@ -470,6 +499,7 @@ gjstest_test_func_gjs_jsapi_util_string_get_ascii(void) runtime = JS_NewRuntime(1024*1024 /* max bytes */); context = JS_NewContext(runtime, 8192); + JS_BeginRequest(context); global = JS_NewObject(context, NULL, NULL, NULL); JS_SetGlobalObject(context, global); JS_InitStandardClasses(context, global); @@ -482,6 +512,7 @@ gjstest_test_func_gjs_jsapi_util_string_get_ascii(void) g_assert(gjs_string_get_ascii_checked(context, void_value) == NULL); g_assert(JS_IsExceptionPending(context)); + JS_EndRequest(context); JS_DestroyContext(context); JS_DestroyRuntime(runtime); } @@ -504,6 +535,7 @@ gjstest_test_func_gjs_jsapi_util_string_get_binary(void) runtime = JS_NewRuntime(1024*1024 /* max bytes */); context = JS_NewContext(runtime, 8192); + JS_BeginRequest(context); global = JS_NewObject(context, NULL, NULL, NULL); JS_SetGlobalObject(context, global); JS_InitStandardClasses(context, global); @@ -550,6 +582,7 @@ gjstest_test_func_gjs_jsapi_util_string_get_binary(void) &data, &len)); g_assert(JS_IsExceptionPending(context)); + JS_EndRequest(context); JS_DestroyContext(context); JS_DestroyRuntime(runtime); } diff --git a/gjs/jsapi-util.c b/gjs/jsapi-util.c index 25bdf5ce..e2f7f14b 100644 --- a/gjs/jsapi-util.c +++ b/gjs/jsapi-util.c @@ -242,6 +242,8 @@ gjs_object_get_property(JSContext *context, jsval value; JSExceptionState *state; + JS_BeginRequest(context); + value = JSVAL_VOID; state = JS_SaveExceptionState(context); JS_GetProperty(context, obj, property_name, &value); @@ -250,6 +252,8 @@ gjs_object_get_property(JSContext *context, if (value_p) *value_p = value; + JS_EndRequest(context); + return value != JSVAL_VOID; } @@ -269,6 +273,8 @@ gjs_object_require_property(JSContext *context, { jsval value; + JS_BeginRequest(context); + value = JSVAL_VOID; JS_GetProperty(context, obj, property_name, &value); @@ -277,6 +283,7 @@ gjs_object_require_property(JSContext *context, if (value != JSVAL_VOID) { JS_ClearPendingException(context); /* in case JS_GetProperty() was on crack */ + JS_EndRequest(context); return TRUE; } else { /* remember gjs_throw() is a no-op if JS_GetProperty() @@ -290,6 +297,8 @@ gjs_object_require_property(JSContext *context, gjs_throw(context, "No property '%s' in object %p (or its value was undefined)", property_name, obj); + + JS_EndRequest(context); return FALSE; } } @@ -318,6 +327,8 @@ gjs_init_class_dynamic(JSContext *context, return NULL; } + JS_BeginRequest(context); + /* We replace the passed-in context and global object with our * runtime-global permanent load context. Otherwise, in a * process with multiple contexts, we'd arbitrarily define @@ -325,6 +336,7 @@ gjs_init_class_dynamic(JSContext *context, * class first, which is not desirable. */ load_context = gjs_runtime_get_load_context(JS_GetRuntime(context)); + JS_BeginRequest(load_context); /* JS_InitClass() wants to define the constructor in the global object, so * we give it a private and namespaced name... passing in the namespace @@ -397,6 +409,8 @@ gjs_init_class_dynamic(JSContext *context, GJS_MODULE_PROP_FLAGS)) goto error; + JS_EndRequest(load_context); + JS_EndRequest(context); return prototype; error: @@ -407,18 +421,23 @@ gjs_init_class_dynamic(JSContext *context, gjs_throw(context, "No exception was set, but class initialize failed somehow"); } + JS_EndRequest(load_context); + JS_EndRequest(context); return NULL; } gboolean gjs_check_constructing(JSContext *context) { + JS_BeginRequest(context); if (!JS_IsConstructing(context)) { + JS_EndRequest(context); gjs_throw(context, "Constructor called as normal method. Use 'new SomeObject()' not 'SomeObject()'"); return FALSE; } + JS_EndRequest(context); return TRUE; } @@ -430,12 +449,15 @@ gjs_get_instance_private_dynamic(JSContext *context, { RuntimeData *rd; JSClass *obj_class; + void *instance; if (static_clasp->name != NULL) { g_warning("Dynamic class should not have a name in the JSClass struct"); return NULL; } + JS_BeginRequest(context); + obj_class = JS_GET_CLASS(context, obj); g_assert(obj_class != NULL); @@ -447,15 +469,20 @@ gjs_get_instance_private_dynamic(JSContext *context, gjs_throw(context, "Object %p proto %p doesn't have a dynamically-registered class, it has %s", obj, JS_GetPrototype(context, obj), obj_class->name); + JS_EndRequest(context); return NULL; } if (static_clasp != ((DynamicJSClass*) obj_class)->static_class) { gjs_throw(context, "Object is not a dynamically-registered class based on expected static class pointer"); + JS_EndRequest(context); return NULL; } - return JS_GetInstancePrivate(context, obj, obj_class, argv); + instance = JS_GetInstancePrivate(context, obj, obj_class, argv); + JS_EndRequest(context); + + return instance; } void* @@ -466,12 +493,15 @@ gjs_get_instance_private_dynamic_with_typecheck(JSContext *context, { RuntimeData *rd; JSClass *obj_class; + void *instance; if (static_clasp->name != NULL) { g_warning("Dynamic class should not have a name in the JSClass struct"); return NULL; } + JS_BeginRequest(context); + obj_class = JS_GET_CLASS(context, obj); g_assert(obj_class != NULL); @@ -480,14 +510,18 @@ gjs_get_instance_private_dynamic_with_typecheck(JSContext *context, /* Check that it's safe to cast to DynamicJSClass */ if (g_hash_table_lookup(rd->dynamic_classes, obj_class) == NULL) { + JS_EndRequest(context); return NULL; } if (static_clasp != ((DynamicJSClass*) obj_class)->static_class) { + JS_EndRequest(context); return NULL; } - return JS_GetInstancePrivate(context, obj, obj_class, argv); + instance = JS_GetInstancePrivate(context, obj, obj_class, argv); + JS_EndRequest(context); + return instance; } JSObject* @@ -501,12 +535,15 @@ gjs_construct_object_dynamic(JSContext *context, JSContext *load_context; JSObject *result; + JS_BeginRequest(context); + /* We replace the passed-in context and global object with our * runtime-global permanent load context. Otherwise, JS_ConstructObject * can't find the constructor in whatever random global object is set * on the passed-in context. */ load_context = gjs_runtime_get_load_context(JS_GetRuntime(context)); + JS_BeginRequest(load_context); proto_class = JS_GET_CLASS(load_context, proto); @@ -530,6 +567,8 @@ gjs_construct_object_dynamic(JSContext *context, if (!result) goto error; + JS_EndRequest(load_context); + JS_EndRequest(context); return result; error: @@ -540,6 +579,8 @@ gjs_construct_object_dynamic(JSContext *context, gjs_throw(context, "No exception was set, but object construction failed somehow"); } + JS_EndRequest(load_context); + JS_EndRequest(context); return NULL; } @@ -555,6 +596,8 @@ gjs_define_string_array(JSContext *context, JSObject *array; int i; + JS_BeginRequest(context); + if (!JS_EnterLocalRootScope(context)) return JS_FALSE; @@ -580,6 +623,8 @@ gjs_define_string_array(JSContext *context, } JS_LeaveLocalRootScope(context); + + JS_EndRequest(context); return array; } @@ -588,6 +633,9 @@ gjs_value_debug_string(JSContext *context, jsval value) { JSString *str; + const char *bytes; + + JS_BeginRequest(context); str = JS_ValueToString(context, value); @@ -616,7 +664,11 @@ gjs_value_debug_string(JSContext *context, g_assert(str != NULL); - return JS_GetStringBytes(str); + bytes = JS_GetStringBytes(str); + + JS_EndRequest(context); + + return bytes; } void @@ -628,6 +680,8 @@ gjs_log_object_props(JSContext *context, JSObject *props_iter; jsid prop_id; + JS_BeginRequest(context); + /* We potentially create new strings, plus the property iterator, * that could get collected as we go through this process. So * create a local root scope. @@ -672,6 +726,7 @@ gjs_log_object_props(JSContext *context, done: JS_LeaveLocalRootScope(context); + JS_EndRequest(context); } void @@ -691,6 +746,10 @@ gjs_explain_scope(JSContext *context, load_context = gjs_runtime_peek_load_context(JS_GetRuntime(context)); call_context = gjs_runtime_peek_call_context(JS_GetRuntime(context)); + JS_BeginRequest(context); + JS_BeginRequest(load_context); + JS_BeginRequest(call_context); + JS_EnterLocalRootScope(context); gjs_debug(GJS_DEBUG_SCOPE, @@ -724,12 +783,18 @@ gjs_explain_scope(JSContext *context, g_string_free(chain, TRUE); JS_LeaveLocalRootScope(context); + + JS_EndRequest(call_context); + JS_EndRequest(load_context); + JS_EndRequest(context); } void gjs_log_exception_props(JSContext *context, jsval exc) { + JS_BeginRequest(context); + /* This is useful when the exception was never sent to an error reporter * due to JSOPTION_DONT_REPORT_UNCAUGHT, or if the exception was not * a normal Error object so jsapi didn't know how to report it sensibly. @@ -766,6 +831,7 @@ gjs_log_exception_props(JSContext *context, gjs_debug(GJS_DEBUG_ERROR, "Exception had some strange type"); } + JS_EndRequest(context); } static JSBool @@ -778,6 +844,8 @@ log_and_maybe_keep_exception(JSContext *context, char *message; JSBool retval = JS_FALSE; + JS_BeginRequest(context); + if (message_p) *message_p = NULL; @@ -824,6 +892,8 @@ log_and_maybe_keep_exception(JSContext *context, out: JS_RemoveRoot(context, &exc); + JS_EndRequest(context); + return retval; } @@ -850,39 +920,51 @@ try_to_chain_stack_trace(JSContext *src_context, JSContext *dst_context, jsval chained, src_stack, dst_stack, new_stack; JSString *new_stack_str; + JS_BeginRequest(src_context); + JS_BeginRequest(dst_context); + if (!JSVAL_IS_OBJECT(src_exc)) - return; // src_exc doesn't have a stack trace + goto out; // src_exc doesn't have a stack trace /* create a new exception in dst_context to get a stack trace */ gjs_throw_literal(dst_context, "Chained exception"); if (!(JS_GetPendingException(dst_context, &chained) && JSVAL_IS_OBJECT(chained))) - return; // gjs_throw_literal didn't work?! + goto out; // gjs_throw_literal didn't work?! JS_ClearPendingException(dst_context); /* get stack trace for src_exc and chained */ if (!(gjs_object_get_property(dst_context, JSVAL_TO_OBJECT(chained), "stack", &dst_stack) && JSVAL_IS_STRING(dst_stack))) - return; // couldn't get chained stack + goto out; // couldn't get chained stack if (!(gjs_object_get_property(src_context, JSVAL_TO_OBJECT(src_exc), "stack", &src_stack) && JSVAL_IS_STRING(src_stack))) - return; // couldn't get source stack + goto out; // couldn't get source stack /* add chained exception's stack trace to src_exc */ new_stack_str = JS_ConcatStrings (dst_context, JSVAL_TO_STRING(src_stack), JSVAL_TO_STRING(dst_stack)); if (new_stack_str==NULL) - return; // couldn't concatenate src and dst stacks?! + goto out; // couldn't concatenate src and dst stacks?! new_stack = STRING_TO_JSVAL(new_stack_str); JS_SetProperty(dst_context, JSVAL_TO_OBJECT(src_exc), "stack", &new_stack); + + out: + JS_EndRequest(dst_context); + JS_EndRequest(src_context); } JSBool gjs_move_exception(JSContext *src_context, JSContext *dest_context) { + JSBool success; + + JS_BeginRequest(src_context); + JS_BeginRequest(dest_context); + /* NOTE: src and dest could be the same. */ jsval exc; if (JS_GetPendingException(src_context, &exc)) { @@ -894,10 +976,15 @@ gjs_move_exception(JSContext *src_context, JS_SetPendingException(dest_context, exc); JS_ClearPendingException(src_context); } - return JS_TRUE; + success = JS_TRUE; } else { - return JS_FALSE; + success = JS_FALSE; } + + JS_EndRequest(dest_context); + JS_EndRequest(src_context); + + return success; } JSBool @@ -911,12 +998,17 @@ gjs_call_function_value(JSContext *context, JSBool result; JSContext *call_context; + JS_BeginRequest(context); + call_context = gjs_runtime_get_call_context(JS_GetRuntime(context)); + JS_BeginRequest(call_context); result = JS_CallFunctionValue(call_context, obj, fval, argc, argv, rval); gjs_move_exception(call_context, context); + JS_EndRequest(call_context); + JS_EndRequest(context); return result; } @@ -1014,6 +1106,9 @@ gjs_date_from_time_t (JSContext *context, time_t time) JSObject *date_constructor; jsval date_prototype; jsval args[1]; + jsval result; + + JS_BeginRequest(context); if (!JS_EnterLocalRootScope(context)) return JSVAL_VOID; @@ -1033,8 +1128,11 @@ gjs_date_from_time_t (JSContext *context, time_t time) date = JS_ConstructObjectWithArguments(context, date_class, NULL, NULL, 1, args); + result = OBJECT_TO_JSVAL(date); JS_LeaveLocalRootScope(context); - return OBJECT_TO_JSVAL(date); + JS_EndRequest(context); + + return result; } /** @@ -1083,6 +1181,8 @@ gjs_parse_args (JSContext *context, guint n_total; guint consumed_args; + JS_BeginRequest(context); + va_start (args, argv); /* Check for optional argument specifier */ @@ -1219,6 +1319,8 @@ gjs_parse_args (JSContext *context, } va_end (args); + + JS_EndRequest(context); return JS_TRUE; error_unwind: @@ -1227,5 +1329,6 @@ gjs_parse_args (JSContext *context, for (i = 0; i < n_unwind; i++) { g_free (unwind_strings[i]); } + JS_EndRequest(context); return JS_FALSE; } diff --git a/modules/dbus-exports.c b/modules/dbus-exports.c index f407667c..bed9b7db 100644 --- a/modules/dbus-exports.c +++ b/modules/dbus-exports.c @@ -1852,24 +1852,30 @@ gjs_js_define_dbus_exports(JSContext *context, { JSObject *exports; JSContext *load_context; + JSBool success; + success = JS_FALSE; load_context = gjs_runtime_get_load_context(JS_GetRuntime(context)); + JS_BeginRequest(load_context); exports = exports_new(load_context, which_bus); if (exports == NULL) { gjs_move_exception(load_context, context); - return JS_FALSE; + goto fail; } if (!add_connect_funcs(context, exports, which_bus)) - return JS_FALSE; + goto fail; if (!JS_DefineProperty(context, in_object, "exports", OBJECT_TO_JSVAL(exports), NULL, NULL, GJS_MODULE_PROP_FLAGS)) - return JS_FALSE; + goto fail; - return JS_TRUE; + success = JS_TRUE; + fail: + JS_EndRequest(load_context); + return success; } diff --git a/modules/dbus.c b/modules/dbus.c index f1311b42..c6007c9e 100644 --- a/modules/dbus.c +++ b/modules/dbus.c @@ -632,9 +632,12 @@ signal_handler_callback(DBusConnection *connection, return; } + JS_BeginRequest(context); + dbus_message_iter_init(message, &arg_iter); if (!gjs_js_values_from_dbus(context, &arg_iter, &arguments)) { gjs_debug(GJS_DEBUG_DBUS, "Failed to marshal dbus signal to JS"); + JS_EndRequest(context); return; } @@ -657,6 +660,8 @@ signal_handler_callback(DBusConnection *connection, gjs_rooted_array_free(context, arguments, TRUE); signal_handler_unref(handler); /* for safety */ + + JS_EndRequest(context); } /* Args are bus_name, object_path, iface, signal, and callback */ @@ -997,6 +1002,8 @@ on_name_acquired(DBusConnection *connection, return; } + JS_BeginRequest(context); + argc = 1; argv[0] = STRING_TO_JSVAL(JS_NewStringCopyZ(context, name)); @@ -1010,6 +1017,8 @@ on_name_acquired(DBusConnection *connection, JS_RemoveRoot(context, &argv[0]); JS_RemoveRoot(context, &rval); + + JS_EndRequest(context); } static void @@ -1032,6 +1041,8 @@ on_name_lost(DBusConnection *connection, return; } + JS_BeginRequest(context); + argc = 1; argv[0] = STRING_TO_JSVAL(JS_NewStringCopyZ(context, name)); @@ -1045,6 +1056,8 @@ on_name_lost(DBusConnection *connection, JS_RemoveRoot(context, &argv[0]); JS_RemoveRoot(context, &rval); + + JS_EndRequest(context); } static void @@ -1209,6 +1222,8 @@ on_name_appeared(DBusConnection *connection, return; } + JS_BeginRequest(context); + argc = 2; gjs_set_values(context, argv, argc, JSVAL_VOID); @@ -1225,6 +1240,8 @@ on_name_appeared(DBusConnection *connection, JS_RemoveRoot(context, &rval); gjs_unroot_value_locations(context, argv, argc); + + JS_EndRequest(context); } static void @@ -1248,6 +1265,8 @@ on_name_vanished(DBusConnection *connection, return; } + JS_BeginRequest(context); + argc = 2; gjs_set_values(context, argv, argc, JSVAL_VOID); @@ -1264,6 +1283,8 @@ on_name_vanished(DBusConnection *connection, JS_RemoveRoot(context, &rval); gjs_unroot_value_locations(context, argv, argc); + + JS_EndRequest(context); } static const GjsDBusWatchNameFuncs watch_name_funcs = { diff --git a/modules/mainloop.c b/modules/mainloop.c index 814619d5..7208e459 100644 --- a/modules/mainloop.c +++ b/modules/mainloop.c @@ -123,6 +123,7 @@ closure_source_func(void *data) /* closure is invalid now */ return FALSE; } + JS_BeginRequest(context); retval = JSVAL_VOID; JS_AddRoot(context, &retval); @@ -135,12 +136,13 @@ closure_source_func(void *data) * JavaScript always makes some sense of any value in * an "if (value) {}" context. */ - if (!JS_ValueToBoolean(gjs_closure_get_context(closure), + if (!JS_ValueToBoolean(context, retval, &bool_val)) bool_val = FALSE; JS_RemoveRoot(context, &retval); + JS_EndRequest(context); return bool_val; } |