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