Skip to content

Commit f098b12

Browse files
committed
to keep ids in 32-bit range
1 parent dbcc164 commit f098b12

File tree

3 files changed

+47
-1
lines changed

3 files changed

+47
-1
lines changed

dart/packages/fory-test/test/datatype_test/enum_serializer_test.dart

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,5 +187,22 @@ void main() {
187187
final ByteReader reader = ByteReader.forBytes(writer.takeBytes());
188188
check(reader.readVarUint32Small7()).equals(1);
189189
});
190+
191+
test('throws when enum id is outside unsigned 32-bit range', () {
192+
final EnumSerializer serializer = EnumSerializer(false, [
193+
EnumWithIds.A,
194+
], {
195+
-1: EnumWithIds.A,
196+
});
197+
198+
final ByteWriter writer = ByteWriter();
199+
check(
200+
() => serializer.write(
201+
writer,
202+
EnumWithIds.A,
203+
_newSerializationContext(),
204+
),
205+
).throws<RangeError>();
206+
});
190207
});
191208
}

dart/packages/fory/lib/src/codegen/analyze/impl/struct/enum_analyzer_impl.dart

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ import 'package:fory/src/codegen/meta/impl/enum_spec_generator.dart';
2626
class EnumAnalyzerImpl implements EnumAnalyzer {
2727
const EnumAnalyzerImpl();
2828

29+
static const int _minEnumId = 0;
30+
static const int _maxEnumId = (1024 * 1024 * 1024 * 4) - 1; // 2^32 - 1
31+
2932
/// Finds a non-constant field annotated with @ForyEnumId().
3033
String? _findIdField(EnumElement enumElement) {
3134
for (final FieldElement field in enumElement.fields) {
@@ -69,6 +72,7 @@ class EnumAnalyzerImpl implements EnumAnalyzer {
6972
final Map<int, String> usedIds = <int, String>{};
7073
final List<String> duplicateIds = <String>[];
7174
final List<String> missingIdValues = <String>[];
75+
final List<String> outOfRangeIds = <String>[];
7276

7377
for (final FieldElement enumField in enumFields) {
7478
final int? id = idFieldName != null
@@ -80,6 +84,11 @@ class EnumAnalyzerImpl implements EnumAnalyzer {
8084
continue;
8185
}
8286

87+
if (id < _minEnumId || id > _maxEnumId) {
88+
outOfRangeIds.add('$id for ${enumField.name}');
89+
continue;
90+
}
91+
8392
final String? firstValueWithId = usedIds[id];
8493
if (firstValueWithId != null) {
8594
duplicateIds.add('$id for $firstValueWithId and ${enumField.name}');
@@ -90,7 +99,7 @@ class EnumAnalyzerImpl implements EnumAnalyzer {
9099
}
91100

92101
final bool useAnnotatedIds =
93-
missingIdValues.isEmpty && duplicateIds.isEmpty;
102+
missingIdValues.isEmpty && duplicateIds.isEmpty && outOfRangeIds.isEmpty;
94103
final bool hasAnyAnnotatedIds = enumIds.isNotEmpty;
95104
if (hasAnyAnnotatedIds && !useAnnotatedIds) {
96105
if (missingIdValues.isNotEmpty) {
@@ -107,6 +116,14 @@ class EnumAnalyzerImpl implements EnumAnalyzer {
107116
'All @ForyEnumId annotations are ignored and ordinal serialization is used.',
108117
);
109118
}
119+
if (outOfRangeIds.isNotEmpty) {
120+
print(
121+
'[WARNING] Enum $enumName in $packageName has @ForyEnumId values outside the '
122+
'unsigned 32-bit range (0 to 4294967295). '
123+
'Offending values: ${outOfRangeIds.join('; ')}. '
124+
'All @ForyEnumId annotations are ignored and ordinal serialization is used.',
125+
);
126+
}
110127
}
111128

112129
return EnumSpecGenerator(

dart/packages/fory/lib/src/serializer/enum_serializer.dart

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ final class _EnumSerializerCache extends SerializerCache {
5050
final class EnumSerializer extends CustomSerializer<Enum> {
5151
static const SerializerCache cache = _EnumSerializerCache();
5252

53+
static const int _minEnumId = 0;
54+
static const int _maxEnumId = (1024 * 1024 * 1024 * 4) - 1; // 2^32 - 1
55+
5356
final List<Enum> values;
5457
final Map<int, Enum>? _idToValue;
5558
final Map<Enum, int>? _valueToId;
@@ -101,6 +104,15 @@ final class EnumSerializer extends CustomSerializer<Enum> {
101104
'Enum value is missing from EnumSpec.idToValue mapping.',
102105
);
103106
}
107+
if (id < _minEnumId || id > _maxEnumId) {
108+
throw RangeError.range(
109+
id,
110+
_minEnumId,
111+
_maxEnumId,
112+
'id',
113+
'Enum id must be within unsigned 32-bit range.',
114+
);
115+
}
104116
bw.writeVarUint32Small7(id);
105117
return;
106118
}

0 commit comments

Comments
 (0)