tor-browser

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

script-file-name-utf8.js (6709B)


      1 // |reftest| skip-if(!xulRuntime.shell)
      2 
      3 // Retrieve the script file name through various functions and ensure it's
      4 // always correctly decoded from UTF-8.
      5 
      6 // Special value when filename cannot be retrieved.
      7 const NOT_SUPPORTED = "*not supported*";
      8 
      9 // Return the file name from the Error#fileName property.
     10 function errorFileName(fileName) {
     11  return evaluate("new Error().fileName", {fileName});
     12 }
     13 
     14 // Return the file name from the Parser by a SyntaxError.
     15 function errorFileNameParser(fileName) {
     16  try {
     17    evaluate("###", {fileName});
     18  } catch (e) {
     19    return e.fileName;
     20  }
     21 }
     22 
     23 // Retrieve the file name through DescriptedCaller (1).
     24 function descriptedCallerViaThisFileName(fileName) {
     25  return evaluate("thisFilename()", {fileName});
     26 }
     27 
     28 // Retrieve the file name through DescriptedCaller (2).
     29 function descriptedCallerViaEvalInContext(fileName) {
     30  return evaluate("evalcx('new Error().fileName')", {fileName});
     31 }
     32 
     33 // Retrieve the file name through DescriptedCaller (3).
     34 function descriptedCallerViaEval(fileName) {
     35  var pattern = / line 1 > eval$/;
     36  return evaluate("eval('new Error().fileName')", {fileName}).replace(pattern, "");
     37 }
     38 
     39 // Retrieve the file name through DescriptedCaller (4).
     40 function descriptedCallerViaFunction(fileName) {
     41  var pattern = / line 1 > Function$/;
     42  return evaluate("Function('return new Error().fileName')()", {fileName}).replace(pattern, "");
     43 }
     44 
     45 // Retrieve the file name through DescriptedCaller (5).
     46 function descriptedCallerViaEvalReturningScope(fileName) {
     47  return evaluate("evalReturningScope('var a = new Error().fileName')", {fileName}).a;
     48 }
     49 
     50 // Retrieve the file name through DescriptedCaller (7).
     51 var wasmModuleConstructorTemp;
     52 function descriptedCallerViaWasm(fileName) {
     53  if (!wasmIsSupported()) {
     54    return fileName;
     55  }
     56 
     57  wasmModuleConstructorTemp = null;
     58  evaluate(`
     59    function wasmEvalText(str, imports) {
     60      let binary = wasmTextToBinary(str);
     61      assertEq(WebAssembly.validate(binary), true);
     62      let m = new WebAssembly.Module(binary);
     63      return new WebAssembly.Instance(m, imports);
     64    }
     65    wasmEvalText('(module (import "" "a" (func)) (func (call 0)) (export "bar" (func 1)))',
     66                  {
     67                    "": {
     68                      a() {
     69                        wasmModuleConstructorTemp = new Error().stack;
     70                        return 0;
     71                      }
     72                    }
     73                  }).exports.bar();
     74  `, {fileName});
     75  var pattern = /^@(.*) line \d+ >.*$/;
     76  var index = 1; // Direct caller is the wasm function.
     77  return wasmModuleConstructorTemp.split("\n")[index].replace(pattern, "$1");
     78 }
     79 
     80 // Return the file name from Reflect.parse().
     81 function reflectParseSource(fileName) {
     82  return Reflect.parse("", {source: fileName}).loc.source;
     83 }
     84 
     85 // Return the file name using the Error#stack property.
     86 function fromErrorStack(fileName) {
     87  var pattern = /^@(.*):\d+:\d+$/;
     88  return evaluate("new Error().stack", {fileName}).split("\n")[0].replace(pattern, "$1");
     89 }
     90 
     91 // Return the file name using the Error#stack property from an asm.js function.
     92 function fromErrorStackAsmJS(fileName) {
     93  var asm = evaluate(`(function asm(stdlib, foreign) {
     94    "use asm";
     95    var f = foreign.f;
     96    function g() {
     97      return f() | 0;
     98    }
     99    return {g: g};
    100  })`, {fileName});
    101 
    102  var stackFileName;
    103  var foreign = {
    104    f() {
    105      var pattern = /^g@(.*):\d+:\d+$/;
    106      var index = 1; // Direct caller is the asm.js function.
    107      var stack = new Error().stack;
    108      stackFileName = stack.split("\n")[index].replace(pattern, "$1");
    109      return 0;
    110    }
    111  };
    112 
    113  asm(this, foreign).g();
    114 
    115  return stackFileName;
    116 }
    117 
    118 // Return the file name using the Error#stacl property when a streaming compiled WASM function.
    119 function fromErrorStackStreamingWasm(fileName) {
    120  if (!wasmIsSupported() || helperThreadCount() == 0) {
    121    return fileName;
    122  }
    123 
    124  var source = new Uint8Array(wasmTextToBinary(`
    125    (module (import "" "a" (func)) (func (call 0)) (export "bar" (func 1)))
    126  `));
    127  source.url = fileName;
    128 
    129  var stackFileName;
    130  var imports = {
    131    "": {
    132      a() {
    133        var pattern = /^@(.*):wasm-function.*$/;
    134        var index = 1; // Direct caller is the asm.js function.
    135        var stack = new Error().stack;
    136        stackFileName = stack.split("\n")[index].replace(pattern, "$1");
    137        return 0;
    138      }
    139    }
    140  };
    141 
    142  var result;
    143  WebAssembly.instantiateStreaming(source, imports).then(r => result = r);
    144 
    145  drainJobQueue();
    146 
    147  result.instance.exports.bar();
    148 
    149  return stackFileName;
    150 }
    151 
    152 // Return the file name using the embedded info in getBacktrace().
    153 function getBacktraceScriptName(fileName) {
    154  var pattern = /^\d+ <TOP LEVEL> \["(.*)":\d+:\d\]$/;
    155  return evaluate("getBacktrace()", {fileName}).split("\n")[0].replace(pattern, "$1");
    156 }
    157 
    158 // Return the file name from the coverage report.
    159 function getLcovInfoScriptName(fileName) {
    160  var g = newGlobal();
    161  var scriptFiles =  g.evaluate("getLcovInfo()", {fileName})
    162                      .split("\n")
    163                      .filter(x => x.startsWith("SF:"));
    164  assertEq(scriptFiles.length, 1);
    165  return scriptFiles[0].substring(3);
    166 }
    167 
    168 // Return the file name from the error during module import.
    169 function moduleResolutionError(fileName) {
    170  const a = parseModule(`import { x } from "b";`, fileName);
    171  const ma = registerModule("a", a);
    172  const b = parseModule(`export var y = 10;`);
    173  const mb = registerModule("b", b);
    174 
    175  try {
    176    moduleLink(ma);
    177  } catch (e) {
    178    return e.fileName;
    179  }
    180 }
    181 
    182 // Return the file name from the profiler stack.
    183 function geckoInterpProfilingStack(fileName) {
    184  enableGeckoProfilingWithSlowAssertions();
    185  const stack = evaluate(`readGeckoInterpProfilingStack();`, { fileName });
    186  if (stack.length === 0) {
    187    return NOT_SUPPORTED;
    188  }
    189  const result = stack[0].dynamicString;
    190  disableGeckoProfiling();
    191  return result;
    192 }
    193 
    194 const testFunctions = [
    195  errorFileName,
    196  errorFileNameParser,
    197  descriptedCallerViaThisFileName,
    198  descriptedCallerViaEvalInContext,
    199  descriptedCallerViaEval,
    200  descriptedCallerViaFunction,
    201  descriptedCallerViaEvalReturningScope,
    202  descriptedCallerViaWasm,
    203  reflectParseSource,
    204  fromErrorStack,
    205  fromErrorStackAsmJS,
    206  fromErrorStackStreamingWasm,
    207  getBacktraceScriptName,
    208  moduleResolutionError,
    209 ];
    210 
    211 if (isLcovEnabled()) {
    212  testFunctions.push(getLcovInfoScriptName);
    213 }
    214 
    215 const fileNames = [
    216  "",
    217  "test",
    218  "Ðëßþ",
    219  "тест",
    220  "テスト",
    221  "\u{1F9EA}",
    222 ];
    223 
    224 for (const fn of testFunctions) {
    225  for (const fileName of fileNames) {
    226    const result = fn(fileName);
    227    if (result === NOT_SUPPORTED) {
    228      continue;
    229    }
    230    assertEq(result, fileName, `Caller '${fn.name}'`);
    231  }
    232 }
    233 
    234 if (typeof reportCompare === "function")
    235  reportCompare(true, true);