Skip to content

feat(dart): add configurable deserialization size guardrails #3434

Merged
chaokunyang merged 5 commits intoapache:mainfrom
yash-agarwa-l:dart_size_limits
Feb 28, 2026
Merged

feat(dart): add configurable deserialization size guardrails #3434
chaokunyang merged 5 commits intoapache:mainfrom
yash-agarwa-l:dart_size_limits

Conversation

@yash-agarwa-l
Copy link
Contributor

@yash-agarwa-l yash-agarwa-l commented Feb 28, 2026

Why?

Untrusted payloads can encode arbitrarily large collection/binary lengths,
causing pre-allocation of huge buffers and OOM crashes before any
elements are even deserialized.

What does this PR do?

  • Adds two config options maxBinarySize and maxCollectionSize
    to ForyConfig (defaults to 1000000 Collection Size and 64MB for BinarySize).
  • Threads ForyConfig into DeserializationContext so serializers can
    access limits at read time.
  • Adds InvalidDataException following existing exception conventions.
  • Enforces maxCollectionSize in ListSerializer, SetSerializer, and
    MapSerializer before pre-allocation.
  • Enforces maxBinarySize in NumericArraySerializer for ObjType.BINARY
    before buffer copy.
  • Adds 15 test cases covering within-limit, at-limit, exceeded, empty,
    and default scenarios for lists, sets, maps, and binary.

Related issues

Closes #3415.

Does this PR introduce any user-facing change?

  • Does this PR introduce any public API change?
  • Does this PR introduce any binary protocol compatibility change?

Benchmark

N/A — guard checks are a single null-check + comparison per
collection/binary read; no measurable performance impact.

}
}

class DeserializationSizeException extends DeserializationException {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We dont' need so many special exception. Could you create a InvalidDataException in dart/packages/fory/lib/src/exception/fory_exception.dart?

Adn open anoterh PR to merge all excpetions into one file name fory_exception.dart under dart/packages/fory/lib/src/ dir? Current fory dart is too java style

@override
T read(ByteReader br, int refId, DeserializationContext pack) {
int remaining = br.readVarUint32Small7();
final int? maxCollectionSize = pack.config.maxCollectionSize;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you should set a default value for maxCollectionSize and maxBinary Size instead use null to span across whole repo

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Set maxCollectionSize to 1000_000, and maxBinarySize default to 64MB

@yash-agarwa-l
Copy link
Contributor Author

Thanks for the reviews, I have made the changes and will also put up a PR for the exceptions.
Just a follow up -- I’ve added a new commit for now. Although it will be squashed into a single commit, is there a preference to amend the original commit, or is a new commit fine?

'Collection', remaining, maxCollectionSize);
if (remaining > pack.config.maxCollectionSize) {
throw InvalidDataException(
'Collection size $remaining exceeds limit ${pack.config.maxCollectionSize}');
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please refine thev error message, to tell user either the inout data is malicouse , or user need to increase maxCollectionSize or maxBinarySize when creating Fory. ditto for other InvalidDataException construction

@yash-agarwa-l
Copy link
Contributor Author

changes made, PTAL.

@chaokunyang
Copy link
Collaborator

Please rename size_guardrail_test.dart to size_guard_test.dart, other parts look good to me

});
});

group('combined guardrails', () {
Copy link
Collaborator

@chaokunyang chaokunyang Feb 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rename all guardrails to guard check

@yash-agarwa-l
Copy link
Contributor Author

done!

@chaokunyang
Copy link
Collaborator

You added two same tests file...:

  • dart/packages/fory-test/test/config_test/size_guard_test.dart
  • dart/packages/fory-test/test/config_test/size_guardrail_test.dart

@yash-agarwa-l
Copy link
Contributor Author

My bad, I missed to add that change that time

Copy link
Collaborator

@chaokunyang chaokunyang left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@chaokunyang chaokunyang merged commit 13eda46 into apache:main Feb 28, 2026
58 checks passed
chaokunyang pushed a commit that referenced this pull request Feb 28, 2026
…on.dart (#3436)

## Why?

The current Dart exception hierarchy spreads runtime exceptions across
four separate files under `dart/packages/fory/lib/src/exception/`, which
is overly Java-style for idiomatic Dart.

## What needs to be done?

- Merge all runtime exception classes from:
  - `exception/**`
  - `codegen/exception/**`
  into a single file: `dart/packages/fory/lib/src/fory_exception.dart`

- Update all imports across serializers, resolvers, context, and codegen
base to point to the new file.
- Delete the `exception/` subdirectory and the `codegen/exception/`
subdirectory.

## Does this introduce any user-facing change?

- [x] Does this introduce any public API change? (import paths change)
- [ ] Does this introduce any binary protocol compatibility change?

## Related

- Requested in #3434 review:
#3434 (comment)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Dart] configurable size guardrails for untrusted payloads

2 participants