diff --git a/dart/packages/fory/lib/src/context/meta_string_reader.dart b/dart/packages/fory/lib/src/context/meta_string_reader.dart index 40d6d3aedb..fa17fe1345 100644 --- a/dart/packages/fory/lib/src/context/meta_string_reader.dart +++ b/dart/packages/fory/lib/src/context/meta_string_reader.dart @@ -54,7 +54,11 @@ final class MetaStringReader { final header = buffer.readVarUint32Small7(); final length = header >>> 1; if ((header & 1) == 1) { - return _dynamicReadMetaStrings[length - 1]; + final index = length - 1; + if (index < 0 || index >= _dynamicReadMetaStrings.length) { + throw StateError('Meta string ref index $index is out of range.'); + } + return _dynamicReadMetaStrings[index]; } final encoded = length > metaStringSmallThreshold ? _readBigMetaString(buffer, length, expected) diff --git a/dart/packages/fory/lib/src/context/ref_reader.dart b/dart/packages/fory/lib/src/context/ref_reader.dart index 09aaaf7feb..d7b0870b94 100644 --- a/dart/packages/fory/lib/src/context/ref_reader.dart +++ b/dart/packages/fory/lib/src/context/ref_reader.dart @@ -26,12 +26,19 @@ final class RefReader { Object? _resolved; int? _resolvedId; + Object? _readRefAt(int id) { + if (id < 0 || id >= _refs.length) { + throw StateError('Read ref id $id is out of range.'); + } + return _refs[id]; + } + int readRefOrNull(Buffer buffer) { final flag = buffer.readByte(); if (flag == RefWriter.refFlag) { final id = buffer.readVarUint32(); _resolvedId = id; - _resolved = _refs[id]; + _resolved = _readRefAt(id); return flag; } _resolvedId = null; @@ -68,9 +75,9 @@ final class RefReader { int? get readRefId => _resolvedId; - Object? getReadRef([int? id]) => id == null ? _resolved : _refs[id]; + Object? getReadRef([int? id]) => id == null ? _resolved : _readRefAt(id); - Object? readRefAt(int id) => _refs[id]; + Object? readRefAt(int id) => _readRefAt(id); void reference(Object? value) { if (_preservedIds.isEmpty) { @@ -86,6 +93,9 @@ final class RefReader { } void setReadRef(int id, Object? value) { + if (id < 0 || id >= _refs.length) { + throw StateError('Read ref id $id is out of range.'); + } _refs[id] = value; } diff --git a/dart/packages/fory/test/context/meta_string_reader_test.dart b/dart/packages/fory/test/context/meta_string_reader_test.dart new file mode 100644 index 0000000000..840eab39dd --- /dev/null +++ b/dart/packages/fory/test/context/meta_string_reader_test.dart @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import 'package:fory/src/config.dart'; +import 'package:fory/src/context/meta_string_reader.dart'; +import 'package:fory/src/memory/buffer.dart'; +import 'package:fory/src/meta/meta_string.dart'; +import 'package:fory/src/resolver/type_resolver.dart'; +import 'package:test/test.dart'; + +void main() { + test('readMetaString rejects a negative dynamic reference index', () { + final reader = MetaStringReader(TypeResolver(const Config())); + final buffer = Buffer(); + + buffer.writeVarUint32Small7(1); + bufferSetReaderIndex(buffer, 0); + + expect( + () => reader.readMetaString(buffer), + throwsA(isA()), + ); + }); + + test('readMetaString still resolves a valid dynamic reference', () { + final reader = MetaStringReader(TypeResolver(const Config())); + final buffer = Buffer(); + + buffer.writeVarUint32Small7(2); + buffer.writeByte(metaStringUtf8Encoding); + buffer.writeBytes([0x61]); + buffer.writeVarUint32Small7(3); + bufferSetReaderIndex(buffer, 0); + + final value = reader.readMetaString(buffer); + expect(value.bytes, orderedEquals([0x61])); + expect(reader.readMetaString(buffer).bytes, orderedEquals([0x61])); + }); +} \ No newline at end of file diff --git a/dart/packages/fory/test/context/ref_reader_test.dart b/dart/packages/fory/test/context/ref_reader_test.dart new file mode 100644 index 0000000000..a1e4417c8a --- /dev/null +++ b/dart/packages/fory/test/context/ref_reader_test.dart @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import 'package:fory/src/context/ref_reader.dart'; +import 'package:fory/src/context/ref_writer.dart'; +import 'package:fory/src/memory/buffer.dart'; +import 'package:test/test.dart'; + +void main() { + test('readRefOrNull rejects out-of-range ref ids', () { + final reader = RefReader(); + final buffer = Buffer(); + + buffer.writeByte(RefWriter.refFlag); + buffer.writeVarUint32(9999); + bufferSetReaderIndex(buffer, 0); + + expect( + () => reader.readRefOrNull(buffer), + throwsA(isA()), + ); + }); + + test('getReadRef rejects out-of-range ref ids', () { + final reader = RefReader(); + + expect( + () => reader.getReadRef(9999), + throwsA(isA()), + ); + }); +} \ No newline at end of file