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 "mozilla/Attributes.h"
8 #include "nsArrayEnumerator.h"
10 #include "nsIArray.h"
11 #include "nsISimpleEnumerator.h"
13 #include "nsCOMArray.h"
14 #include "nsCOMPtr.h"
16 class nsSimpleArrayEnumerator MOZ_FINAL : public nsISimpleEnumerator
17 {
18 public:
19 // nsISupports interface
20 NS_DECL_ISUPPORTS
22 // nsISimpleEnumerator interface
23 NS_DECL_NSISIMPLEENUMERATOR
25 // nsSimpleArrayEnumerator methods
26 nsSimpleArrayEnumerator(nsIArray* aValueArray) :
27 mValueArray(aValueArray), mIndex(0) {
28 }
30 private:
31 ~nsSimpleArrayEnumerator() {}
33 protected:
34 nsCOMPtr<nsIArray> mValueArray;
35 uint32_t mIndex;
36 };
38 NS_IMPL_ISUPPORTS(nsSimpleArrayEnumerator, nsISimpleEnumerator)
40 NS_IMETHODIMP
41 nsSimpleArrayEnumerator::HasMoreElements(bool* aResult)
42 {
43 NS_PRECONDITION(aResult != 0, "null ptr");
44 if (! aResult)
45 return NS_ERROR_NULL_POINTER;
47 if (!mValueArray) {
48 *aResult = false;
49 return NS_OK;
50 }
52 uint32_t cnt;
53 nsresult rv = mValueArray->GetLength(&cnt);
54 if (NS_FAILED(rv)) return rv;
55 *aResult = (mIndex < cnt);
56 return NS_OK;
57 }
59 NS_IMETHODIMP
60 nsSimpleArrayEnumerator::GetNext(nsISupports** aResult)
61 {
62 NS_PRECONDITION(aResult != 0, "null ptr");
63 if (! aResult)
64 return NS_ERROR_NULL_POINTER;
66 if (!mValueArray) {
67 *aResult = nullptr;
68 return NS_OK;
69 }
71 uint32_t cnt;
72 nsresult rv = mValueArray->GetLength(&cnt);
73 if (NS_FAILED(rv)) return rv;
74 if (mIndex >= cnt)
75 return NS_ERROR_UNEXPECTED;
77 return mValueArray->QueryElementAt(mIndex++, NS_GET_IID(nsISupports), (void**)aResult);
78 }
80 nsresult
81 NS_NewArrayEnumerator(nsISimpleEnumerator* *result,
82 nsIArray* array)
83 {
84 nsSimpleArrayEnumerator* enumer = new nsSimpleArrayEnumerator(array);
85 if (enumer == nullptr)
86 return NS_ERROR_OUT_OF_MEMORY;
88 NS_ADDREF(*result = enumer);
89 return NS_OK;
90 }
92 ////////////////////////////////////////////////////////////////////////////////
94 // enumerator implementation for nsCOMArray
95 // creates a snapshot of the array in question
96 // you MUST use NS_NewArrayEnumerator to create this, so that
97 // allocation is done correctly
98 class nsCOMArrayEnumerator MOZ_FINAL : public nsISimpleEnumerator
99 {
100 public:
101 // nsISupports interface
102 NS_DECL_ISUPPORTS
104 // nsISimpleEnumerator interface
105 NS_DECL_NSISIMPLEENUMERATOR
107 // nsSimpleArrayEnumerator methods
108 nsCOMArrayEnumerator() : mIndex(0) {
109 }
111 // specialized operator to make sure we make room for mValues
112 void* operator new (size_t size, const nsCOMArray_base& aArray) CPP_THROW_NEW;
113 void operator delete(void* ptr) {
114 ::operator delete(ptr);
115 }
117 private:
118 ~nsCOMArrayEnumerator(void);
120 protected:
121 uint32_t mIndex; // current position
122 uint32_t mArraySize; // size of the array
124 // this is actually bigger
125 nsISupports* mValueArray[1];
126 };
128 NS_IMPL_ISUPPORTS(nsCOMArrayEnumerator, nsISimpleEnumerator)
130 nsCOMArrayEnumerator::~nsCOMArrayEnumerator()
131 {
132 // only release the entries that we haven't visited yet
133 for (; mIndex < mArraySize; ++mIndex) {
134 NS_IF_RELEASE(mValueArray[mIndex]);
135 }
136 }
138 NS_IMETHODIMP
139 nsCOMArrayEnumerator::HasMoreElements(bool* aResult)
140 {
141 NS_PRECONDITION(aResult != 0, "null ptr");
142 if (! aResult)
143 return NS_ERROR_NULL_POINTER;
145 *aResult = (mIndex < mArraySize);
146 return NS_OK;
147 }
149 NS_IMETHODIMP
150 nsCOMArrayEnumerator::GetNext(nsISupports** aResult)
151 {
152 NS_PRECONDITION(aResult != 0, "null ptr");
153 if (! aResult)
154 return NS_ERROR_NULL_POINTER;
156 if (mIndex >= mArraySize)
157 return NS_ERROR_UNEXPECTED;
159 // pass the ownership of the reference to the caller. Since
160 // we AddRef'ed during creation of |this|, there is no need
161 // to AddRef here
162 *aResult = mValueArray[mIndex++];
164 // this really isn't necessary. just pretend this happens, since
165 // we'll never visit this value again!
166 // mValueArray[(mIndex-1)] = nullptr;
168 return NS_OK;
169 }
171 void*
172 nsCOMArrayEnumerator::operator new (size_t size, const nsCOMArray_base& aArray)
173 CPP_THROW_NEW
174 {
175 // create enough space such that mValueArray points to a large
176 // enough value. Note that the initial value of size gives us
177 // space for mValueArray[0], so we must subtract
178 size += (aArray.Count() - 1) * sizeof(aArray[0]);
180 // do the actual allocation
181 nsCOMArrayEnumerator * result =
182 static_cast<nsCOMArrayEnumerator*>(::operator new(size));
184 // now need to copy over the values, and addref each one
185 // now this might seem like a lot of work, but we're actually just
186 // doing all our AddRef's ahead of time since GetNext() doesn't
187 // need to AddRef() on the way out
188 uint32_t i;
189 uint32_t max = result->mArraySize = aArray.Count();
190 for (i = 0; i<max; i++) {
191 result->mValueArray[i] = aArray[i];
192 NS_IF_ADDREF(result->mValueArray[i]);
193 }
195 return result;
196 }
198 nsresult
199 NS_NewArrayEnumerator(nsISimpleEnumerator* *aResult,
200 const nsCOMArray_base& aArray)
201 {
202 nsCOMArrayEnumerator *enumerator = new (aArray) nsCOMArrayEnumerator();
203 if (!enumerator) return NS_ERROR_OUT_OF_MEMORY;
205 NS_ADDREF(*aResult = enumerator);
206 return NS_OK;
207 }