Exemplo n.º 1
0
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;
}
Exemplo n.º 2
0
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;
}
Exemplo n.º 3
0
// 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);
}
Exemplo n.º 4
0
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;
}
Exemplo n.º 7
0
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;
}
Exemplo n.º 8
0
/*
 * 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;
}
Exemplo n.º 10
0
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;
}
Exemplo n.º 12
0
/*
 * 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"));
}
Exemplo n.º 13
0
/* 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;
}
Exemplo n.º 14
0
bool ScriptInterface::IsExceptionPending(JSContext* cx)
{
	return JS_IsExceptionPending(cx) ? true : false;
}
Exemplo n.º 15
0
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;
}
Exemplo n.º 16
0
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;
}
Exemplo n.º 17
0
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;
}
Exemplo n.º 18
0
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;
}
Exemplo n.º 19
0
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;
}
Exemplo n.º 20
0
/*
 * 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);
}
Exemplo n.º 21
0
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
}
Exemplo n.º 22
0
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;
}
Exemplo n.º 23
0
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;
}
Exemplo n.º 24
0
/*
 * 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);
}
Exemplo n.º 25
0
bool ScriptInterface::IsExceptionPending(JSContext* cx)
{
	JSAutoRequest rq(cx);
	return JS_IsExceptionPending(cx) ? true : false;
}
Exemplo n.º 26
0
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;
}
Exemplo n.º 27
0
   // 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 ;
   }
Exemplo n.º 28
0
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
}
Exemplo n.º 29
0
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);
}
Exemplo n.º 30
0
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);
}