/src/WasmEdge/lib/loader/filemgr.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | // SPDX-License-Identifier: Apache-2.0 |
2 | | // SPDX-FileCopyrightText: 2019-2024 Second State INC |
3 | | |
4 | | #include "loader/filemgr.h" |
5 | | |
6 | | #include <algorithm> |
7 | | #include <iterator> |
8 | | |
9 | | // Error logging of file manager need to be handled in caller. |
10 | | |
11 | | namespace WasmEdge { |
12 | | |
13 | | // Set path to file manager. See "include/loader/filemgr.h". |
14 | 0 | Expect<void> FileMgr::setPath(const std::filesystem::path &FilePath) { |
15 | 0 | reset(); |
16 | 0 | std::error_code ErrCode; |
17 | 0 | Size = std::filesystem::file_size(FilePath, ErrCode); |
18 | 0 | if (likely(!ErrCode)) { |
19 | 0 | if (!MMap::supported()) { |
20 | 0 | Size = 0; |
21 | 0 | Status = ErrCode::Value::IllegalPath; |
22 | 0 | return Unexpect(Status); |
23 | 0 | } |
24 | 0 | FileMap.emplace(FilePath); |
25 | 0 | if (auto *Pointer = FileMap->address(); likely(Pointer)) { |
26 | 0 | Data = reinterpret_cast<const Byte *>(Pointer); |
27 | 0 | Status = ErrCode::Value::Success; |
28 | 0 | } else { |
29 | | // File size is 0, mmap failed. |
30 | | // Will get 'UnexpectedEnd' error while the first reading. |
31 | 0 | FileMap.reset(); |
32 | 0 | } |
33 | 0 | return {}; |
34 | 0 | } |
35 | 0 | Size = 0; |
36 | 0 | Status = ErrCode::Value::IllegalPath; |
37 | 0 | return Unexpect(Status); |
38 | 0 | } |
39 | | |
40 | | // Set code data. See "include/loader/filemgr.h". |
41 | 7.96k | Expect<void> FileMgr::setCode(Span<const Byte> CodeData) { |
42 | 7.96k | reset(); |
43 | 7.96k | Data = CodeData.data(); |
44 | 7.96k | Size = CodeData.size(); |
45 | 7.96k | Status = ErrCode::Value::Success; |
46 | 7.96k | return {}; |
47 | 7.96k | } |
48 | | |
49 | | // Set code data. See "include/loader/filemgr.h". |
50 | 0 | Expect<void> FileMgr::setCode(std::vector<Byte> CodeData) { |
51 | 0 | reset(); |
52 | | // Tell GCC 14 that DataHolder has no data. |
53 | | // Fix the false positive warning, |
54 | | // which is reported by GCC 14 with `maybe-uninitialized` |
55 | 0 | assuming(!DataHolder); |
56 | | |
57 | 0 | DataHolder.emplace(std::move(CodeData)); |
58 | 0 | Data = DataHolder->data(); |
59 | 0 | Size = DataHolder->size(); |
60 | 0 | Status = ErrCode::Value::Success; |
61 | 0 | return {}; |
62 | 0 | } |
63 | | |
64 | | // Read one byte. See "include/loader/filemgr.h". |
65 | 8.38M | Expect<Byte> FileMgr::readByte() { |
66 | 8.38M | if (unlikely(Status != ErrCode::Value::Success)) { |
67 | 0 | return Unexpect(Status); |
68 | 0 | } |
69 | | // Set the flag to the start offset. |
70 | 8.38M | LastPos = Pos; |
71 | | // Check if exceed the data boundary and section boundary. |
72 | 8.38M | EXPECTED_TRY(testRead(1)); |
73 | 8.37M | return Data[Pos++]; |
74 | 8.38M | } |
75 | | |
76 | | // Read number of bytes. See "include/loader/filemgr.h". |
77 | 62.5k | Expect<std::vector<Byte>> FileMgr::readBytes(size_t SizeToRead) { |
78 | | // Set the flag to the start offset. |
79 | 62.5k | LastPos = Pos; |
80 | | // Read bytes into vector. |
81 | 62.5k | std::vector<Byte> Buf(SizeToRead); |
82 | 62.5k | EXPECTED_TRY(readBytes(Buf)); |
83 | 62.5k | return Buf; |
84 | 62.5k | } |
85 | | |
86 | | // Decode and read an unsigned int. See "include/loader/filemgr.h". |
87 | 1.74M | Expect<uint32_t> FileMgr::readU32() { |
88 | 1.74M | if (unlikely(Status != ErrCode::Value::Success)) { |
89 | 0 | return Unexpect(Status); |
90 | 0 | } |
91 | | // Set the flag to the start offset. |
92 | 1.74M | LastPos = Pos; |
93 | | |
94 | | // Read and decode U32. |
95 | 1.74M | uint32_t Result = 0; |
96 | 1.74M | uint32_t Offset = 0; |
97 | 1.74M | Byte Byte = 0x80; |
98 | 4.05M | while (Byte & 0x80) { |
99 | 2.30M | if (unlikely(Offset >= 32)) { |
100 | 9 | Status = ErrCode::Value::IntegerTooLong; |
101 | 9 | return Unexpect(Status); |
102 | 9 | } |
103 | 2.30M | EXPECTED_TRY(testRead(1)); |
104 | 2.30M | Byte = Data[Pos++]; |
105 | 2.30M | Result |= (Byte & UINT32_C(0x7F)) << Offset; |
106 | 2.30M | if (Offset == 28 && unlikely((Byte & UINT32_C(0x70)) != 0)) { |
107 | 33 | Status = ErrCode::Value::IntegerTooLarge; |
108 | 33 | return Unexpect(Status); |
109 | 33 | } |
110 | 2.30M | Offset += 7; |
111 | 2.30M | } |
112 | 1.74M | return Result; |
113 | 1.74M | } |
114 | | |
115 | | // Decode and read an unsigned long long int. See "include/loader/filemgr.h". |
116 | 0 | Expect<uint64_t> FileMgr::readU64() { |
117 | 0 | if (Status != ErrCode::Value::Success) { |
118 | 0 | return Unexpect(Status); |
119 | 0 | } |
120 | | // Set the flag to the start offset. |
121 | 0 | LastPos = Pos; |
122 | | |
123 | | // Read and decode U64. |
124 | 0 | uint64_t Result = 0; |
125 | 0 | uint64_t Offset = 0; |
126 | 0 | Byte Byte = 0x80; |
127 | 0 | while (Byte & 0x80) { |
128 | 0 | if (unlikely(Offset >= 64)) { |
129 | 0 | Status = ErrCode::Value::IntegerTooLong; |
130 | 0 | return Unexpect(Status); |
131 | 0 | } |
132 | 0 | EXPECTED_TRY(testRead(1)); |
133 | 0 | Byte = Data[Pos++]; |
134 | 0 | Result |= (Byte & UINT64_C(0x7F)) << Offset; |
135 | 0 | if (Offset == 63 && unlikely((Byte & UINT32_C(0x7E)) != 0)) { |
136 | 0 | Status = ErrCode::Value::IntegerTooLarge; |
137 | 0 | return Unexpect(Status); |
138 | 0 | } |
139 | 0 | Offset += 7; |
140 | 0 | } |
141 | 0 | return Result; |
142 | 0 | } |
143 | | |
144 | 2.52M | template <typename RetType, size_t N> Expect<RetType> FileMgr::readSN() { |
145 | 2.52M | static_assert(N >= 8, "The N of S_N must have at least length of a byte"); |
146 | 2.52M | static_assert(8 * sizeof(RetType) >= N, |
147 | 2.52M | "RetType cannot hold the full range of S_N"); |
148 | 2.52M | static_assert(std::is_signed_v<RetType>, |
149 | 2.52M | "RetType of S_N must be signed type"); |
150 | | |
151 | 2.52M | if (Status != ErrCode::Value::Success) { |
152 | 0 | return Unexpect(Status); |
153 | 0 | } |
154 | | // Set the flag to the start offset. |
155 | 2.52M | LastPos = Pos; |
156 | | |
157 | | // Read and decode S_N. |
158 | 2.52M | RetType Result = 0; |
159 | 2.52M | size_t Offset = 0; |
160 | 2.52M | size_t RemainingBits = N; |
161 | 2.76M | while (true) { |
162 | 2.76M | if (RemainingBits <= 0) { |
163 | 0 | Status = ErrCode::Value::IntegerTooLong; |
164 | 0 | return Unexpect(Status); |
165 | 0 | } |
166 | | |
167 | | // In the rest logic, RemainingBits must be at least 1. |
168 | 2.76M | EXPECTED_TRY(testRead(1)); |
169 | 2.76M | WasmEdge::Byte Byte = Data[Pos++]; |
170 | | |
171 | 2.76M | const WasmEdge::Byte HighestBitMask = 1 << 7; |
172 | 2.76M | const WasmEdge::Byte SecondHighestBitMask = 1 << 6; |
173 | 2.76M | if (Byte & HighestBitMask) { |
174 | | // The byte has leading 1. It contains 7 bits payload. |
175 | | |
176 | 242k | if (unlikely(RemainingBits < 7)) { |
177 | 22 | Status = ErrCode::Value::IntegerTooLong; |
178 | 22 | return Unexpect(Status); |
179 | 22 | } |
180 | | |
181 | 242k | std::make_unsigned_t<RetType> Payload = |
182 | 242k | Byte & (~HighestBitMask); // & 0b01111111 |
183 | 242k | Result |= (Payload << Offset); |
184 | 242k | Offset += 7; |
185 | 242k | RemainingBits -= 7; |
186 | 2.52M | } else { |
187 | | // The byte has leading 0. It will be the last byte. |
188 | | |
189 | | // The number of bits that take effect in the byte. Since RemainingBits |
190 | | // must be at least 1, EffectiveBits also must be at least 1. It is also |
191 | | // at most 7. |
192 | 2.52M | size_t EffectiveBits = RemainingBits < 7 ? RemainingBits : 7; |
193 | 2.52M | std::make_unsigned_t<RetType> Payload = Byte; |
194 | 2.52M | if (Byte & SecondHighestBitMask) { |
195 | | // The byte is signed. |
196 | 1.95M | if (Byte >= (1 << 7) - (1 << (EffectiveBits - 1))) { |
197 | 1.95M | Payload -= (1 << 7); |
198 | 1.95M | } else { |
199 | 12 | Status = ErrCode::Value::IntegerTooLarge; |
200 | 12 | return Unexpect(Status); |
201 | 12 | } |
202 | 1.95M | } else { |
203 | | // The byte is unsigned. |
204 | 562k | if (Byte >= (1 << (EffectiveBits - 1))) { |
205 | 15 | Status = ErrCode::Value::IntegerTooLarge; |
206 | 15 | return Unexpect(Status); |
207 | 15 | } |
208 | 562k | } |
209 | 2.52M | Result |= (Payload << Offset); |
210 | 2.52M | break; |
211 | 2.52M | } |
212 | 2.76M | } |
213 | | |
214 | 2.52M | return Result; |
215 | 2.52M | } cxx20::expected<long, WasmEdge::ErrCode> WasmEdge::FileMgr::readSN<long, 33ul>() Line | Count | Source | 144 | 220k | template <typename RetType, size_t N> Expect<RetType> FileMgr::readSN() { | 145 | 220k | static_assert(N >= 8, "The N of S_N must have at least length of a byte"); | 146 | 220k | static_assert(8 * sizeof(RetType) >= N, | 147 | 220k | "RetType cannot hold the full range of S_N"); | 148 | 220k | static_assert(std::is_signed_v<RetType>, | 149 | 220k | "RetType of S_N must be signed type"); | 150 | | | 151 | 220k | if (Status != ErrCode::Value::Success) { | 152 | 0 | return Unexpect(Status); | 153 | 0 | } | 154 | | // Set the flag to the start offset. | 155 | 220k | LastPos = Pos; | 156 | | | 157 | | // Read and decode S_N. | 158 | 220k | RetType Result = 0; | 159 | 220k | size_t Offset = 0; | 160 | 220k | size_t RemainingBits = N; | 161 | 235k | while (true) { | 162 | 235k | if (RemainingBits <= 0) { | 163 | 0 | Status = ErrCode::Value::IntegerTooLong; | 164 | 0 | return Unexpect(Status); | 165 | 0 | } | 166 | | | 167 | | // In the rest logic, RemainingBits must be at least 1. | 168 | 235k | EXPECTED_TRY(testRead(1)); | 169 | 235k | WasmEdge::Byte Byte = Data[Pos++]; | 170 | | | 171 | 235k | const WasmEdge::Byte HighestBitMask = 1 << 7; | 172 | 235k | const WasmEdge::Byte SecondHighestBitMask = 1 << 6; | 173 | 235k | if (Byte & HighestBitMask) { | 174 | | // The byte has leading 1. It contains 7 bits payload. | 175 | | | 176 | 14.7k | if (unlikely(RemainingBits < 7)) { | 177 | 3 | Status = ErrCode::Value::IntegerTooLong; | 178 | 3 | return Unexpect(Status); | 179 | 3 | } | 180 | | | 181 | 14.7k | std::make_unsigned_t<RetType> Payload = | 182 | 14.7k | Byte & (~HighestBitMask); // & 0b01111111 | 183 | 14.7k | Result |= (Payload << Offset); | 184 | 14.7k | Offset += 7; | 185 | 14.7k | RemainingBits -= 7; | 186 | 220k | } else { | 187 | | // The byte has leading 0. It will be the last byte. | 188 | | | 189 | | // The number of bits that take effect in the byte. Since RemainingBits | 190 | | // must be at least 1, EffectiveBits also must be at least 1. It is also | 191 | | // at most 7. | 192 | 220k | size_t EffectiveBits = RemainingBits < 7 ? RemainingBits : 7; | 193 | 220k | std::make_unsigned_t<RetType> Payload = Byte; | 194 | 220k | if (Byte & SecondHighestBitMask) { | 195 | | // The byte is signed. | 196 | 62.0k | if (Byte >= (1 << 7) - (1 << (EffectiveBits - 1))) { | 197 | 62.0k | Payload -= (1 << 7); | 198 | 62.0k | } else { | 199 | 3 | Status = ErrCode::Value::IntegerTooLarge; | 200 | 3 | return Unexpect(Status); | 201 | 3 | } | 202 | 158k | } else { | 203 | | // The byte is unsigned. | 204 | 158k | if (Byte >= (1 << (EffectiveBits - 1))) { | 205 | 3 | Status = ErrCode::Value::IntegerTooLarge; | 206 | 3 | return Unexpect(Status); | 207 | 3 | } | 208 | 158k | } | 209 | 220k | Result |= (Payload << Offset); | 210 | 220k | break; | 211 | 220k | } | 212 | 235k | } | 213 | | | 214 | 220k | return Result; | 215 | 220k | } |
cxx20::expected<int, WasmEdge::ErrCode> WasmEdge::FileMgr::readSN<int, 32ul>() Line | Count | Source | 144 | 2.01M | template <typename RetType, size_t N> Expect<RetType> FileMgr::readSN() { | 145 | 2.01M | static_assert(N >= 8, "The N of S_N must have at least length of a byte"); | 146 | 2.01M | static_assert(8 * sizeof(RetType) >= N, | 147 | 2.01M | "RetType cannot hold the full range of S_N"); | 148 | 2.01M | static_assert(std::is_signed_v<RetType>, | 149 | 2.01M | "RetType of S_N must be signed type"); | 150 | | | 151 | 2.01M | if (Status != ErrCode::Value::Success) { | 152 | 0 | return Unexpect(Status); | 153 | 0 | } | 154 | | // Set the flag to the start offset. | 155 | 2.01M | LastPos = Pos; | 156 | | | 157 | | // Read and decode S_N. | 158 | 2.01M | RetType Result = 0; | 159 | 2.01M | size_t Offset = 0; | 160 | 2.01M | size_t RemainingBits = N; | 161 | 2.15M | while (true) { | 162 | 2.15M | if (RemainingBits <= 0) { | 163 | 0 | Status = ErrCode::Value::IntegerTooLong; | 164 | 0 | return Unexpect(Status); | 165 | 0 | } | 166 | | | 167 | | // In the rest logic, RemainingBits must be at least 1. | 168 | 2.15M | EXPECTED_TRY(testRead(1)); | 169 | 2.15M | WasmEdge::Byte Byte = Data[Pos++]; | 170 | | | 171 | 2.15M | const WasmEdge::Byte HighestBitMask = 1 << 7; | 172 | 2.15M | const WasmEdge::Byte SecondHighestBitMask = 1 << 6; | 173 | 2.15M | if (Byte & HighestBitMask) { | 174 | | // The byte has leading 1. It contains 7 bits payload. | 175 | | | 176 | 139k | if (unlikely(RemainingBits < 7)) { | 177 | 6 | Status = ErrCode::Value::IntegerTooLong; | 178 | 6 | return Unexpect(Status); | 179 | 6 | } | 180 | | | 181 | 139k | std::make_unsigned_t<RetType> Payload = | 182 | 139k | Byte & (~HighestBitMask); // & 0b01111111 | 183 | 139k | Result |= (Payload << Offset); | 184 | 139k | Offset += 7; | 185 | 139k | RemainingBits -= 7; | 186 | 2.01M | } else { | 187 | | // The byte has leading 0. It will be the last byte. | 188 | | | 189 | | // The number of bits that take effect in the byte. Since RemainingBits | 190 | | // must be at least 1, EffectiveBits also must be at least 1. It is also | 191 | | // at most 7. | 192 | 2.01M | size_t EffectiveBits = RemainingBits < 7 ? RemainingBits : 7; | 193 | 2.01M | std::make_unsigned_t<RetType> Payload = Byte; | 194 | 2.01M | if (Byte & SecondHighestBitMask) { | 195 | | // The byte is signed. | 196 | 1.63M | if (Byte >= (1 << 7) - (1 << (EffectiveBits - 1))) { | 197 | 1.63M | Payload -= (1 << 7); | 198 | 1.63M | } else { | 199 | 4 | Status = ErrCode::Value::IntegerTooLarge; | 200 | 4 | return Unexpect(Status); | 201 | 4 | } | 202 | 1.63M | } else { | 203 | | // The byte is unsigned. | 204 | 385k | if (Byte >= (1 << (EffectiveBits - 1))) { | 205 | 7 | Status = ErrCode::Value::IntegerTooLarge; | 206 | 7 | return Unexpect(Status); | 207 | 7 | } | 208 | 385k | } | 209 | 2.01M | Result |= (Payload << Offset); | 210 | 2.01M | break; | 211 | 2.01M | } | 212 | 2.15M | } | 213 | | | 214 | 2.01M | return Result; | 215 | 2.01M | } |
cxx20::expected<long, WasmEdge::ErrCode> WasmEdge::FileMgr::readSN<long, 64ul>() Line | Count | Source | 144 | 280k | template <typename RetType, size_t N> Expect<RetType> FileMgr::readSN() { | 145 | 280k | static_assert(N >= 8, "The N of S_N must have at least length of a byte"); | 146 | 280k | static_assert(8 * sizeof(RetType) >= N, | 147 | 280k | "RetType cannot hold the full range of S_N"); | 148 | 280k | static_assert(std::is_signed_v<RetType>, | 149 | 280k | "RetType of S_N must be signed type"); | 150 | | | 151 | 280k | if (Status != ErrCode::Value::Success) { | 152 | 0 | return Unexpect(Status); | 153 | 0 | } | 154 | | // Set the flag to the start offset. | 155 | 280k | LastPos = Pos; | 156 | | | 157 | | // Read and decode S_N. | 158 | 280k | RetType Result = 0; | 159 | 280k | size_t Offset = 0; | 160 | 280k | size_t RemainingBits = N; | 161 | 368k | while (true) { | 162 | 368k | if (RemainingBits <= 0) { | 163 | 0 | Status = ErrCode::Value::IntegerTooLong; | 164 | 0 | return Unexpect(Status); | 165 | 0 | } | 166 | | | 167 | | // In the rest logic, RemainingBits must be at least 1. | 168 | 368k | EXPECTED_TRY(testRead(1)); | 169 | 368k | WasmEdge::Byte Byte = Data[Pos++]; | 170 | | | 171 | 368k | const WasmEdge::Byte HighestBitMask = 1 << 7; | 172 | 368k | const WasmEdge::Byte SecondHighestBitMask = 1 << 6; | 173 | 368k | if (Byte & HighestBitMask) { | 174 | | // The byte has leading 1. It contains 7 bits payload. | 175 | | | 176 | 88.3k | if (unlikely(RemainingBits < 7)) { | 177 | 13 | Status = ErrCode::Value::IntegerTooLong; | 178 | 13 | return Unexpect(Status); | 179 | 13 | } | 180 | | | 181 | 88.3k | std::make_unsigned_t<RetType> Payload = | 182 | 88.3k | Byte & (~HighestBitMask); // & 0b01111111 | 183 | 88.3k | Result |= (Payload << Offset); | 184 | 88.3k | Offset += 7; | 185 | 88.3k | RemainingBits -= 7; | 186 | 279k | } else { | 187 | | // The byte has leading 0. It will be the last byte. | 188 | | | 189 | | // The number of bits that take effect in the byte. Since RemainingBits | 190 | | // must be at least 1, EffectiveBits also must be at least 1. It is also | 191 | | // at most 7. | 192 | 279k | size_t EffectiveBits = RemainingBits < 7 ? RemainingBits : 7; | 193 | 279k | std::make_unsigned_t<RetType> Payload = Byte; | 194 | 279k | if (Byte & SecondHighestBitMask) { | 195 | | // The byte is signed. | 196 | 261k | if (Byte >= (1 << 7) - (1 << (EffectiveBits - 1))) { | 197 | 261k | Payload -= (1 << 7); | 198 | 261k | } else { | 199 | 5 | Status = ErrCode::Value::IntegerTooLarge; | 200 | 5 | return Unexpect(Status); | 201 | 5 | } | 202 | 261k | } else { | 203 | | // The byte is unsigned. | 204 | 18.5k | if (Byte >= (1 << (EffectiveBits - 1))) { | 205 | 5 | Status = ErrCode::Value::IntegerTooLarge; | 206 | 5 | return Unexpect(Status); | 207 | 5 | } | 208 | 18.5k | } | 209 | 279k | Result |= (Payload << Offset); | 210 | 279k | break; | 211 | 279k | } | 212 | 368k | } | 213 | | | 214 | 279k | return Result; | 215 | 280k | } |
|
216 | | |
217 | 220k | Expect<int64_t> FileMgr::readS33() { return readSN<int64_t, 33>(); } |
218 | | |
219 | | // Decode and read a signed int. See "include/loader/filemgr.h". |
220 | 2.01M | Expect<int32_t> FileMgr::readS32() { return readSN<int32_t, 32>(); } |
221 | | |
222 | | // Decode and read a signed long long int. See "include/loader/filemgr.h". |
223 | 280k | Expect<int64_t> FileMgr::readS64() { return readSN<int64_t, 64>(); } |
224 | | |
225 | | // Copy bytes to a float. See "include/loader/filemgr.h". |
226 | 39.1k | Expect<float> FileMgr::readF32() { |
227 | 39.1k | if (Status != ErrCode::Value::Success) { |
228 | 0 | return Unexpect(Status); |
229 | 0 | } |
230 | | // Set the flag to the start offset. |
231 | 39.1k | LastPos = Pos; |
232 | | |
233 | 39.1k | uint32_t Buf = 0; |
234 | 39.1k | Byte Byte = 0x00; |
235 | | // Check if exceed the data boundary and section boundary. |
236 | 39.1k | EXPECTED_TRY(testRead(4)); |
237 | 195k | for (uint32_t I = 0; I < 4; I++) { |
238 | 156k | Byte = Data[Pos++]; |
239 | 156k | Buf |= (Byte & UINT32_C(0xFF)) << (I * UINT32_C(8)); |
240 | 156k | } |
241 | 39.1k | float Result; |
242 | 39.1k | static_assert(sizeof(Buf) == sizeof(Result)); |
243 | 39.1k | std::memcpy(&Result, &Buf, sizeof(Result)); |
244 | 39.1k | return Result; |
245 | 39.1k | } |
246 | | |
247 | | // Copy bytes to a double. See "include/loader/filemgr.h". |
248 | 16.0k | Expect<double> FileMgr::readF64() { |
249 | 16.0k | if (Status != ErrCode::Value::Success) { |
250 | 0 | return Unexpect(Status); |
251 | 0 | } |
252 | | // Set the flag to the start offset. |
253 | 16.0k | LastPos = Pos; |
254 | | |
255 | 16.0k | uint64_t Buf = 0; |
256 | 16.0k | Byte Byte = 0x00; |
257 | | // Check if exceed the data boundary and section boundary. |
258 | 16.0k | EXPECTED_TRY(testRead(8)); |
259 | 144k | for (uint32_t I = 0; I < 8; I++) { |
260 | 128k | Byte = Data[Pos++]; |
261 | 128k | Buf |= (Byte & UINT64_C(0xFF)) << (I * UINT64_C(8)); |
262 | 128k | } |
263 | 16.0k | double Result; |
264 | 16.0k | static_assert(sizeof(Buf) == sizeof(Result)); |
265 | 16.0k | std::memcpy(&Result, &Buf, sizeof(Result)); |
266 | 16.0k | return Result; |
267 | 16.0k | } |
268 | | |
269 | | // Read a vector of bytes. See "include/loader/filemgr.h". |
270 | 84.2k | Expect<std::string> FileMgr::readName() { |
271 | 84.2k | if (unlikely(Status != ErrCode::Value::Success)) { |
272 | 0 | return Unexpect(Status); |
273 | 0 | } |
274 | | // If UTF-8 validation or readU32() or readBytes() failed, the last succeeded |
275 | | // reading offset will be at the start of `Name`. |
276 | 84.2k | LastPos = Pos; |
277 | | |
278 | | // Read the name size. |
279 | 84.2k | EXPECTED_TRY(uint32_t SizeToRead, readU32()); |
280 | | |
281 | | // Check if string length exceed the data boundary. |
282 | 84.1k | if (auto Res = testRead(SizeToRead); unlikely(!Res)) { |
283 | 44 | return Unexpect(ErrCode::Value::LengthOutOfBounds); |
284 | 44 | } |
285 | | |
286 | | // Read the UTF-8 bytes. |
287 | 84.1k | std::string Str(SizeToRead, '\0'); |
288 | 84.1k | EXPECTED_TRY( |
289 | 84.1k | readBytes(Span<Byte>(reinterpret_cast<Byte *>(Str.data()), Str.size()))); |
290 | | |
291 | | // UTF-8 validation. |
292 | 84.1k | bool Valid = true; |
293 | 379k | for (uint32_t I = 0; I < Str.size() && Valid; ++I) { |
294 | 295k | char C = Str.data()[I]; |
295 | 295k | uint32_t N = 0; |
296 | 295k | if ((C & '\x80') == 0) { |
297 | | // 0xxxxxxx, 7 bits UCS, ASCII |
298 | 283k | N = 0; |
299 | 283k | } else if ((C & '\xE0') == '\xC0') { |
300 | | // 110xxxxx, 11 bits UCS, U+80 to U+7FF |
301 | 2.80k | N = 1; |
302 | 9.50k | } else if ((C & '\xF0') == '\xE0') { |
303 | | // 1110xxxx, 16 bits UCS, U+800 to U+D7FF and U+E000 to U+FFFF |
304 | 6.48k | N = 2; |
305 | 6.48k | } else if ((C & '\xF8') == '\xF0') { |
306 | | // 11110xxx, 21 bits UCS, U+10000 to U+10FFFF |
307 | 2.96k | N = 3; |
308 | 2.96k | } else { |
309 | 55 | Valid = false; |
310 | 55 | } |
311 | | |
312 | | // Need to have N more bytes |
313 | 295k | if (I + N >= Str.size()) { |
314 | 16 | Valid = false; |
315 | 16 | } |
316 | | // Invalid ranges |
317 | 295k | if (N == 1 && (C & '\xDE') == '\xC0') { |
318 | | // 11 bits UCS, U+0 to U+80, FAIL |
319 | 2 | Valid = false; |
320 | 295k | } else if (N == 2 && |
321 | 295k | ((C == '\xE0' && (Str.data()[I + 1] & '\xA0') == '\x80') || |
322 | | // 16 bits UCS, U+0 to U+7FF, FAIL |
323 | 6.48k | (C == '\xED' && (Str.data()[I + 1] & '\xA0') == '\xA0') |
324 | | // 16 bits UCS, U+D800 to U+DFFF, FAIL |
325 | 6.48k | )) { |
326 | 6 | Valid = false; |
327 | 295k | } else if (N == 3 && |
328 | 295k | ((C == '\xF0' && (Str.data()[I + 1] & '\xB0') == '\x80') || |
329 | | // 21 bits UCS, U+0 to U+FFFF, FAIL |
330 | 2.96k | (C == '\xF4' && (Str.data()[I + 1] & '\xB0') != '\x80') || |
331 | | // 21 bits UCS, U+110000 to U+13FFFF, FAIL |
332 | 2.96k | (C != '\xF4' && (C & '\xF4') == '\xF4') |
333 | | // 21 bits UCS, U+140000 to U+1FFFFF, FAIL |
334 | 2.96k | )) { |
335 | 13 | Valid = false; |
336 | 13 | } |
337 | | |
338 | 320k | for (uint32_t J = 0; J < N && Valid; ++J) { |
339 | | // N bytes needs to match 10xxxxxx |
340 | 24.5k | if ((Str.data()[I + J + 1] & '\xC0') != '\x80') { |
341 | 35 | Valid = false; |
342 | 35 | } |
343 | 24.5k | } |
344 | 295k | I += N; |
345 | 295k | } |
346 | | |
347 | 84.1k | if (!Valid) { |
348 | 126 | Status = ErrCode::Value::MalformedUTF8; |
349 | 126 | return Unexpect(Status); |
350 | 126 | } |
351 | 84.0k | return Str; |
352 | 84.1k | } |
353 | | |
354 | | // Peek one byte. See "include/loader/filemgr.h". |
355 | 97.8k | Expect<Byte> FileMgr::peekByte() { |
356 | 97.8k | EXPECTED_TRY(Byte B, readByte()); |
357 | 97.7k | Pos--; |
358 | 97.7k | return B; |
359 | 97.8k | } |
360 | | |
361 | | // Get the file header type. See "include/loader/filemgr.h". |
362 | 7.96k | FileMgr::FileHeader FileMgr::getHeaderType() { |
363 | 7.96k | if (Size >= 4) { |
364 | 7.93k | Byte WASMMagic[] = {0x00, 0x61, 0x73, 0x6D}; |
365 | 7.93k | Byte ELFMagic[] = {0x7F, 0x45, 0x4C, 0x46}; |
366 | 7.93k | Byte MAC32agic[] = {0xCE, 0xFA, 0xED, 0xFE}; |
367 | 7.93k | Byte MAC64agic[] = {0xCF, 0xFA, 0xED, 0xFE}; |
368 | 7.93k | if (std::equal(WASMMagic, WASMMagic + 4, Data)) { |
369 | 7.88k | return FileMgr::FileHeader::Wasm; |
370 | 7.88k | } else if (std::equal(ELFMagic, ELFMagic + 4, Data)) { |
371 | 1 | return FileMgr::FileHeader::ELF; |
372 | 51 | } else if (std::equal(MAC32agic, MAC32agic + 4, Data)) { |
373 | 1 | return FileMgr::FileHeader::MachO_32; |
374 | 50 | } else if (std::equal(MAC64agic, MAC64agic + 4, Data)) { |
375 | 1 | return FileMgr::FileHeader::MachO_64; |
376 | 1 | } |
377 | 7.93k | } |
378 | 71 | if (Size >= 2) { |
379 | 70 | Byte DLLMagic[] = {0x4D, 0x5A}; |
380 | 70 | if (std::equal(DLLMagic, DLLMagic + 2, Data)) { |
381 | 1 | return FileMgr::FileHeader::DLL; |
382 | 1 | } |
383 | 70 | } |
384 | 70 | return FileMgr::FileHeader::Unknown; |
385 | 71 | } |
386 | | |
387 | | // Jump a section. See "include/loader/filemgr.h". |
388 | 0 | Expect<void> FileMgr::jumpContent() { |
389 | 0 | if (unlikely(Status != ErrCode::Value::Success)) { |
390 | 0 | return Unexpect(Status); |
391 | 0 | } |
392 | | // Set the flag to the start offset. |
393 | 0 | LastPos = Pos; |
394 | | // Read the section size. |
395 | 0 | EXPECTED_TRY(uint32_t SecSize, readU32()); |
396 | | // Jump the content. |
397 | 0 | EXPECTED_TRY(testRead(SecSize)); |
398 | 0 | Pos += SecSize; |
399 | 0 | return {}; |
400 | 0 | } |
401 | | |
402 | | // Helper function for reading number of bytes. See "include/loader/filemgr.h". |
403 | 146k | Expect<void> FileMgr::readBytes(Span<Byte> Buffer) { |
404 | 146k | if (unlikely(Status != ErrCode::Value::Success)) { |
405 | 0 | return Unexpect(Status); |
406 | 0 | } |
407 | | // The adjustment of `LastPos` should be handled by caller. |
408 | 146k | auto SizeToRead = Buffer.size(); |
409 | 146k | if (likely(SizeToRead > 0)) { |
410 | | // Check if exceed the data boundary. |
411 | 46.5k | EXPECTED_TRY(testRead(SizeToRead)); |
412 | 46.5k | std::copy_n(Data + Pos, SizeToRead, Buffer.begin()); |
413 | 46.5k | Pos += SizeToRead; |
414 | 46.5k | } |
415 | 146k | return {}; |
416 | 146k | } |
417 | | |
418 | | // Helper function for checking boundary. See "include/loader/filemgr.h". |
419 | 13.6M | Expect<void> FileMgr::testRead(uint64_t Read) { |
420 | | // Check if exceed the data boundary |
421 | 13.6M | if (unlikely(getRemainSize() < Read)) { |
422 | 5.95k | Pos = Size; |
423 | 5.95k | LastPos = Pos; |
424 | 5.95k | Status = ErrCode::Value::UnexpectedEnd; |
425 | 5.95k | return Unexpect(Status); |
426 | 5.95k | } |
427 | 13.6M | return {}; |
428 | 13.6M | } |
429 | | |
430 | | } // namespace WasmEdge |