JSBool xpc_qsXPCOMObjectToJsval(XPCLazyCallContext &lccx, nsISupports *p, nsWrapperCache *cache, const nsIID *iid, XPCNativeInterface **iface, jsval *rval) { // From the T_INTERFACE case in XPCConvert::NativeData2JS. // This is one of the slowest things quick stubs do. JSContext *cx = lccx.GetJSContext(); if(!iface) return xpc_qsThrow(cx, NS_ERROR_XPC_BAD_CONVERT_NATIVE); // XXX The OBJ_IS_NOT_GLOBAL here is not really right. In // fact, this code is depending on the fact that the // global object will not have been collected, and // therefore this NativeInterface2JSObject will not end up // creating a new XPCNativeScriptableShared. nsresult rv; if(!XPCConvert::NativeInterface2JSObject(lccx, rval, nsnull, p, iid, iface, cache, lccx.GetCurrentJSObject(), PR_TRUE, OBJ_IS_NOT_GLOBAL, &rv)) { // I can't tell if NativeInterface2JSObject throws JS exceptions // or not. This is a sloppy stab at the right semantics; the // method really ought to be fixed to behave consistently. if(!JS_IsExceptionPending(cx)) xpc_qsThrow(cx, NS_FAILED(rv) ? rv : NS_ERROR_UNEXPECTED); return JS_FALSE; } #ifdef DEBUG JSObject* jsobj = JSVAL_TO_OBJECT(*rval); if(jsobj && !STOBJ_GET_PARENT(jsobj)) NS_ASSERTION(STOBJ_GET_CLASS(jsobj)->flags & JSCLASS_IS_GLOBAL, "Why did we recreate this wrapper?"); #endif return JS_TRUE; }
static bool NativeInterface2JSObjectAndThrowIfFailed(XPCLazyCallContext& aLccx, JSContext* aCx, JS::Value* aRetval, xpcObjectHelper& aHelper, const nsIID* aIID, bool aAllowNativeWrapper) { nsresult rv; if (!XPCConvert::NativeInterface2JSObject(aLccx, aRetval, NULL, aHelper, aIID, NULL, aAllowNativeWrapper, &rv)) { // I can't tell if NativeInterface2JSObject throws JS exceptions // or not. This is a sloppy stab at the right semantics; the // method really ought to be fixed to behave consistently. if (!JS_IsExceptionPending(aCx)) { Throw<true>(aCx, NS_FAILED(rv) ? rv : NS_ERROR_UNEXPECTED); } return false; } return true; }
// static void XPCThrower::BuildAndThrowException(JSContext* cx, nsresult rv, const char* sz) { JSBool success = JS_FALSE; /* no need to set an expection if the security manager already has */ if(rv == NS_ERROR_XPC_SECURITY_MANAGER_VETO && JS_IsExceptionPending(cx)) return; nsCOMPtr<nsIException> finalException; nsCOMPtr<nsIException> defaultException; nsXPCException::NewException(sz, rv, nsnull, nsnull, getter_AddRefs(defaultException)); XPCPerThreadData* tls = XPCPerThreadData::GetData(cx); if(tls) { nsIExceptionManager * exceptionManager = tls->GetExceptionManager(); if(exceptionManager) { // Ask the provider for the exception, if there is no provider // we expect it to set e to null exceptionManager->GetExceptionFromProvider( rv, defaultException, getter_AddRefs(finalException)); // We should get at least the defaultException back, // but just in case if(finalException == nsnull) { finalException = defaultException; } } } // XXX Should we put the following test and call to JS_ReportOutOfMemory // inside this test? if(finalException) success = ThrowExceptionObject(cx, finalException); // If we weren't able to build or throw an exception we're // most likely out of memory if(!success) JS_ReportOutOfMemory(cx); }
bool Throw(JSContext* aCx, nsresult aRv, const char* aMessage) { if (JS_IsExceptionPending(aCx)) { // Don't clobber the existing exception. return false; } CycleCollectedJSRuntime* runtime = CycleCollectedJSRuntime::Get(); nsCOMPtr<nsIException> existingException = runtime->GetPendingException(); if (existingException) { nsresult nr; if (NS_SUCCEEDED(existingException->GetResult(&nr)) && aRv == nr) { // Reuse the existing exception. // Clear pending exception runtime->SetPendingException(nullptr); if (!ThrowExceptionObject(aCx, existingException)) { // If we weren't able to throw an exception we're // most likely out of memory JS_ReportOutOfMemory(aCx); } return false; } } nsRefPtr<Exception> finalException = CreateException(aCx, aRv, aMessage); MOZ_ASSERT(finalException); if (!ThrowExceptionObject(aCx, finalException)) { // If we weren't able to throw an exception we're // most likely out of memory JS_ReportOutOfMemory(aCx); } return false; }
bool js_cocos2dx_audioengine_AudioEngine_setFinishCallback(JSContext *cx, uint32_t argc, jsval *vp) { JS::CallArgs args = JS::CallArgsFromVp(argc, vp); bool ok = true; if (argc == 2) { int arg0; std::function<void (int, const std::basic_string<char> &)> arg1; ok &= jsval_to_int32(cx, args.get(0), (int32_t *)&arg0); do { if(JS_TypeOfValue(cx, args.get(1)) == JSTYPE_FUNCTION) { std::shared_ptr<JSFunctionWrapper> func(new JSFunctionWrapper(cx, args.thisv().toObjectOrNull(), args.get(1))); auto lambda = [=](int larg0, const std::basic_string<char> & larg1) -> void { JSB_AUTOCOMPARTMENT_WITH_GLOBAL_OBJCET jsval largv[2]; largv[0] = int32_to_jsval(cx, larg0); largv[1] = std_string_to_jsval(cx, larg1); JS::RootedValue rval(cx); bool succeed = func->invoke(2, &largv[0], &rval); if (!succeed && JS_IsExceptionPending(cx)) { JS_ReportPendingException(cx); } }; arg1 = lambda; } else { arg1 = nullptr; } } while(0) ; JSB_PRECONDITION2(ok, cx, false, "js_cocos2dx_audioengine_AudioEngine_setFinishCallback : Error processing arguments"); cocos2d::experimental::AudioEngine::setFinishCallback(arg0, arg1); args.rval().setUndefined(); return true; } JS_ReportError(cx, "js_cocos2dx_audioengine_AudioEngine_setFinishCallback : wrong number of arguments"); return false; }
bool js_cocos2dx_nativehelper_NativeHelper_setCallBack(JSContext *cx, uint32_t argc, jsval *vp) { JS::CallArgs args = JS::CallArgsFromVp(argc, vp); bool ok = true; JS::RootedObject obj(cx, args.thisv().toObjectOrNull()); js_proxy_t *proxy = jsb_get_js_proxy(obj); cocos2d::NativeHelper* cobj = (cocos2d::NativeHelper *)(proxy ? proxy->ptr : NULL); JSB_PRECONDITION2( cobj, cx, false, "js_cocos2dx_nativehelper_NativeHelper_setCallBack : Invalid Native Object"); if (argc == 1) { std::function<void ()> arg0; do { if(JS_TypeOfValue(cx, args.get(0)) == JSTYPE_FUNCTION) { std::shared_ptr<JSFunctionWrapper> func(new JSFunctionWrapper(cx, args.thisv().toObjectOrNull(), args.get(0))); auto lambda = [=]() -> void { JSB_AUTOCOMPARTMENT_WITH_GLOBAL_OBJCET JS::RootedValue rval(cx); bool ok = func->invoke(0, nullptr, &rval); if (!ok && JS_IsExceptionPending(cx)) { JS_ReportPendingException(cx); } }; arg0 = lambda; } else { arg0 = nullptr; } } while(0) ; JSB_PRECONDITION2(ok, cx, false, "js_cocos2dx_nativehelper_NativeHelper_setCallBack : Error processing arguments"); cobj->setCallBack(arg0); args.rval().setUndefined(); return true; } JS_ReportError(cx, "js_cocos2dx_nativehelper_NativeHelper_setCallBack : wrong number of arguments: %d, was expecting %d", argc, 1); return false; }
bool Throw(JSContext* aCx, nsresult aRv, const nsACString& aMessage) { if (aRv == NS_ERROR_UNCATCHABLE_EXCEPTION) { // Nuke any existing exception on aCx, to make sure we're uncatchable. JS_ClearPendingException(aCx); return false; } if (JS_IsExceptionPending(aCx)) { // Don't clobber the existing exception. return false; } CycleCollectedJSContext* context = CycleCollectedJSContext::Get(); nsCOMPtr<nsIException> existingException = context->GetPendingException(); // Make sure to clear the pending exception now. Either we're going to reuse // it (and we already grabbed it), or we plan to throw something else and this // pending exception is no longer relevant. context->SetPendingException(nullptr); // Ignore the pending exception if we have a non-default message passed in. if (aMessage.IsEmpty() && existingException) { nsresult nr; if (NS_SUCCEEDED(existingException->GetResult(&nr)) && aRv == nr) { // Reuse the existing exception. ThrowExceptionObject(aCx, existingException); return false; } } RefPtr<Exception> finalException = CreateException(aRv, aMessage); MOZ_ASSERT(finalException); ThrowExceptionObject(aCx, finalException); return false; }
/* * call-seq: * evaluate_compiled_script(script) * * Evaluate +script+ */ static VALUE evaluate_compiled_script(VALUE self, VALUE compiled_script) { JohnsonRuntime* runtime; Data_Get_Struct(self, JohnsonRuntime, runtime); JSContext * context = johnson_get_current_context(runtime); JohnsonContext * johnson_context = OUR_CONTEXT(context); // clean things up first johnson_context->ex = 0; memset(johnson_context->msg, 0, MAX_EXCEPTION_MESSAGE_SIZE); jsval compiled_js; if(!convert_to_js(runtime, compiled_script, &compiled_js)) rb_raise(rb_eRuntimeError, "Script compilation failed"); JSScript * js_script = (JSScript *)JS_GetPrivate(context, JSVAL_TO_OBJECT(compiled_js)); jsval js; JSBool ok = JS_ExecuteScript(context, runtime->global, js_script, &js); if (!ok) { if (JS_IsExceptionPending(context)) { // If there's an exception pending here, it's a syntax error. JS_GetPendingException(context, &johnson_context->ex); JS_ClearPendingException(context); } if (johnson_context->ex) { RAISE_JS_ERROR(self, johnson_context->ex); return Qnil; } } return convert_to_ruby(runtime, js); }
static bool js_cocos2dx_CCRichText_addEventListener(JSContext *cx, uint32_t argc, jsval *vp) { JSObject *obj = JS_THIS_OBJECT(cx, vp); js_proxy_t *proxy = jsb_get_js_proxy(obj); CCRichText* cobj = (CCRichText *)(proxy ? proxy->ptr : NULL); JSB_PRECONDITION2( cobj, cx, false, "Invalid Native Object"); if(argc == 1){ JS::CallArgs args = JS::CallArgsFromVp(argc, vp); std::shared_ptr<JSFunctionWrapper> func(new JSFunctionWrapper(cx, obj, args.get(0))); cobj->addEventListener([=](kRichTextState richTextState, int eventId, int x, int y)->bool{ JS::RootedValue rval(cx); jsval dataVal[4]; dataVal[0] = int32_to_jsval(cx, (int32_t)richTextState); dataVal[1] = int32_to_jsval(cx,eventId); dataVal[2] = int32_to_jsval(cx,x); dataVal[3] = int32_to_jsval(cx,y); bool ok = func->invoke(4, dataVal, &rval); if (!ok && JS_IsExceptionPending(cx)) { JS_ReportPendingException(cx); } if(rval.isBoolean()) { return rval.toBoolean(); } return false; }); return true; } JS_ReportError(cx, "Invalid number of arguments"); return false; }
NORETURN(void) raise_js_error_in_ruby(JohnsonRuntime* runtime) { JSContext * context = johnson_get_current_context(runtime); JohnsonContext * johnson_context = OUR_CONTEXT(context); if (JS_IsExceptionPending(context)) { assert(JS_GetPendingException(context, &(johnson_context->ex))); JS_AddNamedRoot(context, &(johnson_context->ex), "raise_js_error_in_ruby"); JS_ClearPendingException(context); JS_RemoveRoot(context, &(johnson_context->ex)); } VALUE ruby_runtime = (VALUE)JS_GetRuntimePrivate(runtime->js); if (johnson_context->ex) RAISE_JS_ERROR(ruby_runtime, johnson_context->ex); // FIXME: I don't think this is needed, it should // be done on the Ruby side. if (!johnson_context->msg) rb_raise(rb_eRuntimeError, "Unknown JavaScriptError"); // FIXME: I don't think this can ever happen.... rb_raise(rb_eRuntimeError, johnson_context->msg); }
static bool js_cocos2dx_GraphLayer_addEventListener(JSContext *cx, uint32_t argc, jsval *vp) { JSObject *obj = JS_THIS_OBJECT(cx, vp); js_proxy_t *proxy = jsb_get_js_proxy(obj); GraphLayer* cobj = (GraphLayer *)(proxy ? proxy->ptr : NULL); JSB_PRECONDITION2( cobj, cx, false, "Invalid Native Object"); if(argc == 1){ JS::CallArgs args = JS::CallArgsFromVp(argc, vp); std::shared_ptr<JSFunctionWrapper> func(new JSFunctionWrapper(cx, obj, args.get(0))); cobj->addEventListener([=](int x)->void{ jsval arg= int32_to_jsval(cx, (int32_t)x); JS::RootedValue rval(cx); bool ok = func->invoke(1, &arg, &rval); if (!ok && JS_IsExceptionPending(cx)) { JS_ReportPendingException(cx); } }); return true; } JS_ReportError(cx, "Invalid number of arguments"); return false; }
/* * call-seq: * native_compile(script, filename, linenum) * * Compile +script+ with +filename+ using +linenum+ */ static VALUE native_compile(VALUE self, VALUE script, VALUE filename, VALUE linenum) { JohnsonRuntime* runtime; Data_Get_Struct(self, JohnsonRuntime, runtime); JSContext * context = johnson_get_current_context(runtime); JohnsonContext * johnson_context = OUR_CONTEXT(context); JSScript * compiled_js = JS_CompileScript( context, runtime->global, StringValuePtr(script), (size_t)StringValueLen(script), StringValueCStr(filename), (unsigned)NUM2INT(linenum) ); if(compiled_js == NULL) { if (JS_IsExceptionPending(context)) { // If there's an exception pending here, it's a syntax error. JS_GetPendingException(context, &johnson_context->ex); JS_ClearPendingException(context); } if (johnson_context->ex) { RAISE_JS_ERROR(self, johnson_context->ex); return Qnil; } } JSObject * script_object = JS_NewScriptObject(context, compiled_js); PREPARE_RUBY_JROOTS(context, 1); JROOT(script_object); JRETURN_RUBY(make_ruby_land_proxy(runtime, OBJECT_TO_JSVAL(script_object), "JSScriptProxy")); }
/* nsISupports getService (); */ NS_IMETHODIMP nsJSCID::GetService(nsISupports **_retval) { if(!mDetails.IsValid()) return NS_ERROR_XPC_BAD_CID; nsXPConnect* xpc = nsXPConnect::GetXPConnect(); if(!xpc) return NS_ERROR_UNEXPECTED; nsAXPCNativeCallContext *ccxp = nsnull; xpc->GetCurrentNativeCallContext(&ccxp); if(!ccxp) return NS_ERROR_UNEXPECTED; PRUint32 argc; jsval * argv; jsval * vp; JSContext* cx; JSObject* obj; ccxp->GetJSContext(&cx); ccxp->GetArgc(&argc); ccxp->GetArgvPtr(&argv); ccxp->GetRetValPtr(&vp); nsCOMPtr<nsIXPConnectWrappedNative> wrapper; ccxp->GetCalleeWrapper(getter_AddRefs(wrapper)); wrapper->GetJSObject(&obj); // Do the security check if necessary XPCContext* xpcc = XPCContext::GetXPCContext(cx); nsIXPCSecurityManager* sm; sm = xpcc->GetAppropriateSecurityManager( nsIXPCSecurityManager::HOOK_GET_SERVICE); if(sm && NS_FAILED(sm->CanCreateInstance(cx, mDetails.ID()))) { NS_ASSERTION(JS_IsExceptionPending(cx), "security manager vetoed GetService without setting exception"); return NS_OK; } // If an IID was passed in then use it const nsID* iid = GetIIDArg(argc, argv, cx); if (!iid) return NS_ERROR_XPC_BAD_IID; nsCOMPtr<nsIServiceManager> svcMgr; nsresult rv = NS_GetServiceManager(getter_AddRefs(svcMgr)); if (NS_FAILED(rv)) return rv; nsCOMPtr<nsISupports> srvc; rv = svcMgr->GetService(mDetails.ID(), *iid, getter_AddRefs(srvc)); NS_ASSERTION(NS_FAILED(rv) || srvc, "service manager returned success, but service is null!"); if(NS_FAILED(rv) || !srvc) return NS_ERROR_XPC_GS_RETURNED_FAILURE; JSObject* instJSObj; nsCOMPtr<nsIXPConnectJSObjectHolder> holder; rv = xpc->WrapNative(cx, obj, srvc, *iid, getter_AddRefs(holder)); if(NS_FAILED(rv) || !holder || NS_FAILED(holder->GetJSObject(&instJSObj))) return NS_ERROR_XPC_CANT_CREATE_WN; *vp = OBJECT_TO_JSVAL(instJSObj); ccxp->SetReturnValueWasSet(JS_TRUE); return NS_OK; }
bool ScriptInterface::IsExceptionPending(JSContext* cx) { return JS_IsExceptionPending(cx) ? true : false; }
static JSBool do_import(JSContext *context, JSObject *obj, Importer *priv, const char *name) { char *filename; char *full_path; char *dirname = NULL; jsval search_path_val; JSObject *search_path; JSObject *module_obj = NULL; guint32 search_path_len; guint32 i; JSBool result; GPtrArray *directories; jsid search_path_name; search_path_name = gjs_runtime_get_const_string(JS_GetRuntime(context), GJS_STRING_SEARCH_PATH); if (!gjs_object_require_property(context, obj, "importer", search_path_name, &search_path_val)) { return JS_FALSE; } if (!JSVAL_IS_OBJECT(search_path_val)) { gjs_throw(context, "searchPath property on importer is not an object"); return JS_FALSE; } search_path = JSVAL_TO_OBJECT(search_path_val); if (!JS_IsArrayObject(context, search_path)) { gjs_throw(context, "searchPath property on importer is not an array"); return JS_FALSE; } if (!JS_GetArrayLength(context, search_path, &search_path_len)) { gjs_throw(context, "searchPath array has no length"); return JS_FALSE; } result = JS_FALSE; filename = g_strdup_printf("%s.js", name); full_path = NULL; directories = NULL; /* First try importing an internal module like byteArray */ if (priv->is_root && gjs_is_registered_native_module(context, obj, name) && import_native_file(context, obj, name)) { gjs_debug(GJS_DEBUG_IMPORTER, "successfully imported module '%s'", name); result = JS_TRUE; goto out; } for (i = 0; i < search_path_len; ++i) { jsval elem; elem = JSVAL_VOID; if (!JS_GetElement(context, search_path, i, &elem)) { /* this means there was an exception, while elem == JSVAL_VOID * means no element found */ goto out; } if (JSVAL_IS_VOID(elem)) continue; if (!JSVAL_IS_STRING(elem)) { gjs_throw(context, "importer searchPath contains non-string"); goto out; } g_free(dirname); dirname = NULL; if (!gjs_string_to_utf8(context, elem, &dirname)) goto out; /* Error message already set */ /* Ignore empty path elements */ if (dirname[0] == '\0') continue; /* Try importing __init__.js and loading the symbol from it */ if (full_path) g_free(full_path); full_path = g_build_filename(dirname, MODULE_INIT_FILENAME, NULL); module_obj = load_module_init(context, obj, full_path); if (module_obj != NULL) { jsval obj_val; if (JS_GetProperty(context, module_obj, name, &obj_val)) { if (!JSVAL_IS_VOID(obj_val) && JS_DefineProperty(context, obj, name, obj_val, NULL, NULL, GJS_MODULE_PROP_FLAGS & ~JSPROP_PERMANENT)) { result = JS_TRUE; goto out; } } } /* Second try importing a directory (a sub-importer) */ if (full_path) g_free(full_path); full_path = g_build_filename(dirname, name, NULL); if (g_file_test(full_path, G_FILE_TEST_IS_DIR)) { gjs_debug(GJS_DEBUG_IMPORTER, "Adding directory '%s' to child importer '%s'", full_path, name); if (directories == NULL) { directories = g_ptr_array_new(); } g_ptr_array_add(directories, full_path); /* don't free it twice - pass ownership to ptr array */ full_path = NULL; } /* If we just added to directories, we know we don't need to * check for a file. If we added to directories on an earlier * iteration, we want to ignore any files later in the * path. So, always skip the rest of the loop block if we have * directories. */ if (directories != NULL) { continue; } /* Third, if it's not a directory, try importing a file */ g_free(full_path); full_path = g_build_filename(dirname, filename, NULL); if (g_file_test(full_path, G_FILE_TEST_EXISTS)) { if (import_file(context, obj, name, full_path)) { gjs_debug(GJS_DEBUG_IMPORTER, "successfully imported module '%s'", name); result = JS_TRUE; } /* Don't keep searching path if we fail to load the file for * reasons other than it doesn't exist... i.e. broken files * block searching for nonbroken ones */ goto out; } gjs_debug(GJS_DEBUG_IMPORTER, "JS import '%s' not found in %s", name, dirname); } if (directories != NULL) { /* NULL-terminate the char** */ g_ptr_array_add(directories, NULL); if (import_directory(context, obj, name, (const char**) directories->pdata)) { gjs_debug(GJS_DEBUG_IMPORTER, "successfully imported directory '%s'", name); result = JS_TRUE; } } out: if (directories != NULL) { char **str_array; /* NULL-terminate the char** * (maybe for a second time, but doesn't matter) */ g_ptr_array_add(directories, NULL); str_array = (char**) directories->pdata; g_ptr_array_free(directories, FALSE); g_strfreev(str_array); } g_free(full_path); g_free(filename); g_free(dirname); if (!result && !JS_IsExceptionPending(context)) { /* If no exception occurred, the problem is just that we got to the * end of the path. Be sure an exception is set. */ gjs_throw(context, "No JS module '%s' found in search path", name); } return result; }
static JSBool import_file(JSContext *context, JSObject *obj, const char *name, const char *full_path) { char *script; gsize script_len; JSObject *module_obj; GError *error; jsval script_retval; JSBool retval = JS_FALSE; gjs_debug(GJS_DEBUG_IMPORTER, "Importing '%s'", full_path); module_obj = JS_NewObject(context, NULL, NULL, NULL); if (module_obj == NULL) { return JS_FALSE; } if (!define_import(context, obj, module_obj, name)) return JS_FALSE; if (!define_meta_properties(context, module_obj, full_path, name, obj)) goto out; script_len = 0; error = NULL; if (!(g_file_get_contents(full_path, &script, &script_len, &error))) { if (!g_error_matches(error, G_FILE_ERROR, G_FILE_ERROR_ISDIR) && !g_error_matches(error, G_FILE_ERROR, G_FILE_ERROR_NOTDIR) && !g_error_matches(error, G_FILE_ERROR, G_FILE_ERROR_NOENT)) gjs_throw_g_error(context, error); else g_error_free(error); goto out; } g_assert(script != NULL); if (!JS_EvaluateScript(context, module_obj, script, script_len, full_path, 1, /* line number */ &script_retval)) { g_free(script); /* If JSOPTION_DONT_REPORT_UNCAUGHT is set then the exception * would be left set after the evaluate and not go to the error * reporter function. */ if (JS_IsExceptionPending(context)) { gjs_debug(GJS_DEBUG_IMPORTER, "Module '%s' left an exception set", name); gjs_log_and_keep_exception(context); } else { gjs_throw(context, "JS_EvaluateScript() returned FALSE but did not set exception"); } goto out; } g_free(script); if (!finish_import(context, name)) goto out; if (!seal_import(context, obj, name)) goto out; retval = JS_TRUE; out: if (!retval) cancel_import(context, obj, name); return retval; }
static JSObject * load_module_init(JSContext *context, JSObject *in_object, const char *full_path) { char *script; gsize script_len; jsval script_retval; JSObject *module_obj; GError *error; JSBool found; jsid module_init_name; /* First we check if js module has already been loaded */ module_init_name = gjs_runtime_get_const_string(JS_GetRuntime(context), GJS_STRING_MODULE_INIT); if (JS_HasPropertyById(context, in_object, module_init_name, &found) && found) { jsval module_obj_val; if (JS_GetPropertyById(context, in_object, module_init_name, &module_obj_val)) { return JSVAL_TO_OBJECT(module_obj_val); } } module_obj = JS_NewObject(context, NULL, NULL, NULL); if (module_obj == NULL) { return JS_FALSE; } /* https://bugzilla.mozilla.org/show_bug.cgi?id=599651 means we * can't just pass in the global as the parent */ JS_SetParent(context, module_obj, gjs_get_import_global (context)); /* Define module in importer for future use and to avoid module_obj * object to be garbage collected during the evaluation of the script */ JS_DefinePropertyById(context, in_object, module_init_name, OBJECT_TO_JSVAL(module_obj), NULL, NULL, GJS_MODULE_PROP_FLAGS & ~JSPROP_PERMANENT); script_len = 0; error = NULL; if (!g_file_get_contents(full_path, &script, &script_len, &error)) { if (!g_error_matches(error, G_FILE_ERROR, G_FILE_ERROR_ISDIR) && !g_error_matches(error, G_FILE_ERROR, G_FILE_ERROR_NOTDIR) && !g_error_matches(error, G_FILE_ERROR, G_FILE_ERROR_NOENT)) gjs_throw_g_error(context, error); else g_error_free(error); return NULL; } g_assert(script != NULL); gjs_debug(GJS_DEBUG_IMPORTER, "Importing %s", full_path); if (!JS_EvaluateScript(context, module_obj, script, script_len, full_path, 1, /* line number */ &script_retval)) { g_free(script); /* If JSOPTION_DONT_REPORT_UNCAUGHT is set then the exception * would be left set after the evaluate and not go to the error * reporter function. */ if (JS_IsExceptionPending(context)) { gjs_debug(GJS_DEBUG_IMPORTER, "Module " MODULE_INIT_FILENAME " left an exception set"); gjs_log_and_keep_exception(context); } else { gjs_throw(context, "JS_EvaluateScript() returned FALSE but did not set exception"); } return NULL; } g_free(script); return module_obj; }
static JSBool do_import(JSContext *context, JSObject *obj, Importer *priv, std::string &name) { std::string filename; std::string full_path; std::string dirname; jsval search_path_val; JSObject *search_path; JSObject *module_obj = NULL; uint32_t search_path_len; uint32_t i; JSBool result; std::vector<std::string> directories; jsid search_path_name; bool exists; search_path_name = gjs_context_get_const_string(context, GJS_STRING_SEARCH_PATH); if (!gjs_object_require_property(context, obj, "importer", search_path_name, &search_path_val)) { return JS_FALSE; } if (!search_path_val.isObject()) { gjs_throw(context, "searchPath property on importer is not an object"); return JS_FALSE; } search_path = JSVAL_TO_OBJECT(search_path_val); if (!JS_IsArrayObject(context, search_path)) { gjs_throw(context, "searchPath property on importer is not an array"); return JS_FALSE; } if (!JS_GetArrayLength(context, search_path, &search_path_len)) { gjs_throw(context, "searchPath array has no length"); return JS_FALSE; } result = JS_FALSE; filename = std::string(name) + ".js"; /* First try importing an internal module like byteArray */ if (priv->is_root && gjs_is_registered_native_module(context, obj, name) && import_native_file(context, obj, name)) { gjs_debug(GJS_DEBUG_IMPORTER, "successfully imported module '%s'", name); result = JS_TRUE; goto out; } for (i = 0; i < search_path_len; ++i) { jsval elem; elem = JSVAL_VOID; if (!JS_GetElement(context, search_path, i, &elem)) { /* this means there was an exception, while elem == JSVAL_VOID * means no element found */ goto out; } if (JSVAL_IS_VOID(elem)) continue; if (!JSVAL_IS_STRING(elem)) { gjs_throw(context, "importer searchPath contains non-string"); goto out; } if (!gjs_string_to_utf8(context, elem, dirname)) goto out; /* Error message already set */ /* Ignore empty path elements */ if (dirname[0] == '\0') continue; /* Try importing __init__.js and loading the symbol from it */ full_path = pathCombine(dirname, MODULE_INIT_FILENAME); module_obj = load_module_init(context, obj, full_path); if (module_obj != NULL) { jsval obj_val; if (JS_GetProperty(context, module_obj, name.c_str(), &obj_val)) { if (!JSVAL_IS_VOID(obj_val) && JS_DefineProperty(context, obj, name.c_str(), obj_val, NULL, NULL, GJS_MODULE_PROP_FLAGS & ~JSPROP_PERMANENT)) { result = JS_TRUE; goto out; } } } /* Second try importing a directory (a sub-importer) */ full_path = pathCombine(dirname, name); if (is_directory(full_path)) { std::cout << "Adding directory '" << full_path << "' to child importer '" << name << "'\n", directories.push_back(full_path); } /* If we just added to directories, we know we don't need to * check for a file. If we added to directories on an earlier * iteration, we want to ignore any files later in the * path. So, always skip the rest of the loop block if we have * directories. */ if (directories.size() > 0) { continue; } /* Third, if it's not a directory, try importing a file */ full_path = pathCombine(dirname, filename); std::cout << "full path: " << full_path << "\n"; exists = is_regular(full_path); if (!exists) { std::cout << "JS import '" << name << "' not found in " << dirname << "\n"; continue; } if (import_file_on_module (context, obj, name, full_path)) { std::cout << "successfully imported module '" << name << "'\n"; result = JS_TRUE; } /* Don't keep searching path if we fail to load the file for * reasons other than it doesn't exist... i.e. broken files * block searching for nonbroken ones */ goto out; } if (directories.size() > 0) { /* NULL-terminate the char** */ if (import_directory(context, obj, name, directories)) { std::cout << "successfully imported directory '" << name << "'\n"; result = JS_TRUE; } } out: if (!result && !JS_IsExceptionPending(context)) { /* If no exception occurred, the problem is just that we got to the * end of the path. Be sure an exception is set. */ gjs_throw(context, "No JS module '%s' found in search path", name.c_str()); } return result; }
static JSBool go(JSContext* cx, JSObject* obj, HTTPData* http, char* body, size_t bodylen) { CurlState state; char* referer; JSString* jsbody; JSBool ret = JS_FALSE; jsval tmp; state.cx = cx; state.http = http; state.sendbuf = body; state.sendlen = bodylen; state.sent = 0; state.sent_once = 0; state.recvbuf = NULL; state.recvlen = 0; state.read = 0; if(HTTP_HANDLE == NULL) { HTTP_HANDLE = curl_easy_init(); curl_easy_setopt(HTTP_HANDLE, CURLOPT_READFUNCTION, send_body); curl_easy_setopt(HTTP_HANDLE, CURLOPT_SEEKFUNCTION, (curl_seek_callback) seek_body); curl_easy_setopt(HTTP_HANDLE, CURLOPT_HEADERFUNCTION, recv_header); curl_easy_setopt(HTTP_HANDLE, CURLOPT_WRITEFUNCTION, recv_body); curl_easy_setopt(HTTP_HANDLE, CURLOPT_NOPROGRESS, 1); curl_easy_setopt(HTTP_HANDLE, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); curl_easy_setopt(HTTP_HANDLE, CURLOPT_ERRORBUFFER, ERRBUF); curl_easy_setopt(HTTP_HANDLE, CURLOPT_COOKIEFILE, ""); curl_easy_setopt(HTTP_HANDLE, CURLOPT_USERAGENT, "CouchHTTP Client - Relax"); } if(!HTTP_HANDLE) { JS_ReportError(cx, "Failed to initialize cURL handle."); goto done; } if(!JS_GetReservedSlot(cx, obj, 0, &tmp)) { JS_ReportError(cx, "Failed to readreserved slot."); goto done; } if(!(referer = enc_string(cx, tmp, NULL))) { JS_ReportError(cx, "Failed to encode referer."); goto done; } curl_easy_setopt(HTTP_HANDLE, CURLOPT_REFERER, referer); free(referer); if(http->method < 0 || http->method > OPTIONS) { JS_ReportError(cx, "INTERNAL: Unknown method."); goto done; } curl_easy_setopt(HTTP_HANDLE, CURLOPT_CUSTOMREQUEST, METHODS[http->method]); curl_easy_setopt(HTTP_HANDLE, CURLOPT_NOBODY, 0); curl_easy_setopt(HTTP_HANDLE, CURLOPT_FOLLOWLOCATION, 1); curl_easy_setopt(HTTP_HANDLE, CURLOPT_UPLOAD, 0); if(http->method == HEAD) { curl_easy_setopt(HTTP_HANDLE, CURLOPT_NOBODY, 1); curl_easy_setopt(HTTP_HANDLE, CURLOPT_FOLLOWLOCATION, 0); } else if(http->method == POST || http->method == PUT) { curl_easy_setopt(HTTP_HANDLE, CURLOPT_UPLOAD, 1); curl_easy_setopt(HTTP_HANDLE, CURLOPT_FOLLOWLOCATION, 0); } if(body && bodylen) { curl_easy_setopt(HTTP_HANDLE, CURLOPT_INFILESIZE, bodylen); } else { curl_easy_setopt(HTTP_HANDLE, CURLOPT_INFILESIZE, 0); } // curl_easy_setopt(HTTP_HANDLE, CURLOPT_VERBOSE, 1); curl_easy_setopt(HTTP_HANDLE, CURLOPT_URL, http->url); curl_easy_setopt(HTTP_HANDLE, CURLOPT_HTTPHEADER, http->req_headers); curl_easy_setopt(HTTP_HANDLE, CURLOPT_READDATA, &state); curl_easy_setopt(HTTP_HANDLE, CURLOPT_SEEKDATA, &state); curl_easy_setopt(HTTP_HANDLE, CURLOPT_WRITEHEADER, &state); curl_easy_setopt(HTTP_HANDLE, CURLOPT_WRITEDATA, &state); if(curl_easy_perform(HTTP_HANDLE) != 0) { JS_ReportError(cx, "Failed to execute HTTP request: %s", ERRBUF); goto done; } if(!state.resp_headers) { JS_ReportError(cx, "Failed to recieve HTTP headers."); goto done; } tmp = OBJECT_TO_JSVAL(state.resp_headers); if(!JS_DefineProperty( cx, obj, "_headers", tmp, NULL, NULL, JSPROP_READONLY )) { JS_ReportError(cx, "INTERNAL: Failed to set response headers."); goto done; } if(state.recvbuf) { state.recvbuf[state.read] = '\0'; jsbody = dec_string(cx, state.recvbuf, state.read+1); if(!jsbody) { // If we can't decode the body as UTF-8 we forcefully // convert it to a string by just forcing each byte // to a jschar. jsbody = str_from_binary(cx, state.recvbuf, state.read); if(!jsbody) { if(!JS_IsExceptionPending(cx)) { JS_ReportError(cx, "INTERNAL: Failed to decode body."); } goto done; } } tmp = STRING_TO_JSVAL(jsbody); } else { tmp = JS_GetEmptyStringValue(cx); } if(!JS_DefineProperty( cx, obj, "responseText", tmp, NULL, NULL, JSPROP_READONLY )) { JS_ReportError(cx, "INTERNAL: Failed to set responseText."); goto done; } ret = JS_TRUE; done: if(state.recvbuf) JS_free(cx, state.recvbuf); return ret; }
/* * See: * https://bugzilla.mozilla.org/show_bug.cgi?id=166436 * https://bugzilla.mozilla.org/show_bug.cgi?id=215173 * * Very surprisingly, jsapi.h lacks any way to "throw new Error()" * * So here is an awful hack inspired by * http://egachine.berlios.de/embedding-sm-best-practice/embedding-sm-best-practice.html#error-handling */ static void gjs_throw_valist(JSContext *context, const char *error_class, const char *format, va_list args) { char *s; JSBool result; jsval v_constructor, v_message; JSObject *err_obj; 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 * "just in case"; in those cases, we don't want to * overwrite an exception that already exists. * (Do log in case our second exception adds more info, * but don't log as topic ERROR because if the exception is * caught we don't want an ERROR in the logs.) */ gjs_debug(GJS_DEBUG_CONTEXT, "Ignoring second exception: '%s'", s); g_free(s); JS_EndRequest(context); return; } result = JS_FALSE; (void)JS_EnterLocalRootScope(context); if (!gjs_string_from_utf8(context, s, -1, &v_message)) { JS_ReportError(context, "Failed to copy exception string"); goto out; } if (!gjs_object_get_property(context, JS_GetGlobalObject(context), error_class, &v_constructor)) { JS_ReportError(context, "??? Missing Error constructor in global object?"); goto out; } /* throw new Error(message) */ err_obj = JS_New(context, JSVAL_TO_OBJECT(v_constructor), 1, &v_message); JS_SetPendingException(context, OBJECT_TO_JSVAL(err_obj)); result = JS_TRUE; out: JS_LeaveLocalRootScope(context); if (!result) { /* try just reporting it to error handler? should not * happen though pretty much */ JS_ReportError(context, "Failed to throw exception '%s'", s); } g_free(s); JS_EndRequest(context); }
void AutoJSAPI::InitInternal(JSObject* aGlobal, JSContext* aCx, bool aIsMainThread) { MOZ_ASSERT(aCx); MOZ_ASSERT(aIsMainThread == NS_IsMainThread()); #ifdef DEBUG bool haveException = JS_IsExceptionPending(aCx); #endif // DEBUG mCx = aCx; mIsMainThread = aIsMainThread; if (aIsMainThread) { // This Rooted<> is necessary only as long as AutoCxPusher::AutoCxPusher // can GC, which is only possible because XPCJSContextStack::Push calls // nsIPrincipal.Equals. Once that is removed, the Rooted<> will no longer // be necessary. JS::Rooted<JSObject*> global(JS_GetRuntime(aCx), aGlobal); mCxPusher.emplace(mCx); mAutoNullableCompartment.emplace(mCx, global); } else { mAutoNullableCompartment.emplace(mCx, aGlobal); } JSRuntime* rt = JS_GetRuntime(aCx); mOldErrorReporter.emplace(JS_GetErrorReporter(rt)); mOldAutoJSAPIOwnsErrorReporting = JS::ContextOptionsRef(aCx).autoJSAPIOwnsErrorReporting(); JS::ContextOptionsRef(aCx).setAutoJSAPIOwnsErrorReporting(true); JS_SetErrorReporter(rt, WarningOnlyErrorReporter); #ifdef DEBUG if (haveException) { JS::Rooted<JS::Value> exn(aCx); JS_GetPendingException(aCx, &exn); JS_ClearPendingException(aCx); if (exn.isObject()) { JS::Rooted<JSObject*> exnObj(aCx, &exn.toObject()); nsAutoJSString stack, filename, name, message; int32_t line; JS::Rooted<JS::Value> tmp(aCx); if (!JS_GetProperty(aCx, exnObj, "filename", &tmp)) { JS_ClearPendingException(aCx); } if (tmp.isUndefined()) { if (!JS_GetProperty(aCx, exnObj, "fileName", &tmp)) { JS_ClearPendingException(aCx); } } if (!filename.init(aCx, tmp)) { JS_ClearPendingException(aCx); } if (!JS_GetProperty(aCx, exnObj, "stack", &tmp) || !stack.init(aCx, tmp)) { JS_ClearPendingException(aCx); } if (!JS_GetProperty(aCx, exnObj, "name", &tmp) || !name.init(aCx, tmp)) { JS_ClearPendingException(aCx); } if (!JS_GetProperty(aCx, exnObj, "message", &tmp) || !message.init(aCx, tmp)) { JS_ClearPendingException(aCx); } if (!JS_GetProperty(aCx, exnObj, "lineNumber", &tmp) || !JS::ToInt32(aCx, tmp, &line)) { JS_ClearPendingException(aCx); line = 0; } printf_stderr("PREEXISTING EXCEPTION OBJECT: '%s: %s'\n%s:%d\n%s\n", NS_ConvertUTF16toUTF8(name).get(), NS_ConvertUTF16toUTF8(message).get(), NS_ConvertUTF16toUTF8(filename).get(), line, NS_ConvertUTF16toUTF8(stack).get()); } else { // It's a primitive... not much we can do other than stringify it. nsAutoJSString exnStr; if (!exnStr.init(aCx, exn)) { JS_ClearPendingException(aCx); } printf_stderr("PREEXISTING EXCEPTION PRIMITIVE: %s\n", NS_ConvertUTF16toUTF8(exnStr).get()); } MOZ_ASSERT(false, "We had an exception; we should not have"); } #endif // DEBUG }
JSBool js_ReportUncaughtException(JSContext *cx) { jsval exn; JSObject *exnObject; jsval roots[5]; JSTempValueRooter tvr; JSErrorReport *reportp, report; JSString *str; const char *bytes; JSBool ok; if (!JS_IsExceptionPending(cx)) return JS_TRUE; if (!JS_GetPendingException(cx, &exn)) return JS_FALSE; memset(roots, 0, sizeof roots); JS_PUSH_TEMP_ROOT(cx, JS_ARRAY_LENGTH(roots), roots, &tvr); /* * Because js_ValueToString below could error and an exception object * could become unrooted, we must root exnObject. Later, if exnObject is * non-null, we need to root other intermediates, so allocate an operand * stack segment to protect all of these values. */ if (JSVAL_IS_PRIMITIVE(exn)) { exnObject = NULL; } else { exnObject = JSVAL_TO_OBJECT(exn); roots[0] = exn; } JS_ClearPendingException(cx); reportp = js_ErrorFromException(cx, exn); /* XXX L10N angels cry once again (see also jsemit.c, /L10N gaffes/) */ str = js_ValueToString(cx, exn); if (!str) { bytes = "unknown (can't convert to string)"; } else { roots[1] = STRING_TO_JSVAL(str); bytes = js_GetStringBytes(cx, str); if (!bytes) { ok = JS_FALSE; goto out; } } ok = JS_TRUE; if (!reportp && exnObject && OBJ_GET_CLASS(cx, exnObject) == &js_ErrorClass) { const char *filename; uint32 lineno; ok = JS_GetProperty(cx, exnObject, js_message_str, &roots[2]); if (!ok) goto out; if (JSVAL_IS_STRING(roots[2])) { bytes = js_GetStringBytes(cx, JSVAL_TO_STRING(roots[2])); if (!bytes) { ok = JS_FALSE; goto out; } } ok = JS_GetProperty(cx, exnObject, js_fileName_str, &roots[3]); if (!ok) goto out; str = js_ValueToString(cx, roots[3]); if (!str) { ok = JS_FALSE; goto out; } filename = StringToFilename(cx, str); if (!filename) { ok = JS_FALSE; goto out; } ok = JS_GetProperty(cx, exnObject, js_lineNumber_str, &roots[4]); if (!ok) goto out; lineno = js_ValueToECMAUint32 (cx, &roots[4]); ok = !JSVAL_IS_NULL(roots[4]); if (!ok) goto out; reportp = &report; memset(&report, 0, sizeof report); report.filename = filename; report.lineno = (uintN) lineno; } if (!reportp) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_UNCAUGHT_EXCEPTION, bytes); } else { /* Flag the error as an exception. */ reportp->flags |= JSREPORT_EXCEPTION; /* Pass the exception object. */ JS_SetPendingException(cx, exn); js_ReportErrorAgain(cx, bytes, reportp); JS_ClearPendingException(cx); } out: JS_POP_TEMP_ROOT(cx, &tvr); return ok; }
rpmRC rpmjsRunFile(rpmjs js, const char * fn, char *const * Iargv, const char ** resultp) { rpmRC rc = RPMRC_FAIL; if (js == NULL) js = rpmjsI(); if (fn != NULL) { #if defined(WITH_GPSEE) gpsee_interpreter_t * I = js->I; FILE * fp = rpmjsOpenFile(js, fn, resultp); if (fp == NULL) { I->grt->exitType = et_execFailure; /* XXX FIXME: strerror in *resultp */ goto exit; } #ifdef NOTYET /* XXX FIXME */ processInlineFlags(js, fp, &verbosity); gpsee_setVerbosity(verbosity); #endif /* Just compile and exit? */ if (F_ISSET(js->flags, NOEXEC)) { JSScript *script = NULL; JSObject *scrobj = NULL; if (!gpsee_compileScript(I->cx, fn, fp, NULL, &script, I->realm->globalObject, &scrobj)) { I->grt->exitType = et_exception; /* XXX FIXME: isatty(3) */ gpsee_reportUncaughtException(I->cx, JSVAL_NULL, (gpsee_verbosity(0) >= GSR_FORCE_STACK_DUMP_VERBOSITY) || ((gpsee_verbosity(0) >= GPSEE_ERROR_OUTPUT_VERBOSITY) && isatty(STDERR_FILENO))); } else { I->grt->exitType = et_finished; rc = RPMRC_OK; } } else { char *const * Ienviron = NULL; if (F_ISSET(js->flags, ALLOW)) { #if defined(__APPLE__) Ienviron = (char *const *) _NSGetEnviron(); #else Ienviron = environ; #endif } I->grt->exitType = et_execFailure; if (gpsee_runProgramModule(I->cx, fn, NULL, fp, Iargv, Ienviron) == JS_FALSE) { int code = gpsee_getExceptionExitCode(I->cx); if (code >= 0) { I->grt->exitType = et_requested; I->grt->exitCode = code; /* XXX FIXME: format and return code in *resultp. */ /* XXX hack tp get code into rc -> ec by negating */ rc = -code; } else if (JS_IsExceptionPending(I->cx)) { /* XXX FIXME: isatty(3) */ gpsee_reportUncaughtException(I->cx, JSVAL_NULL, (gpsee_verbosity(0) >= GSR_FORCE_STACK_DUMP_VERBOSITY) || ((gpsee_verbosity(0) >= GPSEE_ERROR_OUTPUT_VERBOSITY) && isatty(STDERR_FILENO))); } } else { I->grt->exitType = et_finished; rc = RPMRC_OK; } } fclose(fp); fp = NULL; #endif /* WITH_GPSEE */ } #if defined(WITH_GPSEE) exit: #endif /* WITH_GPSEE */ RPMJSDBG(0, (stderr, "<== %s(%p,%s) rc %d |%s|\n", __FUNCTION__, js, fn, rc, (resultp ? *resultp :""))); return rc; }
/* * This is called upon returning from JS back into Java. Any JS errors * reported during that time will be converted into Java exceptions. It's * possible that a JS error was actually triggered by Java at some point, in * which case the original Java exception is thrown. */ static void throw_any_pending_js_error_as_a_java_exception(JSJavaThreadState *jsj_env) { CapturedJSError *error; JNIEnv *jEnv; jstring message_jstr, linebuf_jstr, filename_jstr; jint index, lineno; JSErrorReport *report; JSContext *cx; jsval pending_exception; jobject java_obj; int dummy_cost; JSBool is_local_refp; JSType primitive_type; jthrowable java_exception; message_jstr = linebuf_jstr = filename_jstr = java_exception = NULL; /* Get the Java JNI environment */ jEnv = jsj_env->jEnv; cx = jsj_env->cx; /* Get the pending JS exception if it exists */ if (cx&&JS_IsExceptionPending(cx)) { if (!JS_GetPendingException(cx, &pending_exception)) goto out_of_memory; /* Find out the JSTYPE of this jsval. */ primitive_type = JS_TypeOfValue(cx, pending_exception); /* Convert jsval exception to a java object and then use it to create an instance of JSException. */ if (!jsj_ConvertJSValueToJavaObject(cx, jEnv, pending_exception, jsj_get_jlObject_descriptor(cx, jEnv), &dummy_cost, &java_obj, &is_local_refp)) goto done; java_exception = (*jEnv)->NewObject(jEnv, njJSException, njJSException_JSException_wrap, primitive_type, java_obj); if (is_local_refp) (*jEnv)->DeleteLocalRef(jEnv, java_obj); if (!java_exception) goto out_of_memory; /* Throw the newly-created JSException */ if ((*jEnv)->Throw(jEnv, java_exception) < 0) { JS_ASSERT(0); jsj_LogError("Couldn't throw JSException\n"); goto done; } JS_ClearPendingException(cx); return; } if (!jsj_env->pending_js_errors) { #ifdef DEBUG /* Any exception should be cleared as soon as it's detected, so there shouldn't be any pending. */ if ((*jEnv)->ExceptionOccurred(jEnv)) { /* A Java exception occurred, but nobody in JS-land noticed. */ JS_ASSERT(0); (*jEnv)->ExceptionClear(jEnv); } #endif return; } /* Get the deepest (oldest) saved JS error */ /* XXX - What's the right thing to do about newer errors ? For now we just throw them away */ error = jsj_env->pending_js_errors; while (error->next) error = error->next; /* * If the JS error was originally the result of a Java exception, rethrow * the original exception. */ if (error->java_exception) { (*jEnv)->Throw(jEnv, error->java_exception); goto done; } /* Propagate any JS errors that did not originate as Java exceptions into Java as an instance of netscape.javascript.JSException */ /* First, marshall the arguments to the JSException constructor */ message_jstr = NULL; if (error->message) { message_jstr = (*jEnv)->NewStringUTF(jEnv, error->message); if (!message_jstr) goto out_of_memory; } report = &error->report; filename_jstr = NULL; if (report->filename) { filename_jstr = (*jEnv)->NewStringUTF(jEnv, report->filename); if (!filename_jstr) goto out_of_memory; } linebuf_jstr = NULL; if (report->linebuf) { linebuf_jstr = (*jEnv)->NewStringUTF(jEnv, report->linebuf); if (!linebuf_jstr) goto out_of_memory; } lineno = report->lineno; index = report->linebuf ? report->tokenptr - report->linebuf : 0; /* Call the JSException constructor */ java_exception = (*jEnv)->NewObject(jEnv, njJSException, njJSException_JSException, message_jstr, filename_jstr, lineno, linebuf_jstr, index); if (!java_exception) goto out_of_memory; /* Throw the newly-created JSException */ if ((*jEnv)->Throw(jEnv, java_exception) < 0) { JS_ASSERT(0); jsj_UnexpectedJavaError(cx, jEnv, "Couldn't throw JSException\n"); } goto done; out_of_memory: /* No recovery possible */ JS_ASSERT(0); jsj_LogError("Out of memory while attempting to throw JSException\n"); done: jsj_ClearPendingJSErrors(jsj_env); /* * Release local references to Java objects, since some JVMs seem reticent * about collecting them otherwise. */ if (message_jstr) (*jEnv)->DeleteLocalRef(jEnv, message_jstr); if (filename_jstr) (*jEnv)->DeleteLocalRef(jEnv, filename_jstr); if (linebuf_jstr) (*jEnv)->DeleteLocalRef(jEnv, linebuf_jstr); if (java_exception) (*jEnv)->DeleteLocalRef(jEnv, java_exception); }
bool ScriptInterface::IsExceptionPending(JSContext* cx) { JSAutoRequest rq(cx); return JS_IsExceptionPending(cx) ? true : false; }
nsresult nsJSUtils::EvaluateString(JSContext* aCx, JS::SourceBufferHolder& aSrcBuf, JS::Handle<JSObject*> aScopeObject, JS::CompileOptions& aCompileOptions, const EvaluateOptions& aEvaluateOptions, JS::MutableHandle<JS::Value> aRetValue, void **aOffThreadToken) { PROFILER_LABEL("nsJSUtils", "EvaluateString", js::ProfileEntry::Category::JS); MOZ_ASSERT_IF(aCompileOptions.versionSet, aCompileOptions.version != JSVERSION_UNKNOWN); MOZ_ASSERT_IF(aEvaluateOptions.coerceToString, aEvaluateOptions.needResult); MOZ_ASSERT_IF(!aEvaluateOptions.reportUncaught, aEvaluateOptions.needResult); MOZ_ASSERT(aCx == nsContentUtils::GetCurrentJSContext()); MOZ_ASSERT(aSrcBuf.get()); // Unfortunately, the JS engine actually compiles scripts with a return value // in a different, less efficient way. Furthermore, it can't JIT them in many // cases. So we need to be explicitly told whether the caller cares about the // return value. Callers can do this by calling the other overload of // EvaluateString() which calls this function with aEvaluateOptions.needResult // set to false. aRetValue.setUndefined(); JS::ExposeObjectToActiveJS(aScopeObject); nsAutoMicroTask mt; nsresult rv = NS_OK; bool ok = false; nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager(); NS_ENSURE_TRUE(ssm->ScriptAllowed(js::GetGlobalForObjectCrossCompartment(aScopeObject)), NS_OK); mozilla::Maybe<AutoDontReportUncaught> dontReport; if (!aEvaluateOptions.reportUncaught) { // We need to prevent AutoLastFrameCheck from reporting and clearing // any pending exceptions. dontReport.emplace(aCx); } // Scope the JSAutoCompartment so that we can later wrap the return value // into the caller's cx. { JSAutoCompartment ac(aCx, aScopeObject); JS::Rooted<JSObject*> rootedScope(aCx, aScopeObject); if (aOffThreadToken) { JS::Rooted<JSScript*> script(aCx, JS::FinishOffThreadScript(aCx, JS_GetRuntime(aCx), *aOffThreadToken)); *aOffThreadToken = nullptr; // Mark the token as having been finished. if (script) { if (aEvaluateOptions.needResult) { ok = JS_ExecuteScript(aCx, rootedScope, script, aRetValue); } else { ok = JS_ExecuteScript(aCx, rootedScope, script); } } else { ok = false; } } else { if (aEvaluateOptions.needResult) { ok = JS::Evaluate(aCx, rootedScope, aCompileOptions, aSrcBuf, aRetValue); } else { ok = JS::Evaluate(aCx, rootedScope, aCompileOptions, aSrcBuf); } } if (ok && aEvaluateOptions.coerceToString && !aRetValue.isUndefined()) { JS::Rooted<JS::Value> value(aCx, aRetValue); JSString* str = JS::ToString(aCx, value); ok = !!str; aRetValue.set(ok ? JS::StringValue(str) : JS::UndefinedValue()); } } if (!ok) { if (aEvaluateOptions.reportUncaught) { ReportPendingException(aCx); if (aEvaluateOptions.needResult) { aRetValue.setUndefined(); } } else { rv = JS_IsExceptionPending(aCx) ? NS_ERROR_FAILURE : NS_ERROR_OUT_OF_MEMORY; JS::Rooted<JS::Value> exn(aCx); JS_GetPendingException(aCx, &exn); if (aEvaluateOptions.needResult) { aRetValue.set(exn); } JS_ClearPendingException(aCx); } } // Wrap the return value into whatever compartment aCx was in. if (aEvaluateOptions.needResult) { JS::Rooted<JS::Value> v(aCx, aRetValue); if (!JS_WrapValue(aCx, &v)) { return NS_ERROR_OUT_OF_MEMORY; } aRetValue.set(v); } return rv; }
// PD_TRACE_DECLARE_FUNCTION ( SDB_SCOPE_EVALUATE, "Scope::evaluate" ) INT32 Scope::evaluate ( const CHAR *code , UINT32 len, const CHAR *filename, UINT32 lineno, CHAR ** result, INT32 printFlag ) { PD_TRACE_ENTRY ( SDB_SCOPE_EVALUATE ); jsval rval = JSVAL_VOID ; jsval exception = JSVAL_VOID ; CHAR * cstrException = NULL ; CHAR * cstr = NULL ; INT32 rc = SDB_OK ; SDB_ASSERT ( _context && _global, "this scope has not been initilized" ) ; SDB_ASSERT ( code , "Invalid arguments" ) ; // set error report sdbSetPrintError( ( printFlag & SPT_EVAL_FLAG_PRINT ) ? TRUE : FALSE ) ; sdbSetNeedClearErrorInfo( TRUE ) ; if ( ! JS_EvaluateScript ( _context , _global , code , len > 0 ? len : ossStrlen ( code ) , filename ? filename : "(default)" , lineno , &rval ) ) { rc = sdbGetErrno() ? sdbGetErrno() : SDB_SPT_EVAL_FAIL ; ; goto error ; } // clear return error if ( sdbIsNeedClearErrorInfo() && !JS_IsExceptionPending( _context ) ) { sdbClearErrorInfo() ; } if ( !result ) { goto done ; } // cstr is freed in done: // cstr is freed by JSFree, so we have to use strdup instead of ossStrdup if ( JSVAL_IS_VOID ( rval ) ) { #if defined (_LINUX) cstr = strdup ( "" ) ; #elif defined (_WINDOWS) cstr = _strdup ( "" ) ; #endif } else { cstr = convertJsvalToString ( _context , rval ) ; } if ( ! cstr ) { rc = SDB_SYS ; goto error ; } *result = ossStrdup ( cstr ) ; if ( !( result && result[0] != '\0') ) { rc = SDB_OOM ; PD_LOG ( PDERROR , "memory allcation fail" ) ; goto error ; } done : SAFE_JS_FREE ( _context , cstr ) ; PD_TRACE_EXITRC ( SDB_SCOPE_EVALUATE, rc ); return rc ; error : if ( JS_GetPendingException ( _context , &exception ) ) { cstrException = convertJsvalToString ( _context , exception ) ; if ( cstrException ) { if ( printFlag & SPT_EVAL_FLAG_PRINT ) { ossPrintf ( "Uncaught exception: %s\n" , cstrException ) ; } SAFE_JS_FREE ( _context , cstrException ) ; } else { JS_ClearPendingException ( _context ) ; } } goto done ; }
void AutoJSAPI::InitInternal(nsIGlobalObject* aGlobalObject, JSObject* aGlobal, JSContext* aCx, bool aIsMainThread) { MOZ_ASSERT(aCx); MOZ_ASSERT(aCx == danger::GetJSContext()); MOZ_ASSERT(aIsMainThread == NS_IsMainThread()); MOZ_ASSERT(bool(aGlobalObject) == bool(aGlobal)); MOZ_ASSERT_IF(aGlobalObject, aGlobalObject->GetGlobalJSObject() == aGlobal); #ifdef DEBUG bool haveException = JS_IsExceptionPending(aCx); #endif // DEBUG mCx = aCx; mIsMainThread = aIsMainThread; mGlobalObject = aGlobalObject; if (aIsMainThread) { // We _could_ just unconditionally emplace mAutoRequest here. It's just not // needed on worker threads, and we're hoping to kill it on the main thread // too. mAutoRequest.emplace(mCx); } if (aGlobal) { JS::ExposeObjectToActiveJS(aGlobal); } mAutoNullableCompartment.emplace(mCx, aGlobal); ScriptSettingsStack::Push(this); mOldWarningReporter.emplace(JS::GetWarningReporter(aCx)); JS::SetWarningReporter(aCx, WarningOnlyErrorReporter); #ifdef DEBUG if (haveException) { JS::Rooted<JS::Value> exn(aCx); JS_GetPendingException(aCx, &exn); JS_ClearPendingException(aCx); if (exn.isObject()) { JS::Rooted<JSObject*> exnObj(aCx, &exn.toObject()); nsAutoJSString stack, filename, name, message; int32_t line; JS::Rooted<JS::Value> tmp(aCx); if (!JS_GetProperty(aCx, exnObj, "filename", &tmp)) { JS_ClearPendingException(aCx); } if (tmp.isUndefined()) { if (!JS_GetProperty(aCx, exnObj, "fileName", &tmp)) { JS_ClearPendingException(aCx); } } if (!filename.init(aCx, tmp)) { JS_ClearPendingException(aCx); } if (!JS_GetProperty(aCx, exnObj, "stack", &tmp) || !stack.init(aCx, tmp)) { JS_ClearPendingException(aCx); } if (!JS_GetProperty(aCx, exnObj, "name", &tmp) || !name.init(aCx, tmp)) { JS_ClearPendingException(aCx); } if (!JS_GetProperty(aCx, exnObj, "message", &tmp) || !message.init(aCx, tmp)) { JS_ClearPendingException(aCx); } if (!JS_GetProperty(aCx, exnObj, "lineNumber", &tmp) || !JS::ToInt32(aCx, tmp, &line)) { JS_ClearPendingException(aCx); line = 0; } printf_stderr("PREEXISTING EXCEPTION OBJECT: '%s: %s'\n%s:%d\n%s\n", NS_ConvertUTF16toUTF8(name).get(), NS_ConvertUTF16toUTF8(message).get(), NS_ConvertUTF16toUTF8(filename).get(), line, NS_ConvertUTF16toUTF8(stack).get()); } else { // It's a primitive... not much we can do other than stringify it. nsAutoJSString exnStr; if (!exnStr.init(aCx, exn)) { JS_ClearPendingException(aCx); } printf_stderr("PREEXISTING EXCEPTION PRIMITIVE: %s\n", NS_ConvertUTF16toUTF8(exnStr).get()); } MOZ_ASSERT(false, "We had an exception; we should not have"); } #endif // DEBUG }
JSDProperty* jsd_GetValueProperty(JSDContext* jsdc, JSDValue* jsdval, JSString* name) { JSContext* cx = jsdc->dumbContext; JSDProperty* jsdprop; JSDProperty* iter = NULL; JSObject* obj; uintN attrs = 0; JSBool found; JSPropertyDesc pd; const jschar * nameChars; size_t nameLen; jsval val, nameval; jsid nameid; JSCrossCompartmentCall *call = NULL; if(!jsd_IsValueObject(jsdc, jsdval)) return NULL; /* If we already have the prop, then return it */ while(NULL != (jsdprop = jsd_IterateProperties(jsdc, jsdval, &iter))) { JSString* propName = jsd_GetValueString(jsdc, jsdprop->name); if(propName) { intN result; if (JS_CompareStrings(cx, propName, name, &result) && !result) return jsdprop; } JSD_DropProperty(jsdc, jsdprop); } /* Not found in property list, look it up explicitly */ if(!(obj = JSVAL_TO_OBJECT(jsdval->val))) return NULL; if (!(nameChars = JS_GetStringCharsZAndLength(cx, name, &nameLen))) return NULL; JS_BeginRequest(cx); call = JS_EnterCrossCompartmentCall(cx, obj); if(!call) { JS_EndRequest(cx); return NULL; } JS_GetUCPropertyAttributes(cx, obj, nameChars, nameLen, &attrs, &found); if (!found) { JS_LeaveCrossCompartmentCall(call); JS_EndRequest(cx); return NULL; } JS_ClearPendingException(cx); if(!JS_GetUCProperty(cx, obj, nameChars, nameLen, &val)) { if (JS_IsExceptionPending(cx)) { if (!JS_GetPendingException(cx, &pd.value)) { JS_LeaveCrossCompartmentCall(call); JS_EndRequest(cx); return NULL; } pd.flags = JSPD_EXCEPTION; } else { pd.flags = JSPD_ERROR; pd.value = JSVAL_VOID; } } else { pd.value = val; } JS_LeaveCrossCompartmentCall(call); JS_EndRequest(cx); nameval = STRING_TO_JSVAL(name); if (!JS_ValueToId(cx, nameval, &nameid) || !JS_IdToValue(cx, nameid, &pd.id)) { return NULL; } pd.slot = pd.spare = 0; pd.alias = JSVAL_NULL; pd.flags |= (attrs & JSPROP_ENUMERATE) ? JSPD_ENUMERATE : 0 | (attrs & JSPROP_READONLY) ? JSPD_READONLY : 0 | (attrs & JSPROP_PERMANENT) ? JSPD_PERMANENT : 0; return _newProperty(jsdc, &pd, JSDPD_HINTED); }
void gjstest_test_func_gjs_jsapi_util_error_throw(void) { GjsUnitTestFixture fixture; JSContext *context; jsval exc, value, previous; char *s = NULL; int strcmp_result; _gjs_unit_test_fixture_begin(&fixture); context = fixture.context; /* Test that we can throw */ gjs_throw(context, "This is an exception %d", 42); g_assert(JS_IsExceptionPending(context)); exc = JSVAL_VOID; JS_GetPendingException(context, &exc); g_assert(!JSVAL_IS_VOID(exc)); value = JSVAL_VOID; JS_GetProperty(context, JSVAL_TO_OBJECT(exc), "message", &value); g_assert(JSVAL_IS_STRING(value)); gjs_string_get_binary_data (context, value, &s, NULL); g_assert(s != NULL); strcmp_result = strcmp(s, "This is an exception 42"); free(s); if (strcmp_result != 0) g_error("Exception has wrong message '%s'", s); /* keep this around before we clear it */ previous = exc; JS_AddValueRoot(context, &previous); JS_ClearPendingException(context); g_assert(!JS_IsExceptionPending(context)); /* Check that we don't overwrite a pending exception */ JS_SetPendingException(context, previous); g_assert(JS_IsExceptionPending(context)); gjs_throw(context, "Second different exception %s", "foo"); g_assert(JS_IsExceptionPending(context)); exc = JSVAL_VOID; JS_GetPendingException(context, &exc); g_assert(!JSVAL_IS_VOID(exc)); g_assert(exc == previous); JS_RemoveValueRoot(context, &previous); _gjs_unit_test_fixture_finish(&fixture); }