Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions lang/py/avro/io.py
Original file line number Diff line number Diff line change
Expand Up @@ -765,7 +765,7 @@ def read_enum(self, writers_schema: avro.schema.EnumSchema, readers_schema: avro
"""
# read data
index_of_symbol = decoder.read_int()
if index_of_symbol >= len(writers_schema.symbols):
if not 0 <= index_of_symbol < len(writers_schema.symbols):
raise avro.errors.SchemaResolutionException(
f"Can't access enum index {index_of_symbol} for enum with {len(writers_schema.symbols)} symbols", writers_schema, readers_schema
)
Expand Down Expand Up @@ -864,7 +864,7 @@ def read_union(self, writers_schema: avro.schema.UnionSchema, readers_schema: av
"""
# schema resolution
index_of_schema = int(decoder.read_long())
if index_of_schema >= len(writers_schema.schemas):
if not 0 <= index_of_schema < len(writers_schema.schemas):
raise avro.errors.SchemaResolutionException(
f"Can't access branch index {index_of_schema} for union with {len(writers_schema.schemas)} branches", writers_schema, readers_schema
)
Expand All @@ -875,7 +875,7 @@ def read_union(self, writers_schema: avro.schema.UnionSchema, readers_schema: av

def skip_union(self, writers_schema: avro.schema.UnionSchema, decoder: BinaryDecoder) -> None:
index_of_schema = int(decoder.read_long())
if index_of_schema >= len(writers_schema.schemas):
if not 0 <= index_of_schema < len(writers_schema.schemas):
raise avro.errors.SchemaResolutionException(
f"Can't access branch index {index_of_schema} for union with {len(writers_schema.schemas)} branches", writers_schema
)
Expand Down
16 changes: 16 additions & 0 deletions lang/py/avro/test/test_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -598,6 +598,22 @@ def test_unknown_symbol(self) -> None:
datum_reader = avro.io.DatumReader(writers_schema, readers_schema)
self.assertRaises(avro.errors.SchemaResolutionException, datum_reader.read, decoder)

def test_negative_enum_index(self) -> None:
# A negative zigzag-encoded index (0x01 -> -1) must be rejected rather than
# silently wrapping to symbols[-1] via Python negative indexing.
writers_schema = avro.schema.parse(json.dumps({"type": "enum", "name": "Test", "symbols": ["FOO", "BAR"]}))
decoder = avro.io.BinaryDecoder(io.BytesIO(b"\x01"))
datum_reader = avro.io.DatumReader(writers_schema, writers_schema)
self.assertRaises(avro.errors.SchemaResolutionException, datum_reader.read, decoder)

def test_negative_union_index(self) -> None:
# A negative branch index must be rejected rather than selecting schemas[-1]
# and decoding the payload with the wrong branch schema.
writers_schema = avro.schema.parse(json.dumps(["null", "string", "long"]))
decoder = avro.io.BinaryDecoder(io.BytesIO(b"\x01\x08"))
datum_reader = avro.io.DatumReader(writers_schema, writers_schema)
self.assertRaises(avro.errors.SchemaResolutionException, datum_reader.read, decoder)

def test_no_default_value(self) -> None:
writers_schema = LONG_RECORD_SCHEMA
datum_to_write = LONG_RECORD_DATUM
Expand Down
Loading