tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

XPCCallContext.cpp (5616B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 /* Call context. */
      8 
      9 #include "xpcprivate.h"
     10 #include "jsfriendapi.h"
     11 #include "js/Object.h"  // JS::GetClass, JS::GetReservedSlot
     12 #include "js/Wrapper.h"
     13 #include "nsContentUtils.h"
     14 
     15 using namespace mozilla;
     16 using namespace xpc;
     17 using namespace JS;
     18 
     19 static inline bool IsTearoffClass(const JSClass* clazz) {
     20  return clazz == &XPC_WN_Tearoff_JSClass;
     21 }
     22 
     23 XPCCallContext::XPCCallContext(
     24    JSContext* cx, HandleObject obj /* = nullptr               */,
     25    HandleObject funobj /* = nullptr               */,
     26    HandleId name /* = JSID_VOID             */, unsigned argc /* = NO_ARGS */,
     27    Value* argv /* = nullptr */, Value* rval /* = nullptr               */)
     28    : mState(INIT_FAILED),
     29      mXPC(nsXPConnect::XPConnect()),
     30      mXPCJSContext(nullptr),
     31      mJSContext(cx),
     32      mWrapper(nullptr),
     33      mTearOff(nullptr),
     34      mMember(nullptr),
     35      mName(cx),
     36      mStaticMemberIsLocal(false),
     37      mArgc(0),
     38      mArgv(nullptr),
     39      mRetVal(nullptr) {
     40  MOZ_ASSERT(cx);
     41  MOZ_ASSERT(cx == nsContentUtils::GetCurrentJSContext());
     42 
     43  if (!mXPC) {
     44    return;
     45  }
     46 
     47  mXPCJSContext = XPCJSContext::Get();
     48 
     49  // hook into call context chain.
     50  mPrevCallContext = mXPCJSContext->SetCallContext(this);
     51 
     52  mState = HAVE_CONTEXT;
     53 
     54  if (!obj) {
     55    return;
     56  }
     57 
     58  mMethodIndex = 0xDEAD;
     59 
     60  mState = HAVE_OBJECT;
     61 
     62  mTearOff = nullptr;
     63 
     64  JSObject* unwrapped =
     65      js::CheckedUnwrapDynamic(obj, cx, /* stopAtWindowProxy = */ false);
     66  if (!unwrapped) {
     67    JS_ReportErrorASCII(mJSContext,
     68                        "Permission denied to call method on |this|");
     69    mState = INIT_FAILED;
     70    return;
     71  }
     72  const JSClass* clasp = JS::GetClass(unwrapped);
     73  if (clasp->isWrappedNative()) {
     74    mWrapper = XPCWrappedNative::Get(unwrapped);
     75  } else if (IsTearoffClass(clasp)) {
     76    mTearOff = XPCWrappedNativeTearOff::Get(unwrapped);
     77    mWrapper = XPCWrappedNative::Get(
     78        &JS::GetReservedSlot(unwrapped, XPCWrappedNativeTearOff::FlatObjectSlot)
     79             .toObject());
     80  }
     81  if (mWrapper && !mTearOff) {
     82    mScriptable = mWrapper->GetScriptable();
     83  }
     84 
     85  if (!name.isVoid()) {
     86    SetName(name);
     87  }
     88 
     89  if (argc != NO_ARGS) {
     90    SetArgsAndResultPtr(argc, argv, rval);
     91  }
     92 
     93  CHECK_STATE(HAVE_OBJECT);
     94 }
     95 
     96 void XPCCallContext::SetName(jsid name) {
     97  CHECK_STATE(HAVE_OBJECT);
     98 
     99  mName = name;
    100 
    101  if (mTearOff) {
    102    mSet = nullptr;
    103    mInterface = mTearOff->GetInterface();
    104    mMember = mInterface->FindMember(mName);
    105    mStaticMemberIsLocal = true;
    106    if (mMember && !mMember->IsConstant()) {
    107      mMethodIndex = mMember->GetIndex();
    108    }
    109  } else {
    110    mSet = mWrapper ? mWrapper->GetSet() : nullptr;
    111 
    112    if (mSet &&
    113        mSet->FindMember(
    114            mName, &mMember, &mInterface,
    115            mWrapper->HasProto() ? mWrapper->GetProto()->GetSet() : nullptr,
    116            &mStaticMemberIsLocal)) {
    117      if (mMember && !mMember->IsConstant()) {
    118        mMethodIndex = mMember->GetIndex();
    119      }
    120    } else {
    121      mMember = nullptr;
    122      mInterface = nullptr;
    123      mStaticMemberIsLocal = false;
    124    }
    125  }
    126 
    127  mState = HAVE_NAME;
    128 }
    129 
    130 void XPCCallContext::SetCallInfo(XPCNativeInterface* iface,
    131                                 XPCNativeMember* member, bool isSetter) {
    132  CHECK_STATE(HAVE_CONTEXT);
    133 
    134  // We are going straight to the method info and need not do a lookup
    135  // by id.
    136 
    137  // don't be tricked if method is called with wrong 'this'
    138  if (mTearOff && mTearOff->GetInterface() != iface) {
    139    mTearOff = nullptr;
    140  }
    141 
    142  mSet = nullptr;
    143  mInterface = iface;
    144  mMember = member;
    145  mMethodIndex = mMember->GetIndex() + (isSetter ? 1 : 0);
    146  mName = mMember->GetName();
    147 
    148  if (mState < HAVE_NAME) {
    149    mState = HAVE_NAME;
    150  }
    151 }
    152 
    153 void XPCCallContext::SetArgsAndResultPtr(unsigned argc, Value* argv,
    154                                         Value* rval) {
    155  CHECK_STATE(HAVE_OBJECT);
    156 
    157  if (mState < HAVE_NAME) {
    158    mSet = nullptr;
    159    mInterface = nullptr;
    160    mMember = nullptr;
    161    mStaticMemberIsLocal = false;
    162  }
    163 
    164  mArgc = argc;
    165  mArgv = argv;
    166  mRetVal = rval;
    167 
    168  mState = HAVE_ARGS;
    169 }
    170 
    171 nsresult XPCCallContext::CanCallNow() {
    172  nsresult rv;
    173 
    174  if (!HasInterfaceAndMember()) {
    175    return NS_ERROR_UNEXPECTED;
    176  }
    177  if (mState < HAVE_ARGS) {
    178    return NS_ERROR_UNEXPECTED;
    179  }
    180 
    181  if (!mTearOff) {
    182    mTearOff = mWrapper->FindTearOff(mJSContext, mInterface, false, &rv);
    183    if (!mTearOff || mTearOff->GetInterface() != mInterface) {
    184      mTearOff = nullptr;
    185      return NS_FAILED(rv) ? rv : NS_ERROR_UNEXPECTED;
    186    }
    187  }
    188 
    189  // Refresh in case FindTearOff extended the set
    190  mSet = mWrapper->GetSet();
    191 
    192  mState = READY_TO_CALL;
    193  return NS_OK;
    194 }
    195 
    196 void XPCCallContext::SystemIsBeingShutDown() {
    197  // XXX This is pretty questionable since the per thread cleanup stuff
    198  // can be making this call on one thread for call contexts on another
    199  // thread.
    200  NS_WARNING(
    201      "Shutting Down XPConnect even through there is a live XPCCallContext");
    202  mXPCJSContext = nullptr;
    203  mState = SYSTEM_SHUTDOWN;
    204  mSet = nullptr;
    205  mInterface = nullptr;
    206 
    207  if (mPrevCallContext) {
    208    mPrevCallContext->SystemIsBeingShutDown();
    209  }
    210 }
    211 
    212 XPCCallContext::~XPCCallContext() {
    213  if (mXPCJSContext) {
    214    DebugOnly<XPCCallContext*> old =
    215        mXPCJSContext->SetCallContext(mPrevCallContext);
    216    MOZ_ASSERT(old == this, "bad pop from per thread data");
    217  }
    218 }