Skip to content

Commit 84ffa91

Browse files
committed
Add bounds checks to DataView and fix some lint issues
1 parent 1882679 commit 84ffa91

File tree

5 files changed

+4512
-3017
lines changed

5 files changed

+4512
-3017
lines changed

std/assembly/dataview.ts

Lines changed: 106 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,129 +1,185 @@
1-
import { HEADER_SIZE } from "./internal/arraybuffer";
1+
import {
2+
HEADER_SIZE,
3+
MAX_BLENGTH
4+
} from "./internal/arraybuffer";
25

36
export class DataView {
7+
48
constructor(
59
readonly buffer: ArrayBuffer,
610
readonly byteOffset: i32 = 0,
7-
readonly byteLength: i32 = i32.MIN_VALUE,
11+
readonly byteLength: i32 = i32.MIN_VALUE // FIXME
812
) {
9-
if (byteLength === i32.MIN_VALUE) byteLength = buffer.byteLength - byteOffset;
10-
11-
if (byteOffset < 0) throw new RangeError("byteOffset cannot be negative");
12-
if (byteLength < 0) throw new RangeError("byteLength cannot be negative");
13-
if (byteOffset + byteLength > buffer.byteLength) throw new RangeError("Length out of range of buffer");
13+
if (byteLength === i32.MIN_VALUE) byteLength = buffer.byteLength - byteOffset; // FIXME
14+
if (<u32>byteOffset > <u32>MAX_BLENGTH) throw new RangeError("Invalid byteOffset");
15+
if (<u32>byteLength > <u32>MAX_BLENGTH) throw new RangeError("Invalid byteLength");
16+
if (byteOffset + byteLength > buffer.byteLength) throw new RangeError("Invalid length");
1417
}
1518

16-
@inline
1719
getFloat32(byteOffset: i32, littleEndian: boolean = false): f32 {
18-
var result: u32 = load<u32>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, HEADER_SIZE);
19-
return reinterpret<f32>(littleEndian ? result : bswap<u32>(result));
20+
checkOffset(byteOffset, 4, this.byteLength);
21+
return littleEndian
22+
? load<f32>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, HEADER_SIZE)
23+
: reinterpret<f32>(
24+
bswap<u32>(
25+
load<u32>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, HEADER_SIZE)
26+
)
27+
);
2028
}
2129

22-
@inline
2330
getFloat64(byteOffset: i32, littleEndian: boolean = false): f64 {
24-
var result: u64 = load<u64>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, HEADER_SIZE);
25-
return reinterpret<f64>(littleEndian ? result : bswap<u64>(result));
31+
checkOffset(byteOffset, 8, this.byteLength);
32+
return littleEndian
33+
? load<f64>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, HEADER_SIZE)
34+
: reinterpret<f64>(
35+
bswap(
36+
load<u64>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, HEADER_SIZE)
37+
)
38+
);
2639
}
2740

28-
@inline
2941
getInt8(byteOffset: i32): i8 {
42+
checkOffset(byteOffset, 1, this.byteLength);
3043
return load<i8>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, HEADER_SIZE);
3144
}
3245

33-
@inline
3446
getInt16(byteOffset: i32, littleEndian: boolean = false): i16 {
47+
checkOffset(byteOffset, 2, this.byteLength);
3548
var result: i16 = load<i16>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, HEADER_SIZE);
3649
return littleEndian ? result : bswap<i16>(result);
3750
}
3851

39-
@inline
4052
getInt32(byteOffset: i32, littleEndian: boolean = false): i32 {
41-
var result: i32 = load<i32>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, HEADER_SIZE);
53+
checkOffset(byteOffset, 4, this.byteLength);
54+
var result = load<i32>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, HEADER_SIZE);
4255
return littleEndian ? result : bswap<i32>(result);
4356
}
4457

45-
@inline
4658
getUint8(byteOffset: i32): u8 {
59+
checkOffset(byteOffset, 1, this.byteLength);
4760
return load<u8>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, HEADER_SIZE);
4861
}
4962

50-
@inline
5163
getUint16(byteOffset: i32, littleEndian: boolean = false): u16 {
64+
checkOffset(byteOffset, 2, this.byteLength);
5265
var result: u16 = load<u16>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, HEADER_SIZE);
5366
return littleEndian ? result : bswap<u16>(result);
5467
}
5568

56-
@inline
5769
getUint32(byteOffset: i32, littleEndian: boolean = false): u32 {
58-
var result: u32 = load<u32>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, HEADER_SIZE);
70+
checkOffset(byteOffset, 4, this.byteLength);
71+
var result = load<u32>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, HEADER_SIZE);
5972
return littleEndian ? result : bswap<u32>(result);
6073
}
6174

62-
@inline
6375
setFloat32(byteOffset: i32, value: f32, littleEndian: boolean = false): void {
64-
var input: f32 = littleEndian ? value : reinterpret<f32>(bswap<u32>(reinterpret<u32>(value)));
65-
store<f32>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, input, HEADER_SIZE);
76+
checkOffset(byteOffset, 4, this.byteLength);
77+
if (littleEndian) {
78+
store<f32>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, value, HEADER_SIZE);
79+
} else {
80+
store<u32>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset,
81+
bswap(
82+
reinterpret<u32>(value)
83+
),
84+
HEADER_SIZE
85+
);
86+
}
6687
}
6788

68-
@inline
6989
setFloat64(byteOffset: i32, value: f64, littleEndian: boolean = false): void {
70-
var input: f64 = littleEndian ? value : reinterpret<f64>(bswap<u64>(reinterpret<u64>(value)));
71-
store<f64>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, input, HEADER_SIZE);
90+
checkOffset(byteOffset, 8, this.byteLength);
91+
if (littleEndian) {
92+
store<f64>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, value, HEADER_SIZE);
93+
} else {
94+
store<u64>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset,
95+
bswap(
96+
reinterpret<u64>(value)
97+
),
98+
HEADER_SIZE
99+
);
100+
}
72101
}
73102

74-
@inline
75103
setInt8(byteOffset: i32, value: i8): void {
104+
checkOffset(byteOffset, 1, this.byteLength);
76105
store<i8>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, value, HEADER_SIZE);
77106
}
78107

79-
@inline
80108
setInt16(byteOffset: i32, value: i16, littleEndian: boolean = false): void {
81-
store<i16>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, littleEndian ? value : bswap<i16>(value), HEADER_SIZE);
109+
checkOffset(byteOffset, 2, this.byteLength);
110+
store<i16>(
111+
changetype<usize>(this.buffer) + this.byteOffset + byteOffset,
112+
littleEndian ? value : bswap(value),
113+
HEADER_SIZE
114+
);
82115
}
83116

84-
@inline
85117
setInt32(byteOffset: i32, value: i32, littleEndian: boolean = false): void {
86-
store<i32>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, littleEndian ? value : bswap<i32>(value), HEADER_SIZE);
118+
checkOffset(byteOffset, 4, this.byteLength);
119+
store<i32>(
120+
changetype<usize>(this.buffer) + this.byteOffset + byteOffset,
121+
littleEndian ? value : bswap(value),
122+
HEADER_SIZE
123+
);
87124
}
88125

89-
@inline
90126
setUint8(byteOffset: i32, value: u8): void {
127+
checkOffset(byteOffset, 1, this.byteLength);
91128
store<u8>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, value, HEADER_SIZE);
92129
}
93130

94-
@inline
95131
setUint16(byteOffset: i32, value: u16, littleEndian: boolean = false): void {
96-
store<u16>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, littleEndian ? value : bswap<u16>(value), HEADER_SIZE);
132+
checkOffset(byteOffset, 2, this.byteLength);
133+
store<u16>(
134+
changetype<usize>(this.buffer) + this.byteOffset + byteOffset,
135+
littleEndian ? value : bswap(value),
136+
HEADER_SIZE
137+
);
97138
}
98139

99-
@inline
100140
setUint32(byteOffset: i32, value: u32, littleEndian: boolean = false): void {
101-
store<u32>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, littleEndian ? value : bswap<u32>(value), HEADER_SIZE);
141+
checkOffset(byteOffset, 4, this.byteLength);
142+
store<u32>(
143+
changetype<usize>(this.buffer) + this.byteOffset + byteOffset,
144+
littleEndian ? value : bswap(value),
145+
HEADER_SIZE
146+
);
102147
}
103148

104-
/**
105-
* Non-standard additions that makes sense in WebAssembly, but won't work in JS
106-
*/
149+
// Non-standard additions that make sense in WebAssembly, but won't work in JS:
107150

108-
@inline
109151
getInt64(byteOffset: i32, littleEndian: boolean = false): i64 {
110-
var result: i64 = load<i64>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, HEADER_SIZE);
111-
return littleEndian ? result : bswap<i64>(result);
152+
checkOffset(byteOffset, 8, this.byteLength);
153+
var result = load<i64>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, HEADER_SIZE);
154+
return littleEndian ? result : bswap(result);
112155
}
113156

114-
@inline
115157
getUint64(byteOffset: i32, littleEndian: boolean = false): u64 {
116-
var result: u64 = load<u64>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, HEADER_SIZE);
117-
return littleEndian ? result : bswap<u64>(result);
158+
checkOffset(byteOffset, 8, this.byteLength);
159+
var result = load<u64>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, HEADER_SIZE);
160+
return littleEndian ? result : bswap(result);
118161
}
119162

120-
@inline
121163
setInt64(byteOffset: i32, value: i64, littleEndian: boolean = false): void {
122-
store<i64>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, littleEndian ? value : bswap<i64>(value), HEADER_SIZE);
164+
checkOffset(byteOffset, 8, this.byteLength);
165+
store<i64>(
166+
changetype<usize>(this.buffer) + this.byteOffset + byteOffset,
167+
littleEndian ? value : bswap(value),
168+
HEADER_SIZE
169+
);
123170
}
124171

125-
@inline
126172
setUint64(byteOffset: i32, value: u64, littleEndian: boolean = false): void {
127-
store<u64>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, littleEndian ? value : bswap<u64>(value), HEADER_SIZE);
173+
checkOffset(byteOffset, 8, this.byteLength);
174+
store<u64>(
175+
changetype<usize>(this.buffer) + this.byteOffset + byteOffset,
176+
littleEndian ? value : bswap(value),
177+
HEADER_SIZE
178+
);
128179
}
129180
}
181+
182+
@inline function checkOffset(byteOffset: i32, n: i32, byteLength: i32): void {
183+
// n and byteLength must be known to be in bounds
184+
if (<u32>byteOffset > <u32>MAX_BLENGTH || byteOffset + n > byteLength) throw new Error("Offset out of bounds");
185+
}

tests/compiler.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ tests.forEach(filename => {
184184
console.log(colorsUtil.red(" abort: " + getString(msg) + " at " + getString(file) + ":" + line + ":" + column));
185185
},
186186
trace: function(msg, n) {
187-
console.log(" " + getString(msg) + (n ? " " : "") + Array.prototype.slice.call(arguments, 2, 2 + n).join(", "));
187+
console.log(" trace: " + getString(msg) + (n ? " " : "") + Array.prototype.slice.call(arguments, 2, 2 + n).join(", "));
188188
},
189189
externalFunction: function() { },
190190
externalConstant: 1

0 commit comments

Comments
 (0)