/* |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 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 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); }
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()); } }
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; }
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"); }
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; }
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* 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; }
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); }