bool Library::Close(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); RootedObject obj(cx); if (args.thisv().isObject()) obj = &args.thisv().toObject(); if (!obj || !IsLibrary(obj)) { JS_ReportErrorASCII(cx, "not a library"); return false; } if (args.length() != 0) { JS_ReportErrorASCII(cx, "close doesn't take any arguments"); return false; } // delete our internal objects UnloadLibrary(obj); JS_SetReservedSlot(obj, SLOT_LIBRARY, PrivateValue(nullptr)); args.rval().setUndefined(); return true; }
bool Library::Name(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); if (args.length() != 1) { JS_ReportErrorASCII(cx, "libraryName takes one argument"); return false; } Value arg = args[0]; JSString* str = nullptr; if (arg.isString()) { str = arg.toString(); } else { JS_ReportErrorASCII(cx, "name argument must be a string"); return false; } AutoString resultString; AppendString(resultString, DLL_PREFIX); AppendString(resultString, str); AppendString(resultString, DLL_SUFFIX); JSString* result = JS_NewUCStringCopyN(cx, resultString.begin(), resultString.length()); if (!result) return false; args.rval().setString(result); return true; }
static bool my_resolve(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* resolvedp) { MOZ_ASSERT_UNREACHABLE("resolve hook should not be called from InitStandardClasses"); JS_ReportErrorASCII(cx, "FAIL"); return false; }
/** * JS method |forget()| * * === JS documentation * * Neutralize the witness. Once this method is called, the witness will * never report any error. */ bool ForgetImpl(JSContext* cx, const JS::CallArgs& args) { if (args.length() != 0) { JS_ReportErrorASCII(cx, "forget() takes no arguments"); return false; } JS::Rooted<JS::Value> valSelf(cx, args.thisv()); JS::Rooted<JSObject*> objSelf(cx, &valSelf.toObject()); RefPtr<FinalizationEvent> event = ExtractFinalizationEvent(objSelf); if (event == nullptr) { JS_ReportErrorASCII(cx, "forget() called twice"); return false; } args.rval().setUndefined(); return true; }
bool Library::Open(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); JSObject* ctypesObj = JS_THIS_OBJECT(cx, vp); if (!ctypesObj) return false; if (!IsCTypesGlobal(ctypesObj)) { JS_ReportErrorASCII(cx, "not a ctypes object"); return false; } if (args.length() != 1 || args[0].isUndefined()) { JS_ReportErrorASCII(cx, "open requires a single argument"); return false; } JSObject* library = Create(cx, args[0], GetCallbacks(ctypesObj)); if (!library) return false; args.rval().setObject(*library); return true; }
bool AccessCheck::checkPassToPrivilegedCode(JSContext* cx, HandleObject wrapper, HandleValue v) { // Primitives are fine. if (!v.isObject()) return true; RootedObject obj(cx, &v.toObject()); // Non-wrappers are fine. if (!js::IsWrapper(obj)) return true; // CPOWs use COWs (in the unprivileged junk scope) for all child->parent // references. Without this test, the child process wouldn't be able to // pass any objects at all to CPOWs. if (mozilla::jsipc::IsWrappedCPOW(obj) && js::GetObjectCompartment(wrapper) == js::GetObjectCompartment(xpc::UnprivilegedJunkScope()) && XRE_IsParentProcess()) { return true; } // COWs are fine to pass to chrome if and only if they have __exposedProps__, // since presumably content should never have a reason to pass an opaque // object back to chrome. if (AccessCheck::isChrome(js::UncheckedUnwrap(wrapper)) && WrapperFactory::IsCOW(obj)) { RootedObject target(cx, js::UncheckedUnwrap(obj)); JSAutoCompartment ac(cx, target); RootedId id(cx, GetJSIDByIndex(cx, XPCJSContext::IDX_EXPOSEDPROPS)); bool found = false; if (!JS_HasPropertyById(cx, target, id, &found)) return false; if (found) return true; } // Same-origin wrappers are fine. if (AccessCheck::wrapperSubsumes(obj)) return true; // Badness. JS_ReportErrorASCII(cx, "Permission denied to pass object to privileged code"); return false; }
bool CreateAlias(JSContext* cx, const char* dstName, JS::HandleObject namespaceObj, const char* srcName) { RootedObject global(cx, JS_GetGlobalForObject(cx, namespaceObj)); if (!global) return false; RootedValue val(cx); if (!JS_GetProperty(cx, namespaceObj, srcName, &val)) return false; if (!val.isObject()) { JS_ReportErrorASCII(cx, "attempted to alias nonexistent function"); return false; } RootedObject function(cx, &val.toObject()); if (!JS_DefineProperty(cx, global, dstName, function, 0)) return false; return true; }
JSObject* Library::Create(JSContext* cx, HandleValue path, const JSCTypesCallbacks* callbacks) { RootedObject libraryObj(cx, JS_NewObject(cx, &sLibraryClass)); if (!libraryObj) return nullptr; // initialize the library JS_SetReservedSlot(libraryObj, SLOT_LIBRARY, PrivateValue(nullptr)); // attach API functions if (!JS_DefineFunctions(cx, libraryObj, sLibraryFunctions)) return nullptr; if (!path.isString()) { JS_ReportErrorASCII(cx, "open takes a string argument"); return nullptr; } PRLibSpec libSpec; RootedFlatString pathStr(cx, JS_FlattenString(cx, path.toString())); if (!pathStr) return nullptr; AutoStableStringChars pathStrChars(cx); if (!pathStrChars.initTwoByte(cx, pathStr)) return nullptr; #ifdef XP_WIN // On Windows, converting to native charset may corrupt path string. // So, we have to use Unicode path directly. char16ptr_t pathChars = pathStrChars.twoByteChars(); libSpec.value.pathname_u = pathChars; libSpec.type = PR_LibSpec_PathnameU; #else // Convert to platform native charset if the appropriate callback has been // provided. char* pathBytes; if (callbacks && callbacks->unicodeToNative) { pathBytes = callbacks->unicodeToNative(cx, pathStrChars.twoByteChars(), pathStr->length()); if (!pathBytes) return nullptr; } else { // Fallback: assume the platform native charset is UTF-8. This is true // for Mac OS X, Android, and probably Linux. size_t nbytes = GetDeflatedUTF8StringLength(cx, pathStrChars.twoByteChars(), pathStr->length()); if (nbytes == (size_t) -1) return nullptr; pathBytes = static_cast<char*>(JS_malloc(cx, nbytes + 1)); if (!pathBytes) return nullptr; ASSERT_OK(DeflateStringToUTF8Buffer(cx, pathStrChars.twoByteChars(), pathStr->length(), pathBytes, &nbytes)); pathBytes[nbytes] = 0; } libSpec.value.pathname = pathBytes; libSpec.type = PR_LibSpec_Pathname; #endif PRLibrary* library = PR_LoadLibraryWithFlags(libSpec, PR_LD_NOW); #ifndef XP_WIN JS_free(cx, pathBytes); #endif if (!library) { #define MAX_ERROR_LEN 1024 char error[MAX_ERROR_LEN] = "Cannot get error from NSPR."; uint32_t errorLen = PR_GetErrorTextLength(); if (errorLen && errorLen < MAX_ERROR_LEN) PR_GetErrorText(error); #undef MAX_ERROR_LEN if (JS::StringIsASCII(error)) { JSAutoByteString pathCharsUTF8; if (pathCharsUTF8.encodeUtf8(cx, pathStr)) JS_ReportErrorUTF8(cx, "couldn't open library %s: %s", pathCharsUTF8.ptr(), error); } else { JSAutoByteString pathCharsLatin1; if (pathCharsLatin1.encodeLatin1(cx, pathStr)) JS_ReportErrorLatin1(cx, "couldn't open library %s: %s", pathCharsLatin1.ptr(), error); } return nullptr; } // stash the library JS_SetReservedSlot(libraryObj, SLOT_LIBRARY, PrivateValue(library)); return libraryObj; }
bool Library::Declare(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); RootedObject obj(cx, JS_THIS_OBJECT(cx, vp)); if (!obj) return false; if (!IsLibrary(obj)) { JS_ReportErrorASCII(cx, "not a library"); return false; } PRLibrary* library = GetLibrary(obj); if (!library) { JS_ReportErrorASCII(cx, "library not open"); return false; } // We allow two API variants: // 1) library.declare(name, abi, returnType, argType1, ...) // declares a function with the given properties, and resolves the symbol // address in the library. // 2) library.declare(name, type) // declares a symbol of 'type', and resolves it. The object that comes // back will be of type 'type', and will point into the symbol data. // This data will be both readable and writable via the usual CData // accessors. If 'type' is a PointerType to a FunctionType, the result will // be a function pointer, as with 1). if (args.length() < 2) { JS_ReportErrorASCII(cx, "declare requires at least two arguments"); return false; } if (!args[0].isString()) { JS_ReportErrorASCII(cx, "first argument must be a string"); return false; } RootedObject fnObj(cx, nullptr); RootedObject typeObj(cx); bool isFunction = args.length() > 2; if (isFunction) { // Case 1). // Create a FunctionType representing the function. fnObj = FunctionType::CreateInternal(cx, args[1], args[2], HandleValueArray::subarray(args, 3, args.length() - 3)); if (!fnObj) return false; // Make a function pointer type. typeObj = PointerType::CreateInternal(cx, fnObj); if (!typeObj) return false; } else { // Case 2). if (args[1].isPrimitive() || !CType::IsCType(args[1].toObjectOrNull()) || !CType::IsSizeDefined(args[1].toObjectOrNull())) { JS_ReportErrorASCII(cx, "second argument must be a type of defined size"); return false; } typeObj = args[1].toObjectOrNull(); if (CType::GetTypeCode(typeObj) == TYPE_pointer) { fnObj = PointerType::GetBaseType(typeObj); isFunction = fnObj && CType::GetTypeCode(fnObj) == TYPE_function; } } void* data; PRFuncPtr fnptr; RootedString nameStr(cx, args[0].toString()); AutoCString symbol; if (isFunction) { // Build the symbol, with mangling if necessary. FunctionType::BuildSymbolName(nameStr, fnObj, symbol); AppendString(symbol, "\0"); // Look up the function symbol. fnptr = PR_FindFunctionSymbol(library, symbol.begin()); if (!fnptr) { JS_ReportErrorASCII(cx, "couldn't find function symbol in library"); return false; } data = &fnptr; } else { // 'typeObj' is another data type. Look up the data symbol. AppendString(symbol, nameStr); AppendString(symbol, "\0"); data = PR_FindSymbol(library, symbol.begin()); if (!data) { JS_ReportErrorASCII(cx, "couldn't find symbol in library"); return false; } } RootedObject result(cx, CData::Create(cx, typeObj, obj, data, isFunction)); if (!result) return false; if (isFunction) JS_SetReservedSlot(result, SLOT_FUNNAME, StringValue(nameStr)); args.rval().setObject(*result); // Seal the CData object, to prevent modification of the function pointer. // This permanently associates this object with the library, and avoids // having to do things like reset SLOT_REFERENT when someone tries to // change the pointer value. // XXX This will need to change when bug 541212 is fixed -- CData::ValueSetter // could be called on a sealed object. if (isFunction && !JS_FreezeObject(cx, result)) return false; return true; }
static void EnterAndThrowASCII(JSContext* cx, JSObject* wrapper, const char* msg) { JSAutoCompartment ac(cx, wrapper); JS_ReportErrorASCII(cx, "%s", msg); }