Skip to content

Commit e673478

Browse files
alexmarkovCommit Queue
authored andcommitted
[vm, corelib] Fix bounds checks when accessing short ByteData buffers
TEST=tests/corelib/regress_57091_test.dart Fixes #57091 Change-Id: Iac828f49d5f4756f1aa228992ce054380bbd8422 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/395421 Commit-Queue: Alexander Markov <[email protected]> Reviewed-by: Martin Kustermann <[email protected]>
1 parent eca32d7 commit e673478

File tree

2 files changed

+105
-20
lines changed

2 files changed

+105
-20
lines changed

sdk/lib/_internal/vm/lib/typed_data_patch.dart

Lines changed: 62 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5157,7 +5157,9 @@ final class _ByteDataView implements ByteData {
51575157

51585158
@pragma("vm:prefer-inline")
51595159
int getInt16(int byteOffset, [Endian endian = Endian.big]) {
5160-
byteOffset = _byteDataByteOffsetCheck(this, byteOffset, length - 1);
5160+
// Check bounds for range [byteOffset, byteOffset + 1].
5161+
_byteDataByteOffsetCheck(this, byteOffset + 1, length);
5162+
byteOffset = _byteDataByteOffsetCheck(this, byteOffset, length);
51615163
var result = _typedData._getInt16(offsetInBytes + byteOffset);
51625164
if (identical(endian, Endian.host)) {
51635165
return result;
@@ -5167,7 +5169,9 @@ final class _ByteDataView implements ByteData {
51675169

51685170
@pragma("vm:prefer-inline")
51695171
void setInt16(int byteOffset, int value, [Endian endian = Endian.big]) {
5170-
byteOffset = _byteDataByteOffsetCheck(this, byteOffset, length - 1);
5172+
// Check bounds for range [byteOffset, byteOffset + 1].
5173+
_byteDataByteOffsetCheck(this, byteOffset + 1, length);
5174+
byteOffset = _byteDataByteOffsetCheck(this, byteOffset, length);
51715175
_typedData._setInt16(
51725176
offsetInBytes + byteOffset,
51735177
identical(endian, Endian.host) ? value : _byteSwap16(value),
@@ -5176,7 +5180,9 @@ final class _ByteDataView implements ByteData {
51765180

51775181
@pragma("vm:prefer-inline")
51785182
int getUint16(int byteOffset, [Endian endian = Endian.big]) {
5179-
byteOffset = _byteDataByteOffsetCheck(this, byteOffset, length - 1);
5183+
// Check bounds for range [byteOffset, byteOffset + 1].
5184+
_byteDataByteOffsetCheck(this, byteOffset + 1, length);
5185+
byteOffset = _byteDataByteOffsetCheck(this, byteOffset, length);
51805186
var result = _typedData._getUint16(offsetInBytes + byteOffset);
51815187
if (identical(endian, Endian.host)) {
51825188
return result;
@@ -5186,7 +5192,9 @@ final class _ByteDataView implements ByteData {
51865192

51875193
@pragma("vm:prefer-inline")
51885194
void setUint16(int byteOffset, int value, [Endian endian = Endian.big]) {
5189-
byteOffset = _byteDataByteOffsetCheck(this, byteOffset, length - 1);
5195+
// Check bounds for range [byteOffset, byteOffset + 1].
5196+
_byteDataByteOffsetCheck(this, byteOffset + 1, length);
5197+
byteOffset = _byteDataByteOffsetCheck(this, byteOffset, length);
51905198
_typedData._setUint16(
51915199
offsetInBytes + byteOffset,
51925200
identical(endian, Endian.host) ? value : _byteSwap16(value),
@@ -5195,7 +5203,9 @@ final class _ByteDataView implements ByteData {
51955203

51965204
@pragma("vm:prefer-inline")
51975205
int getInt32(int byteOffset, [Endian endian = Endian.big]) {
5198-
byteOffset = _byteDataByteOffsetCheck(this, byteOffset, length - 3);
5206+
// Check bounds for range [byteOffset, byteOffset + 3].
5207+
_byteDataByteOffsetCheck(this, byteOffset + 3, length);
5208+
byteOffset = _byteDataByteOffsetCheck(this, byteOffset, length);
51995209
var result = _typedData._getInt32(offsetInBytes + byteOffset);
52005210
if (identical(endian, Endian.host)) {
52015211
return result;
@@ -5205,7 +5215,9 @@ final class _ByteDataView implements ByteData {
52055215

52065216
@pragma("vm:prefer-inline")
52075217
void setInt32(int byteOffset, int value, [Endian endian = Endian.big]) {
5208-
byteOffset = _byteDataByteOffsetCheck(this, byteOffset, length - 3);
5218+
// Check bounds for range [byteOffset, byteOffset + 3].
5219+
_byteDataByteOffsetCheck(this, byteOffset + 3, length);
5220+
byteOffset = _byteDataByteOffsetCheck(this, byteOffset, length);
52095221
_typedData._setInt32(
52105222
offsetInBytes + byteOffset,
52115223
identical(endian, Endian.host) ? value : _byteSwap32(value),
@@ -5214,7 +5226,9 @@ final class _ByteDataView implements ByteData {
52145226

52155227
@pragma("vm:prefer-inline")
52165228
int getUint32(int byteOffset, [Endian endian = Endian.big]) {
5217-
byteOffset = _byteDataByteOffsetCheck(this, byteOffset, length - 3);
5229+
// Check bounds for range [byteOffset, byteOffset + 3].
5230+
_byteDataByteOffsetCheck(this, byteOffset + 3, length);
5231+
byteOffset = _byteDataByteOffsetCheck(this, byteOffset, length);
52185232
var result = _typedData._getUint32(offsetInBytes + byteOffset);
52195233
if (identical(endian, Endian.host)) {
52205234
return result;
@@ -5224,7 +5238,9 @@ final class _ByteDataView implements ByteData {
52245238

52255239
@pragma("vm:prefer-inline")
52265240
void setUint32(int byteOffset, int value, [Endian endian = Endian.big]) {
5227-
byteOffset = _byteDataByteOffsetCheck(this, byteOffset, length - 3);
5241+
// Check bounds for range [byteOffset, byteOffset + 3].
5242+
_byteDataByteOffsetCheck(this, byteOffset + 3, length);
5243+
byteOffset = _byteDataByteOffsetCheck(this, byteOffset, length);
52285244
_typedData._setUint32(
52295245
offsetInBytes + byteOffset,
52305246
identical(endian, Endian.host) ? value : _byteSwap32(value),
@@ -5233,7 +5249,9 @@ final class _ByteDataView implements ByteData {
52335249

52345250
@pragma("vm:prefer-inline")
52355251
int getInt64(int byteOffset, [Endian endian = Endian.big]) {
5236-
byteOffset = _byteDataByteOffsetCheck(this, byteOffset, length - 7);
5252+
// Check bounds for range [byteOffset, byteOffset + 7].
5253+
_byteDataByteOffsetCheck(this, byteOffset + 7, length);
5254+
byteOffset = _byteDataByteOffsetCheck(this, byteOffset, length);
52375255
var result = _typedData._getInt64(offsetInBytes + byteOffset);
52385256
if (identical(endian, Endian.host)) {
52395257
return result;
@@ -5243,7 +5261,9 @@ final class _ByteDataView implements ByteData {
52435261

52445262
@pragma("vm:prefer-inline")
52455263
void setInt64(int byteOffset, int value, [Endian endian = Endian.big]) {
5246-
byteOffset = _byteDataByteOffsetCheck(this, byteOffset, length - 7);
5264+
// Check bounds for range [byteOffset, byteOffset + 7].
5265+
_byteDataByteOffsetCheck(this, byteOffset + 7, length);
5266+
byteOffset = _byteDataByteOffsetCheck(this, byteOffset, length);
52475267
_typedData._setInt64(
52485268
offsetInBytes + byteOffset,
52495269
identical(endian, Endian.host) ? value : _byteSwap64(value),
@@ -5252,7 +5272,9 @@ final class _ByteDataView implements ByteData {
52525272

52535273
@pragma("vm:prefer-inline")
52545274
int getUint64(int byteOffset, [Endian endian = Endian.big]) {
5255-
byteOffset = _byteDataByteOffsetCheck(this, byteOffset, length - 7);
5275+
// Check bounds for range [byteOffset, byteOffset + 7].
5276+
_byteDataByteOffsetCheck(this, byteOffset + 7, length);
5277+
byteOffset = _byteDataByteOffsetCheck(this, byteOffset, length);
52565278
var result = _typedData._getUint64(offsetInBytes + byteOffset);
52575279
if (identical(endian, Endian.host)) {
52585280
return result;
@@ -5262,7 +5284,9 @@ final class _ByteDataView implements ByteData {
52625284

52635285
@pragma("vm:prefer-inline")
52645286
void setUint64(int byteOffset, int value, [Endian endian = Endian.big]) {
5265-
byteOffset = _byteDataByteOffsetCheck(this, byteOffset, length - 7);
5287+
// Check bounds for range [byteOffset, byteOffset + 7].
5288+
_byteDataByteOffsetCheck(this, byteOffset + 7, length);
5289+
byteOffset = _byteDataByteOffsetCheck(this, byteOffset, length);
52665290
_typedData._setUint64(
52675291
offsetInBytes + byteOffset,
52685292
identical(endian, Endian.host) ? value : _byteSwap64(value),
@@ -5271,7 +5295,9 @@ final class _ByteDataView implements ByteData {
52715295

52725296
@pragma("vm:prefer-inline")
52735297
double getFloat32(int byteOffset, [Endian endian = Endian.big]) {
5274-
byteOffset = _byteDataByteOffsetCheck(this, byteOffset, length - 3);
5298+
// Check bounds for range [byteOffset, byteOffset + 3].
5299+
_byteDataByteOffsetCheck(this, byteOffset + 3, length);
5300+
byteOffset = _byteDataByteOffsetCheck(this, byteOffset, length);
52755301
if (identical(endian, Endian.host)) {
52765302
return _typedData._getFloat32(offsetInBytes + byteOffset);
52775303
}
@@ -5283,7 +5309,9 @@ final class _ByteDataView implements ByteData {
52835309

52845310
@pragma("vm:prefer-inline")
52855311
void setFloat32(int byteOffset, double value, [Endian endian = Endian.big]) {
5286-
byteOffset = _byteDataByteOffsetCheck(this, byteOffset, length - 3);
5312+
// Check bounds for range [byteOffset, byteOffset + 3].
5313+
_byteDataByteOffsetCheck(this, byteOffset + 3, length);
5314+
byteOffset = _byteDataByteOffsetCheck(this, byteOffset, length);
52875315
if (identical(endian, Endian.host)) {
52885316
_typedData._setFloat32(offsetInBytes + byteOffset, value);
52895317
return;
@@ -5294,7 +5322,9 @@ final class _ByteDataView implements ByteData {
52945322

52955323
@pragma("vm:prefer-inline")
52965324
double getFloat64(int byteOffset, [Endian endian = Endian.big]) {
5297-
byteOffset = _byteDataByteOffsetCheck(this, byteOffset, length - 7);
5325+
// Check bounds for range [byteOffset, byteOffset + 7].
5326+
_byteDataByteOffsetCheck(this, byteOffset + 7, length);
5327+
byteOffset = _byteDataByteOffsetCheck(this, byteOffset, length);
52985328
if (identical(endian, Endian.host)) {
52995329
return _typedData._getFloat64(offsetInBytes + byteOffset);
53005330
}
@@ -5306,7 +5336,9 @@ final class _ByteDataView implements ByteData {
53065336

53075337
@pragma("vm:prefer-inline")
53085338
void setFloat64(int byteOffset, double value, [Endian endian = Endian.big]) {
5309-
byteOffset = _byteDataByteOffsetCheck(this, byteOffset, length - 7);
5339+
// Check bounds for range [byteOffset, byteOffset + 7].
5340+
_byteDataByteOffsetCheck(this, byteOffset + 7, length);
5341+
byteOffset = _byteDataByteOffsetCheck(this, byteOffset, length);
53105342
if (identical(endian, Endian.host)) {
53115343
_typedData._setFloat64(offsetInBytes + byteOffset, value);
53125344
return;
@@ -5316,7 +5348,9 @@ final class _ByteDataView implements ByteData {
53165348
}
53175349

53185350
Float32x4 getFloat32x4(int byteOffset, [Endian endian = Endian.big]) {
5319-
byteOffset = _byteDataByteOffsetCheck(this, byteOffset, length - 15);
5351+
// Check bounds for range [byteOffset, byteOffset + 15].
5352+
_byteDataByteOffsetCheck(this, byteOffset + 15, length);
5353+
byteOffset = _byteDataByteOffsetCheck(this, byteOffset, length);
53205354
// TODO(johnmccutchan) : Need to resolve this for endianity.
53215355
return _typedData._getFloat32x4(offsetInBytes + byteOffset);
53225356
}
@@ -5326,13 +5360,17 @@ final class _ByteDataView implements ByteData {
53265360
Float32x4 value, [
53275361
Endian endian = Endian.big,
53285362
]) {
5329-
byteOffset = _byteDataByteOffsetCheck(this, byteOffset, length - 15);
5363+
// Check bounds for range [byteOffset, byteOffset + 15].
5364+
_byteDataByteOffsetCheck(this, byteOffset + 15, length);
5365+
byteOffset = _byteDataByteOffsetCheck(this, byteOffset, length);
53305366
// TODO(johnmccutchan) : Need to resolve this for endianity.
53315367
_typedData._setFloat32x4(offsetInBytes + byteOffset, value);
53325368
}
53335369

53345370
Float64x2 getFloat64x2(int byteOffset, [Endian endian = Endian.big]) {
5335-
byteOffset = _byteDataByteOffsetCheck(this, byteOffset, length - 15);
5371+
// Check bounds for range [byteOffset, byteOffset + 15].
5372+
_byteDataByteOffsetCheck(this, byteOffset + 15, length);
5373+
byteOffset = _byteDataByteOffsetCheck(this, byteOffset, length);
53365374
// TODO(johnmccutchan) : Need to resolve this for endianity.
53375375
return _typedData._getFloat64x2(offsetInBytes + byteOffset);
53385376
}
@@ -5342,7 +5380,9 @@ final class _ByteDataView implements ByteData {
53425380
Float64x2 value, [
53435381
Endian endian = Endian.big,
53445382
]) {
5345-
byteOffset = _byteDataByteOffsetCheck(this, byteOffset, length - 15);
5383+
// Check bounds for range [byteOffset, byteOffset + 15].
5384+
_byteDataByteOffsetCheck(this, byteOffset + 15, length);
5385+
byteOffset = _byteDataByteOffsetCheck(this, byteOffset, length);
53465386
// TODO(johnmccutchan) : Need to resolve this for endianity.
53475387
_typedData._setFloat64x2(offsetInBytes + byteOffset, value);
53485388
}
@@ -5402,6 +5442,7 @@ void _throwIfNull(val, String name) {
54025442
}
54035443
}
54045444

5445+
// Length should be non-negative.
54055446
@pragma("vm:recognized", "other")
54065447
@pragma("vm:prefer-inline")
54075448
int _typedDataIndexCheck(Object indexable, int index, int length) {
@@ -5416,6 +5457,7 @@ int _typedDataIndexCheck(Object indexable, int index, int length) {
54165457
return index;
54175458
}
54185459

5460+
// Length should be non-negative.
54195461
@pragma("vm:recognized", "other")
54205462
@pragma("vm:prefer-inline")
54215463
int _byteDataByteOffsetCheck(ByteData indexable, int byteOffset, int length) {
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
// Regression test for https://github.com/dart-lang/sdk/issues/57091.
6+
// Verify that bounds checks correctly happen when accessing short ByteData.
7+
8+
import 'dart:typed_data';
9+
import "package:expect/expect.dart";
10+
11+
void testGet(ByteData data) {
12+
Expect.throws(() => data.getInt8(0));
13+
Expect.throws(() => data.getUint8(0));
14+
Expect.throws(() => data.getInt16(0));
15+
Expect.throws(() => data.getUint16(0));
16+
Expect.throws(() => data.getInt32(0));
17+
Expect.throws(() => data.getUint32(0));
18+
Expect.throws(() => data.getInt64(0));
19+
Expect.throws(() => data.getUint64(0));
20+
Expect.throws(() => data.getFloat32(0));
21+
Expect.throws(() => data.getFloat64(0));
22+
}
23+
24+
void testSet(ByteData data) {
25+
Expect.throws(() => data.setInt8(0, 0));
26+
Expect.throws(() => data.setUint8(0, 0));
27+
Expect.throws(() => data.setInt16(0, 0));
28+
Expect.throws(() => data.setUint16(0, 0));
29+
Expect.throws(() => data.setInt32(0, 0));
30+
Expect.throws(() => data.setUint32(0, 0));
31+
Expect.throws(() => data.setInt64(0, 0));
32+
Expect.throws(() => data.setUint64(0, 0));
33+
Expect.throws(() => data.setFloat32(0, 0));
34+
Expect.throws(() => data.setFloat64(0, 0));
35+
}
36+
37+
void main() {
38+
List<int> output = [];
39+
ByteData bytes = Uint8List.fromList(output).buffer.asByteData();
40+
testGet(bytes);
41+
testSet(bytes);
42+
testGet(bytes.asUnmodifiableView());
43+
}

0 commit comments

Comments
 (0)