tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

source.cpp (13251B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      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/. */
      6 
      7 #include <utility>
      8 
      9 #define ANNOTATE(property) __attribute__((annotate(property)))
     10 
     11 // MarkVariableAsGCSafe is a magic function name used as an
     12 // explicit annotation.
     13 
     14 namespace JS {
     15 namespace detail {
     16 template <typename T>
     17 static void MarkVariableAsGCSafe(T&) {
     18  asm("");
     19 }
     20 }  // namespace detail
     21 }  // namespace JS
     22 
     23 #define JS_HAZ_VARIABLE_IS_GC_SAFE(var) JS::detail::MarkVariableAsGCSafe(var)
     24 
     25 struct Cell {
     26  int f;
     27 } ANNOTATE("GC Thing");
     28 
     29 template <typename T, typename U>
     30 struct UntypedContainer {
     31  char data[sizeof(T) + sizeof(U)];
     32 } ANNOTATE("moz_inherit_type_annotations_from_template_args");
     33 
     34 struct RootedCell {
     35  RootedCell(Cell*) {}
     36 } ANNOTATE("Rooted Pointer");
     37 
     38 class AutoSuppressGC_Base {
     39 public:
     40  AutoSuppressGC_Base() {}
     41  ~AutoSuppressGC_Base() {}
     42 } ANNOTATE("Suppress GC");
     43 
     44 class AutoSuppressGC_Child : public AutoSuppressGC_Base {
     45 public:
     46  AutoSuppressGC_Child() : AutoSuppressGC_Base() {}
     47 };
     48 
     49 class AutoSuppressGC {
     50  AutoSuppressGC_Child helpImBeingSuppressed;
     51 
     52 public:
     53  AutoSuppressGC() {}
     54 };
     55 
     56 class AutoCheckCannotGC {
     57 public:
     58  AutoCheckCannotGC() {}
     59  ~AutoCheckCannotGC() { asm(""); }
     60 } ANNOTATE("Invalidated by GC");
     61 
     62 extern void GC() ANNOTATE("GC Call");
     63 extern void invisible();
     64 
     65 void GC() {
     66  // If the implementation is too trivial, the function body won't be emitted at
     67  // all.
     68  asm("");
     69  invisible();
     70 }
     71 
     72 extern Cell* makecell();
     73 
     74 extern void usecell(Cell*);
     75 
     76 extern bool flipcoin();
     77 
     78 void suppressedFunction() {
     79  GC();  // Calls GC, but is always called within AutoSuppressGC
     80 }
     81 
     82 void halfSuppressedFunction() {
     83  GC();  // Calls GC, but is sometimes called within AutoSuppressGC
     84 }
     85 
     86 void unsuppressedFunction() {
     87  GC();  // Calls GC, never within AutoSuppressGC
     88 }
     89 
     90 class IDL_Interface {
     91 public:
     92  ANNOTATE("Can run script") virtual void canScriptThis() {}
     93  virtual void cannotScriptThis() {}
     94  ANNOTATE("Can run script") virtual void overridden_canScriptThis() = 0;
     95  virtual void overridden_cannotScriptThis() = 0;
     96 };
     97 
     98 class IDL_Subclass : public IDL_Interface {
     99  ANNOTATE("Can run script") void overridden_canScriptThis() override {}
    100  void overridden_cannotScriptThis() override {}
    101 };
    102 
    103 volatile static int x = 3;
    104 volatile static int* xp = &x;
    105 struct GCInDestructor {
    106  ~GCInDestructor() {
    107    invisible();
    108    asm("");
    109    *xp = 4;
    110    GC();
    111  }
    112 };
    113 
    114 template <typename T>
    115 void usecontainer(T* value) {
    116  if (value) asm("");
    117 }
    118 
    119 Cell* cell() {
    120  static Cell c;
    121  return &c;
    122 }
    123 
    124 Cell* f() {
    125  GCInDestructor kaboom;
    126 
    127  Cell* cell1 = cell();
    128  Cell* cell2 = cell();
    129  Cell* cell3 = cell();
    130  Cell* cell4 = cell();
    131  {
    132    AutoSuppressGC nogc;
    133    suppressedFunction();
    134    halfSuppressedFunction();
    135  }
    136  usecell(cell1);
    137  halfSuppressedFunction();
    138  usecell(cell2);
    139  unsuppressedFunction();
    140  {
    141    // Old bug: it would look from the first AutoSuppressGC constructor it
    142    // found to the last destructor. This statement *should* have no effect.
    143    AutoSuppressGC nogc;
    144  }
    145  usecell(cell3);
    146  Cell* cell5 = cell();
    147  usecell(cell5);
    148 
    149  {
    150    // Templatized container that inherits attributes from Cell*, should
    151    // report a hazard.
    152    UntypedContainer<int, Cell*> container1;
    153    usecontainer(&container1);
    154    GC();
    155    usecontainer(&container1);
    156  }
    157 
    158  {
    159    // As above, but with a non-GC type.
    160    UntypedContainer<int, double> container2;
    161    usecontainer(&container2);
    162    GC();
    163    usecontainer(&container2);
    164  }
    165 
    166  // Hazard in return value due to ~GCInDestructor
    167  Cell* cell6 = cell();
    168  return cell6;
    169 }
    170 
    171 Cell* copy_and_gc(Cell* src) {
    172  GC();
    173  return reinterpret_cast<Cell*>(88);
    174 }
    175 
    176 void use(Cell* cell) {
    177  static int x = 0;
    178  if (cell) x++;
    179 }
    180 
    181 struct CellContainer {
    182  Cell* cell;
    183  CellContainer() { asm(""); }
    184 };
    185 
    186 void loopy() {
    187  Cell cell;
    188 
    189  // No hazard: haz1 is not live during call to copy_and_gc.
    190  Cell* haz1;
    191  for (int i = 0; i < 10; i++) {
    192    haz1 = copy_and_gc(haz1);
    193  }
    194 
    195  // No hazard: haz2 is live up to just before the GC, and starting at the
    196  // next statement after it, but not across the GC.
    197  Cell* haz2 = &cell;
    198  for (int j = 0; j < 10; j++) {
    199    use(haz2);
    200    GC();
    201    haz2 = &cell;
    202  }
    203 
    204  // Hazard: haz3 is live from the final statement in one iteration, across
    205  // the GC in the next, to the use in the 2nd statement.
    206  Cell* haz3;
    207  for (int k = 0; k < 10; k++) {
    208    GC();
    209    use(haz3);
    210    haz3 = &cell;
    211  }
    212 
    213  // Hazard: haz4 is live across a GC hidden in a loop.
    214  Cell* haz4 = &cell;
    215  for (int i2 = 0; i2 < 10; i2++) {
    216    GC();
    217  }
    218  use(haz4);
    219 
    220  // Hazard: haz5 is live from within a loop across a GC.
    221  Cell* haz5;
    222  for (int i3 = 0; i3 < 10; i3++) {
    223    haz5 = &cell;
    224  }
    225  GC();
    226  use(haz5);
    227 
    228  // No hazard: similar to the haz3 case, but verifying that we do not get
    229  // into an infinite loop.
    230  Cell* haz6;
    231  for (int i4 = 0; i4 < 10; i4++) {
    232    GC();
    233    haz6 = &cell;
    234  }
    235 
    236  // No hazard: haz7 is constructed within the body, so it can't make a
    237  // hazard across iterations. Note that this requires CellContainer to have
    238  // a constructor, because otherwise the analysis doesn't see where
    239  // variables are declared. (With the constructor, it knows that
    240  // construction of haz7 obliterates any previous value it might have had.
    241  // Not that that's possible given its scope, but the analysis doesn't get
    242  // that information.)
    243  for (int i5 = 0; i5 < 10; i5++) {
    244    GC();
    245    CellContainer haz7;
    246    use(haz7.cell);
    247    haz7.cell = &cell;
    248  }
    249 
    250  // Hazard: make sure we *can* see hazards across iterations involving
    251  // CellContainer;
    252  CellContainer haz8;
    253  for (int i6 = 0; i6 < 10; i6++) {
    254    GC();
    255    use(haz8.cell);
    256    haz8.cell = &cell;
    257  }
    258 }
    259 
    260 namespace mozilla {
    261 template <typename T>
    262 class UniquePtr {
    263  T* val;
    264 
    265 public:
    266  UniquePtr() : val(nullptr) { asm(""); }
    267  UniquePtr(T* p) : val(p) {}
    268  UniquePtr(UniquePtr<T>&& u) : val(u.val) { u.val = nullptr; }
    269  ~UniquePtr() { use(val); }
    270  T* get() { return val; }
    271  void reset() { val = nullptr; }
    272 } ANNOTATE("moz_inherit_type_annotations_from_template_args");
    273 }  // namespace mozilla
    274 
    275 extern void consume(mozilla::UniquePtr<Cell> uptr);
    276 
    277 void safevals() {
    278  Cell cell;
    279 
    280  // Simple hazard.
    281  Cell* unsafe1 = &cell;
    282  GC();
    283  use(unsafe1);
    284 
    285  // Safe because it's known to be nullptr.
    286  Cell* safe2 = &cell;
    287  safe2 = nullptr;
    288  GC();
    289  use(safe2);
    290 
    291  // Unsafe because it may not be nullptr.
    292  Cell* unsafe3 = &cell;
    293  if (reinterpret_cast<long>(&cell) & 0x100) {
    294    unsafe3 = nullptr;
    295  }
    296  GC();
    297  use(unsafe3);
    298 
    299  // Unsafe because it's not nullptr anymore.
    300  Cell* unsafe3b = &cell;
    301  unsafe3b = nullptr;
    302  unsafe3b = &cell;
    303  GC();
    304  use(unsafe3b);
    305 
    306  // Hazard involving UniquePtr.
    307  {
    308    mozilla::UniquePtr<Cell> unsafe4(&cell);
    309    GC();
    310    // Destructor uses unsafe4.
    311  }
    312 
    313  // reset() to safe value before the GC.
    314  {
    315    mozilla::UniquePtr<Cell> safe5(&cell);
    316    safe5.reset();
    317    GC();
    318  }
    319 
    320  // reset() to safe value after the GC.
    321  {
    322    mozilla::UniquePtr<Cell> safe6(&cell);
    323    GC();
    324    safe6.reset();
    325  }
    326 
    327  // reset() to safe value after the GC -- but we've already used it, so it's
    328  // too late.
    329  {
    330    mozilla::UniquePtr<Cell> unsafe7(&cell);
    331    GC();
    332    use(unsafe7.get());
    333    unsafe7.reset();
    334  }
    335 
    336  // initialized to safe value.
    337  {
    338    mozilla::UniquePtr<Cell> safe8;
    339    GC();
    340  }
    341 
    342  // passed to a function that takes ownership before GC.
    343  {
    344    mozilla::UniquePtr<Cell> safe9(&cell);
    345    consume(std::move(safe9));
    346    GC();
    347  }
    348 
    349  // passed to a function that takes ownership after GC.
    350  {
    351    mozilla::UniquePtr<Cell> unsafe10(&cell);
    352    GC();
    353    consume(std::move(unsafe10));
    354  }
    355 
    356  // annotated to be safe before the GC. (This doesn't make
    357  // a lot of sense here; the annotation is for when some
    358  // type is known to only contain safe values, eg it is
    359  // initialized as empty, or it is a union and we know
    360  // that the GC pointer variants are not in use.)
    361  {
    362    mozilla::UniquePtr<Cell> safe11(&cell);
    363    JS_HAZ_VARIABLE_IS_GC_SAFE(safe11);
    364    GC();
    365  }
    366 
    367  // annotate as safe value after the GC -- since nothing else
    368  // has touched the variable, that means it was already safe
    369  // during the GC.
    370  {
    371    mozilla::UniquePtr<Cell> safe12(&cell);
    372    GC();
    373    JS_HAZ_VARIABLE_IS_GC_SAFE(safe12);
    374  }
    375 
    376  // annotate as safe after the GC -- but we've already used it, so it's
    377  // too late.
    378  {
    379    mozilla::UniquePtr<Cell> unsafe13(&cell);
    380    GC();
    381    use(unsafe13.get());
    382    JS_HAZ_VARIABLE_IS_GC_SAFE(unsafe13);
    383  }
    384 
    385  // Check JS_HAZ_CAN_RUN_SCRIPT annotation handling.
    386  IDL_Subclass sub;
    387  IDL_Subclass* subp = &sub;
    388  IDL_Interface* base = &sub;
    389  {
    390    Cell* unsafe14 = &cell;
    391    base->canScriptThis();
    392    use(unsafe14);
    393  }
    394  {
    395    Cell* unsafe15 = &cell;
    396    subp->canScriptThis();
    397    use(unsafe15);
    398  }
    399  {
    400    // Almost the same as the last one, except call using the actual object, not
    401    // a pointer. The type is known, so there is no danger of the actual type
    402    // being a subclass that has overridden the method with an implementation
    403    // that calls script.
    404    Cell* safe16 = &cell;
    405    sub.canScriptThis();
    406    use(safe16);
    407  }
    408  {
    409    Cell* safe17 = &cell;
    410    base->cannotScriptThis();
    411    use(safe17);
    412  }
    413  {
    414    Cell* safe18 = &cell;
    415    subp->cannotScriptThis();
    416    use(safe18);
    417  }
    418  {
    419    // A use after a GC, but not before. (This does not initialize safe19 by
    420    // setting it to a value, because assignment would start its live range, and
    421    // this test is to see if a variable with no known live range start requires
    422    // a use before the GC or not. It should.)
    423    Cell* safe19;
    424    GC();
    425    extern void initCellPtr(Cell**);
    426    initCellPtr(&safe19);
    427  }
    428 }
    429 
    430 // Make sure `this` is live at the beginning of a function.
    431 class Subcell : public Cell {
    432  int method() {
    433    GC();
    434    return f;  // this->f
    435  }
    436 };
    437 
    438 template <typename T>
    439 struct RefPtr {
    440  ~RefPtr() { GC(); }
    441  bool forget() { return true; }
    442  bool use() { return true; }
    443  void assign_with_AddRef(T* aRawPtr) { asm(""); }
    444 };
    445 
    446 extern bool flipcoin();
    447 
    448 Cell* refptr_test1() {
    449  static Cell cell;
    450  RefPtr<float> v1;
    451  Cell* ref_unsafe1 = &cell;
    452  return ref_unsafe1;
    453 }
    454 
    455 Cell* refptr_test2() {
    456  static Cell cell;
    457  RefPtr<float> v2;
    458  Cell* ref_safe2 = &cell;
    459  v2.forget();
    460  return ref_safe2;
    461 }
    462 
    463 Cell* refptr_test3() {
    464  static Cell cell;
    465  RefPtr<float> v3;
    466  Cell* ref_unsafe3 = &cell;
    467  if (x) {
    468    v3.forget();
    469  }
    470  return ref_unsafe3;
    471 }
    472 
    473 Cell* refptr_test4() {
    474  static Cell cell;
    475  RefPtr<int> r;
    476  return &cell;  // hazard in return value
    477 }
    478 
    479 Cell* refptr_test5() {
    480  static Cell cell;
    481  RefPtr<int> r;
    482  return nullptr;  // returning immobile value, so no hazard
    483 }
    484 
    485 float somefloat = 1.2;
    486 
    487 Cell* refptr_test6() {
    488  static Cell cell;
    489  RefPtr<float> v6;
    490  Cell* ref_unsafe6 = &cell;
    491  // v6 can be used without an intervening forget() before the end of the
    492  // function, even though forget() will be called at least once.
    493  v6.forget();
    494  if (x) {
    495    v6.forget();
    496    v6.assign_with_AddRef(&somefloat);
    497  }
    498  return ref_unsafe6;
    499 }
    500 
    501 Cell* refptr_test7() {
    502  static Cell cell;
    503  RefPtr<float> v7;
    504  Cell* ref_unsafe7 = &cell;
    505  // Similar to above, but with a loop.
    506  while (flipcoin()) {
    507    v7.forget();
    508    v7.assign_with_AddRef(&somefloat);
    509  }
    510  return ref_unsafe7;
    511 }
    512 
    513 Cell* refptr_test8() {
    514  static Cell cell;
    515  RefPtr<float> v8;
    516  Cell* ref_unsafe8 = &cell;
    517  // If the loop is traversed, forget() will be called. But that doesn't
    518  // matter, because even on the last iteration v8.use() will have been called
    519  // (and potentially dropped the refcount or whatever.)
    520  while (v8.use()) {
    521    v8.forget();
    522  }
    523  return ref_unsafe8;
    524 }
    525 
    526 Cell* refptr_test9() {
    527  static Cell cell;
    528  RefPtr<float> v9;
    529  Cell* ref_safe9 = &cell;
    530  // Even when not going through the loop, forget() will be called and so the
    531  // dtor will not Release.
    532  while (v9.forget()) {
    533    v9.assign_with_AddRef(&somefloat);
    534  }
    535  return ref_safe9;
    536 }
    537 
    538 Cell* refptr_test10() {
    539  static Cell cell;
    540  RefPtr<float> v10;
    541  Cell* ref_unsafe10 = &cell;
    542  // The destructor has a backwards path that skips the loop body.
    543  v10.assign_with_AddRef(&somefloat);
    544  while (flipcoin()) {
    545    v10.forget();
    546  }
    547  return ref_unsafe10;
    548 }
    549 
    550 std::pair<bool, AutoCheckCannotGC> pair_returning_function() {
    551  return std::make_pair(true, AutoCheckCannotGC());
    552 }
    553 
    554 void aggr_init_unsafe() {
    555  // nogc will be live after the call, so across the GC.
    556  auto [ok, nogc] = pair_returning_function();
    557  GC();
    558 }
    559 
    560 void aggr_init_safe() {
    561  // The analysis should be able to tell that nogc is only live after the call,
    562  // not before. (This is to check for a problem where the return value was
    563  // getting stored into a different temporary than the local nogc variable,
    564  // and so its initialization was never seen and so it was assumed to be live
    565  // throughout the function.)
    566  GC();
    567  auto [ok, nogc] = pair_returning_function();
    568 }
    569 
    570 void stack_array() {
    571  Cell* array[] = {makecell(), makecell()};
    572  Cell* array2[] = {makecell(), makecell()};
    573  GC();
    574  usecell(array[1]);
    575  // Never use array2.
    576 }