summaryrefslogtreecommitdiffstats
path: root/js/src/tests/non262/extensions/clone-errors.js
blob: 38e0e78a6fb29240d697a80fe4ac3556899d689a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
// |reftest| skip-if(!xulRuntime.shell)
// -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// Any copyright is dedicated to the Public Domain.
// http://creativecommons.org/licenses/publicdomain/

function check(v) {
    try {
        serialize(v);
    } catch (exc) {
        return;
    }
    throw new Error("serializing " + JSON.stringify(v) + " should have failed with an exception");
}

// Unsupported object types.
check(this);
check(Math);
check(function () {});
check(new Proxy({}, {}));

// A failing getter.
check({get x() { throw new Error("fail"); }});

// Mismatched scopes.
for (let [write_scope, read_scope] of [['SameProcess', 'DifferentProcessForIndexedDB'],
                                       ['SameProcess', 'DifferentProcess']])
{
  var ab = new ArrayBuffer(12);
  var buffer = serialize(ab, [ab], { scope: write_scope });
  var caught = false;
  try {
    deserialize(buffer, { scope: read_scope });
  } catch (exc) {
    caught = true;
  }
  assertEq(caught, true, `${write_scope} clone buffer should not be deserializable as ${read_scope}`);
}

// Extra data. This is not checked in #define FUZZING builds.
const fuzzing = getBuildConfiguration()['fuzzing-defined'];
const shouldThrow = fuzzing === false;

var clone = serialize({foo: 7}, undefined, {scope: 'DifferentProcess'});
deserialize(clone);
clone.clonebuffer = clone.clonebuffer + "\0\0\0\0\0\0\0\0";
var exc = {message: 'no error'};
try {
  deserialize(clone);
} catch (e) {
  exc = e;
}
if (shouldThrow) {
  assertEq(exc.message.includes("bad serialized structured data"), true);
  assertEq(exc.message.includes("extra data"), true);
}

// Extra data between the main body and "tail" of the clone data.
function dumpData(data) {
  data.forEach((x, i) => print(`[${i}] 0x${(i*8).toString(16)} : 0x${x.toString(16)}`));
}

function testInnerExtraData() {
  const ab = new ArrayBuffer(8);
  (new BigUint64Array(ab))[0] = 0xdeadbeefn;
  const clone = serialize({ABC: 7, CBA: ab}, [ab], {scope: 'DifferentProcess'});

  const data = [...new BigUint64Array(clone.arraybuffer)];
  dumpData(data);

  const fake = new ArrayBuffer(clone.arraybuffer.byteLength + 24);
  const view = new BigUint64Array(fake);
  view.set(new BigUint64Array(clone.arraybuffer), 0);
  view[1] = view[1] & ~1n; // SCTAG_TRANSFER_MAP_HEADER with SCTAG_TM_UNREAD
  view[5] += 24n; // Make space for another ArrayBuffer clone at the end
  view[9] = 0xffff00030000000dn; // Change the constant 7 to 13
  view[16] = 0xfeeddeadbeef2dadn; // Change stored ArrayBuffer contents
  view[17] = view[14]; // SCTAG_ARRAY_BUFFER_OBJECT_V2
  view[18] = view[15]; // 8 bytes long
  view[19] = 0x1cedc0ffeen; // Content

  dumpData(view);
  clone.arraybuffer = fake;

  let d;
  let exc;
  try {
    d = deserialize(clone);
    print(JSON.stringify(d));
    print(new BigUint64Array(d.CBA)[0].toString(16));
  } catch (e) {
    exc = e;
  }

  const fuzzing = getBuildConfiguration()['fuzzing-defined'];
  const shouldThrow = fuzzing === false;

  if (shouldThrow) {
    assertEq(Boolean(exc), true);
    assertEq(exc.message.includes("extra data"), true);
    print(`PASS with FUZZING: Found expected exception "${exc.message}"`);
  } else {
    assertEq(new BigUint64Array(d.CBA)[0].toString(16), "1cedc0ffee");
    assertEq(d.ABC, 13);
    print("PASS without FUZZING");
  }
}

testInnerExtraData();

reportCompare(0, 0, "ok");