◐ Shell
clean mode source ↗

lib: short-circuit WebIDL BufferSource SAB check · nodejs/node@37d3913

1+

// Flags: --expose-internals

2+

'use strict';

3+4+

require('../common');

5+

const assert = require('assert');

6+

const { test } = require('node:test');

7+8+

const { converters } = require('internal/webidl');

9+10+

const TYPED_ARRAY_CTORS = [

11+

Uint8Array, Int8Array, Uint8ClampedArray,

12+

Uint16Array, Int16Array,

13+

Uint32Array, Int32Array,

14+

Float16Array, Float32Array, Float64Array,

15+

BigInt64Array, BigUint64Array,

16+

];

17+18+

test('BufferSource accepts ArrayBuffer', () => {

19+

const ab = new ArrayBuffer(8);

20+

assert.strictEqual(converters.BufferSource(ab), ab);

21+

});

22+23+

test('BufferSource accepts all TypedArray kinds', () => {

24+

for (const Ctor of TYPED_ARRAY_CTORS) {

25+

const ta = new Ctor(4);

26+

assert.strictEqual(converters.BufferSource(ta), ta);

27+

}

28+

});

29+30+

test('BufferSource accepts Buffer', () => {

31+

const buf = Buffer.alloc(8);

32+

assert.strictEqual(converters.BufferSource(buf), buf);

33+

});

34+35+

test('BufferSource accepts DataView', () => {

36+

const dv = new DataView(new ArrayBuffer(8));

37+

assert.strictEqual(converters.BufferSource(dv), dv);

38+

});

39+40+

test('BufferSource accepts ArrayBuffer subclass instance', () => {

41+

class MyAB extends ArrayBuffer {}

42+

const sub = new MyAB(8);

43+

assert.strictEqual(converters.BufferSource(sub), sub);

44+

});

45+46+

test('BufferSource accepts TypedArray with null prototype', () => {

47+

const ta = new Uint8Array(4);

48+

Object.setPrototypeOf(ta, null);

49+

assert.strictEqual(converters.BufferSource(ta), ta);

50+

});

51+52+

test('BufferSource accepts DataView with null prototype', () => {

53+

const dv = new DataView(new ArrayBuffer(4));

54+

Object.setPrototypeOf(dv, null);

55+

assert.strictEqual(converters.BufferSource(dv), dv);

56+

});

57+58+

test('BufferSource accepts ArrayBuffer with null prototype', () => {

59+

const ab = new ArrayBuffer(4);

60+

Object.setPrototypeOf(ab, null);

61+

assert.strictEqual(converters.BufferSource(ab), ab);

62+

});

63+64+

test('BufferSource rejects SharedArrayBuffer', () => {

65+

assert.throws(

66+

() => converters.BufferSource(new SharedArrayBuffer(4)),

67+

{ code: 'ERR_INVALID_ARG_TYPE' },

68+

);

69+

});

70+71+

test('BufferSource rejects SAB-backed TypedArray', () => {

72+

const view = new Uint8Array(new SharedArrayBuffer(4));

73+

assert.throws(

74+

() => converters.BufferSource(view),

75+

{ code: 'ERR_INVALID_ARG_TYPE' },

76+

);

77+

});

78+79+

test('BufferSource rejects SAB-backed DataView', () => {

80+

const dv = new DataView(new SharedArrayBuffer(4));

81+

assert.throws(

82+

() => converters.BufferSource(dv),

83+

{ code: 'ERR_INVALID_ARG_TYPE' },

84+

);

85+

});

86+87+

test('BufferSource rejects SAB view whose buffer prototype was reassigned', () => {

88+

const sab = new SharedArrayBuffer(4);

89+

Object.setPrototypeOf(sab, ArrayBuffer.prototype);

90+

const view = new Uint8Array(sab);

91+

assert.throws(

92+

() => converters.BufferSource(view),

93+

{ code: 'ERR_INVALID_ARG_TYPE' },

94+

);

95+

});

96+97+

test('BufferSource accepts a detached ArrayBuffer', () => {

98+

const ab = new ArrayBuffer(8);

99+

structuredClone(ab, { transfer: [ab] });

100+

assert.strictEqual(ab.byteLength, 0);

101+

assert.strictEqual(converters.BufferSource(ab), ab);

102+

});

103+104+

test('BufferSource rejects objects with a forged @@toStringTag', () => {

105+

const fake = { [Symbol.toStringTag]: 'Uint8Array' };

106+

assert.throws(

107+

() => converters.BufferSource(fake),

108+

{ code: 'ERR_INVALID_ARG_TYPE' },

109+

);

110+

});

111+112+

for (const value of [null, undefined, 0, 1, 1n, '', 'x', true, Symbol('s'), [],

113+

{}, () => {}]) {

114+

test(`BufferSource rejects ${typeof value} ${String(value)}`, () => {

115+

assert.throws(

116+

() => converters.BufferSource(value),

117+

{ code: 'ERR_INVALID_ARG_TYPE' },

118+

);

119+

});

120+

}

121+122+

test('ArrayBufferView accepts all TypedArray kinds', () => {

123+

for (const Ctor of TYPED_ARRAY_CTORS) {

124+

const ta = new Ctor(4);

125+

assert.strictEqual(converters.ArrayBufferView(ta), ta);

126+

}

127+

});

128+129+

test('ArrayBufferView accepts DataView', () => {

130+

const dv = new DataView(new ArrayBuffer(8));

131+

assert.strictEqual(converters.ArrayBufferView(dv), dv);

132+

});

133+134+

test('ArrayBufferView accepts TypedArray subclass instance', () => {

135+

class MyU8 extends Uint8Array {}

136+

const sub = new MyU8(4);

137+

assert.strictEqual(converters.ArrayBufferView(sub), sub);

138+

});

139+140+

test('ArrayBufferView accepts TypedArray with null prototype', () => {

141+

const ta = new Uint8Array(4);

142+

Object.setPrototypeOf(ta, null);

143+

assert.strictEqual(converters.ArrayBufferView(ta), ta);

144+

});

145+146+

test('ArrayBufferView accepts DataView with null prototype', () => {

147+

const dv = new DataView(new ArrayBuffer(4));

148+

Object.setPrototypeOf(dv, null);

149+

assert.strictEqual(converters.ArrayBufferView(dv), dv);

150+

});

151+152+

test('ArrayBufferView rejects raw ArrayBuffer', () => {

153+

assert.throws(

154+

() => converters.ArrayBufferView(new ArrayBuffer(4)),

155+

{ code: 'ERR_INVALID_ARG_TYPE' },

156+

);

157+

});

158+159+

test('ArrayBufferView rejects raw SharedArrayBuffer', () => {

160+

assert.throws(

161+

() => converters.ArrayBufferView(new SharedArrayBuffer(4)),

162+

{ code: 'ERR_INVALID_ARG_TYPE' },

163+

);

164+

});

165+166+

test('ArrayBufferView rejects SAB-backed TypedArray', () => {

167+

const view = new Uint8Array(new SharedArrayBuffer(4));

168+

assert.throws(

169+

() => converters.ArrayBufferView(view),

170+

{ code: 'ERR_INVALID_ARG_TYPE' },

171+

);

172+

});

173+174+

test('ArrayBufferView rejects SAB-backed DataView', () => {

175+

const dv = new DataView(new SharedArrayBuffer(4));

176+

assert.throws(

177+

() => converters.ArrayBufferView(dv),

178+

{ code: 'ERR_INVALID_ARG_TYPE' },

179+

);

180+

});

181+182+

test('ArrayBufferView rejects SAB view whose buffer prototype was reassigned', () => {

183+

const sab = new SharedArrayBuffer(4);

184+

Object.setPrototypeOf(sab, ArrayBuffer.prototype);

185+

const view = new Uint8Array(sab);

186+

assert.throws(

187+

() => converters.ArrayBufferView(view),

188+

{ code: 'ERR_INVALID_ARG_TYPE' },

189+

);

190+

});

191+192+

test('ArrayBufferView rejects objects with a forged @@toStringTag', () => {

193+

const fake = { [Symbol.toStringTag]: 'Uint8Array' };

194+

assert.throws(

195+

() => converters.ArrayBufferView(fake),

196+

{ code: 'ERR_INVALID_ARG_TYPE' },

197+

);

198+

});

199+200+

for (const value of [null, undefined, 0, 1, 1n, '', 'x', true, Symbol('s'), [],

201+

{}, () => {}]) {

202+

test(`ArrayBufferView rejects ${typeof value} ${String(value)}`, () => {

203+

assert.throws(

204+

() => converters.ArrayBufferView(value),

205+

{ code: 'ERR_INVALID_ARG_TYPE' },

206+

);

207+

});

208+

}