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: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sts=4 et sw=4 tw=99:
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/. */
7 #ifndef js_Utility_h
8 #define js_Utility_h
10 #include "mozilla/Assertions.h"
11 #include "mozilla/Attributes.h"
12 #include "mozilla/Compiler.h"
13 #include "mozilla/Move.h"
14 #include "mozilla/NullPtr.h"
15 #include "mozilla/Scoped.h"
16 #include "mozilla/TemplateLib.h"
18 #include <stdlib.h>
19 #include <string.h>
21 #ifdef JS_OOM_DO_BACKTRACES
22 #include <execinfo.h>
23 #include <stdio.h>
24 #endif
26 #include "jstypes.h"
28 /* The public JS engine namespace. */
29 namespace JS {}
31 /* The mozilla-shared reusable template/utility namespace. */
32 namespace mozilla {}
34 /* The private JS engine namespace. */
35 namespace js {}
37 /*
38 * Patterns used by SpiderMonkey to overwrite unused memory. If you are
39 * accessing an object with one of these pattern, you probably have a dangling
40 * pointer.
41 */
42 #define JS_FRESH_NURSERY_PATTERN 0x2F
43 #define JS_SWEPT_NURSERY_PATTERN 0x2B
44 #define JS_ALLOCATED_NURSERY_PATTERN 0x2D
45 #define JS_FRESH_TENURED_PATTERN 0x4F
46 #define JS_SWEPT_TENURED_PATTERN 0x4B
47 #define JS_ALLOCATED_TENURED_PATTERN 0x4D
48 #define JS_SWEPT_CODE_PATTERN 0x3b
49 #define JS_SWEPT_FRAME_PATTERN 0x5b
51 #define JS_ASSERT(expr) MOZ_ASSERT(expr)
52 #define JS_ASSERT_IF(cond, expr) MOZ_ASSERT_IF(cond, expr)
54 #define JS_STATIC_ASSERT(cond) static_assert(cond, "JS_STATIC_ASSERT")
55 #define JS_STATIC_ASSERT_IF(cond, expr) MOZ_STATIC_ASSERT_IF(cond, expr, "JS_STATIC_ASSERT_IF")
57 extern MOZ_NORETURN JS_PUBLIC_API(void)
58 JS_Assert(const char *s, const char *file, int ln);
60 /*
61 * Abort the process in a non-graceful manner. This will cause a core file,
62 * call to the debugger or other moral equivalent as well as causing the
63 * entire process to stop.
64 */
65 extern JS_PUBLIC_API(void) JS_Abort(void);
67 /*
68 * Custom allocator support for SpiderMonkey
69 */
70 #if defined JS_USE_CUSTOM_ALLOCATOR
71 # include "jscustomallocator.h"
72 #else
73 # if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
74 /*
75 * In order to test OOM conditions, when the testing function
76 * oomAfterAllocations COUNT is passed, we fail continuously after the NUM'th
77 * allocation from now.
78 */
79 extern JS_PUBLIC_DATA(uint32_t) OOM_maxAllocations; /* set in builtin/TestingFunctions.cpp */
80 extern JS_PUBLIC_DATA(uint32_t) OOM_counter; /* data race, who cares. */
82 #ifdef JS_OOM_BREAKPOINT
83 static MOZ_NEVER_INLINE void js_failedAllocBreakpoint() { asm(""); }
84 #define JS_OOM_CALL_BP_FUNC() js_failedAllocBreakpoint()
85 #else
86 #define JS_OOM_CALL_BP_FUNC() do {} while(0)
87 #endif
89 # define JS_OOM_POSSIBLY_FAIL() \
90 do \
91 { \
92 if (++OOM_counter > OOM_maxAllocations) { \
93 JS_OOM_CALL_BP_FUNC();\
94 return nullptr; \
95 } \
96 } while (0)
98 # else
99 # define JS_OOM_POSSIBLY_FAIL() do {} while(0)
100 # endif /* DEBUG || JS_OOM_BREAKPOINT */
102 static inline void* js_malloc(size_t bytes)
103 {
104 JS_OOM_POSSIBLY_FAIL();
105 return malloc(bytes);
106 }
108 static inline void* js_calloc(size_t bytes)
109 {
110 JS_OOM_POSSIBLY_FAIL();
111 return calloc(bytes, 1);
112 }
114 static inline void* js_calloc(size_t nmemb, size_t size)
115 {
116 JS_OOM_POSSIBLY_FAIL();
117 return calloc(nmemb, size);
118 }
120 static inline void* js_realloc(void* p, size_t bytes)
121 {
122 JS_OOM_POSSIBLY_FAIL();
123 return realloc(p, bytes);
124 }
126 static inline void js_free(void* p)
127 {
128 free(p);
129 }
130 #endif/* JS_USE_CUSTOM_ALLOCATOR */
132 #include <new>
134 /*
135 * Low-level memory management in SpiderMonkey:
136 *
137 * ** Do not use the standard malloc/free/realloc: SpiderMonkey allows these
138 * to be redefined (via JS_USE_CUSTOM_ALLOCATOR) and Gecko even #define's
139 * these symbols.
140 *
141 * ** Do not use the builtin C++ operator new and delete: these throw on
142 * error and we cannot override them not to.
143 *
144 * Allocation:
145 *
146 * - If the lifetime of the allocation is tied to the lifetime of a GC-thing
147 * (that is, finalizing the GC-thing will free the allocation), call one of
148 * the following functions:
149 *
150 * JSContext::{malloc_,realloc_,calloc_,new_}
151 * JSRuntime::{malloc_,realloc_,calloc_,new_}
152 *
153 * These functions accumulate the number of bytes allocated which is used as
154 * part of the GC-triggering heuristic.
155 *
156 * The difference between the JSContext and JSRuntime versions is that the
157 * cx version reports an out-of-memory error on OOM. (This follows from the
158 * general SpiderMonkey idiom that a JSContext-taking function reports its
159 * own errors.)
160 *
161 * - Otherwise, use js_malloc/js_realloc/js_calloc/js_free/js_new
162 *
163 * Deallocation:
164 *
165 * - Ordinarily, use js_free/js_delete.
166 *
167 * - For deallocations during GC finalization, use one of the following
168 * operations on the FreeOp provided to the finalizer:
169 *
170 * FreeOp::{free_,delete_}
171 *
172 * The advantage of these operations is that the memory is batched and freed
173 * on another thread.
174 */
176 #define JS_NEW_BODY(allocator, t, parms) \
177 void *memory = allocator(sizeof(t)); \
178 return memory ? new(memory) t parms : nullptr;
180 /*
181 * Given a class which should provide 'new' methods, add
182 * JS_DECLARE_NEW_METHODS (see JSContext for a usage example). This
183 * adds news with up to 12 parameters. Add more versions of new below if
184 * you need more than 12 parameters.
185 *
186 * Note: Do not add a ; at the end of a use of JS_DECLARE_NEW_METHODS,
187 * or the build will break.
188 */
189 #define JS_DECLARE_NEW_METHODS(NEWNAME, ALLOCATOR, QUALIFIERS)\
190 template <class T>\
191 QUALIFIERS T *NEWNAME() MOZ_HEAP_ALLOCATOR {\
192 JS_NEW_BODY(ALLOCATOR, T, ())\
193 }\
194 \
195 template <class T, class P1>\
196 QUALIFIERS T *NEWNAME(P1 &&p1) MOZ_HEAP_ALLOCATOR {\
197 JS_NEW_BODY(ALLOCATOR, T,\
198 (mozilla::Forward<P1>(p1)))\
199 }\
200 \
201 template <class T, class P1, class P2>\
202 QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2) MOZ_HEAP_ALLOCATOR {\
203 JS_NEW_BODY(ALLOCATOR, T,\
204 (mozilla::Forward<P1>(p1),\
205 mozilla::Forward<P2>(p2)))\
206 }\
207 \
208 template <class T, class P1, class P2, class P3>\
209 QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3) MOZ_HEAP_ALLOCATOR {\
210 JS_NEW_BODY(ALLOCATOR, T,\
211 (mozilla::Forward<P1>(p1),\
212 mozilla::Forward<P2>(p2),\
213 mozilla::Forward<P3>(p3)))\
214 }\
215 \
216 template <class T, class P1, class P2, class P3, class P4>\
217 QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4) MOZ_HEAP_ALLOCATOR {\
218 JS_NEW_BODY(ALLOCATOR, T,\
219 (mozilla::Forward<P1>(p1),\
220 mozilla::Forward<P2>(p2),\
221 mozilla::Forward<P3>(p3),\
222 mozilla::Forward<P4>(p4)))\
223 }\
224 \
225 template <class T, class P1, class P2, class P3, class P4, class P5>\
226 QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5) MOZ_HEAP_ALLOCATOR {\
227 JS_NEW_BODY(ALLOCATOR, T,\
228 (mozilla::Forward<P1>(p1),\
229 mozilla::Forward<P2>(p2),\
230 mozilla::Forward<P3>(p3),\
231 mozilla::Forward<P4>(p4),\
232 mozilla::Forward<P5>(p5)))\
233 }\
234 \
235 template <class T, class P1, class P2, class P3, class P4, class P5, class P6>\
236 QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5, P6 &&p6) MOZ_HEAP_ALLOCATOR {\
237 JS_NEW_BODY(ALLOCATOR, T,\
238 (mozilla::Forward<P1>(p1),\
239 mozilla::Forward<P2>(p2),\
240 mozilla::Forward<P3>(p3),\
241 mozilla::Forward<P4>(p4),\
242 mozilla::Forward<P5>(p5),\
243 mozilla::Forward<P6>(p6)))\
244 }\
245 \
246 template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7>\
247 QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5, P6 &&p6, P7 &&p7) MOZ_HEAP_ALLOCATOR {\
248 JS_NEW_BODY(ALLOCATOR, T,\
249 (mozilla::Forward<P1>(p1),\
250 mozilla::Forward<P2>(p2),\
251 mozilla::Forward<P3>(p3),\
252 mozilla::Forward<P4>(p4),\
253 mozilla::Forward<P5>(p5),\
254 mozilla::Forward<P6>(p6),\
255 mozilla::Forward<P7>(p7)))\
256 }\
257 \
258 template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8>\
259 QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5, P6 &&p6, P7 &&p7, P8 &&p8) MOZ_HEAP_ALLOCATOR {\
260 JS_NEW_BODY(ALLOCATOR, T,\
261 (mozilla::Forward<P1>(p1),\
262 mozilla::Forward<P2>(p2),\
263 mozilla::Forward<P3>(p3),\
264 mozilla::Forward<P4>(p4),\
265 mozilla::Forward<P5>(p5),\
266 mozilla::Forward<P6>(p6),\
267 mozilla::Forward<P7>(p7),\
268 mozilla::Forward<P8>(p8)))\
269 }\
270 \
271 template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9>\
272 QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5, P6 &&p6, P7 &&p7, P8 &&p8, P9 &&p9) MOZ_HEAP_ALLOCATOR {\
273 JS_NEW_BODY(ALLOCATOR, T,\
274 (mozilla::Forward<P1>(p1),\
275 mozilla::Forward<P2>(p2),\
276 mozilla::Forward<P3>(p3),\
277 mozilla::Forward<P4>(p4),\
278 mozilla::Forward<P5>(p5),\
279 mozilla::Forward<P6>(p6),\
280 mozilla::Forward<P7>(p7),\
281 mozilla::Forward<P8>(p8),\
282 mozilla::Forward<P9>(p9)))\
283 }\
284 \
285 template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9, class P10>\
286 QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5, P6 &&p6, P7 &&p7, P8 &&p8, P9 &&p9, P10 &&p10) MOZ_HEAP_ALLOCATOR {\
287 JS_NEW_BODY(ALLOCATOR, T,\
288 (mozilla::Forward<P1>(p1),\
289 mozilla::Forward<P2>(p2),\
290 mozilla::Forward<P3>(p3),\
291 mozilla::Forward<P4>(p4),\
292 mozilla::Forward<P5>(p5),\
293 mozilla::Forward<P6>(p6),\
294 mozilla::Forward<P7>(p7),\
295 mozilla::Forward<P8>(p8),\
296 mozilla::Forward<P9>(p9),\
297 mozilla::Forward<P10>(p10)))\
298 }\
299 \
300 template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9, class P10, class P11>\
301 QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5, P6 &&p6, P7 &&p7, P8 &&p8, P9 &&p9, P10 &&p10, P11 &&p11) MOZ_HEAP_ALLOCATOR {\
302 JS_NEW_BODY(ALLOCATOR, T,\
303 (mozilla::Forward<P1>(p1),\
304 mozilla::Forward<P2>(p2),\
305 mozilla::Forward<P3>(p3),\
306 mozilla::Forward<P4>(p4),\
307 mozilla::Forward<P5>(p5),\
308 mozilla::Forward<P6>(p6),\
309 mozilla::Forward<P7>(p7),\
310 mozilla::Forward<P8>(p8),\
311 mozilla::Forward<P9>(p9),\
312 mozilla::Forward<P10>(p10),\
313 mozilla::Forward<P11>(p11)))\
314 }\
315 \
316 template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9, class P10, class P11, class P12>\
317 QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5, P6 &&p6, P7 &&p7, P8 &&p8, P9 &&p9, P10 &&p10, P11 &&p11, P12 &&p12) MOZ_HEAP_ALLOCATOR {\
318 JS_NEW_BODY(ALLOCATOR, T,\
319 (mozilla::Forward<P1>(p1),\
320 mozilla::Forward<P2>(p2),\
321 mozilla::Forward<P3>(p3),\
322 mozilla::Forward<P4>(p4),\
323 mozilla::Forward<P5>(p5),\
324 mozilla::Forward<P6>(p6),\
325 mozilla::Forward<P7>(p7),\
326 mozilla::Forward<P8>(p8),\
327 mozilla::Forward<P9>(p9),\
328 mozilla::Forward<P10>(p10),\
329 mozilla::Forward<P11>(p11),\
330 mozilla::Forward<P12>(p12)))\
331 }\
333 JS_DECLARE_NEW_METHODS(js_new, js_malloc, static MOZ_ALWAYS_INLINE)
335 template <class T>
336 static MOZ_ALWAYS_INLINE void
337 js_delete(T *p)
338 {
339 if (p) {
340 p->~T();
341 js_free(p);
342 }
343 }
345 template<class T>
346 static MOZ_ALWAYS_INLINE void
347 js_delete_poison(T *p)
348 {
349 if (p) {
350 p->~T();
351 memset(p, 0x3B, sizeof(T));
352 js_free(p);
353 }
354 }
356 template <class T>
357 static MOZ_ALWAYS_INLINE T *
358 js_pod_malloc()
359 {
360 return (T *)js_malloc(sizeof(T));
361 }
363 template <class T>
364 static MOZ_ALWAYS_INLINE T *
365 js_pod_calloc()
366 {
367 return (T *)js_calloc(sizeof(T));
368 }
370 template <class T>
371 static MOZ_ALWAYS_INLINE T *
372 js_pod_malloc(size_t numElems)
373 {
374 if (numElems & mozilla::tl::MulOverflowMask<sizeof(T)>::value)
375 return nullptr;
376 return (T *)js_malloc(numElems * sizeof(T));
377 }
379 template <class T>
380 static MOZ_ALWAYS_INLINE T *
381 js_pod_calloc(size_t numElems)
382 {
383 if (numElems & mozilla::tl::MulOverflowMask<sizeof(T)>::value)
384 return nullptr;
385 return (T *)js_calloc(numElems * sizeof(T));
386 }
388 namespace js {
390 template<typename T>
391 struct ScopedFreePtrTraits
392 {
393 typedef T* type;
394 static T* empty() { return nullptr; }
395 static void release(T* ptr) { js_free(ptr); }
396 };
397 SCOPED_TEMPLATE(ScopedJSFreePtr, ScopedFreePtrTraits)
399 template <typename T>
400 struct ScopedDeletePtrTraits : public ScopedFreePtrTraits<T>
401 {
402 static void release(T *ptr) { js_delete(ptr); }
403 };
404 SCOPED_TEMPLATE(ScopedJSDeletePtr, ScopedDeletePtrTraits)
406 template <typename T>
407 struct ScopedReleasePtrTraits : public ScopedFreePtrTraits<T>
408 {
409 static void release(T *ptr) { if (ptr) ptr->release(); }
410 };
411 SCOPED_TEMPLATE(ScopedReleasePtr, ScopedReleasePtrTraits)
413 } /* namespace js */
415 namespace js {
417 /* Integral types for all hash functions. */
418 typedef uint32_t HashNumber;
419 const unsigned HashNumberSizeBits = 32;
421 namespace detail {
423 /*
424 * Given a raw hash code, h, return a number that can be used to select a hash
425 * bucket.
426 *
427 * This function aims to produce as uniform an output distribution as possible,
428 * especially in the most significant (leftmost) bits, even though the input
429 * distribution may be highly nonrandom, given the constraints that this must
430 * be deterministic and quick to compute.
431 *
432 * Since the leftmost bits of the result are best, the hash bucket index is
433 * computed by doing ScrambleHashCode(h) / (2^32/N) or the equivalent
434 * right-shift, not ScrambleHashCode(h) % N or the equivalent bit-mask.
435 *
436 * FIXME: OrderedHashTable uses a bit-mask; see bug 775896.
437 */
438 inline HashNumber
439 ScrambleHashCode(HashNumber h)
440 {
441 /*
442 * Simply returning h would not cause any hash tables to produce wrong
443 * answers. But it can produce pathologically bad performance: The caller
444 * right-shifts the result, keeping only the highest bits. The high bits of
445 * hash codes are very often completely entropy-free. (So are the lowest
446 * bits.)
447 *
448 * So we use Fibonacci hashing, as described in Knuth, The Art of Computer
449 * Programming, 6.4. This mixes all the bits of the input hash code h.
450 *
451 * The value of goldenRatio is taken from the hex
452 * expansion of the golden ratio, which starts 1.9E3779B9....
453 * This value is especially good if values with consecutive hash codes
454 * are stored in a hash table; see Knuth for details.
455 */
456 static const HashNumber goldenRatio = 0x9E3779B9U;
457 return h * goldenRatio;
458 }
460 } /* namespace detail */
462 } /* namespace js */
464 namespace JS {
466 /*
467 * Methods for poisoning GC heap pointer words and checking for poisoned words.
468 * These are in this file for use in Value methods and so forth.
469 *
470 * If the moving GC hazard analysis is in use and detects a non-rooted stack
471 * pointer to a GC thing, one byte of that pointer is poisoned to refer to an
472 * invalid location. For both 32 bit and 64 bit systems, the fourth byte of the
473 * pointer is overwritten, to reduce the likelihood of accidentally changing
474 * a live integer value.
475 */
477 inline void PoisonPtr(void *v)
478 {
479 #if defined(JSGC_ROOT_ANALYSIS) && defined(JS_DEBUG)
480 uint8_t *ptr = (uint8_t *) v + 3;
481 *ptr = JS_FREE_PATTERN;
482 #endif
483 }
485 template <typename T>
486 inline bool IsPoisonedPtr(T *v)
487 {
488 #if defined(JSGC_ROOT_ANALYSIS) && defined(JS_DEBUG)
489 uint32_t mask = uintptr_t(v) & 0xff000000;
490 return mask == uint32_t(JS_FREE_PATTERN << 24);
491 #else
492 return false;
493 #endif
494 }
496 }
498 /* sixgill annotation defines */
499 #ifndef HAVE_STATIC_ANNOTATIONS
500 # define HAVE_STATIC_ANNOTATIONS
501 # ifdef XGILL_PLUGIN
502 # define STATIC_PRECONDITION(COND) __attribute__((precondition(#COND)))
503 # define STATIC_PRECONDITION_ASSUME(COND) __attribute__((precondition_assume(#COND)))
504 # define STATIC_POSTCONDITION(COND) __attribute__((postcondition(#COND)))
505 # define STATIC_POSTCONDITION_ASSUME(COND) __attribute__((postcondition_assume(#COND)))
506 # define STATIC_INVARIANT(COND) __attribute__((invariant(#COND)))
507 # define STATIC_INVARIANT_ASSUME(COND) __attribute__((invariant_assume(#COND)))
508 # define STATIC_PASTE2(X,Y) X ## Y
509 # define STATIC_PASTE1(X,Y) STATIC_PASTE2(X,Y)
510 # define STATIC_ASSERT(COND) \
511 JS_BEGIN_MACRO \
512 __attribute__((assert_static(#COND), unused)) \
513 int STATIC_PASTE1(assert_static_, __COUNTER__); \
514 JS_END_MACRO
515 # define STATIC_ASSUME(COND) \
516 JS_BEGIN_MACRO \
517 __attribute__((assume_static(#COND), unused)) \
518 int STATIC_PASTE1(assume_static_, __COUNTER__); \
519 JS_END_MACRO
520 # define STATIC_ASSERT_RUNTIME(COND) \
521 JS_BEGIN_MACRO \
522 __attribute__((assert_static_runtime(#COND), unused)) \
523 int STATIC_PASTE1(assert_static_runtime_, __COUNTER__); \
524 JS_END_MACRO
525 # else /* XGILL_PLUGIN */
526 # define STATIC_PRECONDITION(COND) /* nothing */
527 # define STATIC_PRECONDITION_ASSUME(COND) /* nothing */
528 # define STATIC_POSTCONDITION(COND) /* nothing */
529 # define STATIC_POSTCONDITION_ASSUME(COND) /* nothing */
530 # define STATIC_INVARIANT(COND) /* nothing */
531 # define STATIC_INVARIANT_ASSUME(COND) /* nothing */
532 # define STATIC_ASSERT(COND) JS_BEGIN_MACRO /* nothing */ JS_END_MACRO
533 # define STATIC_ASSUME(COND) JS_BEGIN_MACRO /* nothing */ JS_END_MACRO
534 # define STATIC_ASSERT_RUNTIME(COND) JS_BEGIN_MACRO /* nothing */ JS_END_MACRO
535 # endif /* XGILL_PLUGIN */
536 # define STATIC_SKIP_INFERENCE STATIC_INVARIANT(skip_inference())
537 #endif /* HAVE_STATIC_ANNOTATIONS */
539 #endif /* js_Utility_h */