Tue, 06 Jan 2015 21:39:09 +0100
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 ¶mInfo = 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 ¶mInfo = 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