static bool ProcessLine(AutoJSAPI& jsapi, const char* buffer, int startline) { JSContext* cx = jsapi.cx(); JS::RootedScript script(cx); JS::RootedValue result(cx); JS::CompileOptions options(cx); options.setFileAndLine("typein", startline) .setIsRunOnce(true); if (!JS_CompileScript(cx, buffer, strlen(buffer), options, &script)) return false; if (compileOnly) return true; if (!JS_ExecuteScript(cx, script, &result)) return false; if (result.isUndefined()) return true; RootedString str(cx); if (!(str = ToString(cx, result))) return false; JSAutoByteString bytes; if (!bytes.encodeLatin1(cx, str)) return false; fprintf(gOutFile, "%s\n", bytes.ptr()); return true; }
// static void XPCThrower::Verbosify(XPCCallContext& ccx, char** psz, PRBool own) { char* sz = nsnull; if(ccx.HasInterfaceAndMember()) { XPCNativeInterface* iface = ccx.GetInterface(); jsid id = ccx.GetMember()->GetName(); JSAutoByteString bytes; const char *name = JSID_IS_VOID(id) ? "Unknown" : bytes.encode(ccx, JSID_TO_STRING(id)); if(!name) { name = ""; } sz = JS_smprintf("%s [%s.%s]", *psz, iface->GetNameString(), name); } if(sz) { if(own) JS_smprintf_free(*psz); *psz = sz; } }
static void ThrowBadArg(JSContext *cx, nsresult rv, const char *ifaceName, jsid memberId, const char *memberName, unsigned paramnum) { /* Only one memberId or memberName should be given. */ MOZ_ASSERT(JSID_IS_VOID(memberId) != !memberName); // From XPCThrower::ThrowBadParam. char* sz; const char* format; if (!nsXPCException::NameAndFormatForNSResult(rv, nullptr, &format)) format = ""; JSAutoByteString memberNameBytes; if (!memberName) { memberName = JSID_IS_STRING(memberId) ? memberNameBytes.encodeLatin1(cx, JSID_TO_STRING(memberId)) : "unknown"; } sz = JS_smprintf("%s arg %u [%s.%s]", format, (unsigned int) paramnum, ifaceName, memberName); dom::Throw(cx, rv, sz); if (sz) JS_smprintf_free(sz); }
/* |callee| requires a usage string provided by JS_DefineFunctionsWithHelp. */ void js::ReportUsageErrorASCII(JSContext* cx, HandleObject callee, const char* msg) { const char* usageStr = "usage"; PropertyName* usageAtom = Atomize(cx, usageStr, strlen(usageStr))->asPropertyName(); RootedId id(cx, NameToId(usageAtom)); DebugOnly<Shape*> shape = static_cast<Shape*>(callee->as<JSFunction>().lookup(cx, id)); MOZ_ASSERT(!shape->configurable()); MOZ_ASSERT(!shape->writable()); MOZ_ASSERT(shape->hasDefaultGetter()); RootedValue usage(cx); if (!JS_GetProperty(cx, callee, "usage", &usage)) return; if (!usage.isString()) { JS_ReportErrorASCII(cx, "%s", msg); } else { RootedString usageStr(cx, usage.toString()); JSAutoByteString str; if (!str.encodeUtf8(cx, usageStr)) return; JS_ReportErrorUTF8(cx, "%s. Usage: %s", msg, str.ptr()); } }
static JSBool DumpHeapComplete(JSContext *cx, unsigned argc, jsval *vp) { const char *fileName = NULL; JSAutoByteString fileNameBytes; if (argc > 0) { Value v = JS_ARGV(cx, vp)[0]; if (v.isString()) { JSString *str = v.toString(); if (!fileNameBytes.encodeLatin1(cx, str)) return false; fileName = fileNameBytes.ptr(); } } FILE *dumpFile; if (!fileName) { dumpFile = stdout; } else { dumpFile = fopen(fileName, "w"); if (!dumpFile) { JS_ReportError(cx, "can't open %s", fileName); return false; } } js::DumpHeapComplete(JS_GetRuntime(cx), dumpFile); fclose(dumpFile); JS_SET_RVAL(cx, vp, JSVAL_VOID); return true; }
static inline void ReportInvalidTrapResult(JSContext* cx, JSObject* proxy, JSAtom* atom) { RootedValue v(cx, ObjectOrNullValue(proxy)); JSAutoByteString bytes; if (!AtomToPrintableString(cx, atom, &bytes)) return; ReportValueError2(cx, JSMSG_INVALID_TRAP_RESULT, JSDVG_IGNORE_STACK, v, nullptr, bytes.ptr()); }
static bool DumpHeapComplete(JSContext *cx, unsigned argc, jsval *vp) { CallArgs args = CallArgsFromVp(argc, vp); DumpHeapNurseryBehaviour nurseryBehaviour = js::IgnoreNurseryObjects; FILE *dumpFile = nullptr; unsigned i = 0; if (argc > i) { Value v = args[i]; if (v.isString()) { JSString *str = v.toString(); bool same = false; if (!JS_StringEqualsAscii(cx, str, "collectNurseryBeforeDump", &same)) return false; if (same) { nurseryBehaviour = js::CollectNurseryBeforeDump; ++i; } } } if (argc > i) { Value v = args[i]; if (v.isString()) { if (!fuzzingSafe) { JSString *str = v.toString(); JSAutoByteString fileNameBytes; if (!fileNameBytes.encodeLatin1(cx, str)) return false; const char *fileName = fileNameBytes.ptr(); dumpFile = fopen(fileName, "w"); if (!dumpFile) { JS_ReportError(cx, "can't open %s", fileName); return false; } } ++i; } } if (i != argc) { JS_ReportError(cx, "bad arguments passed to dumpHeapComplete"); return false; } js::DumpHeapComplete(JS_GetRuntime(cx), dumpFile ? dumpFile : stdout, nurseryBehaviour); if (dumpFile) fclose(dumpFile); JS_SET_RVAL(cx, vp, JSVAL_VOID); return true; }
bool ModuleBuilder::appendLocalExportEntry(HandleExportEntryObject exp) { if (!module_->initialEnvironment().lookup(cx_, AtomToId(exp->localName()))) { JSAutoByteString str; str.encodeLatin1(cx_, exp->localName()); JS_ReportErrorNumber(cx_, GetErrorMessage, nullptr, JSMSG_MISSING_EXPORT, str.ptr()); return false; } return localExportEntries_.append(exp); }
static bool ThrowCallFailed(JSContext *cx, nsresult rv, const char *ifaceName, HandleId memberId, const char *memberName) { /* Only one of memberId or memberName should be given. */ MOZ_ASSERT(JSID_IS_VOID(memberId) != !memberName); // From XPCThrower::ThrowBadResult. char* sz; const char* format; const char* name; /* * If there is a pending exception when the native call returns and * it has the same error result as returned by the native call, then * the native call may be passing through an error from a previous JS * call. So we'll just throw that exception into our JS. */ if (XPCThrower::CheckForPendingException(rv, cx)) return false; // else... if (!nsXPCException::NameAndFormatForNSResult(NS_ERROR_XPC_NATIVE_RETURNED_FAILURE, nullptr, &format) || !format) { format = ""; } JSAutoByteString memberNameBytes; if (!memberName) { memberName = JSID_IS_STRING(memberId) ? memberNameBytes.encodeLatin1(cx, JSID_TO_STRING(memberId)) : "unknown"; } if (nsXPCException::NameAndFormatForNSResult(rv, &name, nullptr) && name) { sz = JS_smprintf("%s 0x%x (%s) [%s.%s]", format, rv, name, ifaceName, memberName); } else { sz = JS_smprintf("%s 0x%x [%s.%s]", format, rv, ifaceName, memberName); } XPCThrower::BuildAndThrowException(cx, rv, sz); if (sz) JS_smprintf_free(sz); return false; }
static bool ThrowCallFailed(JSContext *cx, nsresult rv, const char *ifaceName, HandleId memberId, const char *memberName) { /* Only one of memberId or memberName should be given. */ MOZ_ASSERT(JSID_IS_VOID(memberId) != !memberName); // From XPCThrower::ThrowBadResult. char* sz; const char* format; const char* name; // If the cx already has a pending exception, just throw that. // // We used to check here to make sure the exception matched rv (whatever // that means). But this meant that we'd be calling into JSAPI below with // a pending exception, which isn't really kosher. The first exception thrown // should generally take precedence anyway. if (JS_IsExceptionPending(cx)) return false; // else... if (!nsXPCException::NameAndFormatForNSResult(NS_ERROR_XPC_NATIVE_RETURNED_FAILURE, nullptr, &format) || !format) { format = ""; } JSAutoByteString memberNameBytes; if (!memberName) { memberName = JSID_IS_STRING(memberId) ? memberNameBytes.encodeLatin1(cx, JSID_TO_STRING(memberId)) : "unknown"; } if (nsXPCException::NameAndFormatForNSResult(rv, &name, nullptr) && name) { sz = JS_smprintf("%s 0x%x (%s) [%s.%s]", format, rv, name, ifaceName, memberName); } else { sz = JS_smprintf("%s 0x%x [%s.%s]", format, rv, ifaceName, memberName); } dom::Throw(cx, rv, sz); if (sz) JS_smprintf_free(sz); return false; }
static JSBool perlsub_construct( JSContext *cx, DEFJSFSARGS_ ) { dTHX; DECJSFSARGS; JSObject *func = JSVAL_TO_OBJECT(JS_ARGV_CALLEE(argv)); SV *callee = (SV *)JS_GetPrivate(cx, func); SV *caller = NULL; #if JS_VERSION < 185 JSObject *This = JSVAL_TO_OBJECT(argv[-1]); #else JSObject *This = JS_NewObjectForConstructor(cx, vp); #endif JSObject *proto = JS_GetPrototype(cx, This); PJS_DEBUG1("Want construct, This is a %s", PJS_GET_CLASS(cx, This)->name); if(PJS_GET_CLASS(cx, proto) == &perlpackage_class || ( JS_LookupProperty(cx, func, "prototype", &argv[-1]) && JSVAL_IS_OBJECT(argv[-1]) && !JSVAL_IS_NULL(argv[-1]) && (proto = JS_GetPrototype(cx, JSVAL_TO_OBJECT(argv[-1]))) && strEQ(PJS_GET_CLASS(cx, proto)->name, PJS_PACKAGE_CLASS_NAME)) ) { SV *rsv = NULL; char *pkgname = PJS_GetPackageName(aTHX_ cx, proto); #if JS_VERSION >= 185 JSAutoByteString bytes; bytes.initBytes(pkgname); #endif caller = newSVpv(pkgname, 0); argv[-1] = OBJECT_TO_JSVAL(This); if(!PJS_Call_sv_with_jsvals_rsv(aTHX_ cx, obj, callee, caller, argc, argv, &rsv, G_SCALAR)) return JS_FALSE; if(SvROK(rsv) && sv_derived_from(rsv, pkgname)) { JSObject *newobj = PJS_NewPerlObject(aTHX_ cx, JS_GetParent(cx, func), rsv); *rval = OBJECT_TO_JSVAL(newobj); return JS_TRUE; } JS_ReportError(cx, "%s's constructor don't return an object", SvPV_nolen(caller)); } else JS_ReportError(cx, "Can't use as a constructor"); // Yet! ;-) return JS_FALSE; }
JSBool xpc_DumpEvalInJSStackFrame(JSContext* cx, JSUint32 frameno, const char* text) { JSStackFrame* fp; JSStackFrame* iter = nsnull; JSUint32 num = 0; if(!cx || !text) { puts("invalid params passed to xpc_DumpEvalInJSStackFrame!"); return JS_FALSE; } printf("js[%d]> %s\n", frameno, text); while(nsnull != (fp = JS_FrameIterator(cx, &iter))) { if(num == frameno) break; num++; } if(!fp) { puts("invalid frame number!"); return JS_FALSE; } JSAutoRequest ar(cx); JSExceptionState* exceptionState = JS_SaveExceptionState(cx); JSErrorReporter older = JS_SetErrorReporter(cx, xpcDumpEvalErrorReporter); jsval rval; JSString* str; JSAutoByteString bytes; if(JS_EvaluateInStackFrame(cx, fp, text, strlen(text), "eval", 1, &rval) && nsnull != (str = JS_ValueToString(cx, rval)) && bytes.encode(cx, str)) { printf("%s\n", bytes.ptr()); } else puts("eval failed!"); JS_SetErrorReporter(cx, older); JS_RestoreExceptionState(cx, exceptionState); return JS_TRUE; }
JSBool xpc_DumpEvalInJSStackFrame(JSContext* cx, uint32_t frameno, const char* text) { if (!cx || !text) { DebugDump("%s", "invalid params passed to xpc_DumpEvalInJSStackFrame!\n"); return false; } DebugDump("js[%d]> %s\n", frameno, text); uint32_t num = 0; JSAbstractFramePtr frame = JSNullFramePtr(); JSBrokenFrameIterator iter(cx); while (!iter.done()) { if (num == frameno) { frame = iter.abstractFramePtr(); break; } ++iter; num++; } if (!frame) { DebugDump("%s", "invalid frame number!\n"); return false; } JSAutoRequest ar(cx); JSExceptionState* exceptionState = JS_SaveExceptionState(cx); JSErrorReporter older = JS_SetErrorReporter(cx, xpcDumpEvalErrorReporter); jsval rval; JSString* str; JSAutoByteString bytes; if (frame.evaluateInStackFrame(cx, text, strlen(text), "eval", 1, &rval) && nullptr != (str = JS_ValueToString(cx, rval)) && bytes.encode(cx, str)) { DebugDump("%s\n", bytes.ptr()); } else DebugDump("%s", "eval failed!\n"); JS_SetErrorReporter(cx, older); JS_RestoreExceptionState(cx, exceptionState); return true; }
/* |callee| requires a usage string provided by JS_DefineFunctionsWithHelp. */ void js::ReportUsageErrorASCII(JSContext* cx, HandleObject callee, const char* msg) { RootedValue usage(cx); if (!JS_GetProperty(cx, callee, "usage", &usage)) return; if (!usage.isString()) { JS_ReportErrorASCII(cx, "%s", msg); } else { RootedString usageStr(cx, usage.toString()); JSAutoByteString str; if (!str.encodeUtf8(cx, usageStr)) return; JS_ReportErrorUTF8(cx, "%s. Usage: %s", msg, str.ptr()); } }
// static void XPCThrower::Verbosify(XPCCallContext& ccx, char** psz, PRBool own) { char* sz = nsnull; if(ccx.HasInterfaceAndMember()) { XPCNativeInterface* iface = ccx.GetInterface(); jsid id = JSID_VOID; #ifdef XPC_IDISPATCH_SUPPORT NS_ASSERTION(ccx.GetIDispatchMember() == nsnull || ccx.GetMember() == nsnull, "Both IDispatch member and regular XPCOM member " "were set in XPCCallContext"); if(ccx.GetIDispatchMember()) { XPCDispInterface::Member * member = reinterpret_cast<XPCDispInterface::Member*>(ccx.GetIDispatchMember()); if(member && JSID_IS_STRING(member->GetName())) { id = member->GetName(); } } else #endif { id = ccx.GetMember()->GetName(); } JSAutoByteString bytes; const char *name = JSID_IS_VOID(id) ? "Unknown" : bytes.encode(ccx, JSID_TO_STRING(id)); if(!name) { name = ""; } sz = JS_smprintf("%s [%s.%s]", *psz, iface->GetNameString(), name); } if(sz) { if(own) JS_smprintf_free(*psz); *psz = sz; } }
JSErrorReport* js::ErrorObject::getOrCreateErrorReport(JSContext* cx) { if (JSErrorReport* r = getErrorReport()) return r; // We build an error report on the stack and then use CopyErrorReport to do // the nitty-gritty malloc stuff. JSErrorReport report; // Type. JSExnType type_ = type(); report.exnType = type_; // Filename. JSAutoByteString filenameStr; if (!filenameStr.encodeLatin1(cx, fileName(cx))) return nullptr; report.filename = filenameStr.ptr(); // Coordinates. report.lineno = lineNumber(); report.column = columnNumber(); // Message. Note that |new Error()| will result in an undefined |message| // slot, so we need to explicitly substitute the empty string in that case. RootedString message(cx, getMessage()); if (!message) message = cx->runtime()->emptyString; if (!message->ensureFlat(cx)) return nullptr; UniquePtr<char[], JS::FreePolicy> utf8 = StringToNewUTF8CharsZ(cx, *message); if (!utf8) return nullptr; report.initOwnedMessage(utf8.release()); // Cache and return. JSErrorReport* copy = CopyErrorReport(cx, &report); if (!copy) return nullptr; setReservedSlot(ERROR_REPORT_SLOT, PrivateValue(copy)); return copy; }
// {{{ Conversions bool JSGlobal::JS_btoa(JSContext *cx, JS::CallArgs &args) { if (args[0].isString()) { JSAutoByteString cdata; JS::RootedString str(cx, args[0].toString()); cdata.encodeUtf8(cx, str); char *ret = Utils::B64Encode( reinterpret_cast<unsigned char *>(cdata.ptr()), cdata.length()); args.rval().setString(JS_NewStringCopyZ(cx, ret)); free(ret); } else { args.rval().setNull(); JS_ReportWarning(cx, "btoa() non-string given"); } return true; }
static bool DefaultCalendar(JSContext* cx, const JSAutoByteString& locale, MutableHandleValue rval) { UErrorCode status = U_ZERO_ERROR; UCalendar* cal = ucal_open(nullptr, 0, locale.ptr(), UCAL_DEFAULT, &status); // This correctly handles nullptr |cal| when opening failed. ScopedICUObject<UCalendar, ucal_close> closeCalendar(cal); const char* calendar = ucal_getType(cal, &status); if (U_FAILURE(status)) { intl::ReportInternalError(cx); return false; } // ICU returns old-style keyword values; map them to BCP 47 equivalents JSString* str = JS_NewStringCopyZ(cx, uloc_toUnicodeLocaleType("ca", calendar)); if (!str) return false; rval.setString(str); return true; }
// // Native method Install // static JSBool InstallTriggerGlobalInstall(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { nsIDOMInstallTriggerGlobal *nativeThis = getTriggerNative(cx, obj); if (!nativeThis) return JS_FALSE; *rval = JSVAL_FALSE; // make sure XPInstall is enabled, return false if not nsIScriptGlobalObject *globalObject = nsnull; nsIScriptContext *scriptContext = GetScriptContextFromJSContext(cx); if (scriptContext) globalObject = scriptContext->GetGlobalObject(); if (!globalObject) return JS_TRUE; nsCOMPtr<nsIScriptSecurityManager> secman(do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID)); if (!secman) { JS_ReportError(cx, "Could not the script security manager service."); return JS_FALSE; } // get the principal. if it doesn't exist, die. nsCOMPtr<nsIPrincipal> principal; secman->GetSubjectPrincipal(getter_AddRefs(principal)); if (!principal) { JS_ReportError(cx, "Could not get the Subject Principal during InstallTrigger.Install()"); return JS_FALSE; } // get window.location to construct relative URLs nsCOMPtr<nsIURI> baseURL; JSObject* global = JS_GetGlobalObject(cx); if (global) { jsval v; if (JS_GetProperty(cx,global,"location",&v)) { nsAutoString location; ConvertJSValToStr( location, cx, v ); NS_NewURI(getter_AddRefs(baseURL), location); } } PRBool abortLoad = PR_FALSE; // parse associative array of installs if ( argc >= 1 && JSVAL_IS_OBJECT(argv[0]) && JSVAL_TO_OBJECT(argv[0]) ) { nsXPITriggerInfo *trigger = new nsXPITriggerInfo(); if (!trigger) return JS_FALSE; trigger->SetPrincipal(principal); JSIdArray *ida = JS_Enumerate( cx, JSVAL_TO_OBJECT(argv[0]) ); if ( ida ) { jsval v; const PRUnichar *name, *URL; const PRUnichar *iconURL = nsnull; for (int i = 0; i < ida->length && !abortLoad; i++ ) { JS_IdToValue( cx, ida->vector[i], &v ); JSString * str = JS_ValueToString( cx, v ); if (!str) { abortLoad = PR_TRUE; break; } name = reinterpret_cast<const PRUnichar*>(JS_GetStringChars( str )); URL = iconURL = nsnull; JSAutoByteString hash; JS_GetUCProperty( cx, JSVAL_TO_OBJECT(argv[0]), reinterpret_cast<const jschar*>(name), nsCRT::strlen(name), &v ); if ( JSVAL_IS_OBJECT(v) && JSVAL_TO_OBJECT(v) ) { jsval v2; if (JS_GetProperty( cx, JSVAL_TO_OBJECT(v), "URL", &v2 ) && !JSVAL_IS_VOID(v2)) { JSString *str = JS_ValueToString(cx, v2); if (!str) { abortLoad = PR_TRUE; break; } URL = reinterpret_cast<const PRUnichar*>(JS_GetStringChars(str)); } if (JS_GetProperty( cx, JSVAL_TO_OBJECT(v), "IconURL", &v2 ) && !JSVAL_IS_VOID(v2)) { JSString *str = JS_ValueToString(cx, v2); if (!str) { abortLoad = PR_TRUE; break; } iconURL = reinterpret_cast<const PRUnichar*>(JS_GetStringChars(str)); } if (JS_GetProperty( cx, JSVAL_TO_OBJECT(v), "Hash", &v2) && !JSVAL_IS_VOID(v2)) { JSString *str = JS_ValueToString(cx, v2); if (!str || !hash.encode(cx, str)) { abortLoad = PR_TRUE; break; } } } else { JSString *str = JS_ValueToString(cx, v); if (!str) { abortLoad = PR_TRUE; break; } URL = reinterpret_cast<const PRUnichar*>(JS_GetStringChars(str)); } if ( URL ) { // Get relative URL to load nsAutoString xpiURL(URL); if (baseURL) { nsCAutoString resolvedURL; baseURL->Resolve(NS_ConvertUTF16toUTF8(xpiURL), resolvedURL); xpiURL = NS_ConvertUTF8toUTF16(resolvedURL); } nsAutoString icon(iconURL); if (iconURL && baseURL) { nsCAutoString resolvedIcon; baseURL->Resolve(NS_ConvertUTF16toUTF8(icon), resolvedIcon); icon = NS_ConvertUTF8toUTF16(resolvedIcon); } // Make sure we're allowed to load this URL and the icon URL nsresult rv = InstallTriggerCheckLoadURIFromScript(cx, xpiURL); if (NS_FAILED(rv)) abortLoad = PR_TRUE; if (!abortLoad && iconURL) { rv = InstallTriggerCheckLoadURIFromScript(cx, icon); if (NS_FAILED(rv)) abortLoad = PR_TRUE; } if (!abortLoad) { // Add the install item to the trigger collection nsXPITriggerItem *item = new nsXPITriggerItem( name, xpiURL.get(), icon.get(), hash ); if ( item ) { trigger->Add( item ); } else abortLoad = PR_TRUE; } } else abortLoad = PR_TRUE; } JS_DestroyIdArray( cx, ida ); } // pass on only if good stuff found if (!abortLoad && trigger->Size() > 0) { nsCOMPtr<nsIURI> checkuri; nsresult rv = nativeThis->GetOriginatingURI(globalObject, getter_AddRefs(checkuri)); if (NS_SUCCEEDED(rv)) { nsCOMPtr<nsIDOMWindowInternal> win(do_QueryInterface(globalObject)); nsCOMPtr<nsIXPIInstallInfo> installInfo = new nsXPIInstallInfo(win, checkuri, trigger, 0); if (installInfo) { // installInfo now owns triggers PRBool enabled = PR_FALSE; nativeThis->UpdateEnabled(checkuri, XPI_WHITELIST, &enabled); if (!enabled) { nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService(); if (os) os->NotifyObservers(installInfo, "xpinstall-install-blocked", nsnull); } else { // save callback function if any (ignore bad args for now) if ( argc >= 2 && JS_TypeOfValue(cx,argv[1]) == JSTYPE_FUNCTION ) { trigger->SaveCallback( cx, argv[1] ); } PRBool result; nativeThis->StartInstall(installInfo, &result); *rval = BOOLEAN_TO_JSVAL(result); } return JS_TRUE; } } } // didn't pass it on so we must delete trigger delete trigger; } JS_ReportError(cx, "Incorrect arguments to InstallTrigger.Install()"); return JS_FALSE; }
void XPCShellEnvironment::ProcessFile(JSContext *cx, JS::Handle<JSObject*> obj, const char *filename, FILE *file, bool forceTTY) { XPCShellEnvironment* env = this; JS::Rooted<JS::Value> result(cx); int lineno, startline; bool ok, hitEOF; char *bufp, buffer[4096]; JSString *str; if (forceTTY) { file = stdin; } else if (!isatty(fileno(file))) { /* * It's not interactive - just execute it. * * Support the UNIX #! shell hack; gobble the first line if it starts * with '#'. TODO - this isn't quite compatible with sharp variables, * as a legal js program (using sharp variables) might start with '#'. * But that would require multi-character lookahead. */ int ch = fgetc(file); if (ch == '#') { while((ch = fgetc(file)) != EOF) { if(ch == '\n' || ch == '\r') break; } } ungetc(ch, file); JSAutoRequest ar(cx); JSAutoCompartment ac(cx, obj); JS::CompileOptions options(cx); options.setUTF8(true) .setFileAndLine(filename, 1); JS::Rooted<JSScript*> script(cx, JS::Compile(cx, obj, options, file)); if (script) (void)JS_ExecuteScript(cx, obj, script, result.address()); return; } /* It's an interactive filehandle; drop into read-eval-print loop. */ lineno = 1; hitEOF = false; do { bufp = buffer; *bufp = '\0'; JSAutoRequest ar(cx); JSAutoCompartment ac(cx, obj); /* * Accumulate lines until we get a 'compilable unit' - one that either * generates an error (before running out of source) or that compiles * cleanly. This should be whenever we get a complete statement that * coincides with the end of a line. */ startline = lineno; do { if (!GetLine(bufp, file, startline == lineno ? "js> " : "")) { hitEOF = true; break; } bufp += strlen(bufp); lineno++; } while (!JS_BufferIsCompilableUnit(cx, obj, buffer, strlen(buffer))); /* Clear any pending exception from previous failed compiles. */ JS_ClearPendingException(cx); JS::CompileOptions options(cx); options.setFileAndLine("typein", startline); JS::Rooted<JSScript*> script(cx, JS_CompileScript(cx, obj, buffer, strlen(buffer), options)); if (script) { JSErrorReporter older; ok = JS_ExecuteScript(cx, obj, script, result.address()); if (ok && result != JSVAL_VOID) { /* Suppress error reports from JS::ToString(). */ older = JS_SetErrorReporter(cx, nullptr); str = JS::ToString(cx, result); JSAutoByteString bytes; if (str) bytes.encodeLatin1(cx, str); JS_SetErrorReporter(cx, older); if (!!bytes) fprintf(stdout, "%s\n", bytes.ptr()); else ok = false; } } } while (!hitEOF && !env->IsQuitting()); fprintf(stdout, "\n"); }
nsresult RilConsumer::Send(JSContext* aCx, const CallArgs& aArgs) { if (NS_WARN_IF(!mSocket) || NS_WARN_IF(mSocket->GetConnectionStatus() == SOCKET_DISCONNECTED)) { // Probably shutting down. return NS_OK; } UniquePtr<UnixSocketRawData> raw; Value v = aArgs[1]; if (v.isString()) { JSAutoByteString abs; Rooted<JSString*> str(aCx, v.toString()); if (!abs.encodeUtf8(aCx, str)) { return NS_ERROR_FAILURE; } raw = MakeUnique<UnixSocketRawData>(abs.ptr(), abs.length()); } else if (!v.isPrimitive()) { JSObject* obj = v.toObjectOrNull(); if (!JS_IsTypedArrayObject(obj)) { JS_ReportError(aCx, "Object passed in wasn't a typed array"); return NS_ERROR_FAILURE; } uint32_t type = JS_GetArrayBufferViewType(obj); if (type != js::Scalar::Int8 && type != js::Scalar::Uint8 && type != js::Scalar::Uint8Clamped) { JS_ReportError(aCx, "Typed array data is not octets"); return NS_ERROR_FAILURE; } size_t size = JS_GetTypedArrayByteLength(obj); bool isShared; void* data; { AutoCheckCannotGC nogc; data = JS_GetArrayBufferViewData(obj, &isShared, nogc); } if (isShared) { JS_ReportError( aCx, "Incorrect argument. Shared memory not supported"); return NS_ERROR_FAILURE; } raw = MakeUnique<UnixSocketRawData>(data, size); } else { JS_ReportError( aCx, "Incorrect argument. Expecting a string or a typed array"); return NS_ERROR_FAILURE; } if (!raw) { JS_ReportError(aCx, "Unable to post to RIL"); return NS_ERROR_FAILURE; } mSocket->SendSocketData(raw.release()); return NS_OK; }
static char * FormatFrame(JSContext *cx, const NonBuiltinScriptFrameIter &iter, char *buf, int num, bool showArgs, bool showLocals, bool showThisProps) { JS_ASSERT(!cx->isExceptionPending()); RootedScript script(cx, iter.script()); jsbytecode* pc = iter.pc(); RootedObject scopeChain(cx, iter.scopeChain()); JSAutoCompartment ac(cx, scopeChain); const char *filename = script->filename(); unsigned lineno = PCToLineNumber(script, pc); RootedFunction fun(cx, iter.maybeCallee()); RootedString funname(cx); if (fun) funname = fun->atom(); RootedValue thisVal(cx); AutoPropertyDescArray thisProps(cx); if (iter.computeThis(cx)) { thisVal = iter.thisv(); if (showThisProps && !thisVal.isPrimitive()) { RootedObject thisObj(cx, &thisVal.toObject()); thisProps.fetch(thisObj); } } // print the frame number and function name if (funname) { JSAutoByteString funbytes; buf = JS_sprintf_append(buf, "%d %s(", num, funbytes.encodeLatin1(cx, funname)); } else if (fun) { buf = JS_sprintf_append(buf, "%d anonymous(", num); } else { buf = JS_sprintf_append(buf, "%d <TOP LEVEL>", num); } if (!buf) return buf; if (showArgs && iter.hasArgs()) { BindingVector bindings(cx); if (fun && fun->isInterpreted()) { if (!FillBindingVector(script, &bindings)) return buf; } bool first = true; for (unsigned i = 0; i < iter.numActualArgs(); i++) { RootedValue arg(cx); if (i < iter.numFormalArgs() && script->formalIsAliased(i)) { for (AliasedFormalIter fi(script); ; fi++) { if (fi.frameIndex() == i) { arg = iter.callObj().aliasedVar(fi); break; } } } else if (script->argsObjAliasesFormals() && iter.hasArgsObj()) { arg = iter.argsObj().arg(i); } else { arg = iter.unaliasedActual(i, DONT_CHECK_ALIASING); } JSAutoByteString valueBytes; const char *value = FormatValue(cx, arg, valueBytes); JSAutoByteString nameBytes; const char *name = nullptr; if (i < bindings.length()) { name = nameBytes.encodeLatin1(cx, bindings[i].name()); if (!buf) return nullptr; } if (value) { buf = JS_sprintf_append(buf, "%s%s%s%s%s%s", !first ? ", " : "", name ? name :"", name ? " = " : "", arg.isString() ? "\"" : "", value ? value : "?unknown?", arg.isString() ? "\"" : ""); if (!buf) return buf; first = false; } else { buf = JS_sprintf_append(buf, " <Failed to get argument while inspecting stack frame>\n"); if (!buf) return buf; cx->clearPendingException(); } } } // print filename and line number buf = JS_sprintf_append(buf, "%s [\"%s\":%d]\n", fun ? ")" : "", filename ? filename : "<unknown>", lineno); if (!buf) return buf; // Note: Right now we don't dump the local variables anymore, because // that is hard to support across all the JITs etc. // print the value of 'this' if (showLocals) { if (!thisVal.isUndefined()) { JSAutoByteString thisValBytes; RootedString thisValStr(cx, ToString<CanGC>(cx, thisVal)); const char *str = nullptr; if (thisValStr && (str = thisValBytes.encodeLatin1(cx, thisValStr))) { buf = JS_sprintf_append(buf, " this = %s\n", str); if (!buf) return buf; } else { buf = JS_sprintf_append(buf, " <failed to get 'this' value>\n"); cx->clearPendingException(); } } } // print the properties of 'this', if it is an object if (showThisProps && thisProps->array) { for (uint32_t i = 0; i < thisProps->length; i++) { JSPropertyDesc* desc = &thisProps->array[i]; if (desc->flags & JSPD_ENUMERATE) { JSAutoByteString nameBytes; JSAutoByteString valueBytes; const char *name = FormatValue(cx, desc->id, nameBytes); const char *value = FormatValue(cx, desc->value, valueBytes); if (name && value) { buf = JS_sprintf_append(buf, " this.%s = %s%s%s\n", name, desc->value.isString() ? "\"" : "", value, desc->value.isString() ? "\"" : ""); if (!buf) return buf; } else { buf = JS_sprintf_append(buf, " <Failed to format values while inspecting stack frame>\n"); cx->clearPendingException(); } } } } JS_ASSERT(!cx->isExceptionPending()); return buf; }
static char * FormatFrame(JSContext *cx, const ScriptFrameIter &iter, char *buf, int num, JSBool showArgs, JSBool showLocals, JSBool showThisProps) { AssertCanGC(); RootedScript script(cx, iter.script()); jsbytecode* pc = iter.pc(); RootedObject scopeChain(cx, iter.scopeChain()); JSAutoCompartment ac(cx, scopeChain); const char *filename = script->filename; unsigned lineno = PCToLineNumber(script, pc); RootedFunction fun(cx, iter.maybeCallee()); RootedString funname(cx); if (fun) funname = fun->atom(); RootedObject callObj(cx); AutoPropertyDescArray callProps(cx); if (!iter.isIon() && (showArgs || showLocals)) { callObj = JS_GetFrameCallObject(cx, Jsvalify(iter.interpFrame())); if (callObj) callProps.fetch(callObj); } RootedValue thisVal(cx); AutoPropertyDescArray thisProps(cx); if (iter.computeThis()) { thisVal = iter.thisv(); if (showThisProps && !thisVal.isPrimitive()) thisProps.fetch(&thisVal.toObject()); } // print the frame number and function name if (funname) { JSAutoByteString funbytes; buf = JS_sprintf_append(buf, "%d %s(", num, funbytes.encode(cx, funname)); } else if (fun) { buf = JS_sprintf_append(buf, "%d anonymous(", num); } else { buf = JS_sprintf_append(buf, "%d <TOP LEVEL>", num); } if (!buf) return buf; // print the function arguments if (showArgs && callObj) { uint32_t namedArgCount = 0; for (uint32_t i = 0; i < callProps->length; i++) { JSPropertyDesc* desc = &callProps->array[i]; JSAutoByteString nameBytes; const char *name = NULL; if (JSVAL_IS_STRING(desc->id)) name = FormatValue(cx, desc->id, nameBytes); JSAutoByteString valueBytes; const char *value = FormatValue(cx, desc->value, valueBytes); buf = JS_sprintf_append(buf, "%s%s%s%s%s%s", namedArgCount ? ", " : "", name ? name :"", name ? " = " : "", desc->value.isString() ? "\"" : "", value ? value : "?unknown?", desc->value.isString() ? "\"" : ""); if (!buf) return buf; namedArgCount++; } // print any unnamed trailing args (found in 'arguments' object) RootedValue val(cx); if (JS_GetProperty(cx, callObj, "arguments", val.address()) && val.isObject()) { uint32_t argCount; RootedObject argsObj(cx, &val.toObject()); if (JS_GetProperty(cx, argsObj, "length", val.address()) && ToUint32(cx, val, &argCount) && argCount > namedArgCount) { for (uint32_t k = namedArgCount; k < argCount; k++) { char number[8]; JS_snprintf(number, 8, "%d", (int) k); if (JS_GetProperty(cx, argsObj, number, val.address())) { JSAutoByteString valueBytes; const char *value = FormatValue(cx, val, valueBytes); buf = JS_sprintf_append(buf, "%s%s%s%s", k ? ", " : "", val.isString() ? "\"" : "", value ? value : "?unknown?", val.isString() ? "\"" : ""); if (!buf) return buf; } } } } } // print filename and line number buf = JS_sprintf_append(buf, "%s [\"%s\":%d]\n", fun ? ")" : "", filename ? filename : "<unknown>", lineno); if (!buf) return buf; // print local variables if (showLocals && callProps->array) { for (uint32_t i = 0; i < callProps->length; i++) { JSPropertyDesc* desc = &callProps->array[i]; JSAutoByteString nameBytes; JSAutoByteString valueBytes; const char *name = FormatValue(cx, desc->id, nameBytes); const char *value = FormatValue(cx, desc->value, valueBytes); if (name && value) { buf = JS_sprintf_append(buf, " %s = %s%s%s\n", name, desc->value.isString() ? "\"" : "", value, desc->value.isString() ? "\"" : ""); if (!buf) return buf; } } } // print the value of 'this' if (showLocals) { if (!thisVal.isUndefined()) { JSAutoByteString thisValBytes; RootedString thisValStr(cx, ToString(cx, thisVal)); if (thisValStr) { if (const char *str = thisValBytes.encode(cx, thisValStr)) { buf = JS_sprintf_append(buf, " this = %s\n", str); if (!buf) return buf; } } } else { buf = JS_sprintf_append(buf, " <failed to get 'this' value>\n"); } } // print the properties of 'this', if it is an object if (showThisProps && thisProps->array) { for (uint32_t i = 0; i < thisProps->length; i++) { JSPropertyDesc* desc = &thisProps->array[i]; if (desc->flags & JSPD_ENUMERATE) { JSAutoByteString nameBytes; JSAutoByteString valueBytes; const char *name = FormatValue(cx, desc->id, nameBytes); const char *value = FormatValue(cx, desc->value, valueBytes); if (name && value) { buf = JS_sprintf_append(buf, " this.%s = %s%s%s\n", name, desc->value.isString() ? "\"" : "", value, desc->value.isString() ? "\"" : ""); if (!buf) return buf; } } } } return buf; }
void JS_FASTCALL stubs::DefFun(VMFrame &f, JSFunction *fun_) { /* * A top-level function defined in Global or Eval code (see ECMA-262 * Ed. 3), or else a SpiderMonkey extension: a named function statement in * a compound statement (not at the top statement level of global code, or * at the top level of a function body). */ JSContext *cx = f.cx; StackFrame *fp = f.fp(); RootedFunction fun(f.cx, fun_); /* * If static link is not current scope, clone fun's object to link to the * current scope via parent. We do this to enable sharing of compiled * functions among multiple equivalent scopes, amortizing the cost of * compilation over a number of executions. Examples include XUL scripts * and event handlers shared among Firefox or other Mozilla app chrome * windows, and user-defined JS functions precompiled and then shared among * requests in server-side JS. */ HandleObject scopeChain = f.fp()->scopeChain(); if (fun->environment() != scopeChain) { fun = CloneFunctionObjectIfNotSingleton(cx, fun, scopeChain); if (!fun) THROW(); } else { JS_ASSERT(f.script()->compileAndGo); JS_ASSERT(f.fp()->isGlobalFrame() || f.fp()->isEvalInFunction()); } /* * ECMA requires functions defined when entering Eval code to be * impermanent. */ unsigned attrs = fp->isEvalFrame() ? JSPROP_ENUMERATE : JSPROP_ENUMERATE | JSPROP_PERMANENT; /* * We define the function as a property of the variable object and not the * current scope chain even for the case of function expression statements * and functions defined by eval inside let or with blocks. */ JSObject *parent = &fp->varObj(); /* ES5 10.5 (NB: with subsequent errata). */ PropertyName *name = fun->atom->asPropertyName(); JSProperty *prop = NULL; JSObject *pobj; if (!parent->lookupProperty(cx, name, &pobj, &prop)) THROW(); Value rval = ObjectValue(*fun); do { /* Steps 5d, 5f. */ if (!prop || pobj != parent) { if (!parent->defineProperty(cx, name, rval, JS_PropertyStub, JS_StrictPropertyStub, attrs)) { THROW(); } break; } /* Step 5e. */ JS_ASSERT(parent->isNative()); Shape *shape = reinterpret_cast<Shape *>(prop); if (parent->isGlobal()) { if (shape->configurable()) { if (!parent->defineProperty(cx, name, rval, JS_PropertyStub, JS_StrictPropertyStub, attrs)) { THROW(); } break; } if (shape->isAccessorDescriptor() || !shape->writable() || !shape->enumerable()) { JSAutoByteString bytes; if (js_AtomToPrintableString(cx, name, &bytes)) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_REDEFINE_PROP, bytes.ptr()); } THROW(); } } /* * Non-global properties, and global properties which we aren't simply * redefining, must be set. First, this preserves their attributes. * Second, this will produce warnings and/or errors as necessary if the * specified Call object property is not writable (const). */ /* Step 5f. */ if (!parent->setProperty(cx, name, &rval, strict)) THROW(); } while (false); }
JSBool js_ReportUncaughtException(JSContext *cx) { jsval exn; JSObject *exnObject; jsval roots[5]; JSErrorReport *reportp, report; JSString *str; const char *bytes; if (!JS_IsExceptionPending(cx)) return true; if (!JS_GetPendingException(cx, &exn)) return false; PodArrayZero(roots); AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(roots), Valueify(roots)); /* * 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, Valueify(exn)); JSAutoByteString bytesStorage; if (!str) { bytes = "unknown (can't convert to string)"; } else { roots[1] = STRING_TO_JSVAL(str); if (!bytesStorage.encode(cx, str)) return false; bytes = bytesStorage.ptr(); } JSAutoByteString filename; if (!reportp && exnObject && exnObject->getClass() == &js_ErrorClass) { if (!JS_GetProperty(cx, exnObject, js_message_str, &roots[2])) return false; if (JSVAL_IS_STRING(roots[2])) { bytesStorage.clear(); if (!bytesStorage.encode(cx, str)) return false; bytes = bytesStorage.ptr(); } if (!JS_GetProperty(cx, exnObject, js_fileName_str, &roots[3])) return false; str = js_ValueToString(cx, Valueify(roots[3])); if (!str || !filename.encode(cx, str)) return false; if (!JS_GetProperty(cx, exnObject, js_lineNumber_str, &roots[4])) return false; uint32_t lineno; if (!ValueToECMAUint32(cx, Valueify(roots[4]), &lineno)) return false; reportp = &report; PodZero(&report); report.filename = filename.ptr(); report.lineno = (uintN) lineno; if (JSVAL_IS_STRING(roots[2])) { JSFixedString *fixed = JSVAL_TO_STRING(roots[2])->ensureFixed(cx); if (!fixed) return false; report.ucmessage = fixed->chars(); } } 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); } return true; }
static JS::UniqueChars FormatFrame(JSContext* cx, const FrameIter& iter, JS::UniqueChars&& inBuf, int num, bool showArgs, bool showLocals, bool showThisProps) { MOZ_ASSERT(!cx->isExceptionPending()); RootedScript script(cx, iter.script()); jsbytecode* pc = iter.pc(); RootedObject envChain(cx, iter.environmentChain(cx)); JSAutoCompartment ac(cx, envChain); const char* filename = script->filename(); unsigned lineno = PCToLineNumber(script, pc); RootedFunction fun(cx, iter.maybeCallee(cx)); RootedString funname(cx); if (fun) funname = fun->displayAtom(); RootedValue thisVal(cx); if (iter.hasUsableAbstractFramePtr() && iter.isFunctionFrame() && fun && !fun->isArrow() && !fun->isDerivedClassConstructor() && !(fun->isBoundFunction() && iter.isConstructing())) { if (!GetFunctionThis(cx, iter.abstractFramePtr(), &thisVal)) return nullptr; } // print the frame number and function name JS::UniqueChars buf(Move(inBuf)); if (funname) { JSAutoByteString funbytes; char* str = funbytes.encodeLatin1(cx, funname); if (!str) return nullptr; buf = sprintf_append(cx, Move(buf), "%d %s(", num, str); } else if (fun) { buf = sprintf_append(cx, Move(buf), "%d anonymous(", num); } else { buf = sprintf_append(cx, Move(buf), "%d <TOP LEVEL>", num); } if (!buf) return nullptr; if (showArgs && iter.hasArgs()) { PositionalFormalParameterIter fi(script); bool first = true; for (unsigned i = 0; i < iter.numActualArgs(); i++) { RootedValue arg(cx); if (i < iter.numFormalArgs() && fi.closedOver()) { arg = iter.callObj(cx).aliasedBinding(fi); } else if (iter.hasUsableAbstractFramePtr()) { if (script->analyzedArgsUsage() && script->argsObjAliasesFormals() && iter.hasArgsObj()) { arg = iter.argsObj().arg(i); } else { arg = iter.unaliasedActual(i, DONT_CHECK_ALIASING); } } else { arg = MagicValue(JS_OPTIMIZED_OUT); } JSAutoByteString valueBytes; const char* value = FormatValue(cx, arg, valueBytes); if (!value) { if (cx->isThrowingOutOfMemory()) return nullptr; cx->clearPendingException(); } JSAutoByteString nameBytes; const char* name = nullptr; if (i < iter.numFormalArgs()) { MOZ_ASSERT(fi.argumentSlot() == i); if (!fi.isDestructured()) { name = nameBytes.encodeLatin1(cx, fi.name()); if (!name) return nullptr; } else { name = "(destructured parameter)"; } fi++; } if (value) { buf = sprintf_append(cx, Move(buf), "%s%s%s%s%s%s", !first ? ", " : "", name ? name :"", name ? " = " : "", arg.isString() ? "\"" : "", value, arg.isString() ? "\"" : ""); if (!buf) return nullptr; first = false; } else { buf = sprintf_append(cx, Move(buf), " <Failed to get argument while inspecting stack frame>\n"); if (!buf) return nullptr; } } } // print filename and line number buf = sprintf_append(cx, Move(buf), "%s [\"%s\":%d]\n", fun ? ")" : "", filename ? filename : "<unknown>", lineno); if (!buf) return nullptr; // Note: Right now we don't dump the local variables anymore, because // that is hard to support across all the JITs etc. // print the value of 'this' if (showLocals) { if (!thisVal.isUndefined()) { JSAutoByteString thisValBytes; RootedString thisValStr(cx, ToString<CanGC>(cx, thisVal)); if (!thisValStr) { if (cx->isThrowingOutOfMemory()) return nullptr; cx->clearPendingException(); } if (thisValStr) { const char* str = thisValBytes.encodeLatin1(cx, thisValStr); if (!str) return nullptr; buf = sprintf_append(cx, Move(buf), " this = %s\n", str); } else { buf = sprintf_append(cx, Move(buf), " <failed to get 'this' value>\n"); } if (!buf) return nullptr; } } if (showThisProps && thisVal.isObject()) { RootedObject obj(cx, &thisVal.toObject()); AutoIdVector keys(cx); if (!GetPropertyKeys(cx, obj, JSITER_OWNONLY, &keys)) { if (cx->isThrowingOutOfMemory()) return nullptr; cx->clearPendingException(); } RootedId id(cx); for (size_t i = 0; i < keys.length(); i++) { RootedId id(cx, keys[i]); RootedValue key(cx, IdToValue(id)); RootedValue v(cx); if (!GetProperty(cx, obj, obj, id, &v)) { if (cx->isThrowingOutOfMemory()) return nullptr; cx->clearPendingException(); buf = sprintf_append(cx, Move(buf), " <Failed to fetch property while inspecting stack frame>\n"); if (!buf) return nullptr; continue; } JSAutoByteString nameBytes; const char* name = FormatValue(cx, key, nameBytes); if (!name) { if (cx->isThrowingOutOfMemory()) return nullptr; cx->clearPendingException(); } JSAutoByteString valueBytes; const char* value = FormatValue(cx, v, valueBytes); if (!value) { if (cx->isThrowingOutOfMemory()) return nullptr; cx->clearPendingException(); } if (name && value) { buf = sprintf_append(cx, Move(buf), " this.%s = %s%s%s\n", name, v.isString() ? "\"" : "", value, v.isString() ? "\"" : ""); } else { buf = sprintf_append(cx, Move(buf), " <Failed to format values while inspecting stack frame>\n"); } if (!buf) return nullptr; } } MOZ_ASSERT(!cx->isExceptionPending()); return buf; }
static bool DefinePropertyIfFound(XPCCallContext& ccx, HandleObject obj, HandleId idArg, XPCNativeSet* set, XPCNativeInterface* ifaceArg, XPCNativeMember* member, XPCWrappedNativeScope* scope, bool reflectToStringAndToSource, XPCWrappedNative* wrapperToReflectInterfaceNames, XPCWrappedNative* wrapperToReflectDoubleWrap, XPCNativeScriptableInfo* scriptableInfo, unsigned propFlags, bool* resolved) { RootedId id(ccx, idArg); RefPtr<XPCNativeInterface> iface = ifaceArg; XPCJSContext* xpccx = ccx.GetContext(); bool found; const char* name; propFlags |= JSPROP_RESOLVING; if (set) { if (iface) found = true; else found = set->FindMember(id, &member, &iface); } else found = (nullptr != (member = iface->FindMember(id))); if (!found) { if (reflectToStringAndToSource) { JSNative call; uint32_t flags = 0; if (scriptableInfo) { nsCOMPtr<nsIClassInfo> classInfo = do_QueryInterface( scriptableInfo->GetCallback()); if (classInfo) { nsresult rv = classInfo->GetFlags(&flags); if (NS_FAILED(rv)) return Throw(rv, ccx); } } bool overwriteToString = !(flags & nsIClassInfo::DOM_OBJECT) || Preferences::GetBool("dom.XPCToStringForDOMClasses", false); if(id == xpccx->GetStringID(XPCJSContext::IDX_TO_STRING) && overwriteToString) { call = XPC_WN_Shared_ToString; name = xpccx->GetStringName(XPCJSContext::IDX_TO_STRING); } else if (id == xpccx->GetStringID(XPCJSContext::IDX_TO_SOURCE)) { call = XPC_WN_Shared_ToSource; name = xpccx->GetStringName(XPCJSContext::IDX_TO_SOURCE); } else if (id == SYMBOL_TO_JSID( JS::GetWellKnownSymbol(ccx, JS::SymbolCode::toPrimitive))) { call = XPC_WN_Shared_toPrimitive; name = "[Symbol.toPrimitive]"; } else { call = nullptr; } if (call) { RootedFunction fun(ccx, JS_NewFunction(ccx, call, 0, 0, name)); if (!fun) { JS_ReportOutOfMemory(ccx); return false; } AutoResolveName arn(ccx, id); if (resolved) *resolved = true; RootedObject value(ccx, JS_GetFunctionObject(fun)); return JS_DefinePropertyById(ccx, obj, id, value, propFlags & ~JSPROP_ENUMERATE); } } // This *might* be a tearoff name that is not yet part of our // set. Let's lookup the name and see if it is the name of an // interface. Then we'll see if the object actually *does* this // interface and add a tearoff as necessary. if (wrapperToReflectInterfaceNames) { JSAutoByteString name; RefPtr<XPCNativeInterface> iface2; XPCWrappedNativeTearOff* to; RootedObject jso(ccx); nsresult rv = NS_OK; if (JSID_IS_STRING(id) && name.encodeLatin1(ccx, JSID_TO_STRING(id)) && (iface2 = XPCNativeInterface::GetNewOrUsed(name.ptr()), iface2) && nullptr != (to = wrapperToReflectInterfaceNames-> FindTearOff(iface2, true, &rv)) && nullptr != (jso = to->GetJSObject())) { AutoResolveName arn(ccx, id); if (resolved) *resolved = true; return JS_DefinePropertyById(ccx, obj, id, jso, propFlags & ~JSPROP_ENUMERATE); } else if (NS_FAILED(rv) && rv != NS_ERROR_NO_INTERFACE) { return Throw(rv, ccx); } } // This *might* be a double wrapped JSObject if (wrapperToReflectDoubleWrap && id == xpccx->GetStringID(XPCJSContext::IDX_WRAPPED_JSOBJECT) && GetDoubleWrappedJSObject(ccx, wrapperToReflectDoubleWrap)) { // We build and add a getter function. // A security check is done on a per-get basis. JSFunction* fun; id = xpccx->GetStringID(XPCJSContext::IDX_WRAPPED_JSOBJECT); name = xpccx->GetStringName(XPCJSContext::IDX_WRAPPED_JSOBJECT); fun = JS_NewFunction(ccx, XPC_WN_DoubleWrappedGetter, 0, 0, name); if (!fun) return false; RootedObject funobj(ccx, JS_GetFunctionObject(fun)); if (!funobj) return false; propFlags |= JSPROP_GETTER | JSPROP_SHARED; propFlags &= ~JSPROP_ENUMERATE; AutoResolveName arn(ccx, id); if (resolved) *resolved = true; return JS_DefinePropertyById(ccx, obj, id, UndefinedHandleValue, propFlags, JS_DATA_TO_FUNC_PTR(JSNative, funobj.get()), nullptr); } if (resolved) *resolved = false; return true; } if (!member) { if (wrapperToReflectInterfaceNames) { XPCWrappedNativeTearOff* to = wrapperToReflectInterfaceNames->FindTearOff(iface, true); if (!to) return false; RootedObject jso(ccx, to->GetJSObject()); if (!jso) return false; AutoResolveName arn(ccx, id); if (resolved) *resolved = true; return JS_DefinePropertyById(ccx, obj, id, jso, propFlags & ~JSPROP_ENUMERATE); } if (resolved) *resolved = false; return true; } if (member->IsConstant()) { RootedValue val(ccx); AutoResolveName arn(ccx, id); if (resolved) *resolved = true; return member->GetConstantValue(ccx, iface, val.address()) && JS_DefinePropertyById(ccx, obj, id, val, propFlags); } if (scope->HasInterposition()) { Rooted<PropertyDescriptor> desc(ccx); if (!xpc::InterposeProperty(ccx, obj, iface->GetIID(), id, &desc)) return false; if (desc.object()) { AutoResolveName arn(ccx, id); if (resolved) *resolved = true; desc.attributesRef() |= JSPROP_RESOLVING; return JS_DefinePropertyById(ccx, obj, id, desc); } } if (id == xpccx->GetStringID(XPCJSContext::IDX_TO_STRING) || id == xpccx->GetStringID(XPCJSContext::IDX_TO_SOURCE) || (scriptableInfo && scriptableInfo->GetFlags().DontEnumQueryInterface() && id == xpccx->GetStringID(XPCJSContext::IDX_QUERY_INTERFACE))) propFlags &= ~JSPROP_ENUMERATE; RootedValue funval(ccx); if (!member->NewFunctionObject(ccx, iface, obj, funval.address())) return false; if (member->IsMethod()) { AutoResolveName arn(ccx, id); if (resolved) *resolved = true; return JS_DefinePropertyById(ccx, obj, id, funval, propFlags); } // else... MOZ_ASSERT(member->IsAttribute(), "way broken!"); propFlags |= JSPROP_GETTER | JSPROP_SHARED; propFlags &= ~JSPROP_READONLY; JSObject* funobj = funval.toObjectOrNull(); JSNative getter = JS_DATA_TO_FUNC_PTR(JSNative, funobj); JSNative setter; if (member->IsWritableAttribute()) { propFlags |= JSPROP_SETTER; setter = JS_DATA_TO_FUNC_PTR(JSNative, funobj); } else { setter = nullptr; } AutoResolveName arn(ccx, id); if (resolved) *resolved = true; return JS_DefinePropertyById(ccx, obj, id, UndefinedHandleValue, propFlags, getter, setter); }
static char* FormatFrame(JSContext* cx, const ScriptFrameIter& iter, char* buf, int num, bool showArgs, bool showLocals, bool showThisProps) { MOZ_ASSERT(!cx->isExceptionPending()); RootedScript script(cx, iter.script()); jsbytecode* pc = iter.pc(); RootedObject scopeChain(cx, iter.scopeChain(cx)); JSAutoCompartment ac(cx, scopeChain); const char* filename = script->filename(); unsigned lineno = PCToLineNumber(script, pc); RootedFunction fun(cx, iter.maybeCallee(cx)); RootedString funname(cx); if (fun) funname = fun->displayAtom(); RootedValue thisVal(cx); if (iter.hasUsableAbstractFramePtr() && iter.computeThis(cx)) { thisVal = iter.computedThisValue(); } // print the frame number and function name if (funname) { JSAutoByteString funbytes; buf = JS_sprintf_append(buf, "%d %s(", num, funbytes.encodeLatin1(cx, funname)); } else if (fun) { buf = JS_sprintf_append(buf, "%d anonymous(", num); } else { buf = JS_sprintf_append(buf, "%d <TOP LEVEL>", num); } if (!buf) return buf; if (showArgs && iter.hasArgs()) { BindingIter bi(script); bool first = true; for (unsigned i = 0; i < iter.numActualArgs(); i++) { RootedValue arg(cx); if (i < iter.numFormalArgs() && script->formalIsAliased(i)) { for (AliasedFormalIter fi(script); ; fi++) { if (fi.frameIndex() == i) { arg = iter.callObj(cx).aliasedVar(fi); break; } } } else if (script->argsObjAliasesFormals() && iter.hasArgsObj()) { arg = iter.argsObj().arg(i); } else { if (iter.hasUsableAbstractFramePtr()) arg = iter.unaliasedActual(i, DONT_CHECK_ALIASING); else arg = MagicValue(JS_OPTIMIZED_OUT); } JSAutoByteString valueBytes; const char* value = FormatValue(cx, arg, valueBytes); JSAutoByteString nameBytes; const char* name = nullptr; if (i < iter.numFormalArgs()) { MOZ_ASSERT(i == bi.argIndex()); name = nameBytes.encodeLatin1(cx, bi->name()); if (!buf) return nullptr; bi++; } if (value) { buf = JS_sprintf_append(buf, "%s%s%s%s%s%s", !first ? ", " : "", name ? name :"", name ? " = " : "", arg.isString() ? "\"" : "", value, arg.isString() ? "\"" : ""); if (!buf) return buf; first = false; } else { buf = JS_sprintf_append(buf, " <Failed to get argument while inspecting stack frame>\n"); if (!buf) return buf; cx->clearPendingException(); } } } // print filename and line number buf = JS_sprintf_append(buf, "%s [\"%s\":%d]\n", fun ? ")" : "", filename ? filename : "<unknown>", lineno); if (!buf) return buf; // Note: Right now we don't dump the local variables anymore, because // that is hard to support across all the JITs etc. // print the value of 'this' if (showLocals) { if (!thisVal.isUndefined()) { JSAutoByteString thisValBytes; RootedString thisValStr(cx, ToString<CanGC>(cx, thisVal)); const char* str = nullptr; if (thisValStr && (str = thisValBytes.encodeLatin1(cx, thisValStr))) { buf = JS_sprintf_append(buf, " this = %s\n", str); if (!buf) return buf; } else { buf = JS_sprintf_append(buf, " <failed to get 'this' value>\n"); cx->clearPendingException(); } } } if (showThisProps && thisVal.isObject()) { RootedObject obj(cx, &thisVal.toObject()); AutoIdVector keys(cx); if (!GetPropertyKeys(cx, obj, JSITER_OWNONLY, &keys)) { cx->clearPendingException(); return buf; } RootedId id(cx); for (size_t i = 0; i < keys.length(); i++) { RootedId id(cx, keys[i]); RootedValue key(cx, IdToValue(id)); RootedValue v(cx); if (!GetProperty(cx, obj, obj, id, &v)) { buf = JS_sprintf_append(buf, " <Failed to fetch property while inspecting stack frame>\n"); cx->clearPendingException(); continue; } JSAutoByteString nameBytes; JSAutoByteString valueBytes; const char* name = FormatValue(cx, key, nameBytes); const char* value = FormatValue(cx, v, valueBytes); if (name && value) { buf = JS_sprintf_append(buf, " this.%s = %s%s%s\n", name, v.isString() ? "\"" : "", value, v.isString() ? "\"" : ""); if (!buf) return buf; } else { buf = JS_sprintf_append(buf, " <Failed to format values while inspecting stack frame>\n"); cx->clearPendingException(); } } } MOZ_ASSERT(!cx->isExceptionPending()); return buf; }
static char* FormatJSFrame(JSContext* cx, JSStackFrame* fp, char* buf, int num, JSBool showArgs, JSBool showLocals, JSBool showThisProps) { JSPropertyDescArray callProps = {0, nsnull}; JSPropertyDescArray thisProps = {0, nsnull}; JSBool gotThisVal = JS_FALSE; jsval thisVal; JSObject* callObj = nsnull; JSString* funname = nsnull; JSAutoByteString funbytes; const char* filename = nsnull; PRInt32 lineno = 0; JSFunction* fun = nsnull; uint32 namedArgCount = 0; jsval val; JSBool isString; // get the info for this stack frame JSScript* script = JS_GetFrameScript(cx, fp); jsbytecode* pc = JS_GetFramePC(cx, fp); JSAutoRequest ar(cx); JSAutoEnterCompartment ac; if(!ac.enter(cx, JS_GetFrameScopeChain(cx, fp))) return buf; if(script && pc) { filename = JS_GetScriptFilename(cx, script); lineno = (PRInt32) JS_PCToLineNumber(cx, script, pc); fun = JS_GetFrameFunction(cx, fp); if(fun) funname = JS_GetFunctionId(fun); if(showArgs || showLocals) { callObj = JS_GetFrameCallObject(cx, fp); if(callObj) if(!JS_GetPropertyDescArray(cx, callObj, &callProps)) callProps.array = nsnull; // just to be sure } gotThisVal = JS_GetFrameThis(cx, fp, &thisVal); if (!gotThisVal || !showThisProps || JSVAL_IS_PRIMITIVE(thisVal) || !JS_GetPropertyDescArray(cx, JSVAL_TO_OBJECT(thisVal), &thisProps)) { thisProps.array = nsnull; // just to be sure } } // print the frame number and function name if(funname) buf = JS_sprintf_append(buf, "%d %s(", num, funbytes.encode(cx, funname)); else if(fun) buf = JS_sprintf_append(buf, "%d anonymous(", num); else buf = JS_sprintf_append(buf, "%d <TOP LEVEL>", num); if(!buf) goto out; // print the function arguments if(showArgs && callObj) { for(uint32 i = 0; i < callProps.length; i++) { JSPropertyDesc* desc = &callProps.array[i]; if(desc->flags & JSPD_ARGUMENT) { JSAutoByteString nameBytes; const char* name = JSVAL2String(cx, desc->id, &isString, &nameBytes); if(!isString) name = nsnull; JSAutoByteString valueBytes; const char* value = JSVAL2String(cx, desc->value, &isString, &valueBytes); buf = JS_sprintf_append(buf, "%s%s%s%s%s%s", namedArgCount ? ", " : "", name ? name :"", name ? " = " : "", isString ? "\"" : "", value ? value : "?unknown?", isString ? "\"" : ""); if(!buf) goto out; namedArgCount++; } } // print any unnamed trailing args (found in 'arguments' object) if(JS_GetProperty(cx, callObj, "arguments", &val) && JSVAL_IS_OBJECT(val)) { uint32 argCount; JSObject* argsObj = JSVAL_TO_OBJECT(val); if(JS_GetProperty(cx, argsObj, "length", &val) && JS_ValueToECMAUint32(cx, val, &argCount) && argCount > namedArgCount) { for(uint32 k = namedArgCount; k < argCount; k++) { char number[8]; JS_snprintf(number, 8, "%d", (int) k); if(JS_GetProperty(cx, argsObj, number, &val)) { JSAutoByteString valueBytes; const char *value = JSVAL2String(cx, val, &isString, &valueBytes); buf = JS_sprintf_append(buf, "%s%s%s%s", k ? ", " : "", isString ? "\"" : "", value ? value : "?unknown?", isString ? "\"" : ""); if(!buf) goto out; } } } } } // print filename and line number buf = JS_sprintf_append(buf, "%s [\"%s\":%d]\n", fun ? ")" : "", filename ? filename : "<unknown>", lineno); if(!buf) goto out; // print local variables if(showLocals && callProps.array) { for(uint32 i = 0; i < callProps.length; i++) { JSPropertyDesc* desc = &callProps.array[i]; if(desc->flags & JSPD_VARIABLE) { JSAutoByteString nameBytes; JSAutoByteString valueBytes; const char *name = JSVAL2String(cx, desc->id, nsnull, &nameBytes); const char *value = JSVAL2String(cx, desc->value, &isString, &valueBytes); if(name && value) { buf = JS_sprintf_append(buf, TAB "%s = %s%s%s\n", name, isString ? "\"" : "", value, isString ? "\"" : ""); if(!buf) goto out; } } } } // print the value of 'this' if(showLocals) { if(gotThisVal) { JSString* thisValStr; JSAutoByteString thisValBytes; if(nsnull != (thisValStr = JS_ValueToString(cx, thisVal)) && thisValBytes.encode(cx, thisValStr)) { buf = JS_sprintf_append(buf, TAB "this = %s\n", thisValBytes.ptr()); if(!buf) goto out; } } else buf = JS_sprintf_append(buf, TAB "<failed to get 'this' value>\n"); } // print the properties of 'this', if it is an object if(showThisProps && thisProps.array) { for(uint32 i = 0; i < thisProps.length; i++) { JSPropertyDesc* desc = &thisProps.array[i]; if(desc->flags & JSPD_ENUMERATE) { JSAutoByteString nameBytes; JSAutoByteString valueBytes; const char *name = JSVAL2String(cx, desc->id, nsnull, &nameBytes); const char *value = JSVAL2String(cx, desc->value, &isString, &valueBytes); if(name && value) { buf = JS_sprintf_append(buf, TAB "this.%s = %s%s%s\n", name, isString ? "\"" : "", value, isString ? "\"" : ""); if(!buf) goto out; } } } } out: if(callProps.array) JS_PutPropertyDescArray(cx, &callProps); if(thisProps.array) JS_PutPropertyDescArray(cx, &thisProps); return buf; }