Example #1
0
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;
}
Example #2
0
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;
}
Example #5
0
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;
}
Example #6
0
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;
}
Example #7
0
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;
}
Example #8
0
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;
}
Example #9
0
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;
}
Example #10
0
static void
EnterAndThrowASCII(JSContext* cx, JSObject* wrapper, const char* msg)
{
    JSAutoCompartment ac(cx, wrapper);
    JS_ReportErrorASCII(cx, "%s", msg);
}