Skip to content

Type-check the exemplar in the EnumMap server field serializer - #10392

Open
Nexory wants to merge 2 commits into
gwtproject:mainfrom
Nexory:enummap-server-typecheck
Open

Type-check the exemplar in the EnumMap server field serializer#10392
Nexory wants to merge 2 commits into
gwtproject:mainfrom
Nexory:enummap-server-typecheck

Conversation

@Nexory

@Nexory Nexory commented Aug 11, 2026

Copy link
Copy Markdown

Fixes #10391.

EnumMap_ServerCustomFieldSerializer overrode the type-checking server
instantiateInstance but threw the type information away and called the
untyped client instantiate, which reads the exemplar with a bare
readObject(). Every other collection serializer reads what it instantiates
from through the typed path; TreeMap/TreeSet are the direct precedent
(readObject(Comparator.class, resolvedTypes)).

Because the exemplar was read untyped, a request could substitute a non-enum
type for it, and new EnumMap(nonEnumClass) throws an uncaught
NullPointerException (keyUniverse is null) instead of a clean serialization
error.

This adds a server-side instantiate(streamReader, expectedParameterTypes, resolvedTypes) that reads the exemplar with readObject(Enum.class, resolvedTypes), so a non-enum is rejected with SerializedTypeViolationException
the same way the other serializers reject mismatched types. A legitimate enum
constant still passes, and the resulting getClass() is unchanged from before,
so behaviour for valid EnumMaps is identical.

Test

RPCTypeCheckTest.testEnumMapSpoofingClass builds an EnumMap RPC message whose
exemplar is an Integer and runs it through RPC.decodeRequest. Before this
change it fails with an uncaught NullPointerException; after it, the request
is rejected with IncompatibleRemoteServiceException wrapping
SerializedTypeViolationException, matching the existing spoofing tests for the
other collections. The full RPCTypeCheckTest passes (26 tests).

Diff

  • EnumMap_ServerCustomFieldSerializer.java (+16/-1): the typed instantiate.
  • RPCTypeCheckTest.java (+39): the test, its request generator, and an
    EnumMap method on the existing ClassesParamTestClass test service.
  • RPCTypeCheckFactory.java (+11): a helper to write an EnumMap message with a
    substituted exemplar.

Note

I confirmed the failing input is reachable through the normal servlet path: an
embedded RemoteServiceServlet with an EnumMap parameter and a strict
serialization policy (only the service's own types allow-listed) returns HTTP
500 on the crafted request before this change and handles it cleanly after. I
can share that harness if useful. Happy to adjust the approach; using
Enum.class as the expected type is the least invasive floor, but reading the
exemplar against expectedParameterTypes[0] when present would be stricter if
you prefer.

Nexory added 2 commits August 11, 2026 19:56
EnumMap_ServerCustomFieldSerializer overrode the type-checking server
instantiateInstance but discarded the type information and called the untyped
client instantiate, which reads the exemplar with a bare readObject(). Every
other collection serializer reads what it instantiates from through the typed
path; TreeMap and TreeSet are the direct precedent.

Because the exemplar was read untyped, a request could substitute a non-enum
type for it, and new EnumMap(nonEnumClass) throws an uncaught
NullPointerException instead of a clean serialization error. Add a server-side
instantiate that reads the exemplar with readObject(Enum.class, resolvedTypes),
so a non-enum is rejected with SerializedTypeViolationException like the other
serializers. A valid enum constant still passes and getClass() is unchanged, so
behaviour for valid EnumMaps is identical.
The type-check test family covers every collection serializer for exemplar and
element substitution except EnumMap. Add testEnumMapSpoofingClass, its request
generator, and an EnumMap method on the existing ClassesParamTestClass service.
Before the serializer change the test fails with an uncaught
NullPointerException; after it, the request is rejected with
IncompatibleRemoteServiceException wrapping SerializedTypeViolationException,
matching the other spoofing tests. RPCTypeCheckTest passes with 26 tests.
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.

EnumMap RPC deserialization throws an uncaught NullPointerException on crafted input

1 participant