Skip to content

Commit e35c0ea

Browse files
lucylqfacebook-github-bot
authored andcommitted
Add minimum_length to extended header for BC
Summary: Error happening when we have older PTE files with extended header size 24. When we call 'from_bytes', we expect header size 32 after adding segment_data_size field. This is BC on C++ side because we have a minimum length. Add minimum length to python to make the change BC. Differential Revision: D82492169
1 parent 5a1c117 commit e35c0ea

File tree

2 files changed

+58
-12
lines changed

2 files changed

+58
-12
lines changed

exir/_serialize/_program.py

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,7 @@ class _ExtendedHeader:
136136

137137
# The magic bytes that should be at the beginning of the header.
138138
EXPECTED_MAGIC: ClassVar[bytes] = b"eh00"
139-
# The length of the header in bytes.
140-
EXPECTED_LENGTH: ClassVar[int] = (
139+
MINIMUM_LENGTH: ClassVar[int] = (
141140
# Header magic
142141
4
143142
# Header length
@@ -146,10 +145,18 @@ class _ExtendedHeader:
146145
+ 8
147146
# Segment base offset
148147
+ 8
148+
)
149+
# The length of the header in bytes.
150+
EXPECTED_LENGTH: ClassVar[int] = (
151+
MINIMUM_LENGTH
149152
# Segment data size
150153
+ 8
151154
)
152155

156+
# To find the header, callers should provide at least this many bytes of
157+
# the head of the serialized Program data.
158+
NUM_HEAD_BYTES: ClassVar[int] = 64
159+
153160
# Instance attributes. @dataclass will turn these into ctor args.
154161

155162
# The size of the serialized program data in bytes.
@@ -187,21 +194,29 @@ def from_bytes(data: bytes) -> "_ExtendedHeader":
187194
+ f"< {_ExtendedHeader.EXPECTED_LENGTH}"
188195
)
189196

197+
magic = data[0:4]
198+
length = int.from_bytes(data[4:8], byteorder=_HEADER_BYTEORDER)
199+
program_size = int.from_bytes(data[8:16], byteorder=_HEADER_BYTEORDER)
200+
segment_base_offset = int.from_bytes(data[16:24], byteorder=_HEADER_BYTEORDER)
201+
segment_data_size = (
202+
int.from_bytes(data[24:32], byteorder=_HEADER_BYTEORDER)
203+
if length > _ExtendedHeader.MINIMUM_LENGTH
204+
else 0
205+
)
206+
190207
return _ExtendedHeader(
191-
magic=data[0:4],
192-
length=int.from_bytes(data[4:8], byteorder=_HEADER_BYTEORDER),
193-
program_size=int.from_bytes(data[8:16], byteorder=_HEADER_BYTEORDER),
194-
segment_base_offset=int.from_bytes(
195-
data[16:24], byteorder=_HEADER_BYTEORDER
196-
),
197-
segment_data_size=int.from_bytes(data[24:32], byteorder=_HEADER_BYTEORDER),
208+
magic=magic,
209+
length=length,
210+
program_size=program_size,
211+
segment_base_offset=segment_base_offset,
212+
segment_data_size=segment_data_size,
198213
)
199214

200215
def is_valid(self) -> bool:
201216
"""Returns true if the extended header appears to be well-formed."""
202217
return (
203218
self.magic == _ExtendedHeader.EXPECTED_MAGIC
204-
and self.length >= _ExtendedHeader.EXPECTED_LENGTH
219+
and self.length >= _ExtendedHeader.MINIMUM_LENGTH
205220
)
206221

207222
def to_bytes(self) -> bytes:

exir/_serialize/test/test_program.py

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1009,14 +1009,30 @@ def test_named_data_segments(self) -> None:
10091009
EXAMPLE_HEADER_DATA: bytes = (
10101010
# Magic bytes
10111011
b"eh00"
1012-
# uint32_t header size (little endian)
1012+
# uint32_t header size (little endian) --> 32
10131013
+ b"\x20\x00\x00\x00"
10141014
# uint64_t program size
10151015
+ b"\x44\x33\x44\x33\x22\x11\x22\x11"
10161016
# uint64_t segment base offset
10171017
+ b"\x88\x77\x88\x77\x66\x55\x66\x55"
10181018
# uint64_t segment data size
10191019
+ b"\x22\x33\x22\x33\x44\x55\x44\x55"
1020+
# Padding; provide at least NUM_HEAD_BYTES for the header.
1021+
+ b"\x99" * (_ExtendedHeader.NUM_HEAD_BYTES - 32)
1022+
)
1023+
1024+
# Minimum fields in an extended header (no segment data size).
1025+
EXAMPLE_HEADER_DATA_MIN: bytes = (
1026+
# Magic bytes
1027+
b"eh00"
1028+
# uint32_t header size (little endian) --> 24
1029+
+ b"\x18\x00\x00\x00"
1030+
# uint64_t program size
1031+
+ b"\x44\x33\x44\x33\x22\x11\x22\x11"
1032+
# uint64_t segment base offset
1033+
+ b"\x88\x77\x88\x77\x66\x55\x66\x55"
1034+
# Padding; provide at least NUM_HEAD_BYTES for the header.
1035+
+ b"\x99" * (_ExtendedHeader.NUM_HEAD_BYTES - 24)
10201036
)
10211037

10221038

@@ -1060,6 +1076,20 @@ def test_from_bytes_valid(self) -> None:
10601076
self.assertEqual(eh.segment_base_offset, EXAMPLE_SEGMENT_BASE_OFFSET)
10611077
self.assertEqual(eh.segment_data_size, EXAMPLE_SEGMENT_DATA_SIZE)
10621078

1079+
def test_from_bytes_minimum(self) -> None:
1080+
# Parse the serialized extended header.
1081+
eh = _ExtendedHeader.from_bytes(EXAMPLE_HEADER_DATA_MIN)
1082+
1083+
# This is a valid header: good magic and length.
1084+
self.assertTrue(eh.is_valid())
1085+
1086+
self.assertEqual(eh.magic, _ExtendedHeader.EXPECTED_MAGIC)
1087+
self.assertEqual(eh.length, _ExtendedHeader.MINIMUM_LENGTH)
1088+
self.assertEqual(eh.program_size, EXAMPLE_PROGRAM_SIZE)
1089+
self.assertEqual(eh.segment_base_offset, EXAMPLE_SEGMENT_BASE_OFFSET)
1090+
# Does not contain segment_data_size; should be 0
1091+
self.assertEqual(eh.segment_data_size, 0)
1092+
10631093
def test_from_bytes_with_more_data_than_necessary(self) -> None:
10641094
# Pass in more data than necessary to parse the header.
10651095
header_data_with_suffix = EXAMPLE_HEADER_DATA + b"\x55" * 16
@@ -1167,4 +1197,5 @@ def test_from_bytes_invalid_length(self) -> None:
11671197
self.assertEqual(eh.length, 16)
11681198
self.assertEqual(eh.program_size, EXAMPLE_PROGRAM_SIZE)
11691199
self.assertEqual(eh.segment_base_offset, EXAMPLE_SEGMENT_BASE_OFFSET)
1170-
self.assertEqual(eh.segment_data_size, EXAMPLE_SEGMENT_DATA_SIZE)
1200+
# Length cut short; segment_data_size parsed as 0.
1201+
self.assertEqual(eh.segment_data_size, 0)

0 commit comments

Comments
 (0)