Coverage Report

Created: 2026-06-30 06:10

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: 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
9.46k
Expect<void> FileMgr::setCode(Span<const Byte> CodeData) {
49
9.46k
  reset();
50
9.46k
  Data = CodeData.data();
51
9.46k
  Size = CodeData.size();
52
9.46k
  Status = ErrCode::Value::Success;
53
9.46k
  return {};
54
9.46k
}
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
12.4M
Expect<Byte> FileMgr::readByte() {
73
12.4M
  if (unlikely(Status != ErrCode::Value::Success)) {
74
0
    return Unexpect(Status);
75
0
  }
76
  // Set the flag to the start offset.
77
12.4M
  LastPos = Pos;
78
  // Check whether reading exceeds the data or section boundary.
79
12.4M
  EXPECTED_TRY(testRead(1));
80
12.4M
  return Data[Pos++];
81
12.4M
}
82
83
// Read bytes. See "include/loader/filemgr.h".
84
73.2k
Expect<std::vector<Byte>> FileMgr::readBytes(size_t SizeToRead) {
85
  // Set the flag to the start offset.
86
73.2k
  LastPos = Pos;
87
  // Read bytes into vector.
88
73.2k
  std::vector<Byte> Buf(SizeToRead);
89
73.2k
  EXPECTED_TRY(readBytes(Buf));
90
73.1k
  return Buf;
91
73.2k
}
92
93
// Decode and read an unsigned int. See "include/loader/filemgr.h".
94
1.89M
Expect<uint32_t> FileMgr::readU32() {
95
1.89M
  if (unlikely(Status != ErrCode::Value::Success)) {
96
0
    return Unexpect(Status);
97
0
  }
98
  // Set the flag to the start offset.
99
1.89M
  LastPos = Pos;
100
101
  // Read and decode U32.
102
1.89M
  uint32_t Result = 0;
103
1.89M
  uint32_t Offset = 0;
104
1.89M
  Byte Byte = 0x80;
105
4.39M
  while (Byte & 0x80) {
106
2.50M
    if (unlikely(Offset >= 32)) {
107
8
      Status = ErrCode::Value::IntegerTooLong;
108
8
      return Unexpect(Status);
109
8
    }
110
2.50M
    EXPECTED_TRY(testRead(1));
111
2.50M
    Byte = Data[Pos++];
112
2.50M
    Result |= (Byte & UINT32_C(0x7F)) << Offset;
113
2.50M
    if (Offset == 28 && unlikely((Byte & UINT32_C(0x70)) != 0)) {
114
58
      Status = ErrCode::Value::IntegerTooLarge;
115
58
      return Unexpect(Status);
116
58
    }
117
2.50M
    Offset += 7;
118
2.50M
  }
119
1.89M
  return Result;
120
1.89M
}
121
122
// Decode and read an unsigned long long int. See "include/loader/filemgr.h".
123
176k
Expect<uint64_t> FileMgr::readU64() {
124
176k
  if (Status != ErrCode::Value::Success) {
125
0
    return Unexpect(Status);
126
0
  }
127
  // Set the flag to the start offset.
128
176k
  LastPos = Pos;
129
130
  // Read and decode U64.
131
176k
  uint64_t Result = 0;
132
176k
  uint64_t Offset = 0;
133
176k
  Byte Byte = 0x80;
134
388k
  while (Byte & 0x80) {
135
212k
    if (unlikely(Offset >= 64)) {
136
2
      Status = ErrCode::Value::IntegerTooLong;
137
2
      return Unexpect(Status);
138
2
    }
139
212k
    EXPECTED_TRY(testRead(1));
140
212k
    Byte = Data[Pos++];
141
212k
    Result |= (Byte & UINT64_C(0x7F)) << Offset;
142
212k
    if (Offset == 63 && unlikely((Byte & UINT32_C(0x7E)) != 0)) {
143
7
      Status = ErrCode::Value::IntegerTooLarge;
144
7
      return Unexpect(Status);
145
7
    }
146
212k
    Offset += 7;
147
212k
  }
148
176k
  return Result;
149
176k
}
150
151
3.63M
template <typename RetType, size_t N> Expect<RetType> FileMgr::readSN() {
152
3.63M
  static_assert(N >= 8, "The N of S_N must have at least length of a byte");
153
3.63M
  static_assert(8 * sizeof(RetType) >= N,
154
3.63M
                "RetType cannot hold the full range of S_N");
155
3.63M
  static_assert(std::is_signed_v<RetType>,
156
3.63M
                "RetType of S_N must be signed type");
157
158
3.63M
  if (Status != ErrCode::Value::Success) {
159
0
    return Unexpect(Status);
160
0
  }
161
  // Set the flag to the start offset.
162
3.63M
  LastPos = Pos;
163
164
  // Read and decode S_N.
165
3.63M
  RetType Result = 0;
166
3.63M
  size_t Offset = 0;
167
3.63M
  size_t RemainingBits = N;
168
3.99M
  while (true) {
169
3.99M
    if (RemainingBits <= 0) {
170
0
      Status = ErrCode::Value::IntegerTooLong;
171
0
      return Unexpect(Status);
172
0
    }
173
174
    // In the remaining logic, RemainingBits must be at least 1.
175
3.99M
    EXPECTED_TRY(testRead(1));
176
3.99M
    WasmEdge::Byte Byte = Data[Pos++];
177
178
3.99M
    const WasmEdge::Byte HighestBitMask = 1 << 7;
179
3.99M
    const WasmEdge::Byte SecondHighestBitMask = 1 << 6;
180
3.99M
    if (Byte & HighestBitMask) {
181
      // The byte has a leading 1. It contains a 7-bit payload.
182
183
356k
      if (unlikely(RemainingBits < 7)) {
184
34
        Status = ErrCode::Value::IntegerTooLong;
185
34
        return Unexpect(Status);
186
34
      }
187
188
356k
      std::make_unsigned_t<RetType> Payload =
189
356k
          Byte & (~HighestBitMask); // & 0b01111111
190
356k
      Result |= (Payload << Offset);
191
356k
      Offset += 7;
192
356k
      RemainingBits -= 7;
193
3.63M
    } else {
194
      // The byte has a leading 0. It will be the last byte.
195
196
      // The number of bits that take effect in the byte. Since RemainingBits
197
      // must be at least 1, EffectiveBits also must be at least 1. It is also
198
      // at most 7.
199
3.63M
      size_t EffectiveBits = RemainingBits < 7 ? RemainingBits : 7;
200
3.63M
      std::make_unsigned_t<RetType> Payload = Byte;
201
3.63M
      if (Byte & SecondHighestBitMask) {
202
        // The byte is signed.
203
2.77M
        if (Byte >= (1 << 7) - (1 << (EffectiveBits - 1))) {
204
2.77M
          Payload -= (1 << 7);
205
2.77M
        } else {
206
19
          Status = ErrCode::Value::IntegerTooLarge;
207
19
          return Unexpect(Status);
208
19
        }
209
2.77M
      } else {
210
        // The byte is unsigned.
211
867k
        if (Byte >= (1 << (EffectiveBits - 1))) {
212
15
          Status = ErrCode::Value::IntegerTooLarge;
213
15
          return Unexpect(Status);
214
15
        }
215
867k
      }
216
3.63M
      Result |= (Payload << Offset);
217
3.63M
      break;
218
3.63M
    }
219
3.99M
  }
220
221
3.63M
  return Result;
222
3.63M
}
cxx20::expected<long, WasmEdge::ErrCode> WasmEdge::FileMgr::readSN<long, 33ul>()
Line
Count
Source
151
947k
template <typename RetType, size_t N> Expect<RetType> FileMgr::readSN() {
152
947k
  static_assert(N >= 8, "The N of S_N must have at least length of a byte");
153
947k
  static_assert(8 * sizeof(RetType) >= N,
154
947k
                "RetType cannot hold the full range of S_N");
155
947k
  static_assert(std::is_signed_v<RetType>,
156
947k
                "RetType of S_N must be signed type");
157
158
947k
  if (Status != ErrCode::Value::Success) {
159
0
    return Unexpect(Status);
160
0
  }
161
  // Set the flag to the start offset.
162
947k
  LastPos = Pos;
163
164
  // Read and decode S_N.
165
947k
  RetType Result = 0;
166
947k
  size_t Offset = 0;
167
947k
  size_t RemainingBits = N;
168
1.01M
  while (true) {
169
1.01M
    if (RemainingBits <= 0) {
170
0
      Status = ErrCode::Value::IntegerTooLong;
171
0
      return Unexpect(Status);
172
0
    }
173
174
    // In the remaining logic, RemainingBits must be at least 1.
175
1.01M
    EXPECTED_TRY(testRead(1));
176
1.01M
    WasmEdge::Byte Byte = Data[Pos++];
177
178
1.01M
    const WasmEdge::Byte HighestBitMask = 1 << 7;
179
1.01M
    const WasmEdge::Byte SecondHighestBitMask = 1 << 6;
180
1.01M
    if (Byte & HighestBitMask) {
181
      // The byte has a leading 1. It contains a 7-bit payload.
182
183
64.0k
      if (unlikely(RemainingBits < 7)) {
184
11
        Status = ErrCode::Value::IntegerTooLong;
185
11
        return Unexpect(Status);
186
11
      }
187
188
64.0k
      std::make_unsigned_t<RetType> Payload =
189
64.0k
          Byte & (~HighestBitMask); // & 0b01111111
190
64.0k
      Result |= (Payload << Offset);
191
64.0k
      Offset += 7;
192
64.0k
      RemainingBits -= 7;
193
946k
    } else {
194
      // The byte has a leading 0. It will be the last byte.
195
196
      // The number of bits that take effect in the byte. Since RemainingBits
197
      // must be at least 1, EffectiveBits also must be at least 1. It is also
198
      // at most 7.
199
946k
      size_t EffectiveBits = RemainingBits < 7 ? RemainingBits : 7;
200
946k
      std::make_unsigned_t<RetType> Payload = Byte;
201
946k
      if (Byte & SecondHighestBitMask) {
202
        // The byte is signed.
203
548k
        if (Byte >= (1 << 7) - (1 << (EffectiveBits - 1))) {
204
548k
          Payload -= (1 << 7);
205
548k
        } else {
206
6
          Status = ErrCode::Value::IntegerTooLarge;
207
6
          return Unexpect(Status);
208
6
        }
209
548k
      } else {
210
        // The byte is unsigned.
211
398k
        if (Byte >= (1 << (EffectiveBits - 1))) {
212
4
          Status = ErrCode::Value::IntegerTooLarge;
213
4
          return Unexpect(Status);
214
4
        }
215
398k
      }
216
946k
      Result |= (Payload << Offset);
217
946k
      break;
218
946k
    }
219
1.01M
  }
220
221
946k
  return Result;
222
947k
}
cxx20::expected<int, WasmEdge::ErrCode> WasmEdge::FileMgr::readSN<int, 32ul>()
Line
Count
Source
151
2.38M
template <typename RetType, size_t N> Expect<RetType> FileMgr::readSN() {
152
2.38M
  static_assert(N >= 8, "The N of S_N must have at least length of a byte");
153
2.38M
  static_assert(8 * sizeof(RetType) >= N,
154
2.38M
                "RetType cannot hold the full range of S_N");
155
2.38M
  static_assert(std::is_signed_v<RetType>,
156
2.38M
                "RetType of S_N must be signed type");
157
158
2.38M
  if (Status != ErrCode::Value::Success) {
159
0
    return Unexpect(Status);
160
0
  }
161
  // Set the flag to the start offset.
162
2.38M
  LastPos = Pos;
163
164
  // Read and decode S_N.
165
2.38M
  RetType Result = 0;
166
2.38M
  size_t Offset = 0;
167
2.38M
  size_t RemainingBits = N;
168
2.54M
  while (true) {
169
2.54M
    if (RemainingBits <= 0) {
170
0
      Status = ErrCode::Value::IntegerTooLong;
171
0
      return Unexpect(Status);
172
0
    }
173
174
    // In the remaining logic, RemainingBits must be at least 1.
175
2.54M
    EXPECTED_TRY(testRead(1));
176
2.54M
    WasmEdge::Byte Byte = Data[Pos++];
177
178
2.54M
    const WasmEdge::Byte HighestBitMask = 1 << 7;
179
2.54M
    const WasmEdge::Byte SecondHighestBitMask = 1 << 6;
180
2.54M
    if (Byte & HighestBitMask) {
181
      // The byte has a leading 1. It contains a 7-bit payload.
182
183
165k
      if (unlikely(RemainingBits < 7)) {
184
8
        Status = ErrCode::Value::IntegerTooLong;
185
8
        return Unexpect(Status);
186
8
      }
187
188
165k
      std::make_unsigned_t<RetType> Payload =
189
165k
          Byte & (~HighestBitMask); // & 0b01111111
190
165k
      Result |= (Payload << Offset);
191
165k
      Offset += 7;
192
165k
      RemainingBits -= 7;
193
2.38M
    } else {
194
      // The byte has a leading 0. It will be the last byte.
195
196
      // The number of bits that take effect in the byte. Since RemainingBits
197
      // must be at least 1, EffectiveBits also must be at least 1. It is also
198
      // at most 7.
199
2.38M
      size_t EffectiveBits = RemainingBits < 7 ? RemainingBits : 7;
200
2.38M
      std::make_unsigned_t<RetType> Payload = Byte;
201
2.38M
      if (Byte & SecondHighestBitMask) {
202
        // The byte is signed.
203
1.93M
        if (Byte >= (1 << 7) - (1 << (EffectiveBits - 1))) {
204
1.93M
          Payload -= (1 << 7);
205
1.93M
        } else {
206
5
          Status = ErrCode::Value::IntegerTooLarge;
207
5
          return Unexpect(Status);
208
5
        }
209
1.93M
      } else {
210
        // The byte is unsigned.
211
446k
        if (Byte >= (1 << (EffectiveBits - 1))) {
212
5
          Status = ErrCode::Value::IntegerTooLarge;
213
5
          return Unexpect(Status);
214
5
        }
215
446k
      }
216
2.38M
      Result |= (Payload << Offset);
217
2.38M
      break;
218
2.38M
    }
219
2.54M
  }
220
221
2.38M
  return Result;
222
2.38M
}
cxx20::expected<long, WasmEdge::ErrCode> WasmEdge::FileMgr::readSN<long, 64ul>()
Line
Count
Source
151
309k
template <typename RetType, size_t N> Expect<RetType> FileMgr::readSN() {
152
309k
  static_assert(N >= 8, "The N of S_N must have at least length of a byte");
153
309k
  static_assert(8 * sizeof(RetType) >= N,
154
309k
                "RetType cannot hold the full range of S_N");
155
309k
  static_assert(std::is_signed_v<RetType>,
156
309k
                "RetType of S_N must be signed type");
157
158
309k
  if (Status != ErrCode::Value::Success) {
159
0
    return Unexpect(Status);
160
0
  }
161
  // Set the flag to the start offset.
162
309k
  LastPos = Pos;
163
164
  // Read and decode S_N.
165
309k
  RetType Result = 0;
166
309k
  size_t Offset = 0;
167
309k
  size_t RemainingBits = N;
168
436k
  while (true) {
169
436k
    if (RemainingBits <= 0) {
170
0
      Status = ErrCode::Value::IntegerTooLong;
171
0
      return Unexpect(Status);
172
0
    }
173
174
    // In the remaining logic, RemainingBits must be at least 1.
175
436k
    EXPECTED_TRY(testRead(1));
176
436k
    WasmEdge::Byte Byte = Data[Pos++];
177
178
436k
    const WasmEdge::Byte HighestBitMask = 1 << 7;
179
436k
    const WasmEdge::Byte SecondHighestBitMask = 1 << 6;
180
436k
    if (Byte & HighestBitMask) {
181
      // The byte has a leading 1. It contains a 7-bit payload.
182
183
127k
      if (unlikely(RemainingBits < 7)) {
184
15
        Status = ErrCode::Value::IntegerTooLong;
185
15
        return Unexpect(Status);
186
15
      }
187
188
127k
      std::make_unsigned_t<RetType> Payload =
189
127k
          Byte & (~HighestBitMask); // & 0b01111111
190
127k
      Result |= (Payload << Offset);
191
127k
      Offset += 7;
192
127k
      RemainingBits -= 7;
193
309k
    } else {
194
      // The byte has a leading 0. It will be the last byte.
195
196
      // The number of bits that take effect in the byte. Since RemainingBits
197
      // must be at least 1, EffectiveBits also must be at least 1. It is also
198
      // at most 7.
199
309k
      size_t EffectiveBits = RemainingBits < 7 ? RemainingBits : 7;
200
309k
      std::make_unsigned_t<RetType> Payload = Byte;
201
309k
      if (Byte & SecondHighestBitMask) {
202
        // The byte is signed.
203
286k
        if (Byte >= (1 << 7) - (1 << (EffectiveBits - 1))) {
204
286k
          Payload -= (1 << 7);
205
286k
        } else {
206
8
          Status = ErrCode::Value::IntegerTooLarge;
207
8
          return Unexpect(Status);
208
8
        }
209
286k
      } else {
210
        // The byte is unsigned.
211
22.9k
        if (Byte >= (1 << (EffectiveBits - 1))) {
212
6
          Status = ErrCode::Value::IntegerTooLarge;
213
6
          return Unexpect(Status);
214
6
        }
215
22.9k
      }
216
309k
      Result |= (Payload << Offset);
217
309k
      break;
218
309k
    }
219
436k
  }
220
221
309k
  return Result;
222
309k
}
223
224
947k
Expect<int64_t> FileMgr::readS33() { return readSN<int64_t, 33>(); }
225
226
// Decode and read a signed int. See "include/loader/filemgr.h".
227
2.38M
Expect<int32_t> FileMgr::readS32() { return readSN<int32_t, 32>(); }
228
229
// Decode and read a signed long long int. See "include/loader/filemgr.h".
230
309k
Expect<int64_t> FileMgr::readS64() { return readSN<int64_t, 64>(); }
231
232
// Copy bytes to a float. See "include/loader/filemgr.h".
233
44.7k
Expect<float> FileMgr::readF32() {
234
44.7k
  if (Status != ErrCode::Value::Success) {
235
0
    return Unexpect(Status);
236
0
  }
237
  // Set the flag to the start offset.
238
44.7k
  LastPos = Pos;
239
240
44.7k
  uint32_t Buf = 0;
241
44.7k
  Byte Byte = 0x00;
242
  // Check whether reading exceeds the data or section boundary.
243
44.7k
  EXPECTED_TRY(testRead(4));
244
223k
  for (uint32_t I = 0; I < 4; I++) {
245
178k
    Byte = Data[Pos++];
246
178k
    Buf |= (Byte & UINT32_C(0xFF)) << (I * UINT32_C(8));
247
178k
  }
248
44.7k
  float Result;
249
44.7k
  static_assert(sizeof(Buf) == sizeof(Result));
250
44.7k
  std::memcpy(&Result, &Buf, sizeof(Result));
251
44.7k
  return Result;
252
44.7k
}
253
254
// Copy bytes to a double. See "include/loader/filemgr.h".
255
19.0k
Expect<double> FileMgr::readF64() {
256
19.0k
  if (Status != ErrCode::Value::Success) {
257
0
    return Unexpect(Status);
258
0
  }
259
  // Set the flag to the start offset.
260
19.0k
  LastPos = Pos;
261
262
19.0k
  uint64_t Buf = 0;
263
19.0k
  Byte Byte = 0x00;
264
  // Check whether reading exceeds the data or section boundary.
265
19.0k
  EXPECTED_TRY(testRead(8));
266
171k
  for (uint32_t I = 0; I < 8; I++) {
267
152k
    Byte = Data[Pos++];
268
152k
    Buf |= (Byte & UINT64_C(0xFF)) << (I * UINT64_C(8));
269
152k
  }
270
19.0k
  double Result;
271
19.0k
  static_assert(sizeof(Buf) == sizeof(Result));
272
19.0k
  std::memcpy(&Result, &Buf, sizeof(Result));
273
19.0k
  return Result;
274
19.0k
}
275
276
// Read a vector of bytes. See "include/loader/filemgr.h".
277
96.9k
Expect<std::string> FileMgr::readName() {
278
96.9k
  if (unlikely(Status != ErrCode::Value::Success)) {
279
0
    return Unexpect(Status);
280
0
  }
281
  // If UTF-8 validation, readU32(), or readBytes() failed, the last successful
282
  // reading offset will be at the start of `Name`.
283
96.9k
  LastPos = Pos;
284
285
  // Read the name size.
286
96.9k
  EXPECTED_TRY(uint32_t SizeToRead, readU32());
287
288
  // Check whether the string length exceeds the data boundary.
289
96.9k
  if (auto Res = testRead(SizeToRead); unlikely(!Res)) {
290
69
    return Unexpect(ErrCode::Value::LengthOutOfBounds);
291
69
  }
292
293
  // Read the UTF-8 bytes.
294
96.8k
  std::string Str(SizeToRead, '\0');
295
96.8k
  EXPECTED_TRY(
296
96.8k
      readBytes(Span<Byte>(reinterpret_cast<Byte *>(Str.data()), Str.size())));
297
298
  // UTF-8 validation.
299
96.8k
  bool Valid = true;
300
416k
  for (uint32_t I = 0; I < Str.size() && Valid; ++I) {
301
319k
    char C = Str.data()[I];
302
319k
    uint32_t N = 0;
303
319k
    if ((C & '\x80') == 0) {
304
      // 0xxxxxxx, 7 bits UCS, ASCII
305
309k
      N = 0;
306
309k
    } else if ((C & '\xE0') == '\xC0') {
307
      // 110xxxxx, 11 bits UCS, U+80 to U+7FF
308
2.26k
      N = 1;
309
8.10k
    } else if ((C & '\xF0') == '\xE0') {
310
      // 1110xxxx, 16 bits UCS, U+800 to U+D7FF and U+E000 to U+FFFF
311
5.42k
      N = 2;
312
5.42k
    } else if ((C & '\xF8') == '\xF0') {
313
      // 11110xxx, 21 bits UCS, U+10000 to U+10FFFF
314
2.62k
      N = 3;
315
2.62k
    } else {
316
50
      Valid = false;
317
50
    }
318
319
    // Need N more bytes.
320
319k
    if (I + N >= Str.size()) {
321
13
      Valid = false;
322
13
    }
323
    // Invalid ranges
324
319k
    if (N == 1 && (C & '\xDE') == '\xC0') {
325
      // 11 bits UCS, U+0 to U+80, FAIL
326
3
      Valid = false;
327
319k
    } else if (N == 2 &&
328
5.42k
               ((C == '\xE0' && (Str.data()[I + 1] & '\xA0') == '\x80') ||
329
                // 16 bits UCS, U+0 to U+7FF, FAIL
330
5.42k
                (C == '\xED' && (Str.data()[I + 1] & '\xA0') == '\xA0')
331
                // 16 bits UCS, U+D800 to U+DFFF, FAIL
332
5.42k
                )) {
333
5
      Valid = false;
334
319k
    } else if (N == 3 &&
335
2.62k
               ((C == '\xF0' && (Str.data()[I + 1] & '\xB0') == '\x80') ||
336
                // 21 bits UCS, U+0 to U+FFFF, FAIL
337
2.62k
                (C == '\xF4' && (Str.data()[I + 1] & '\xB0') != '\x80') ||
338
                // 21 bits UCS, U+110000 to U+13FFFF, FAIL
339
2.62k
                (C != '\xF4' && (C & '\xF4') == '\xF4')
340
                // 21 bits UCS, U+140000 to U+1FFFFF, FAIL
341
2.62k
                )) {
342
11
      Valid = false;
343
11
    }
344
345
340k
    for (uint32_t J = 0; J < N && Valid; ++J) {
346
      // N bytes need to match 10xxxxxx
347
20.9k
      if ((Str.data()[I + J + 1] & '\xC0') != '\x80') {
348
40
        Valid = false;
349
40
      }
350
20.9k
    }
351
319k
    I += N;
352
319k
  }
353
354
96.8k
  if (!Valid) {
355
121
    Status = ErrCode::Value::MalformedUTF8;
356
121
    return Unexpect(Status);
357
121
  }
358
96.7k
  return Str;
359
96.8k
}
360
361
// Peek one byte. See "include/loader/filemgr.h".
362
697k
Expect<Byte> FileMgr::peekByte() {
363
697k
  EXPECTED_TRY(Byte B, readByte());
364
697k
  Pos--;
365
697k
  return B;
366
697k
}
367
368
// Get the file header type. See "include/loader/filemgr.h".
369
9.46k
FileMgr::FileHeader FileMgr::getHeaderType() {
370
9.46k
  if (Size >= 4) {
371
9.43k
    Byte WASMMagic[] = {0x00, 0x61, 0x73, 0x6D};
372
9.43k
    Byte ELFMagic[] = {0x7F, 0x45, 0x4C, 0x46};
373
9.43k
    Byte MAC32agic[] = {0xCE, 0xFA, 0xED, 0xFE};
374
9.43k
    Byte MAC64agic[] = {0xCF, 0xFA, 0xED, 0xFE};
375
9.43k
    if (std::equal(WASMMagic, WASMMagic + 4, Data)) {
376
9.38k
      return FileMgr::FileHeader::Wasm;
377
9.38k
    } else if (std::equal(ELFMagic, ELFMagic + 4, Data)) {
378
1
      return FileMgr::FileHeader::ELF;
379
48
    } else if (std::equal(MAC32agic, MAC32agic + 4, Data)) {
380
1
      return FileMgr::FileHeader::MachO_32;
381
47
    } else if (std::equal(MAC64agic, MAC64agic + 4, Data)) {
382
1
      return FileMgr::FileHeader::MachO_64;
383
1
    }
384
9.43k
  }
385
75
  if (Size >= 2) {
386
73
    Byte DLLMagic[] = {0x4D, 0x5A};
387
73
    if (std::equal(DLLMagic, DLLMagic + 2, Data)) {
388
1
      return FileMgr::FileHeader::DLL;
389
1
    }
390
73
  }
391
74
  return FileMgr::FileHeader::Unknown;
392
75
}
393
394
// Jump a section. See "include/loader/filemgr.h".
395
0
Expect<void> FileMgr::jumpContent() {
396
0
  if (unlikely(Status != ErrCode::Value::Success)) {
397
0
    return Unexpect(Status);
398
0
  }
399
  // Set the flag to the start offset.
400
0
  LastPos = Pos;
401
  // Read the section size.
402
0
  EXPECTED_TRY(uint32_t SecSize, readU32());
403
  // Jump the content.
404
0
  EXPECTED_TRY(testRead(SecSize));
405
0
  Pos += SecSize;
406
0
  return {};
407
0
}
408
409
// Helper function for reading bytes. See "include/loader/filemgr.h".
410
170k
Expect<void> FileMgr::readBytes(Span<Byte> Buffer) {
411
170k
  if (unlikely(Status != ErrCode::Value::Success)) {
412
0
    return Unexpect(Status);
413
0
  }
414
  // The adjustment of `LastPos` should be handled by the caller.
415
170k
  auto SizeToRead = Buffer.size();
416
170k
  if (likely(SizeToRead > 0)) {
417
    // Check whether reading exceeds the data boundary.
418
52.6k
    EXPECTED_TRY(testRead(SizeToRead));
419
52.6k
    std::copy_n(Data + Pos, SizeToRead, Buffer.begin());
420
52.6k
    Pos += SizeToRead;
421
52.6k
  }
422
170k
  return {};
423
170k
}
424
425
// Helper function for checking boundary. See "include/loader/filemgr.h".
426
19.4M
Expect<void> FileMgr::testRead(uint64_t Read) {
427
  // Check whether reading exceeds the data boundary.
428
19.4M
  if (unlikely(getRemainSize() < Read)) {
429
7.34k
    Pos = Size;
430
7.34k
    LastPos = Pos;
431
7.34k
    Status = ErrCode::Value::UnexpectedEnd;
432
7.34k
    return Unexpect(Status);
433
7.34k
  }
434
19.3M
  return {};
435
19.4M
}
436
437
} // namespace WasmEdge