dom/xslt/xpath/txXPCOMExtensionFunction.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "nsAutoPtr.h"
     7 #include "nsComponentManagerUtils.h"
     8 #include "nsDependentString.h"
     9 #include "nsIAtom.h"
    10 #include "nsIInterfaceInfoManager.h"
    11 #include "nsServiceManagerUtils.h"
    12 #include "txExpr.h"
    13 #include "txIFunctionEvaluationContext.h"
    14 #include "txIXPathContext.h"
    15 #include "txNodeSetAdaptor.h"
    16 #include "txXPathTreeWalker.h"
    17 #include "xptcall.h"
    18 #include "txXPathObjectAdaptor.h"
    19 #include "mozilla/Attributes.h"
    20 #include "nsIClassInfo.h"
    21 #include "nsIInterfaceInfo.h"
    23 NS_IMPL_ISUPPORTS(txXPathObjectAdaptor, txIXPathObject)
    25 class txFunctionEvaluationContext MOZ_FINAL : public txIFunctionEvaluationContext
    26 {
    27 public:
    28     txFunctionEvaluationContext(txIEvalContext *aContext, nsISupports *aState);
    30     NS_DECL_ISUPPORTS
    31     NS_DECL_TXIFUNCTIONEVALUATIONCONTEXT
    33     void ClearContext()
    34     {
    35         mContext = nullptr;
    36     }
    38 private:
    39     txIEvalContext *mContext;
    40     nsCOMPtr<nsISupports> mState;
    41 };
    43 txFunctionEvaluationContext::txFunctionEvaluationContext(txIEvalContext *aContext,
    44                                                          nsISupports *aState)
    45     : mContext(aContext),
    46       mState(aState)
    47 {
    48 }
    50 NS_IMPL_ISUPPORTS(txFunctionEvaluationContext, txIFunctionEvaluationContext)
    52 NS_IMETHODIMP
    53 txFunctionEvaluationContext::GetPosition(uint32_t *aPosition)
    54 {
    55     NS_ENSURE_TRUE(mContext, NS_ERROR_FAILURE);
    57     *aPosition = mContext->position();
    59     return NS_OK;
    60 }
    62 NS_IMETHODIMP
    63 txFunctionEvaluationContext::GetSize(uint32_t *aSize)
    64 {
    65     NS_ENSURE_TRUE(mContext, NS_ERROR_FAILURE);
    67     *aSize = mContext->size();
    69     return NS_OK;
    70 }
    72 NS_IMETHODIMP
    73 txFunctionEvaluationContext::GetContextNode(nsIDOMNode **aNode)
    74 {
    75     NS_ENSURE_TRUE(mContext, NS_ERROR_FAILURE);
    77     return txXPathNativeNode::getNode(mContext->getContextNode(), aNode);
    78 }
    80 NS_IMETHODIMP
    81 txFunctionEvaluationContext::GetState(nsISupports **aState)
    82 {
    83     NS_IF_ADDREF(*aState = mState);
    85     return NS_OK;
    86 }
    88 enum txArgumentType {
    89     eBOOLEAN = nsXPTType::T_BOOL,
    90     eNUMBER = nsXPTType::T_DOUBLE,
    91     eSTRING = nsXPTType::T_DOMSTRING,
    92     eNODESET,
    93     eCONTEXT,
    94     eOBJECT,
    95     eUNKNOWN
    96 };
    98 class txXPCOMExtensionFunctionCall : public FunctionCall
    99 {
   100 public:
   101     txXPCOMExtensionFunctionCall(nsISupports *aHelper, const nsIID &aIID,
   102                                  uint16_t aMethodIndex,
   103 #ifdef TX_TO_STRING
   104                                  nsIAtom *aName,
   105 #endif
   106                                  nsISupports *aState);
   108     TX_DECL_FUNCTION
   110 private:
   111     txArgumentType GetParamType(const nsXPTParamInfo &aParam,
   112                                 nsIInterfaceInfo *aInfo);
   114     nsCOMPtr<nsISupports> mHelper;
   115     nsIID mIID;
   116     uint16_t mMethodIndex;
   117 #ifdef TX_TO_STRING
   118     nsCOMPtr<nsIAtom> mName;
   119 #endif
   120     nsCOMPtr<nsISupports> mState;
   121 };
   123 txXPCOMExtensionFunctionCall::txXPCOMExtensionFunctionCall(nsISupports *aHelper,
   124                                                            const nsIID &aIID,
   125                                                            uint16_t aMethodIndex,
   126 #ifdef TX_TO_STRING
   127                                                            nsIAtom *aName,
   128 #endif
   129                                                            nsISupports *aState)
   130     : mHelper(aHelper),
   131       mIID(aIID),
   132       mMethodIndex(aMethodIndex),
   133 #ifdef TX_TO_STRING
   134       mName(aName),
   135 #endif
   136       mState(aState)
   137 {
   138 }
   140 class txInterfacesArrayHolder
   141 {
   142 public:
   143     txInterfacesArrayHolder(nsIID **aArray, uint32_t aCount) : mArray(aArray),
   144                                                                mCount(aCount)
   145     {
   146     }
   147     ~txInterfacesArrayHolder()
   148     {
   149         NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(mCount, mArray);
   150     }
   152 private:
   153     nsIID **mArray;
   154     uint32_t mCount;
   155 };
   157 static nsresult
   158 LookupFunction(const char *aContractID, nsIAtom* aName, nsIID &aIID,
   159                uint16_t &aMethodIndex, nsISupports **aHelper)
   160 {
   161     nsresult rv;
   162     nsCOMPtr<nsISupports> helper = do_GetService(aContractID, &rv);
   163     NS_ENSURE_SUCCESS(rv, rv);
   165     nsCOMPtr<nsIClassInfo> classInfo = do_QueryInterface(helper, &rv);
   166     NS_ENSURE_SUCCESS(rv, rv);
   168     nsCOMPtr<nsIInterfaceInfoManager> iim =
   169         do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID);
   170     NS_ENSURE_TRUE(iim, NS_ERROR_FAILURE);
   172     nsIID** iidArray = nullptr;
   173     uint32_t iidCount = 0;
   174     rv = classInfo->GetInterfaces(&iidCount, &iidArray);
   175     NS_ENSURE_SUCCESS(rv, rv);
   177     txInterfacesArrayHolder holder(iidArray, iidCount);
   179     // Remove any minus signs and uppercase the following letter (so
   180     // foo-bar becomes fooBar). Note that if there are any names that already
   181     // have uppercase letters they might cause false matches (both fooBar and
   182     // foo-bar matching fooBar).
   183     const char16_t *name = aName->GetUTF16String();
   184     nsAutoCString methodName;
   185     char16_t letter;
   186     bool upperNext = false;
   187     while ((letter = *name)) {
   188         if (letter == '-') {
   189             upperNext = true;
   190         }
   191         else {
   192             MOZ_ASSERT(nsCRT::IsAscii(letter),
   193                        "invalid static_cast coming up");
   194             methodName.Append(upperNext ?
   195                               nsCRT::ToUpper(static_cast<char>(letter)) :
   196                               letter);
   197             upperNext = false;
   198         }
   199         ++name;
   200     }
   202     uint32_t i;
   203     for (i = 0; i < iidCount; ++i) {
   204         nsIID *iid = iidArray[i];
   206         nsCOMPtr<nsIInterfaceInfo> info;
   207         rv = iim->GetInfoForIID(iid, getter_AddRefs(info));
   208         NS_ENSURE_SUCCESS(rv, rv);
   210         uint16_t methodIndex;
   211         const nsXPTMethodInfo *methodInfo;
   212         rv = info->GetMethodInfoForName(methodName.get(), &methodIndex,
   213                                         &methodInfo);
   214         if (NS_SUCCEEDED(rv)) {
   215             // Exclude notxpcom and hidden. Also check that we have at least a
   216             // return value (the xpidl compiler ensures that that return value
   217             // is the last argument).
   218             uint8_t paramCount = methodInfo->GetParamCount();
   219             if (methodInfo->IsNotXPCOM() || methodInfo->IsHidden() ||
   220                 paramCount == 0 ||
   221                 !methodInfo->GetParam(paramCount - 1).IsRetval()) {
   222                 return NS_ERROR_FAILURE;
   223             }
   225             aIID = *iid;
   226             aMethodIndex = methodIndex;
   227             return helper->QueryInterface(aIID, (void**)aHelper);
   228         }
   229     }
   231     return NS_ERROR_XPATH_UNKNOWN_FUNCTION;
   232 }
   234 /* static */
   235 nsresult
   236 TX_ResolveFunctionCallXPCOM(const nsCString &aContractID, int32_t aNamespaceID,
   237                             nsIAtom* aName, nsISupports *aState,
   238                             FunctionCall **aFunction)
   239 {
   240     nsIID iid;
   241     uint16_t methodIndex = 0;
   242     nsCOMPtr<nsISupports> helper;
   244     nsresult rv = LookupFunction(aContractID.get(), aName, iid, methodIndex,
   245                                  getter_AddRefs(helper));
   246     NS_ENSURE_SUCCESS(rv, rv);
   248     if (!aFunction) {
   249         return NS_OK;
   250     }
   252     *aFunction = new txXPCOMExtensionFunctionCall(helper, iid, methodIndex,
   253 #ifdef TX_TO_STRING
   254                                                   aName,
   255 #endif
   256                                                   aState);
   258     return *aFunction ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
   259 }
   261 txArgumentType
   262 txXPCOMExtensionFunctionCall::GetParamType(const nsXPTParamInfo &aParam,
   263                                            nsIInterfaceInfo *aInfo)
   264 {
   265     uint8_t tag = aParam.GetType().TagPart();
   266     switch (tag) {
   267         case nsXPTType::T_BOOL:
   268         case nsXPTType::T_DOUBLE:
   269         case nsXPTType::T_DOMSTRING:
   270         {
   271             return txArgumentType(tag);
   272         }
   273         case nsXPTType::T_INTERFACE:
   274         case nsXPTType::T_INTERFACE_IS:
   275         {
   276             nsIID iid;
   277             aInfo->GetIIDForParamNoAlloc(mMethodIndex, &aParam, &iid);
   278             if (iid.Equals(NS_GET_IID(txINodeSet))) {
   279                 return eNODESET;
   280             }
   281             if (iid.Equals(NS_GET_IID(txIFunctionEvaluationContext))) {
   282                 return eCONTEXT;
   283             }
   284             if (iid.Equals(NS_GET_IID(txIXPathObject))) {
   285                 return eOBJECT;
   286             }
   287         }
   288         // FALLTHROUGH
   289         default:
   290         {
   291             // XXX Error!
   292             return eUNKNOWN;
   293         }
   294     }
   295 }
   297 class txParamArrayHolder
   298 {
   299 public:
   300     txParamArrayHolder()
   301         : mCount(0)
   302     {
   303     }
   304     ~txParamArrayHolder();
   306     bool Init(uint8_t aCount);
   307     operator nsXPTCVariant*() const
   308     {
   309       return mArray;
   310     }
   312 private:
   313     nsAutoArrayPtr<nsXPTCVariant> mArray;
   314     uint8_t mCount;
   315 };
   317 txParamArrayHolder::~txParamArrayHolder()
   318 {
   319     uint8_t i;
   320     for (i = 0; i < mCount; ++i) {
   321         nsXPTCVariant &variant = mArray[i];
   322         if (variant.DoesValNeedCleanup()) {
   323             if (variant.type.TagPart() == nsXPTType::T_DOMSTRING)
   324                 delete (nsAString*)variant.val.p;
   325             else {
   326                 NS_ABORT_IF_FALSE(variant.type.TagPart() == nsXPTType::T_INTERFACE ||
   327                                   variant.type.TagPart() == nsXPTType::T_INTERFACE_IS,
   328                                   "We only support cleanup of strings and interfaces "
   329                                   "here, and this looks like neither!");
   330                 static_cast<nsISupports*>(variant.val.p)->Release();
   331             }
   332         }
   333     }
   334 }
   336 bool
   337 txParamArrayHolder::Init(uint8_t aCount)
   338 {
   339     mCount = aCount;
   340     mArray = new nsXPTCVariant[mCount];
   341     if (!mArray) {
   342         return false;
   343     }
   345     memset(mArray, 0, mCount * sizeof(nsXPTCVariant));
   347     return true;
   348 }
   350 nsresult
   351 txXPCOMExtensionFunctionCall::evaluate(txIEvalContext* aContext,
   352                                        txAExprResult** aResult)
   353 {
   354     nsCOMPtr<nsIInterfaceInfoManager> iim =
   355         do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID);
   356     NS_ENSURE_TRUE(iim, NS_ERROR_FAILURE);
   358     nsCOMPtr<nsIInterfaceInfo> info;
   359     nsresult rv = iim->GetInfoForIID(&mIID, getter_AddRefs(info));
   360     NS_ENSURE_SUCCESS(rv, rv);
   362     const nsXPTMethodInfo *methodInfo;
   363     rv = info->GetMethodInfo(mMethodIndex, &methodInfo);
   364     NS_ENSURE_SUCCESS(rv, rv);
   366     uint8_t paramCount = methodInfo->GetParamCount();
   367     uint8_t inArgs = paramCount - 1;
   369     txParamArrayHolder invokeParams;
   370     if (!invokeParams.Init(paramCount)) {
   371         return NS_ERROR_OUT_OF_MEMORY;
   372     }
   374     const nsXPTParamInfo &paramInfo = methodInfo->GetParam(0);
   375     txArgumentType type = GetParamType(paramInfo, info);
   376     if (type == eUNKNOWN) {
   377         return NS_ERROR_FAILURE;
   378     }
   380     txFunctionEvaluationContext *context;
   381     uint32_t paramStart = 0;
   382     if (type == eCONTEXT) {
   383         if (paramInfo.IsOut()) {
   384             // We don't support out values.
   385             return NS_ERROR_FAILURE;
   386         }
   388         // Create context wrapper.
   389         context = new txFunctionEvaluationContext(aContext, mState);
   390         if (!context) {
   391             return NS_ERROR_OUT_OF_MEMORY;
   392         }
   394         nsXPTCVariant &invokeParam = invokeParams[0];
   395         invokeParam.type = paramInfo.GetType();
   396         invokeParam.SetValNeedsCleanup();
   397         NS_ADDREF((txIFunctionEvaluationContext*&)invokeParam.val.p = context);
   399         // Skip first argument, since it's the context.
   400         paramStart = 1;
   401     }
   402     else {
   403         context = nullptr;
   404     }
   406     // XXX varargs
   407     if (!requireParams(inArgs - paramStart, inArgs - paramStart, aContext)) {
   408         return NS_ERROR_FAILURE;
   409     }
   411     uint32_t i;
   412     for (i = paramStart; i < inArgs; ++i) {
   413         Expr* expr = mParams[i - paramStart];
   415         const nsXPTParamInfo &paramInfo = methodInfo->GetParam(i);
   416         txArgumentType type = GetParamType(paramInfo, info);
   417         if (type == eUNKNOWN) {
   418             return NS_ERROR_FAILURE;
   419         }
   421         nsXPTCVariant &invokeParam = invokeParams[i];
   422         if (paramInfo.IsOut()) {
   423             // We don't support out values.
   424             return NS_ERROR_FAILURE;
   425         }
   427         invokeParam.type = paramInfo.GetType();
   428         switch (type) {
   429             case eNODESET:
   430             {
   431                 nsRefPtr<txNodeSet> nodes;
   432                 rv = evaluateToNodeSet(expr, aContext, getter_AddRefs(nodes));
   433                 NS_ENSURE_SUCCESS(rv, rv);
   435                 txNodeSetAdaptor *adaptor = new txNodeSetAdaptor(nodes);
   436                 if (!adaptor) {
   437                     return NS_ERROR_OUT_OF_MEMORY;
   438                 }
   440                 nsCOMPtr<txINodeSet> nodeSet = adaptor;
   441                 rv = adaptor->Init();
   442                 NS_ENSURE_SUCCESS(rv, rv);
   444                 invokeParam.SetValNeedsCleanup();
   445                 nodeSet.swap((txINodeSet*&)invokeParam.val.p);
   446                 break;
   447             }
   448             case eBOOLEAN:
   449             {
   450                 rv = expr->evaluateToBool(aContext, invokeParam.val.b);
   451                 NS_ENSURE_SUCCESS(rv, rv);
   453                 break;
   454             }
   455             case eNUMBER:
   456             {
   457                 double dbl;
   458                 rv = evaluateToNumber(mParams[0], aContext, &dbl);
   459                 NS_ENSURE_SUCCESS(rv, rv);
   461                 invokeParam.val.d = dbl;
   462                 break;
   463             }
   464             case eSTRING:
   465             {
   466                 nsString *value = new nsString();
   467                 if (!value) {
   468                     return NS_ERROR_OUT_OF_MEMORY;
   469                 }
   471                 rv = expr->evaluateToString(aContext, *value);
   472                 NS_ENSURE_SUCCESS(rv, rv);
   474                 invokeParam.SetValNeedsCleanup();
   475                 invokeParam.val.p = value;
   476                 break;
   477             }
   478             case eOBJECT:
   479             {
   480               nsRefPtr<txAExprResult> exprRes;
   481               rv = expr->evaluate(aContext, getter_AddRefs(exprRes));
   482               NS_ENSURE_SUCCESS(rv, rv);
   484               nsCOMPtr<txIXPathObject> adaptor =
   485                 new txXPathObjectAdaptor(exprRes);
   486               if (!adaptor) {
   487                   return NS_ERROR_OUT_OF_MEMORY;
   488               }
   490               invokeParam.SetValNeedsCleanup();
   491               adaptor.swap((txIXPathObject*&)invokeParam.val.p);
   492               break;
   493             }
   494             case eCONTEXT:
   495             case eUNKNOWN:
   496             {
   497                 // We only support passing the context as the *first* argument.
   498                 return NS_ERROR_FAILURE;
   499             }
   500         }
   501     }
   503     const nsXPTParamInfo &returnInfo = methodInfo->GetParam(inArgs);
   504     txArgumentType returnType = GetParamType(returnInfo, info);
   505     if (returnType == eUNKNOWN) {
   506         return NS_ERROR_FAILURE;
   507     }
   509     nsXPTCVariant &returnParam = invokeParams[inArgs];
   510     returnParam.type = returnInfo.GetType();
   511     if (returnType == eSTRING) {
   512         nsString *value = new nsString();
   513         if (!value) {
   514             return NS_ERROR_FAILURE;
   515         }
   517         returnParam.SetValNeedsCleanup();
   518         returnParam.val.p = value;
   519     }
   520     else {
   521         returnParam.SetIndirect();
   522         if (returnType == eNODESET || returnType == eOBJECT) {
   523             returnParam.SetValNeedsCleanup();
   524         }
   525     }
   527     rv = NS_InvokeByIndex(mHelper, mMethodIndex, paramCount, invokeParams);
   529     // In case someone is holding on to the txFunctionEvaluationContext which
   530     // could thus stay alive longer than this function.
   531     if (context) {
   532         context->ClearContext();
   533     }
   535     NS_ENSURE_SUCCESS(rv, rv);
   537     switch (returnType) {
   538         case eNODESET:
   539         {
   540             txINodeSet* nodeSet = static_cast<txINodeSet*>(returnParam.val.p);
   541             nsCOMPtr<txIXPathObject> object = do_QueryInterface(nodeSet, &rv);
   542             NS_ENSURE_SUCCESS(rv, rv);
   544             NS_ADDREF(*aResult = object->GetResult());
   546             return NS_OK;
   547         }
   548         case eBOOLEAN:
   549         {
   550             aContext->recycler()->getBoolResult(returnParam.val.b, aResult);
   552             return NS_OK;
   553         }
   554         case eNUMBER:
   555         {
   556             return aContext->recycler()->getNumberResult(returnParam.val.d,
   557                                                          aResult);
   558         }
   559         case eSTRING:
   560         {
   561             nsString *returned = static_cast<nsString*>
   562                                             (returnParam.val.p);
   563             return aContext->recycler()->getStringResult(*returned, aResult);
   564         }
   565         case eOBJECT:
   566         {
   567             txIXPathObject *object =
   568                  static_cast<txIXPathObject*>(returnParam.val.p);
   570             NS_ADDREF(*aResult = object->GetResult());
   572             return NS_OK;
   573         }
   574         default:
   575         {
   576             // Huh?
   577             return NS_ERROR_FAILURE;
   578         }
   579     }
   580 }
   582 Expr::ResultType
   583 txXPCOMExtensionFunctionCall::getReturnType()
   584 {
   585     // It doesn't really matter what we return here, but it might
   586     // be a good idea to try to keep this as unoptimizable as possible
   587     return ANY_RESULT;
   588 }
   590 bool
   591 txXPCOMExtensionFunctionCall::isSensitiveTo(ContextSensitivity aContext)
   592 {
   593     // It doesn't really matter what we return here, but it might
   594     // be a good idea to try to keep this as unoptimizable as possible
   595     return true;
   596 }
   598 #ifdef TX_TO_STRING
   599 nsresult
   600 txXPCOMExtensionFunctionCall::getNameAtom(nsIAtom** aAtom)
   601 {
   602     NS_ADDREF(*aAtom = mName);
   604     return NS_OK;
   605 }
   606 #endif

mercurial