Example #1
0
/* PRBool resolve (in nsIXPConnectWrappedNative wrapper, in JSContextPtr cx, in JSObjectPtr obj, in jsval id); */
NS_IMETHODIMP
nsJSIID::NewResolve(nsIXPConnectWrappedNative *wrapper,
                    JSContext * cx, JSObject * obj,
                    jsid id, PRUint32 flags,
                    JSObject * *objp, PRBool *_retval)
{
    XPCCallContext ccx(JS_CALLER, cx);

    AutoMarkingNativeInterfacePtr iface(ccx);

    const nsIID* iid;
    mInfo->GetIIDShared(&iid);

    iface = XPCNativeInterface::GetNewOrUsed(ccx, iid);

    if(!iface)
        return NS_OK;

    XPCNativeMember* member = iface->FindMember(id);
    if(member && member->IsConstant())
    {
        jsval val;
        if(!member->GetConstantValue(ccx, iface, &val))
            return NS_ERROR_OUT_OF_MEMORY;

        *objp = obj;
        *_retval = JS_DefinePropertyById(cx, obj, id, val, nsnull, nsnull,
                                         JSPROP_ENUMERATE | JSPROP_READONLY |
                                         JSPROP_PERMANENT);
    }

    return NS_OK;
}
Example #2
0
/* PRBool enumerate (in nsIXPConnectWrappedNative wrapper, in JSContextPtr cx, in JSObjectPtr obj); */
NS_IMETHODIMP
nsJSIID::Enumerate(nsIXPConnectWrappedNative *wrapper,
                   JSContext * cx, JSObject * obj, PRBool *_retval)
{
    // In this case, let's just eagerly resolve...

    XPCCallContext ccx(JS_CALLER, cx);

    AutoMarkingNativeInterfacePtr iface(ccx);

    const nsIID* iid;
    mInfo->GetIIDShared(&iid);

    iface = XPCNativeInterface::GetNewOrUsed(ccx, iid);

    if(!iface)
        return NS_OK;

    PRUint16 count = iface->GetMemberCount();
    for(PRUint16 i = 0; i < count; i++)
    {
        XPCNativeMember* member = iface->GetMemberAt(i);
        if(member && member->IsConstant() &&
           !xpc_ForcePropertyResolve(cx, obj, member->GetName()))
        {
            return NS_ERROR_UNEXPECTED;
        }
    }
    return NS_OK;
}
Example #3
0
NS_IMETHODIMP
nsJSIID::Enumerate(nsIXPConnectWrappedNative* wrapper,
                   JSContext * cx, JSObject * objArg, bool* _retval)
{
    // In this case, let's just eagerly resolve...

    RootedObject obj(cx, objArg);
    XPCCallContext ccx(cx);

    RefPtr<XPCNativeInterface> iface =
        XPCNativeInterface::GetNewOrUsed(mInfo);

    if (!iface)
        return NS_OK;

    uint16_t count = iface->GetMemberCount();
    for (uint16_t i = 0; i < count; i++) {
        XPCNativeMember* member = iface->GetMemberAt(i);
        if (member && member->IsConstant() &&
            !xpc_ForcePropertyResolve(cx, obj, member->GetName())) {
            return NS_ERROR_UNEXPECTED;
        }
    }
    return NS_OK;
}
Example #4
0
NS_IMETHODIMP
nsJSIID::Resolve(nsIXPConnectWrappedNative* wrapper,
                 JSContext * cx, JSObject * objArg,
                 jsid idArg, bool* resolvedp,
                 bool* _retval)
{
    RootedObject obj(cx, objArg);
    RootedId id(cx, idArg);
    XPCCallContext ccx(JS_CALLER, cx);

    AutoMarkingNativeInterfacePtr iface(ccx);

    iface = XPCNativeInterface::GetNewOrUsed(mInfo);

    if (!iface)
        return NS_OK;

    XPCNativeMember* member = iface->FindMember(id);
    if (member && member->IsConstant()) {
        RootedValue val(cx);
        if (!member->GetConstantValue(ccx, iface, val.address()))
            return NS_ERROR_OUT_OF_MEMORY;

        *resolvedp = true;
        *_retval = JS_DefinePropertyById(cx, obj, id, val,
                                         JSPROP_ENUMERATE | JSPROP_READONLY |
                                         JSPROP_PERMANENT | JSPROP_RESOLVING);
    }

    return NS_OK;
}
bool
XPC_WN_GetterSetter(JSContext* cx, unsigned argc, Value* vp)
{
    JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
    MOZ_ASSERT(JS_TypeOfValue(cx, args.calleev()) == JSTYPE_FUNCTION, "bad function");
    RootedObject funobj(cx, &args.callee());

    RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
    if (!obj)
        return false;

    obj = FixUpThisIfBroken(obj, funobj);
    XPCCallContext ccx(cx, obj, funobj, JSID_VOIDHANDLE, args.length(),
                       args.array(), vp);
    XPCWrappedNative* wrapper = ccx.GetWrapper();
    THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);

    RefPtr<XPCNativeInterface> iface;
    XPCNativeMember*    member;

    if (!XPCNativeMember::GetCallInfo(funobj, &iface, &member))
        return Throw(NS_ERROR_XPC_CANT_GET_METHOD_INFO, cx);

    if (args.length() != 0 && member->IsWritableAttribute()) {
        ccx.SetCallInfo(iface, member, true);
        bool retval = XPCWrappedNative::SetAttribute(ccx);
        if (retval)
            args.rval().set(args[0]);
        return retval;
    }
    // else...

    ccx.SetCallInfo(iface, member, false);
    return XPCWrappedNative::GetAttribute(ccx);
}
Example #6
0
XPCWrappedNative*
XPCCallContext::UnwrapThisIfAllowed(HandleObject obj, HandleObject fun, unsigned argc)
{
    // We should only get here for objects that aren't safe to unwrap.
    MOZ_ASSERT(!js::CheckedUnwrap(obj));
    MOZ_ASSERT(js::IsObjectInContextCompartment(obj, mJSContext));

    // We can't do anything here without a function.
    if (!fun)
        return nullptr;

    // Determine if we're allowed to unwrap the security wrapper to invoke the
    // method.
    //
    // We have the Interface and Member that this corresponds to, but
    // unfortunately our access checks are based on the object class name and
    // property name. So we cheat a little bit here - we verify that the object
    // does indeed implement the method's Interface, and then just check that we
    // can successfully access property with method's name from the object.

    // First, get the XPCWN out of the underlying object. We should have a wrapper
    // here, potentially an outer window proxy, and then an XPCWN.
    MOZ_ASSERT(js::IsWrapper(obj));
    RootedObject unwrapped(mJSContext, js::UncheckedUnwrap(obj, /* stopAtOuter = */ false));
#ifdef DEBUG
    JS::Rooted<JSObject*> wrappedObj(mJSContext, js::Wrapper::wrappedObject(obj));
    MOZ_ASSERT(unwrapped == JS_ObjectToInnerObject(mJSContext, wrappedObj));
#endif

    // Make sure we have an XPCWN, and grab it.
    if (!IS_WN_REFLECTOR(unwrapped))
        return nullptr;
    XPCWrappedNative *wn = XPCWrappedNative::Get(unwrapped);

    // Next, get the call info off the function object.
    XPCNativeInterface *interface;
    XPCNativeMember *member;
    XPCNativeMember::GetCallInfo(fun, &interface, &member);

    // To be extra safe, make sure that the underlying native implements the
    // interface before unwrapping. Even if we didn't check this, we'd still
    // theoretically fail during tearoff lookup for mismatched methods.
    if (!wn->HasInterfaceNoQI(*interface->GetIID()))
        return nullptr;

    // See if the access is permitted.
    //
    // NB: This calculation of SET vs GET is a bit wonky, but that's what
    // XPC_WN_GetterSetter does.
    bool set = argc && argc != NO_ARGS && member->IsWritableAttribute();
    js::Wrapper::Action act = set ? js::Wrapper::SET : js::Wrapper::GET;
    const js::Wrapper *handler = js::Wrapper::wrapperHandler(obj);
    bool ignored;
    JS::Rooted<jsid> id(mJSContext, member->GetName());
    if (!handler->enter(mJSContext, obj, id, act, &ignored))
        return nullptr;

    // Ok, this call is safe.
    return wn;
}
static bool
XPC_WN_Shared_toPrimitive(JSContext* cx, unsigned argc, Value* vp)
{
    CallArgs args = CallArgsFromVp(argc, vp);

    RootedObject obj(cx);
    if (!JS_ValueToObject(cx, args.thisv(), &obj))
        return false;
    XPCCallContext ccx(cx, obj);
    XPCWrappedNative* wrapper = ccx.GetWrapper();
    THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);

    JSType hint;
    if (!GetFirstArgumentAsTypeHint(cx, args, &hint))
        return false;

    if (hint == JSTYPE_NUMBER) {
        args.rval().set(JS_GetNaNValue(cx));
        return true;
    }

    MOZ_ASSERT(hint == JSTYPE_STRING || hint == JSTYPE_VOID);
    ccx.SetName(ccx.GetContext()->GetStringID(XPCJSContext::IDX_TO_STRING));
    ccx.SetArgsAndResultPtr(0, nullptr, args.rval().address());

    XPCNativeMember* member = ccx.GetMember();
    if (member && member->IsMethod()) {
        if (!XPCWrappedNative::CallMethod(ccx))
            return false;

        if (args.rval().isPrimitive())
            return true;
    }

    // else...
    return ToStringGuts(ccx);
}
bool
XPC_WN_Shared_Enumerate(JSContext* cx, HandleObject obj)
{
    XPCCallContext ccx(cx, obj);
    XPCWrappedNative* wrapper = ccx.GetWrapper();
    THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);

    // Since we aren't going to enumerate tearoff names and the prototype
    // handles non-mutated members, we can do this potential short-circuit.
    if (!wrapper->HasMutatedSet())
        return true;

    XPCNativeSet* set = wrapper->GetSet();
    XPCNativeSet* protoSet = wrapper->HasProto() ?
                                wrapper->GetProto()->GetSet() : nullptr;

    uint16_t interface_count = set->GetInterfaceCount();
    XPCNativeInterface** interfaceArray = set->GetInterfaceArray();
    for (uint16_t i = 0; i < interface_count; i++) {
        XPCNativeInterface* iface = interfaceArray[i];
        uint16_t member_count = iface->GetMemberCount();
        for (uint16_t k = 0; k < member_count; k++) {
            XPCNativeMember* member = iface->GetMemberAt(k);
            jsid name = member->GetName();

            // Skip if this member is going to come from the proto.
            uint16_t index;
            if (protoSet &&
                protoSet->FindMember(name, nullptr, &index) && index == i)
                continue;
            if (!xpc_ForcePropertyResolve(cx, obj, name))
                return false;
        }
    }
    return true;
}
static bool
ResolveNativeProperty(JSContext *cx, JSObject *wrapper, JSObject *holder, jsid id, bool set,
                      JSPropertyDescriptor *desc)
{
    desc->obj = NULL;

    NS_ASSERTION(holder->getJSClass() == &HolderClass, "expected a native property holder object");
    JSObject *wnObject = GetWrappedNativeObjectFromHolder(holder);
    XPCWrappedNative *wn = GetWrappedNative(wnObject);

    // This will do verification and the method lookup for us.
    XPCCallContext ccx(JS_CALLER, cx, wnObject, nsnull, id);

    // There are no native numeric properties, so we can shortcut here. We will not
    // find the property.
    if (!JSID_IS_ATOM(id)) {
        /* Not found */
        return true;
    }

    XPCNativeInterface *iface;
    XPCNativeMember *member;
    if (ccx.GetWrapper() != wn ||
        !wn->IsValid()  ||
        !(iface = ccx.GetInterface()) ||
        !(member = ccx.GetMember())) {
        /* Not found */
        return true;
    }

    desc->obj = holder;
    desc->attrs = JSPROP_ENUMERATE;
    desc->getter = NULL;
    desc->setter = NULL;
    desc->shortid = 0;
    desc->value = JSVAL_VOID;

    jsval fval = JSVAL_VOID;
    if (member->IsConstant()) {
        if (!member->GetConstantValue(ccx, iface, &desc->value)) {
            JS_ReportError(cx, "Failed to convert constant native property to JS value");
            return false;
        }
    } else if (member->IsAttribute()) {
        // This is a getter/setter. Clone a function for it.
        if (!member->NewFunctionObject(ccx, iface, wrapper, &fval)) {
            JS_ReportError(cx, "Failed to clone function object for native getter/setter");
            return false;
        }

        desc->attrs |= JSPROP_GETTER;
        if (member->IsWritableAttribute())
            desc->attrs |= JSPROP_SETTER;

        // Make the property shared on the holder so no slot is allocated
        // for it. This avoids keeping garbage alive through that slot.
        desc->attrs |= JSPROP_SHARED;
    } else {
        // This is a method. Clone a function for it.
        if (!member->NewFunctionObject(ccx, iface, wrapper, &desc->value)) {
            JS_ReportError(cx, "Failed to clone function object for native function");
            return false;
        }

        // Without a wrapper the function would live on the prototype. Since we
        // don't have one, we have to avoid calling the scriptable helper's
        // GetProperty method for this property, so stub out the getter and
        // setter here explicitly.
        desc->getter = JS_PropertyStub;
        desc->setter = JS_StrictPropertyStub;
    }

    if (!JS_WrapValue(cx, &desc->value) || !JS_WrapValue(cx, &fval))
        return false;

    if (desc->attrs & JSPROP_GETTER)
        desc->getter = CastAsJSPropertyOp(JSVAL_TO_OBJECT(fval));
    if (desc->attrs & JSPROP_SETTER)
        desc->setter = CastAsJSStrictPropertyOp(JSVAL_TO_OBJECT(fval));

    // Define the property.
    return JS_DefinePropertyById(cx, holder, id, desc->value,
                                 desc->getter, desc->setter, desc->attrs);
}
// static
XPCNativeInterface*
XPCNativeInterface::NewInstance(XPCCallContext& ccx,
                                nsIInterfaceInfo* aInfo)
{
    static const PRUint16 MAX_LOCAL_MEMBER_COUNT = 16;
    XPCNativeMember local_members[MAX_LOCAL_MEMBER_COUNT];
    XPCNativeInterface* obj = nsnull;
    XPCNativeMember* members = nsnull;

    int i;
    JSBool failed = false;
    PRUint16 constCount;
    PRUint16 methodCount;
    PRUint16 totalCount;
    PRUint16 realTotalCount = 0;
    XPCNativeMember* cur;
    JSString* str = NULL;
    jsid name;
    jsid interfaceName;

    // XXX Investigate lazy init? This is a problem given the
    // 'placement new' scheme - we need to at least know how big to make
    // the object. We might do a scan of methods to determine needed size,
    // then make our object, but avoid init'ing *any* members until asked?
    // Find out how often we create these objects w/o really looking at
    // (or using) the members.

    bool canScript;
    if (NS_FAILED(aInfo->IsScriptable(&canScript)) || !canScript)
        return nsnull;

    if (NS_FAILED(aInfo->GetMethodCount(&methodCount)) ||
        NS_FAILED(aInfo->GetConstantCount(&constCount)))
        return nsnull;

    // If the interface does not have nsISupports in its inheritance chain
    // then we know we can't reflect its methods. However, some interfaces that
    // are used just to reflect constants are declared this way. We need to
    // go ahead and build the thing. But, we'll ignore whatever methods it may
    // have.
    if (!nsXPConnect::IsISupportsDescendant(aInfo))
        methodCount = 0;

    totalCount = methodCount + constCount;

    if (totalCount > MAX_LOCAL_MEMBER_COUNT) {
        members = new XPCNativeMember[totalCount];
        if (!members)
            return nsnull;
    } else {
        members = local_members;
    }

    // NOTE: since getters and setters share a member, we might not use all
    // of the member objects.

    for (i = 0; i < methodCount; i++) {
        const nsXPTMethodInfo* info;
        if (NS_FAILED(aInfo->GetMethodInfo(i, &info))) {
            failed = true;
            break;
        }

        // don't reflect Addref or Release
        if (i == 1 || i == 2)
            continue;

        if (!XPCConvert::IsMethodReflectable(*info))
            continue;

        str = JS_InternString(ccx, info->GetName());
        if (!str) {
            NS_ERROR("bad method name");
            failed = true;
            break;
        }
        name = INTERNED_STRING_TO_JSID(ccx, str);

        if (info->IsSetter()) {
            NS_ASSERTION(realTotalCount,"bad setter");
            // Note: ASSUMES Getter/Setter pairs are next to each other
            // This is a rule of the typelib spec.
            cur = &members[realTotalCount-1];
            NS_ASSERTION(cur->GetName() == name,"bad setter");
            NS_ASSERTION(cur->IsReadOnlyAttribute(),"bad setter");
            NS_ASSERTION(cur->GetIndex() == i-1,"bad setter");
            cur->SetWritableAttribute();
        } else {
            // XXX need better way to find dups
            // NS_ASSERTION(!LookupMemberByID(name),"duplicate method name");
            cur = &members[realTotalCount++];
            cur->SetName(name);
            if (info->IsGetter())
                cur->SetReadOnlyAttribute(i);
            else
                cur->SetMethod(i);
        }
    }

    if (!failed) {
        for (i = 0; i < constCount; i++) {
            const nsXPTConstant* constant;
            if (NS_FAILED(aInfo->GetConstant(i, &constant))) {
                failed = true;
                break;
            }

            str = JS_InternString(ccx, constant->GetName());
            if (!str) {
                NS_ERROR("bad constant name");
                failed = true;
                break;
            }
            name = INTERNED_STRING_TO_JSID(ccx, str);

            // XXX need better way to find dups
            //NS_ASSERTION(!LookupMemberByID(name),"duplicate method/constant name");

            cur = &members[realTotalCount++];
            cur->SetName(name);
            cur->SetConstant(i);
        }
    }

    if (!failed) {
        const char* bytes;
        if (NS_FAILED(aInfo->GetNameShared(&bytes)) || !bytes ||
            nsnull == (str = JS_InternString(ccx, bytes))) {
            failed = true;
        }
        interfaceName = INTERNED_STRING_TO_JSID(ccx, str);
    }

    if (!failed) {
        // Use placement new to create an object with the right amount of space
        // to hold the members array
        int size = sizeof(XPCNativeInterface);
        if (realTotalCount > 1)
            size += (realTotalCount - 1) * sizeof(XPCNativeMember);
        void* place = new char[size];
        if (place)
            obj = new(place) XPCNativeInterface(aInfo, interfaceName);

        if (obj) {
            obj->mMemberCount = realTotalCount;
            // copy valid members
            if (realTotalCount)
                memcpy(obj->mMembers, members,
                       realTotalCount * sizeof(XPCNativeMember));
        }
    }

    if (members && members != local_members)
        delete [] members;

    return obj;
}
// static
XPCNativeInterface*
XPCNativeInterface::NewInstance(nsIInterfaceInfo* aInfo)
{
    AutoJSContext cx;
    static const uint16_t MAX_LOCAL_MEMBER_COUNT = 16;
    XPCNativeMember local_members[MAX_LOCAL_MEMBER_COUNT];
    XPCNativeInterface* obj = nullptr;
    XPCNativeMember* members = nullptr;

    int i;
    bool failed = false;
    uint16_t constCount;
    uint16_t methodCount;
    uint16_t totalCount;
    uint16_t realTotalCount = 0;
    XPCNativeMember* cur;
    RootedString str(cx);
    RootedId interfaceName(cx);

    // XXX Investigate lazy init? This is a problem given the
    // 'placement new' scheme - we need to at least know how big to make
    // the object. We might do a scan of methods to determine needed size,
    // then make our object, but avoid init'ing *any* members until asked?
    // Find out how often we create these objects w/o really looking at
    // (or using) the members.

    bool canScript;
    if (NS_FAILED(aInfo->IsScriptable(&canScript)) || !canScript)
        return nullptr;

    bool mainProcessScriptableOnly;
    if (NS_FAILED(aInfo->IsMainProcessScriptableOnly(&mainProcessScriptableOnly)))
        return nullptr;
    if (mainProcessScriptableOnly && !XRE_IsParentProcess()) {
        nsCOMPtr<nsIConsoleService> console(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
        if (console) {
            const char* intfNameChars;
            aInfo->GetNameShared(&intfNameChars);
            nsPrintfCString errorMsg("Use of %s in content process is deprecated.", intfNameChars);

            nsAutoString filename;
            uint32_t lineno = 0, column = 0;
            nsJSUtils::GetCallingLocation(cx, filename, &lineno, &column);
            nsCOMPtr<nsIScriptError> error(do_CreateInstance(NS_SCRIPTERROR_CONTRACTID));
            error->Init(NS_ConvertUTF8toUTF16(errorMsg),
                        filename, EmptyString(),
                        lineno, column, nsIScriptError::warningFlag, "chrome javascript");
            console->LogMessage(error);
        }
    }

    if (NS_FAILED(aInfo->GetMethodCount(&methodCount)) ||
            NS_FAILED(aInfo->GetConstantCount(&constCount)))
        return nullptr;

    // If the interface does not have nsISupports in its inheritance chain
    // then we know we can't reflect its methods. However, some interfaces that
    // are used just to reflect constants are declared this way. We need to
    // go ahead and build the thing. But, we'll ignore whatever methods it may
    // have.
    if (!nsXPConnect::IsISupportsDescendant(aInfo))
        methodCount = 0;

    totalCount = methodCount + constCount;

    if (totalCount > MAX_LOCAL_MEMBER_COUNT) {
        members = new XPCNativeMember[totalCount];
        if (!members)
            return nullptr;
    } else {
        members = local_members;
    }

    // NOTE: since getters and setters share a member, we might not use all
    // of the member objects.

    for (i = 0; i < methodCount; i++) {
        const nsXPTMethodInfo* info;
        if (NS_FAILED(aInfo->GetMethodInfo(i, &info))) {
            failed = true;
            break;
        }

        // don't reflect Addref or Release
        if (i == 1 || i == 2)
            continue;

        if (!XPCConvert::IsMethodReflectable(*info))
            continue;

        str = JS_AtomizeAndPinString(cx, info->GetName());
        if (!str) {
            NS_ERROR("bad method name");
            failed = true;
            break;
        }
        jsid name = INTERNED_STRING_TO_JSID(cx, str);

        if (info->IsSetter()) {
            MOZ_ASSERT(realTotalCount,"bad setter");
            // Note: ASSUMES Getter/Setter pairs are next to each other
            // This is a rule of the typelib spec.
            cur = &members[realTotalCount-1];
            MOZ_ASSERT(cur->GetName() == name,"bad setter");
            MOZ_ASSERT(cur->IsReadOnlyAttribute(),"bad setter");
            MOZ_ASSERT(cur->GetIndex() == i-1,"bad setter");
            cur->SetWritableAttribute();
        } else {
            // XXX need better way to find dups
            // MOZ_ASSERT(!LookupMemberByID(name),"duplicate method name");
            if (realTotalCount == XPCNativeMember::GetMaxIndexInInterface()) {
                NS_WARNING("Too many members in interface");
                failed = true;
                break;
            }
            cur = &members[realTotalCount];
            cur->SetName(name);
            if (info->IsGetter())
                cur->SetReadOnlyAttribute(i);
            else
                cur->SetMethod(i);
            cur->SetIndexInInterface(realTotalCount);
            ++realTotalCount;
        }
    }

    if (!failed) {
        for (i = 0; i < constCount; i++) {
            RootedValue constant(cx);
            nsXPIDLCString namestr;
            if (NS_FAILED(aInfo->GetConstant(i, &constant, getter_Copies(namestr)))) {
                failed = true;
                break;
            }

            str = JS_AtomizeAndPinString(cx, namestr);
            if (!str) {
                NS_ERROR("bad constant name");
                failed = true;
                break;
            }
            jsid name = INTERNED_STRING_TO_JSID(cx, str);

            // XXX need better way to find dups
            //MOZ_ASSERT(!LookupMemberByID(name),"duplicate method/constant name");
            if (realTotalCount == XPCNativeMember::GetMaxIndexInInterface()) {
                NS_WARNING("Too many members in interface");
                failed = true;
                break;
            }
            cur = &members[realTotalCount];
            cur->SetName(name);
            cur->SetConstant(i);
            cur->SetIndexInInterface(realTotalCount);
            ++realTotalCount;
        }
    }

    if (!failed) {
        const char* bytes;
        if (NS_FAILED(aInfo->GetNameShared(&bytes)) || !bytes ||
                nullptr == (str = JS_AtomizeAndPinString(cx, bytes))) {
            failed = true;
        }
        interfaceName = INTERNED_STRING_TO_JSID(cx, str);
    }

    if (!failed) {
        // Use placement new to create an object with the right amount of space
        // to hold the members array
        int size = sizeof(XPCNativeInterface);
        if (realTotalCount > 1)
            size += (realTotalCount - 1) * sizeof(XPCNativeMember);
        void* place = new char[size];
        if (place)
            obj = new(place) XPCNativeInterface(aInfo, interfaceName);

        if (obj) {
            obj->mMemberCount = realTotalCount;
            // copy valid members
            if (realTotalCount)
                memcpy(obj->mMembers, members,
                       realTotalCount * sizeof(XPCNativeMember));
        }
    }

    if (members && members != local_members)
        delete [] members;

    return obj;
}