tor-browser

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

nnl-test.js (4508B)


      1 // Generates combinations of different block types and operations for
      2 // non-defaultable locals (local.set / .tee / .get).
      3 // See the function references specification on the updated algorithm
      4 // for validating non-null references in locals.
      5 
      6 const KINDS = [
      7  "block",
      8  "loop",
      9  "try",
     10  "catch",
     11  "delegate",
     12  "if",
     13  "else",
     14 ]
     15 const INITIALIZED = [
     16  "nowhere",
     17  "outer",
     18  "inner",
     19  "outer-tee",
     20  "inner-tee",
     21 ];
     22 const USED = [
     23  "outer",
     24  "inner",
     25  "after-inner",
     26  "after-outer",
     27 ];
     28 
     29 function generateBlock(kind, contents) {
     30  switch (kind) {
     31    case "block": {
     32      return `block\n${contents}end\n`
     33    }
     34    case "loop": {
     35      return `loop\n${contents}end\n`
     36    }
     37    case "try": {
     38      return `try\n${contents}end\n`
     39    }
     40    case "catch": {
     41      return `try\ncatch_all\n${contents}end\n`
     42    }
     43    case "delegate": {
     44      return `try\n${contents}\ndelegate 0\n`
     45    }
     46    case "if": {
     47      return `i32.const 0\nif\n${contents}end\n`
     48    }
     49    case "else": {
     50      return `i32.const 0\nif\nelse\n${contents}end\n`
     51    }
     52  }
     53 }
     54 
     55 // Generate a variation of the module below:
     56 //
     57 // (func
     58 //  (block
     59 //    $outer
     60 //    (block
     61 //      $inner
     62 //    )
     63 //    $after-inner
     64 //  )
     65 //  $after-outer
     66 // )
     67 //
     68 // Where a local is used and initialized at different points depending on the
     69 // parameters. The block kinds of the inner and outer block may also be
     70 // customized.
     71 function generateModule(outerBlockKind, innerBlockKind, initializedWhere, usedWhere) {
     72  const INITIALIZE_STMT = '(local.set 0 ref.func 0)\n';
     73  const INITIALIZE_STMT2 = '(drop (local.tee 0 ref.func 0))\n';
     74  const USE_STMT = '(drop local.get 0)\n';
     75 
     76  // inner block
     77  let innerBlockContents = '';
     78  if (initializedWhere === 'inner') {
     79    innerBlockContents += INITIALIZE_STMT;
     80  } else if (initializedWhere === 'inner-tee') {
     81    innerBlockContents += INITIALIZE_STMT2;
     82  }
     83  if (usedWhere === 'inner') {
     84    innerBlockContents += USE_STMT;
     85  }
     86  let innerBlock = generateBlock(innerBlockKind, innerBlockContents);
     87 
     88  // outer block
     89  let outerBlockContents = '';
     90  if (initializedWhere === 'outer') {
     91    outerBlockContents += INITIALIZE_STMT;
     92  } else if (initializedWhere === 'outer-tee') {
     93    outerBlockContents += INITIALIZE_STMT2;
     94  }
     95  if (usedWhere === 'outer') {
     96    outerBlockContents += USE_STMT;
     97  }
     98  outerBlockContents += innerBlock;
     99  if (usedWhere === 'after-inner') {
    100    outerBlockContents += USE_STMT;
    101  }
    102  let outerBlock = generateBlock(outerBlockKind, outerBlockContents);
    103 
    104  // after outer block
    105  let afterOuterBlock = '';
    106  if (usedWhere === 'after-outer') {
    107    afterOuterBlock += USE_STMT;
    108  }
    109 
    110  return `(module
    111  (type $t (func))
    112  (func (export "test")
    113    (local (ref $t))
    114 ${outerBlock}${afterOuterBlock}  )
    115 )`;
    116 }
    117 
    118 const LOGGING = false;
    119 
    120 for (let outer of KINDS) {
    121  for (let inner of KINDS) {
    122    for (let initialized of INITIALIZED) {
    123      for (let used of USED) {
    124        let text = generateModule(outer, inner, initialized, used);
    125 
    126        let expectPass;
    127        switch (initialized) {
    128          case "outer":
    129          case "outer-tee": {
    130            // Defining the local in the outer block makes it valid
    131            // in the outer block, the inner block, and after the
    132            // inner block
    133            expectPass = used !== "after-outer";
    134            break;
    135          }
    136          case "inner":
    137          case "inner-tee": {
    138            // Defining the local in the inner block makes it valid
    139            // in the inner block
    140            //
    141            // NOTE: an extension to typing could make this valid
    142            // after the inner block in some cases
    143            expectPass = used === "inner";
    144            break;
    145          }
    146          case "nowhere": {
    147            // Not defining the local makes it always invalid to
    148            // use
    149            expectPass = false;
    150            break;
    151          }
    152        }
    153 
    154        if (LOGGING) {
    155          console.log();
    156          console.log(`TEST: outer=${outer}, inner=${inner}, initialized=${initialized}, used=${used}`);
    157          console.log(expectPass ? "EXPECT PASS" : "EXPECT FAIL");
    158          console.log(text);
    159        }
    160 
    161        let binary = wasmTextToBinary(text);
    162        assertEq(WebAssembly.validate(binary), expectPass);
    163        if (!expectPass) {
    164          // Check if the error message is right.
    165          try {
    166            new WebAssembly.Module(binary);
    167          } catch (ex) {
    168            assertEq(true, /local\.get read from unset local/.test(ex.message));
    169          }
    170        }
    171      }
    172    }
    173  }
    174 }