tor-browser

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

async-max-frame-count.js (2979B)


      1 // Test that async stacks are limited on recursion.
      2 
      3 const defaultAsyncStackLimit = 60;
      4 
      5 function recur(n, limit) {
      6  if (n > 0) {
      7    return callFunctionWithAsyncStack(function recur() {return recur(n - 1, limit)},
      8                                      saveStack(limit), "Recurse");
      9  }
     10  return saveStack(limit);
     11 }
     12 
     13 function checkRecursion(n, limit) {
     14  print("checkRecursion(" + String(n) + ", " + String(limit) + ")");
     15 
     16  try {
     17    var stack = recur(n, limit);
     18  } catch (e) {
     19    // Some platforms, like ASAN builds, can end up overrecursing. Tolerate
     20    // these failures.
     21    assertEq(/too much recursion/.test("" + e), true);
     22    return;
     23  }
     24 
     25  // Async stacks are limited even if we didn't ask for a limit. There is a
     26  // default limit on frames attached on top of any synchronous frames, and
     27  // every time the limit is reached when capturing, half of the frames are
     28  // truncated from the old end of the async stack.
     29  if (limit == 0) {
     30    // Always add one synchronous frame that is the last call to `recur`.
     31    if (n + 1 < defaultAsyncStackLimit) {
     32      limit = defaultAsyncStackLimit + 1;
     33    } else {
     34      limit = n + 2 - (defaultAsyncStackLimit / 2);
     35    }
     36  }
     37 
     38  // The first `n` or `limit` frames should have `recur` as their `asyncParent`.
     39  for (var i = 0; i < Math.min(n, limit); i++) {
     40    assertEq(stack.functionDisplayName, "recur");
     41    assertEq(stack.parent, null);
     42    stack = stack.asyncParent;
     43  }
     44 
     45  // This frame should be the first call to `recur`.
     46  if (limit > n) {
     47    assertEq(stack.functionDisplayName, "recur");
     48    assertEq(stack.asyncParent, null);
     49    stack = stack.parent;
     50  } else {
     51    assertEq(stack, null);
     52  }
     53 
     54  // This frame should be the call to `checkRecursion`.
     55  if (limit > n + 1) {
     56    assertEq(stack.functionDisplayName, "checkRecursion");
     57    assertEq(stack.asyncParent, null);
     58    stack = stack.parent;
     59  } else {
     60    assertEq(stack, null);
     61  }
     62 
     63  // We should be at the top frame, which is the test script itself.
     64  if (limit > n + 2) {
     65    assertEq(stack.functionDisplayName, null);
     66    assertEq(stack.asyncParent, null);
     67    assertEq(stack.parent, null);
     68  } else {
     69    assertEq(stack, null);
     70  }
     71 }
     72 
     73 // Check capturing with no limit, which should still apply a default limit.
     74 checkRecursion(0, 0);
     75 checkRecursion(1, 0);
     76 checkRecursion(2, 0);
     77 checkRecursion(defaultAsyncStackLimit - 10, 0);
     78 checkRecursion(defaultAsyncStackLimit, 0);
     79 checkRecursion(defaultAsyncStackLimit + 10, 0);
     80 
     81 // Limit of 1 frame.
     82 checkRecursion(0, 1);
     83 checkRecursion(1, 1);
     84 checkRecursion(2, 1);
     85 
     86 // Limit of 2 frames.
     87 checkRecursion(0, 2);
     88 checkRecursion(1, 2);
     89 checkRecursion(2, 2);
     90 
     91 // Limit of 3 frames.
     92 checkRecursion(0, 3);
     93 checkRecursion(1, 3);
     94 checkRecursion(2, 3);
     95 
     96 // Limit higher than the default limit.
     97 checkRecursion(defaultAsyncStackLimit + 10, defaultAsyncStackLimit + 10);
     98 checkRecursion(defaultAsyncStackLimit + 11, defaultAsyncStackLimit + 10);
     99 checkRecursion(defaultAsyncStackLimit + 12, defaultAsyncStackLimit + 10);