Coverage Report

Created: 2025-10-10 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/WasmEdge/lib/loader/filemgr.cpp
Line
Count
Source
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.89k
Expect<void> FileMgr::setCode(Span<const Byte> CodeData) {
42
7.89k
  reset();
43
7.89k
  Data = CodeData.data();
44
7.89k
  Size = CodeData.size();
45
7.89k
  Status = ErrCode::Value::Success;
46
7.89k
  return {};
47
7.89k
}
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.72M
Expect<Byte> FileMgr::readByte() {
66
8.72M
  if (unlikely(Status != ErrCode::Value::Success)) {
67
0
    return Unexpect(Status);
68
0
  }
69
  // Set the flag to the start offset.
70
8.72M
  LastPos = Pos;
71
  // Check if exceed the data boundary and section boundary.
72
8.72M
  EXPECTED_TRY(testRead(1));
73
8.72M
  return Data[Pos++];
74
8.72M
}
75
76
// Read number of bytes. See "include/loader/filemgr.h".
77
70.3k
Expect<std::vector<Byte>> FileMgr::readBytes(size_t SizeToRead) {
78
  // Set the flag to the start offset.
79
70.3k
  LastPos = Pos;
80
  // Read bytes into vector.
81
70.3k
  std::vector<Byte> Buf(SizeToRead);
82
70.3k
  EXPECTED_TRY(readBytes(Buf));
83
70.3k
  return Buf;
84
70.3k
}
85
86
// Decode and read an unsigned int. See "include/loader/filemgr.h".
87
1.76M
Expect<uint32_t> FileMgr::readU32() {
88
1.76M
  if (unlikely(Status != ErrCode::Value::Success)) {
89
0
    return Unexpect(Status);
90
0
  }
91
  // Set the flag to the start offset.
92
1.76M
  LastPos = Pos;
93
94
  // Read and decode U32.
95
1.76M
  uint32_t Result = 0;
96
1.76M
  uint32_t Offset = 0;
97
1.76M
  Byte Byte = 0x80;
98
4.11M
  while (Byte & 0x80) {
99
2.34M
    if (unlikely(Offset >= 32)) {
100
6
      Status = ErrCode::Value::IntegerTooLong;
101
6
      return Unexpect(Status);
102
6
    }
103
2.34M
    EXPECTED_TRY(testRead(1));
104
2.34M
    Byte = Data[Pos++];
105
2.34M
    Result |= (Byte & UINT32_C(0x7F)) << Offset;
106
2.34M
    if (Offset == 28 && unlikely((Byte & UINT32_C(0x70)) != 0)) {
107
32
      Status = ErrCode::Value::IntegerTooLarge;
108
32
      return Unexpect(Status);
109
32
    }
110
2.34M
    Offset += 7;
111
2.34M
  }
112
1.76M
  return Result;
113
1.76M
}
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.70M
template <typename RetType, size_t N> Expect<RetType> FileMgr::readSN() {
145
2.70M
  static_assert(N >= 8, "The N of S_N must have at least length of a byte");
146
2.70M
  static_assert(8 * sizeof(RetType) >= N,
147
2.70M
                "RetType cannot hold the full range of S_N");
148
2.70M
  static_assert(std::is_signed_v<RetType>,
149
2.70M
                "RetType of S_N must be signed type");
150
151
2.70M
  if (Status != ErrCode::Value::Success) {
152
0
    return Unexpect(Status);
153
0
  }
154
  // Set the flag to the start offset.
155
2.70M
  LastPos = Pos;
156
157
  // Read and decode S_N.
158
2.70M
  RetType Result = 0;
159
2.70M
  size_t Offset = 0;
160
2.70M
  size_t RemainingBits = N;
161
2.95M
  while (true) {
162
2.95M
    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.95M
    EXPECTED_TRY(testRead(1));
169
2.95M
    WasmEdge::Byte Byte = Data[Pos++];
170
171
2.95M
    const WasmEdge::Byte HighestBitMask = 1 << 7;
172
2.95M
    const WasmEdge::Byte SecondHighestBitMask = 1 << 6;
173
2.95M
    if (Byte & HighestBitMask) {
174
      // The byte has leading 1. It contains 7 bits payload.
175
176
248k
      if (unlikely(RemainingBits < 7)) {
177
21
        Status = ErrCode::Value::IntegerTooLong;
178
21
        return Unexpect(Status);
179
21
      }
180
181
248k
      std::make_unsigned_t<RetType> Payload =
182
248k
          Byte & (~HighestBitMask); // & 0b01111111
183
248k
      Result |= (Payload << Offset);
184
248k
      Offset += 7;
185
248k
      RemainingBits -= 7;
186
2.70M
    } 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.70M
      size_t EffectiveBits = RemainingBits < 7 ? RemainingBits : 7;
193
2.70M
      std::make_unsigned_t<RetType> Payload = Byte;
194
2.70M
      if (Byte & SecondHighestBitMask) {
195
        // The byte is signed.
196
2.07M
        if (Byte >= (1 << 7) - (1 << (EffectiveBits - 1))) {
197
2.07M
          Payload -= (1 << 7);
198
2.07M
        } else {
199
12
          Status = ErrCode::Value::IntegerTooLarge;
200
12
          return Unexpect(Status);
201
12
        }
202
2.07M
      } else {
203
        // The byte is unsigned.
204
626k
        if (Byte >= (1 << (EffectiveBits - 1))) {
205
16
          Status = ErrCode::Value::IntegerTooLarge;
206
16
          return Unexpect(Status);
207
16
        }
208
626k
      }
209
2.70M
      Result |= (Payload << Offset);
210
2.70M
      break;
211
2.70M
    }
212
2.95M
  }
213
214
2.70M
  return Result;
215
2.70M
}
cxx20::expected<long, WasmEdge::ErrCode> WasmEdge::FileMgr::readSN<long, 33ul>()
Line
Count
Source
144
263k
template <typename RetType, size_t N> Expect<RetType> FileMgr::readSN() {
145
263k
  static_assert(N >= 8, "The N of S_N must have at least length of a byte");
146
263k
  static_assert(8 * sizeof(RetType) >= N,
147
263k
                "RetType cannot hold the full range of S_N");
148
263k
  static_assert(std::is_signed_v<RetType>,
149
263k
                "RetType of S_N must be signed type");
150
151
263k
  if (Status != ErrCode::Value::Success) {
152
0
    return Unexpect(Status);
153
0
  }
154
  // Set the flag to the start offset.
155
263k
  LastPos = Pos;
156
157
  // Read and decode S_N.
158
263k
  RetType Result = 0;
159
263k
  size_t Offset = 0;
160
263k
  size_t RemainingBits = N;
161
277k
  while (true) {
162
277k
    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
277k
    EXPECTED_TRY(testRead(1));
169
277k
    WasmEdge::Byte Byte = Data[Pos++];
170
171
277k
    const WasmEdge::Byte HighestBitMask = 1 << 7;
172
277k
    const WasmEdge::Byte SecondHighestBitMask = 1 << 6;
173
277k
    if (Byte & HighestBitMask) {
174
      // The byte has leading 1. It contains 7 bits payload.
175
176
13.6k
      if (unlikely(RemainingBits < 7)) {
177
3
        Status = ErrCode::Value::IntegerTooLong;
178
3
        return Unexpect(Status);
179
3
      }
180
181
13.6k
      std::make_unsigned_t<RetType> Payload =
182
13.6k
          Byte & (~HighestBitMask); // & 0b01111111
183
13.6k
      Result |= (Payload << Offset);
184
13.6k
      Offset += 7;
185
13.6k
      RemainingBits -= 7;
186
263k
    } 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
263k
      size_t EffectiveBits = RemainingBits < 7 ? RemainingBits : 7;
193
263k
      std::make_unsigned_t<RetType> Payload = Byte;
194
263k
      if (Byte & SecondHighestBitMask) {
195
        // The byte is signed.
196
59.3k
        if (Byte >= (1 << 7) - (1 << (EffectiveBits - 1))) {
197
59.3k
          Payload -= (1 << 7);
198
59.3k
        } else {
199
3
          Status = ErrCode::Value::IntegerTooLarge;
200
3
          return Unexpect(Status);
201
3
        }
202
204k
      } else {
203
        // The byte is unsigned.
204
204k
        if (Byte >= (1 << (EffectiveBits - 1))) {
205
3
          Status = ErrCode::Value::IntegerTooLarge;
206
3
          return Unexpect(Status);
207
3
        }
208
204k
      }
209
263k
      Result |= (Payload << Offset);
210
263k
      break;
211
263k
    }
212
277k
  }
213
214
263k
  return Result;
215
263k
}
cxx20::expected<int, WasmEdge::ErrCode> WasmEdge::FileMgr::readSN<int, 32ul>()
Line
Count
Source
144
2.14M
template <typename RetType, size_t N> Expect<RetType> FileMgr::readSN() {
145
2.14M
  static_assert(N >= 8, "The N of S_N must have at least length of a byte");
146
2.14M
  static_assert(8 * sizeof(RetType) >= N,
147
2.14M
                "RetType cannot hold the full range of S_N");
148
2.14M
  static_assert(std::is_signed_v<RetType>,
149
2.14M
                "RetType of S_N must be signed type");
150
151
2.14M
  if (Status != ErrCode::Value::Success) {
152
0
    return Unexpect(Status);
153
0
  }
154
  // Set the flag to the start offset.
155
2.14M
  LastPos = Pos;
156
157
  // Read and decode S_N.
158
2.14M
  RetType Result = 0;
159
2.14M
  size_t Offset = 0;
160
2.14M
  size_t RemainingBits = N;
161
2.28M
  while (true) {
162
2.28M
    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.28M
    EXPECTED_TRY(testRead(1));
169
2.28M
    WasmEdge::Byte Byte = Data[Pos++];
170
171
2.28M
    const WasmEdge::Byte HighestBitMask = 1 << 7;
172
2.28M
    const WasmEdge::Byte SecondHighestBitMask = 1 << 6;
173
2.28M
    if (Byte & HighestBitMask) {
174
      // The byte has leading 1. It contains 7 bits payload.
175
176
141k
      if (unlikely(RemainingBits < 7)) {
177
5
        Status = ErrCode::Value::IntegerTooLong;
178
5
        return Unexpect(Status);
179
5
      }
180
181
141k
      std::make_unsigned_t<RetType> Payload =
182
141k
          Byte & (~HighestBitMask); // & 0b01111111
183
141k
      Result |= (Payload << Offset);
184
141k
      Offset += 7;
185
141k
      RemainingBits -= 7;
186
2.14M
    } 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.14M
      size_t EffectiveBits = RemainingBits < 7 ? RemainingBits : 7;
193
2.14M
      std::make_unsigned_t<RetType> Payload = Byte;
194
2.14M
      if (Byte & SecondHighestBitMask) {
195
        // The byte is signed.
196
1.74M
        if (Byte >= (1 << 7) - (1 << (EffectiveBits - 1))) {
197
1.74M
          Payload -= (1 << 7);
198
1.74M
        } else {
199
3
          Status = ErrCode::Value::IntegerTooLarge;
200
3
          return Unexpect(Status);
201
3
        }
202
1.74M
      } else {
203
        // The byte is unsigned.
204
402k
        if (Byte >= (1 << (EffectiveBits - 1))) {
205
7
          Status = ErrCode::Value::IntegerTooLarge;
206
7
          return Unexpect(Status);
207
7
        }
208
402k
      }
209
2.14M
      Result |= (Payload << Offset);
210
2.14M
      break;
211
2.14M
    }
212
2.28M
  }
213
214
2.14M
  return Result;
215
2.14M
}
cxx20::expected<long, WasmEdge::ErrCode> WasmEdge::FileMgr::readSN<long, 64ul>()
Line
Count
Source
144
296k
template <typename RetType, size_t N> Expect<RetType> FileMgr::readSN() {
145
296k
  static_assert(N >= 8, "The N of S_N must have at least length of a byte");
146
296k
  static_assert(8 * sizeof(RetType) >= N,
147
296k
                "RetType cannot hold the full range of S_N");
148
296k
  static_assert(std::is_signed_v<RetType>,
149
296k
                "RetType of S_N must be signed type");
150
151
296k
  if (Status != ErrCode::Value::Success) {
152
0
    return Unexpect(Status);
153
0
  }
154
  // Set the flag to the start offset.
155
296k
  LastPos = Pos;
156
157
  // Read and decode S_N.
158
296k
  RetType Result = 0;
159
296k
  size_t Offset = 0;
160
296k
  size_t RemainingBits = N;
161
390k
  while (true) {
162
390k
    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
390k
    EXPECTED_TRY(testRead(1));
169
390k
    WasmEdge::Byte Byte = Data[Pos++];
170
171
390k
    const WasmEdge::Byte HighestBitMask = 1 << 7;
172
390k
    const WasmEdge::Byte SecondHighestBitMask = 1 << 6;
173
390k
    if (Byte & HighestBitMask) {
174
      // The byte has leading 1. It contains 7 bits payload.
175
176
94.0k
      if (unlikely(RemainingBits < 7)) {
177
13
        Status = ErrCode::Value::IntegerTooLong;
178
13
        return Unexpect(Status);
179
13
      }
180
181
94.0k
      std::make_unsigned_t<RetType> Payload =
182
94.0k
          Byte & (~HighestBitMask); // & 0b01111111
183
94.0k
      Result |= (Payload << Offset);
184
94.0k
      Offset += 7;
185
94.0k
      RemainingBits -= 7;
186
296k
    } 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
296k
      size_t EffectiveBits = RemainingBits < 7 ? RemainingBits : 7;
193
296k
      std::make_unsigned_t<RetType> Payload = Byte;
194
296k
      if (Byte & SecondHighestBitMask) {
195
        // The byte is signed.
196
276k
        if (Byte >= (1 << 7) - (1 << (EffectiveBits - 1))) {
197
276k
          Payload -= (1 << 7);
198
276k
        } else {
199
6
          Status = ErrCode::Value::IntegerTooLarge;
200
6
          return Unexpect(Status);
201
6
        }
202
276k
      } else {
203
        // The byte is unsigned.
204
19.4k
        if (Byte >= (1 << (EffectiveBits - 1))) {
205
6
          Status = ErrCode::Value::IntegerTooLarge;
206
6
          return Unexpect(Status);
207
6
        }
208
19.4k
      }
209
296k
      Result |= (Payload << Offset);
210
296k
      break;
211
296k
    }
212
390k
  }
213
214
296k
  return Result;
215
296k
}
216
217
263k
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.14M
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
296k
Expect<int64_t> FileMgr::readS64() { return readSN<int64_t, 64>(); }
224
225
// Copy bytes to a float. See "include/loader/filemgr.h".
226
41.2k
Expect<float> FileMgr::readF32() {
227
41.2k
  if (Status != ErrCode::Value::Success) {
228
0
    return Unexpect(Status);
229
0
  }
230
  // Set the flag to the start offset.
231
41.2k
  LastPos = Pos;
232
233
41.2k
  uint32_t Buf = 0;
234
41.2k
  Byte Byte = 0x00;
235
  // Check if exceed the data boundary and section boundary.
236
41.2k
  EXPECTED_TRY(testRead(4));
237
206k
  for (uint32_t I = 0; I < 4; I++) {
238
164k
    Byte = Data[Pos++];
239
164k
    Buf |= (Byte & UINT32_C(0xFF)) << (I * UINT32_C(8));
240
164k
  }
241
41.2k
  float Result;
242
41.2k
  static_assert(sizeof(Buf) == sizeof(Result));
243
41.2k
  std::memcpy(&Result, &Buf, sizeof(Result));
244
41.2k
  return Result;
245
41.2k
}
246
247
// Copy bytes to a double. See "include/loader/filemgr.h".
248
16.8k
Expect<double> FileMgr::readF64() {
249
16.8k
  if (Status != ErrCode::Value::Success) {
250
0
    return Unexpect(Status);
251
0
  }
252
  // Set the flag to the start offset.
253
16.8k
  LastPos = Pos;
254
255
16.8k
  uint64_t Buf = 0;
256
16.8k
  Byte Byte = 0x00;
257
  // Check if exceed the data boundary and section boundary.
258
16.8k
  EXPECTED_TRY(testRead(8));
259
151k
  for (uint32_t I = 0; I < 8; I++) {
260
134k
    Byte = Data[Pos++];
261
134k
    Buf |= (Byte & UINT64_C(0xFF)) << (I * UINT64_C(8));
262
134k
  }
263
16.8k
  double Result;
264
16.8k
  static_assert(sizeof(Buf) == sizeof(Result));
265
16.8k
  std::memcpy(&Result, &Buf, sizeof(Result));
266
16.8k
  return Result;
267
16.8k
}
268
269
// Read a vector of bytes. See "include/loader/filemgr.h".
270
89.7k
Expect<std::string> FileMgr::readName() {
271
89.7k
  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
89.7k
  LastPos = Pos;
277
278
  // Read the name size.
279
89.7k
  EXPECTED_TRY(uint32_t SizeToRead, readU32());
280
281
  // Check if string length exceed the data boundary.
282
89.7k
  if (auto Res = testRead(SizeToRead); unlikely(!Res)) {
283
43
    return Unexpect(ErrCode::Value::LengthOutOfBounds);
284
43
  }
285
286
  // Read the UTF-8 bytes.
287
89.7k
  std::string Str(SizeToRead, '\0');
288
89.7k
  EXPECTED_TRY(
289
89.7k
      readBytes(Span<Byte>(reinterpret_cast<Byte *>(Str.data()), Str.size())));
290
291
  // UTF-8 validation.
292
89.7k
  bool Valid = true;
293
388k
  for (uint32_t I = 0; I < Str.size() && Valid; ++I) {
294
298k
    char C = Str.data()[I];
295
298k
    uint32_t N = 0;
296
298k
    if ((C & '\x80') == 0) {
297
      // 0xxxxxxx, 7 bits UCS, ASCII
298
288k
      N = 0;
299
288k
    } else if ((C & '\xE0') == '\xC0') {
300
      // 110xxxxx, 11 bits UCS, U+80 to U+7FF
301
2.17k
      N = 1;
302
7.84k
    } else if ((C & '\xF0') == '\xE0') {
303
      // 1110xxxx, 16 bits UCS, U+800 to U+D7FF and U+E000 to U+FFFF
304
5.19k
      N = 2;
305
5.19k
    } else if ((C & '\xF8') == '\xF0') {
306
      // 11110xxx, 21 bits UCS, U+10000 to U+10FFFF
307
2.59k
      N = 3;
308
2.59k
    } else {
309
56
      Valid = false;
310
56
    }
311
312
    // Need to have N more bytes
313
298k
    if (I + N >= Str.size()) {
314
15
      Valid = false;
315
15
    }
316
    // Invalid ranges
317
298k
    if (N == 1 && (C & '\xDE') == '\xC0') {
318
      // 11 bits UCS, U+0 to U+80, FAIL
319
2
      Valid = false;
320
298k
    } else if (N == 2 &&
321
5.19k
               ((C == '\xE0' && (Str.data()[I + 1] & '\xA0') == '\x80') ||
322
                // 16 bits UCS, U+0 to U+7FF, FAIL
323
5.19k
                (C == '\xED' && (Str.data()[I + 1] & '\xA0') == '\xA0')
324
                // 16 bits UCS, U+D800 to U+DFFF, FAIL
325
5.19k
                )) {
326
4
      Valid = false;
327
298k
    } else if (N == 3 &&
328
2.59k
               ((C == '\xF0' && (Str.data()[I + 1] & '\xB0') == '\x80') ||
329
                // 21 bits UCS, U+0 to U+FFFF, FAIL
330
2.59k
                (C == '\xF4' && (Str.data()[I + 1] & '\xB0') != '\x80') ||
331
                // 21 bits UCS, U+110000 to U+13FFFF, FAIL
332
2.58k
                (C != '\xF4' && (C & '\xF4') == '\xF4')
333
                // 21 bits UCS, U+140000 to U+1FFFFF, FAIL
334
2.59k
                )) {
335
13
      Valid = false;
336
13
    }
337
338
318k
    for (uint32_t J = 0; J < N && Valid; ++J) {
339
      // N bytes needs to match 10xxxxxx
340
20.2k
      if ((Str.data()[I + J + 1] & '\xC0') != '\x80') {
341
41
        Valid = false;
342
41
      }
343
20.2k
    }
344
298k
    I += N;
345
298k
  }
346
347
89.7k
  if (!Valid) {
348
130
    Status = ErrCode::Value::MalformedUTF8;
349
130
    return Unexpect(Status);
350
130
  }
351
89.5k
  return Str;
352
89.7k
}
353
354
// Peek one byte. See "include/loader/filemgr.h".
355
95.9k
Expect<Byte> FileMgr::peekByte() {
356
95.9k
  EXPECTED_TRY(Byte B, readByte());
357
95.9k
  Pos--;
358
95.9k
  return B;
359
95.9k
}
360
361
// Get the file header type. See "include/loader/filemgr.h".
362
7.89k
FileMgr::FileHeader FileMgr::getHeaderType() {
363
7.89k
  if (Size >= 4) {
364
7.87k
    Byte WASMMagic[] = {0x00, 0x61, 0x73, 0x6D};
365
7.87k
    Byte ELFMagic[] = {0x7F, 0x45, 0x4C, 0x46};
366
7.87k
    Byte MAC32agic[] = {0xCE, 0xFA, 0xED, 0xFE};
367
7.87k
    Byte MAC64agic[] = {0xCF, 0xFA, 0xED, 0xFE};
368
7.87k
    if (std::equal(WASMMagic, WASMMagic + 4, Data)) {
369
7.84k
      return FileMgr::FileHeader::Wasm;
370
7.84k
    } else if (std::equal(ELFMagic, ELFMagic + 4, Data)) {
371
1
      return FileMgr::FileHeader::ELF;
372
29
    } else if (std::equal(MAC32agic, MAC32agic + 4, Data)) {
373
1
      return FileMgr::FileHeader::MachO_32;
374
28
    } else if (std::equal(MAC64agic, MAC64agic + 4, Data)) {
375
1
      return FileMgr::FileHeader::MachO_64;
376
1
    }
377
7.87k
  }
378
44
  if (Size >= 2) {
379
43
    Byte DLLMagic[] = {0x4D, 0x5A};
380
43
    if (std::equal(DLLMagic, DLLMagic + 2, Data)) {
381
1
      return FileMgr::FileHeader::DLL;
382
1
    }
383
43
  }
384
43
  return FileMgr::FileHeader::Unknown;
385
44
}
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
160k
Expect<void> FileMgr::readBytes(Span<Byte> Buffer) {
404
160k
  if (unlikely(Status != ErrCode::Value::Success)) {
405
0
    return Unexpect(Status);
406
0
  }
407
  // The adjustment of `LastPos` should be handled by caller.
408
160k
  auto SizeToRead = Buffer.size();
409
160k
  if (likely(SizeToRead > 0)) {
410
    // Check if exceed the data boundary.
411
46.9k
    EXPECTED_TRY(testRead(SizeToRead));
412
46.9k
    std::copy_n(Data + Pos, SizeToRead, Buffer.begin());
413
46.9k
    Pos += SizeToRead;
414
46.9k
  }
415
160k
  return {};
416
160k
}
417
418
// Helper function for checking boundary. See "include/loader/filemgr.h".
419
14.2M
Expect<void> FileMgr::testRead(uint64_t Read) {
420
  // Check if exceed the data boundary
421
14.2M
  if (unlikely(getRemainSize() < Read)) {
422
5.96k
    Pos = Size;
423
5.96k
    LastPos = Pos;
424
5.96k
    Status = ErrCode::Value::UnexpectedEnd;
425
5.96k
    return Unexpect(Status);
426
5.96k
  }
427
14.2M
  return {};
428
14.2M
}
429
430
} // namespace WasmEdge