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.
michael@0 | 1 | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
michael@0 | 2 | * vim: set ts=8 sts=4 et sw=4 tw=99: |
michael@0 | 3 | * This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 4 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 5 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 6 | |
michael@0 | 7 | /* JS::Anchor implementation. */ |
michael@0 | 8 | |
michael@0 | 9 | #ifndef js_Anchor_h |
michael@0 | 10 | #define js_Anchor_h |
michael@0 | 11 | |
michael@0 | 12 | #include "mozilla/Attributes.h" |
michael@0 | 13 | |
michael@0 | 14 | #include "js/TypeDecls.h" |
michael@0 | 15 | |
michael@0 | 16 | namespace JS { |
michael@0 | 17 | |
michael@0 | 18 | /* |
michael@0 | 19 | * Protecting non-Value, non-JSObject *, non-JSString * values from collection |
michael@0 | 20 | * |
michael@0 | 21 | * Most of the time, the garbage collector's conservative stack scanner works |
michael@0 | 22 | * behind the scenes, finding all live values and protecting them from being |
michael@0 | 23 | * collected. However, when JSAPI client code obtains a pointer to data the |
michael@0 | 24 | * scanner does not know about, owned by an object the scanner does know about, |
michael@0 | 25 | * Care Must Be Taken. |
michael@0 | 26 | * |
michael@0 | 27 | * The scanner recognizes only a select set of types: pointers to JSObjects and |
michael@0 | 28 | * similar things (JSFunctions, and so on), pointers to JSStrings, and Values. |
michael@0 | 29 | * So while the scanner finds all live |JSString| pointers, it does not notice |
michael@0 | 30 | * |jschar| pointers. |
michael@0 | 31 | * |
michael@0 | 32 | * So suppose we have: |
michael@0 | 33 | * |
michael@0 | 34 | * void f(JSString *str) { |
michael@0 | 35 | * const jschar *ch = JS_GetStringCharsZ(str); |
michael@0 | 36 | * ... do stuff with ch, but no uses of str ...; |
michael@0 | 37 | * } |
michael@0 | 38 | * |
michael@0 | 39 | * After the call to |JS_GetStringCharsZ|, there are no further uses of |
michael@0 | 40 | * |str|, which means that the compiler is within its rights to not store |
michael@0 | 41 | * it anywhere. But because the stack scanner will not notice |ch|, there |
michael@0 | 42 | * is no longer any live value in this frame that would keep the string |
michael@0 | 43 | * alive. If |str| is the last reference to that |JSString|, and the |
michael@0 | 44 | * collector runs while we are using |ch|, the string's array of |jschar|s |
michael@0 | 45 | * may be freed out from under us. |
michael@0 | 46 | * |
michael@0 | 47 | * Note that there is only an issue when 1) we extract a thing X the scanner |
michael@0 | 48 | * doesn't recognize from 2) a thing Y the scanner does recognize, and 3) if Y |
michael@0 | 49 | * gets garbage-collected, then X gets freed. If we have code like this: |
michael@0 | 50 | * |
michael@0 | 51 | * void g(JSObject *obj) { |
michael@0 | 52 | * JS::Value x; |
michael@0 | 53 | * JS_GetProperty(obj, "x", &x); |
michael@0 | 54 | * ... do stuff with x ... |
michael@0 | 55 | * } |
michael@0 | 56 | * |
michael@0 | 57 | * there's no problem, because the value we've extracted, x, is a Value, a |
michael@0 | 58 | * type that the conservative scanner recognizes. |
michael@0 | 59 | * |
michael@0 | 60 | * Conservative GC frees us from the obligation to explicitly root the types it |
michael@0 | 61 | * knows about, but when we work with derived values like |ch|, we must root |
michael@0 | 62 | * their owners, as the derived value alone won't keep them alive. |
michael@0 | 63 | * |
michael@0 | 64 | * A JS::Anchor is a kind of GC root that allows us to keep the owners of |
michael@0 | 65 | * derived values like |ch| alive throughout the Anchor's lifetime. We could |
michael@0 | 66 | * fix the above code as follows: |
michael@0 | 67 | * |
michael@0 | 68 | * void f(JSString *str) { |
michael@0 | 69 | * JS::Anchor<JSString *> a_str(str); |
michael@0 | 70 | * const jschar *ch = JS_GetStringCharsZ(str); |
michael@0 | 71 | * ... do stuff with ch, but no uses of str ...; |
michael@0 | 72 | * } |
michael@0 | 73 | * |
michael@0 | 74 | * This simply ensures that |str| will be live until |a_str| goes out of scope. |
michael@0 | 75 | * As long as we don't retain a pointer to the string's characters for longer |
michael@0 | 76 | * than that, we have avoided all garbage collection hazards. |
michael@0 | 77 | */ |
michael@0 | 78 | template<typename T> class AnchorPermitted; |
michael@0 | 79 | template<> class AnchorPermitted<JSObject *> { }; |
michael@0 | 80 | template<> class AnchorPermitted<const JSObject *> { }; |
michael@0 | 81 | template<> class AnchorPermitted<JSFunction *> { }; |
michael@0 | 82 | template<> class AnchorPermitted<const JSFunction *> { }; |
michael@0 | 83 | template<> class AnchorPermitted<JSString *> { }; |
michael@0 | 84 | template<> class AnchorPermitted<const JSString *> { }; |
michael@0 | 85 | template<> class AnchorPermitted<Value> { }; |
michael@0 | 86 | template<> class AnchorPermitted<const JSScript *> { }; |
michael@0 | 87 | template<> class AnchorPermitted<JSScript *> { }; |
michael@0 | 88 | |
michael@0 | 89 | template<typename T> |
michael@0 | 90 | class Anchor : AnchorPermitted<T> |
michael@0 | 91 | { |
michael@0 | 92 | public: |
michael@0 | 93 | Anchor() { } |
michael@0 | 94 | explicit Anchor(T t) { hold = t; } |
michael@0 | 95 | inline ~Anchor(); |
michael@0 | 96 | |
michael@0 | 97 | private: |
michael@0 | 98 | T hold; |
michael@0 | 99 | |
michael@0 | 100 | /* |
michael@0 | 101 | * Rooting analysis considers use of operator= to be a use of an anchor. |
michael@0 | 102 | * For simplicity, Anchor is treated as if it contained a GC thing, from |
michael@0 | 103 | * construction. Thus if we had |
michael@0 | 104 | * |
michael@0 | 105 | * void operator=(const T &t) { hold = t; } |
michael@0 | 106 | * |
michael@0 | 107 | * and this code |
michael@0 | 108 | * |
michael@0 | 109 | * JS::Anchor<JSString*> anchor; |
michael@0 | 110 | * stuff that could GC, producing |str|; |
michael@0 | 111 | * anchor = str; |
michael@0 | 112 | * |
michael@0 | 113 | * the last line would be seen as a hazard, because the final = would "use" |
michael@0 | 114 | * |anchor| that is a GC thing -- which could have been moved around by the |
michael@0 | 115 | * GC. The workaround is to structure your code so that JS::Anchor is |
michael@0 | 116 | * always constructed, living for however long the corresponding value must |
michael@0 | 117 | * live. |
michael@0 | 118 | */ |
michael@0 | 119 | void operator=(const T &t) MOZ_DELETE; |
michael@0 | 120 | |
michael@0 | 121 | Anchor(const Anchor &other) MOZ_DELETE; |
michael@0 | 122 | void operator=(const Anchor &other) MOZ_DELETE; |
michael@0 | 123 | }; |
michael@0 | 124 | |
michael@0 | 125 | template<typename T> |
michael@0 | 126 | inline Anchor<T>::~Anchor() |
michael@0 | 127 | { |
michael@0 | 128 | #ifdef __GNUC__ |
michael@0 | 129 | /* |
michael@0 | 130 | * No code is generated for this. But because this is marked 'volatile', G++ will |
michael@0 | 131 | * assume it has important side-effects, and won't delete it. (G++ never looks at |
michael@0 | 132 | * the actual text and notices it's empty.) And because we have passed |hold| to |
michael@0 | 133 | * it, GCC will keep |hold| alive until this point. |
michael@0 | 134 | * |
michael@0 | 135 | * The "memory" clobber operand ensures that G++ will not move prior memory |
michael@0 | 136 | * accesses after the asm --- it's a barrier. Unfortunately, it also means that |
michael@0 | 137 | * G++ will assume that all memory has changed after the asm, as it would for a |
michael@0 | 138 | * call to an unknown function. I don't know of a way to avoid that consequence. |
michael@0 | 139 | */ |
michael@0 | 140 | asm volatile("":: "g" (hold) : "memory"); |
michael@0 | 141 | #else |
michael@0 | 142 | /* |
michael@0 | 143 | * An adequate portable substitute, for non-structure types. |
michael@0 | 144 | * |
michael@0 | 145 | * The compiler promises that, by the end of an expression statement, the |
michael@0 | 146 | * last-stored value to a volatile object is the same as it would be in an |
michael@0 | 147 | * unoptimized, direct implementation (the "abstract machine" whose behavior the |
michael@0 | 148 | * language spec describes). However, the compiler is still free to reorder |
michael@0 | 149 | * non-volatile accesses across this store --- which is what we must prevent. So |
michael@0 | 150 | * assigning the held value to a volatile variable, as we do here, is not enough. |
michael@0 | 151 | * |
michael@0 | 152 | * In our case, however, garbage collection only occurs at function calls, so it |
michael@0 | 153 | * is sufficient to ensure that the destructor's store isn't moved earlier across |
michael@0 | 154 | * any function calls that could collect. It is hard to imagine the compiler |
michael@0 | 155 | * analyzing the program so thoroughly that it could prove that such motion was |
michael@0 | 156 | * safe. In practice, compilers treat calls to the collector as opaque operations |
michael@0 | 157 | * --- in particular, as operations which could access volatile variables, across |
michael@0 | 158 | * which this destructor must not be moved. |
michael@0 | 159 | * |
michael@0 | 160 | * ("Objection, your honor! *Alleged* killer whale!") |
michael@0 | 161 | * |
michael@0 | 162 | * The disadvantage of this approach is that it does generate code for the store. |
michael@0 | 163 | * We do need to use Anchors in some cases where cycles are tight. |
michael@0 | 164 | * |
michael@0 | 165 | * Note that there is a Anchor<Value>::~Anchor() specialization in Value.h. |
michael@0 | 166 | */ |
michael@0 | 167 | volatile T sink; |
michael@0 | 168 | sink = hold; |
michael@0 | 169 | #endif /* defined(__GNUC__) */ |
michael@0 | 170 | } |
michael@0 | 171 | |
michael@0 | 172 | } // namespace JS |
michael@0 | 173 | |
michael@0 | 174 | #endif /* js_Anchor_h */ |