xref: /aosp_15_r20/external/executorch/schema/test/extended_header_test.cpp (revision 523fa7a60841cd1ecfb9cc4201f1ca8b03ed023a)
1 /*
2  * Copyright (c) Meta Platforms, Inc. and affiliates.
3  * All rights reserved.
4  *
5  * This source code is licensed under the BSD-style license found in the
6  * LICENSE file in the root directory of this source tree.
7  */
8 
9 #include <executorch/schema/extended_header.h>
10 
11 #include <gtest/gtest.h>
12 
13 #include <executorch/runtime/core/result.h>
14 #include <executorch/runtime/platform/runtime.h>
15 
16 using namespace ::testing;
17 using executorch::runtime::Error;
18 using executorch::runtime::ExtendedHeader;
19 using executorch::runtime::Result;
20 
21 class ExtendedHeaderTest : public ::testing::Test {
22  protected:
SetUp()23   void SetUp() override {
24     // Since these tests cause ET_LOG to be called, the PAL must be initialized
25     // first.
26     executorch::runtime::runtime_init();
27   }
28 };
29 
30 /**
31  * An example, valid extended header.
32  *
33  * This data is intentionally fragile. If the header layout or magic changes,
34  * this test data must change too. The layout of the header is a contract, not
35  * an implementation detail.
36  */
37 // clang-format off
38 constexpr char kExampleHeaderData[] = {
39   // Magic bytes
40   'e', 'h', '0', '0',
41   // uint32_t header size (little endian)
42   0x18, 0x00, 0x00, 0x00,
43   // uint64_t program size
44   0x71, 0x61, 0x51, 0x41, 0x31, 0x21, 0x11, 0x01,
45   // uint64_t segment base offset
46   0x72, 0x62, 0x52, 0x42, 0x32, 0x22, 0x12, 0x02,
47 };
48 // clang-format on
49 
50 /// The program_size field encoded in kExampleHeaderData. Each byte is unique
51 /// within the header data.
52 constexpr uint64_t kExampleProgramSize = 0x0111213141516171;
53 
54 /// The segment_base_offset field encoded in kExampleHeaderData. Each byte is
55 /// unique within the header data.
56 constexpr uint64_t kExampleSegmentBaseOffset = 0x0212223242526272;
57 
58 /// The offset to the header's length field, which is in the 4 bytes after the
59 /// magic.
60 constexpr size_t kHeaderLengthOffset =
61     ExtendedHeader::kHeaderOffset + ExtendedHeader::kMagicSize;
62 
63 /**
64  * Returns fake serialized Program head data that contains kExampleHeaderData at
65  * the expected offset.
66  */
CreateExampleProgramHead()67 std::vector<uint8_t> CreateExampleProgramHead() {
68   // Allocate memory representing the head of the serialized Program.
69   std::vector<uint8_t> ret(ExtendedHeader::kNumHeadBytes);
70   // Write non-zeros into it to make it more obvious if we read outside the
71   // header.
72   memset(ret.data(), 0x55, ret.size());
73   // Copy the example header into the right offset.
74   memcpy(
75       ret.data() + ExtendedHeader::kHeaderOffset,
76       kExampleHeaderData,
77       sizeof(kExampleHeaderData));
78   return ret;
79 }
80 
TEST_F(ExtendedHeaderTest,ValidHeaderParsesCorrectly)81 TEST_F(ExtendedHeaderTest, ValidHeaderParsesCorrectly) {
82   std::vector<uint8_t> program = CreateExampleProgramHead();
83 
84   Result<ExtendedHeader> header =
85       ExtendedHeader::Parse(program.data(), program.size());
86 
87   // The header should be present.
88   ASSERT_EQ(header.error(), Error::Ok);
89 
90   // Since each byte of these fields is unique, success demonstrates that the
91   // endian-to-int conversion is correct and looks at the expected bytes of the
92   // header.
93   EXPECT_EQ(header->program_size, kExampleProgramSize);
94   EXPECT_EQ(header->segment_base_offset, kExampleSegmentBaseOffset);
95 }
96 
TEST_F(ExtendedHeaderTest,ShortDataFails)97 TEST_F(ExtendedHeaderTest, ShortDataFails) {
98   std::vector<uint8_t> program = CreateExampleProgramHead();
99 
100   // Try parsing a smaller-than-required part of the data.
101   ASSERT_GE(program.size(), ExtendedHeader::kNumHeadBytes);
102   Result<ExtendedHeader> header =
103       ExtendedHeader::Parse(program.data(), ExtendedHeader::kNumHeadBytes - 1);
104 
105   // Should have been rejected.
106   EXPECT_EQ(header.error(), Error::InvalidArgument);
107 }
108 
TEST_F(ExtendedHeaderTest,MissingHeaderNotFound)109 TEST_F(ExtendedHeaderTest, MissingHeaderNotFound) {
110   // Program head data without the extended header magic bytes.
111   std::vector<uint8_t> program(ExtendedHeader::kNumHeadBytes);
112   memset(program.data(), 0x55, program.size());
113 
114   // The header should not be found.
115   Result<ExtendedHeader> header =
116       ExtendedHeader::Parse(program.data(), program.size());
117   EXPECT_EQ(header.error(), Error::NotFound);
118 }
119 
TEST_F(ExtendedHeaderTest,BadMagicTreatedAsMissing)120 TEST_F(ExtendedHeaderTest, BadMagicTreatedAsMissing) {
121   // Get a valid header.
122   std::vector<uint8_t> program = CreateExampleProgramHead();
123 
124   // Should be present.
125   {
126     Result<ExtendedHeader> header =
127         ExtendedHeader::Parse(program.data(), program.size());
128     ASSERT_EQ(header.error(), Error::Ok);
129   }
130 
131   // Change a character in the magic.
132   program[ExtendedHeader::kHeaderOffset] = 'x';
133 
134   // No longer present.
135   {
136     Result<ExtendedHeader> header =
137         ExtendedHeader::Parse(program.data(), program.size());
138     EXPECT_EQ(header.error(), Error::NotFound);
139   }
140 }
141 
TEST_F(ExtendedHeaderTest,ShorterHeaderLengthFails)142 TEST_F(ExtendedHeaderTest, ShorterHeaderLengthFails) {
143   // Get a valid header.
144   std::vector<uint8_t> program = CreateExampleProgramHead();
145 
146   // Should be present.
147   {
148     Result<ExtendedHeader> header =
149         ExtendedHeader::Parse(program.data(), program.size());
150     ASSERT_EQ(header.error(), Error::Ok);
151   }
152 
153   // Make the header length smaller.
154   // First demonstrate that we're looking in the right place.
155   EXPECT_EQ(program[kHeaderLengthOffset], 0x18);
156   program[kHeaderLengthOffset] = 0x10;
157 
158   // Program now considered invalid.
159   {
160     Result<ExtendedHeader> header =
161         ExtendedHeader::Parse(program.data(), program.size());
162     EXPECT_EQ(header.error(), Error::InvalidProgram);
163   }
164 }
165 
TEST_F(ExtendedHeaderTest,LongerHeaderLengthSucceeds)166 TEST_F(ExtendedHeaderTest, LongerHeaderLengthSucceeds) {
167   // Get a valid header.
168   std::vector<uint8_t> program = CreateExampleProgramHead();
169 
170   // Make the header length larger.
171   // First demonstrate that we're looking in the right place.
172   EXPECT_EQ(program[kHeaderLengthOffset], 0x18);
173   program[kHeaderLengthOffset] = 0x20;
174 
175   // Should still be present and contain the expected values.
176   {
177     Result<ExtendedHeader> header =
178         ExtendedHeader::Parse(program.data(), program.size());
179     ASSERT_EQ(header.error(), Error::Ok);
180     EXPECT_EQ(header->program_size, kExampleProgramSize);
181     EXPECT_EQ(header->segment_base_offset, kExampleSegmentBaseOffset);
182   }
183 }
184