Coverage Report

Created: 2026-11-12 06:35

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
34.4k
Expect<void> FileMgr::setCode(Span<const Byte> CodeData) {
49
34.4k
  reset();
50
34.4k
  Data = CodeData.data();
51
34.4k
  Size = CodeData.size();
52
34.4k
  Status = ErrCode::Value::Success;
53
34.4k
  return {};
54
34.4k
}
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
69.9M
Expect<Byte> FileMgr::readByte() {
73
69.9M
  if (unlikely(Status != ErrCode::Value::Success)) {
74
0
    return Unexpect(Status);
75
0
  }
76
  // Set the flag to the start offset.
77
69.9M
  LastPos = Pos;
78
  // Check whether reading exceeds the data or section boundary.
79
69.9M
  EXPECTED_TRY(testRead(1));
80
69.9M
  return Data[Pos++];
81
69.9M
}
82
83
// Read bytes. See "include/loader/filemgr.h".
84
4.68M
Expect<std::vector<Byte>> FileMgr::readBytes(size_t SizeToRead) {
85
4.68M
  if (unlikely(Status != ErrCode::Value::Success)) {
86
0
    return Unexpect(Status);
87
0
  }
88
  // Set the flag to the start offset.
89
4.68M
  LastPos = Pos;
90
  // Check whether reading exceeds the data boundary before allocating.
91
4.68M
  EXPECTED_TRY(testRead(SizeToRead));
92
  // Read bytes into vector.
93
4.68M
  std::vector<Byte> Buf(SizeToRead);
94
4.68M
  EXPECTED_TRY(readBytes(Buf));
95
4.68M
  return Buf;
96
4.68M
}
97
98
// Decode and read an unsigned int. See "include/loader/filemgr.h".
99
41.8M
Expect<uint32_t> FileMgr::readU32() {
100
41.8M
  if (unlikely(Status != ErrCode::Value::Success)) {
101
0
    return Unexpect(Status);
102
0
  }
103
  // Set the flag to the start offset.
104
41.8M
  LastPos = Pos;
105
106
  // Read and decode U32.
107
41.8M
  uint32_t Result = 0;
108
41.8M
  uint32_t Offset = 0;
109
41.8M
  Byte Byte = 0x80;
110
85.7M
  while (Byte & 0x80) {
111
43.8M
    if (unlikely(Offset >= 32)) {
112
16
      Status = ErrCode::Value::IntegerTooLong;
113
16
      return Unexpect(Status);
114
16
    }
115
43.8M
    EXPECTED_TRY(testRead(1));
116
43.8M
    Byte = Data[Pos++];
117
43.8M
    Result |= (Byte & UINT32_C(0x7F)) << Offset;
118
43.8M
    if (Offset == 28 && unlikely((Byte & UINT32_C(0x70)) != 0)) {
119
184
      Status = ErrCode::Value::IntegerTooLarge;
120
184
      return Unexpect(Status);
121
184
    }
122
43.8M
    Offset += 7;
123
43.8M
  }
124
41.8M
  return Result;
125
41.8M
}
126
127
// Decode and read an unsigned long long int. See "include/loader/filemgr.h".
128
588k
Expect<uint64_t> FileMgr::readU64() {
129
588k
  if (Status != ErrCode::Value::Success) {
130
0
    return Unexpect(Status);
131
0
  }
132
  // Set the flag to the start offset.
133
588k
  LastPos = Pos;
134
135
  // Read and decode U64.
136
588k
  uint64_t Result = 0;
137
588k
  uint64_t Offset = 0;
138
588k
  Byte Byte = 0x80;
139
1.26M
  while (Byte & 0x80) {
140
676k
    if (unlikely(Offset >= 64)) {
141
3
      Status = ErrCode::Value::IntegerTooLong;
142
3
      return Unexpect(Status);
143
3
    }
144
676k
    EXPECTED_TRY(testRead(1));
145
676k
    Byte = Data[Pos++];
146
676k
    Result |= (Byte & UINT64_C(0x7F)) << Offset;
147
676k
    if (Offset == 63 && unlikely((Byte & UINT32_C(0x7E)) != 0)) {
148
15
      Status = ErrCode::Value::IntegerTooLarge;
149
15
      return Unexpect(Status);
150
15
    }
151
676k
    Offset += 7;
152
676k
  }
153
588k
  return Result;
154
588k
}
155
156
12.4M
template <typename RetType, size_t N> Expect<RetType> FileMgr::readSN() {
157
12.4M
  static_assert(N >= 8, "The N of S_N must have at least length of a byte");
158
12.4M
  static_assert(8 * sizeof(RetType) >= N,
159
12.4M
                "RetType cannot hold the full range of S_N");
160
12.4M
  static_assert(std::is_signed_v<RetType>,
161
12.4M
                "RetType of S_N must be signed type");
162
163
12.4M
  if (Status != ErrCode::Value::Success) {
164
0
    return Unexpect(Status);
165
0
  }
166
  // Set the flag to the start offset.
167
12.4M
  LastPos = Pos;
168
169
  // Read and decode S_N.
170
12.4M
  RetType Result = 0;
171
12.4M
  size_t Offset = 0;
172
12.4M
  size_t RemainingBits = N;
173
13.3M
  while (true) {
174
13.3M
    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
13.3M
    EXPECTED_TRY(testRead(1));
181
13.3M
    WasmEdge::Byte Byte = Data[Pos++];
182
183
13.3M
    const WasmEdge::Byte HighestBitMask = 1 << 7;
184
13.3M
    const WasmEdge::Byte SecondHighestBitMask = 1 << 6;
185
13.3M
    if (Byte & HighestBitMask) {
186
      // The byte has a leading 1. It contains a 7-bit payload.
187
188
875k
      if (unlikely(RemainingBits < 7)) {
189
115
        Status = ErrCode::Value::IntegerTooLong;
190
115
        return Unexpect(Status);
191
115
      }
192
193
875k
      std::make_unsigned_t<RetType> Payload =
194
875k
          Byte & (~HighestBitMask); // & 0b01111111
195
875k
      Result |= (Payload << Offset);
196
875k
      Offset += 7;
197
875k
      RemainingBits -= 7;
198
12.4M
    } 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
12.4M
      size_t EffectiveBits = RemainingBits < 7 ? RemainingBits : 7;
205
12.4M
      std::make_unsigned_t<RetType> Payload = Byte;
206
12.4M
      if (Byte & SecondHighestBitMask) {
207
        // The byte is signed.
208
9.95M
        if (Byte >= (1 << 7) - (1 << (EffectiveBits - 1))) {
209
9.95M
          Payload -= (1 << 7);
210
9.95M
        } else {
211
36
          Status = ErrCode::Value::IntegerTooLarge;
212
36
          return Unexpect(Status);
213
36
        }
214
9.95M
      } else {
215
        // The byte is unsigned.
216
2.48M
        if (Byte >= (1 << (EffectiveBits - 1))) {
217
22
          Status = ErrCode::Value::IntegerTooLarge;
218
22
          return Unexpect(Status);
219
22
        }
220
2.48M
      }
221
12.4M
      Result |= (Payload << Offset);
222
12.4M
      break;
223
12.4M
    }
224
13.3M
  }
225
226
12.4M
  return Result;
227
12.4M
}
cxx20::expected<long, WasmEdge::ErrCode> WasmEdge::FileMgr::readSN<long, 33ul>()
Line
Count
Source
156
9.16M
template <typename RetType, size_t N> Expect<RetType> FileMgr::readSN() {
157
9.16M
  static_assert(N >= 8, "The N of S_N must have at least length of a byte");
158
9.16M
  static_assert(8 * sizeof(RetType) >= N,
159
9.16M
                "RetType cannot hold the full range of S_N");
160
9.16M
  static_assert(std::is_signed_v<RetType>,
161
9.16M
                "RetType of S_N must be signed type");
162
163
9.16M
  if (Status != ErrCode::Value::Success) {
164
0
    return Unexpect(Status);
165
0
  }
166
  // Set the flag to the start offset.
167
9.16M
  LastPos = Pos;
168
169
  // Read and decode S_N.
170
9.16M
  RetType Result = 0;
171
9.16M
  size_t Offset = 0;
172
9.16M
  size_t RemainingBits = N;
173
9.25M
  while (true) {
174
9.25M
    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
9.25M
    EXPECTED_TRY(testRead(1));
181
9.25M
    WasmEdge::Byte Byte = Data[Pos++];
182
183
9.25M
    const WasmEdge::Byte HighestBitMask = 1 << 7;
184
9.25M
    const WasmEdge::Byte SecondHighestBitMask = 1 << 6;
185
9.25M
    if (Byte & HighestBitMask) {
186
      // The byte has a leading 1. It contains a 7-bit payload.
187
188
85.2k
      if (unlikely(RemainingBits < 7)) {
189
56
        Status = ErrCode::Value::IntegerTooLong;
190
56
        return Unexpect(Status);
191
56
      }
192
193
85.2k
      std::make_unsigned_t<RetType> Payload =
194
85.2k
          Byte & (~HighestBitMask); // & 0b01111111
195
85.2k
      Result |= (Payload << Offset);
196
85.2k
      Offset += 7;
197
85.2k
      RemainingBits -= 7;
198
9.16M
    } 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
9.16M
      size_t EffectiveBits = RemainingBits < 7 ? RemainingBits : 7;
205
9.16M
      std::make_unsigned_t<RetType> Payload = Byte;
206
9.16M
      if (Byte & SecondHighestBitMask) {
207
        // The byte is signed.
208
7.27M
        if (Byte >= (1 << 7) - (1 << (EffectiveBits - 1))) {
209
7.27M
          Payload -= (1 << 7);
210
7.27M
        } else {
211
8
          Status = ErrCode::Value::IntegerTooLarge;
212
8
          return Unexpect(Status);
213
8
        }
214
7.27M
      } else {
215
        // The byte is unsigned.
216
1.89M
        if (Byte >= (1 << (EffectiveBits - 1))) {
217
3
          Status = ErrCode::Value::IntegerTooLarge;
218
3
          return Unexpect(Status);
219
3
        }
220
1.89M
      }
221
9.16M
      Result |= (Payload << Offset);
222
9.16M
      break;
223
9.16M
    }
224
9.25M
  }
225
226
9.16M
  return Result;
227
9.16M
}
cxx20::expected<int, WasmEdge::ErrCode> WasmEdge::FileMgr::readSN<int, 32ul>()
Line
Count
Source
156
2.33M
template <typename RetType, size_t N> Expect<RetType> FileMgr::readSN() {
157
2.33M
  static_assert(N >= 8, "The N of S_N must have at least length of a byte");
158
2.33M
  static_assert(8 * sizeof(RetType) >= N,
159
2.33M
                "RetType cannot hold the full range of S_N");
160
2.33M
  static_assert(std::is_signed_v<RetType>,
161
2.33M
                "RetType of S_N must be signed type");
162
163
2.33M
  if (Status != ErrCode::Value::Success) {
164
0
    return Unexpect(Status);
165
0
  }
166
  // Set the flag to the start offset.
167
2.33M
  LastPos = Pos;
168
169
  // Read and decode S_N.
170
2.33M
  RetType Result = 0;
171
2.33M
  size_t Offset = 0;
172
2.33M
  size_t RemainingBits = N;
173
2.63M
  while (true) {
174
2.63M
    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.63M
    EXPECTED_TRY(testRead(1));
181
2.63M
    WasmEdge::Byte Byte = Data[Pos++];
182
183
2.63M
    const WasmEdge::Byte HighestBitMask = 1 << 7;
184
2.63M
    const WasmEdge::Byte SecondHighestBitMask = 1 << 6;
185
2.63M
    if (Byte & HighestBitMask) {
186
      // The byte has a leading 1. It contains a 7-bit payload.
187
188
301k
      if (unlikely(RemainingBits < 7)) {
189
17
        Status = ErrCode::Value::IntegerTooLong;
190
17
        return Unexpect(Status);
191
17
      }
192
193
301k
      std::make_unsigned_t<RetType> Payload =
194
301k
          Byte & (~HighestBitMask); // & 0b01111111
195
301k
      Result |= (Payload << Offset);
196
301k
      Offset += 7;
197
301k
      RemainingBits -= 7;
198
2.33M
    } 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.33M
      size_t EffectiveBits = RemainingBits < 7 ? RemainingBits : 7;
205
2.33M
      std::make_unsigned_t<RetType> Payload = Byte;
206
2.33M
      if (Byte & SecondHighestBitMask) {
207
        // The byte is signed.
208
1.86M
        if (Byte >= (1 << 7) - (1 << (EffectiveBits - 1))) {
209
1.86M
          Payload -= (1 << 7);
210
1.86M
        } else {
211
11
          Status = ErrCode::Value::IntegerTooLarge;
212
11
          return Unexpect(Status);
213
11
        }
214
1.86M
      } else {
215
        // The byte is unsigned.
216
469k
        if (Byte >= (1 << (EffectiveBits - 1))) {
217
8
          Status = ErrCode::Value::IntegerTooLarge;
218
8
          return Unexpect(Status);
219
8
        }
220
469k
      }
221
2.33M
      Result |= (Payload << Offset);
222
2.33M
      break;
223
2.33M
    }
224
2.63M
  }
225
226
2.33M
  return Result;
227
2.33M
}
cxx20::expected<long, WasmEdge::ErrCode> WasmEdge::FileMgr::readSN<long, 64ul>()
Line
Count
Source
156
936k
template <typename RetType, size_t N> Expect<RetType> FileMgr::readSN() {
157
936k
  static_assert(N >= 8, "The N of S_N must have at least length of a byte");
158
936k
  static_assert(8 * sizeof(RetType) >= N,
159
936k
                "RetType cannot hold the full range of S_N");
160
936k
  static_assert(std::is_signed_v<RetType>,
161
936k
                "RetType of S_N must be signed type");
162
163
936k
  if (Status != ErrCode::Value::Success) {
164
0
    return Unexpect(Status);
165
0
  }
166
  // Set the flag to the start offset.
167
936k
  LastPos = Pos;
168
169
  // Read and decode S_N.
170
936k
  RetType Result = 0;
171
936k
  size_t Offset = 0;
172
936k
  size_t RemainingBits = N;
173
1.42M
  while (true) {
174
1.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
1.42M
    EXPECTED_TRY(testRead(1));
181
1.42M
    WasmEdge::Byte Byte = Data[Pos++];
182
183
1.42M
    const WasmEdge::Byte HighestBitMask = 1 << 7;
184
1.42M
    const WasmEdge::Byte SecondHighestBitMask = 1 << 6;
185
1.42M
    if (Byte & HighestBitMask) {
186
      // The byte has a leading 1. It contains a 7-bit payload.
187
188
487k
      if (unlikely(RemainingBits < 7)) {
189
42
        Status = ErrCode::Value::IntegerTooLong;
190
42
        return Unexpect(Status);
191
42
      }
192
193
487k
      std::make_unsigned_t<RetType> Payload =
194
487k
          Byte & (~HighestBitMask); // & 0b01111111
195
487k
      Result |= (Payload << Offset);
196
487k
      Offset += 7;
197
487k
      RemainingBits -= 7;
198
936k
    } 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
936k
      size_t EffectiveBits = RemainingBits < 7 ? RemainingBits : 7;
205
936k
      std::make_unsigned_t<RetType> Payload = Byte;
206
936k
      if (Byte & SecondHighestBitMask) {
207
        // The byte is signed.
208
818k
        if (Byte >= (1 << 7) - (1 << (EffectiveBits - 1))) {
209
818k
          Payload -= (1 << 7);
210
818k
        } else {
211
17
          Status = ErrCode::Value::IntegerTooLarge;
212
17
          return Unexpect(Status);
213
17
        }
214
818k
      } else {
215
        // The byte is unsigned.
216
117k
        if (Byte >= (1 << (EffectiveBits - 1))) {
217
11
          Status = ErrCode::Value::IntegerTooLarge;
218
11
          return Unexpect(Status);
219
11
        }
220
117k
      }
221
936k
      Result |= (Payload << Offset);
222
936k
      break;
223
936k
    }
224
1.42M
  }
225
226
936k
  return Result;
227
936k
}
228
229
9.16M
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.33M
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
936k
Expect<int64_t> FileMgr::readS64() { return readSN<int64_t, 64>(); }
236
237
// Copy bytes to a float. See "include/loader/filemgr.h".
238
71.1k
Expect<float> FileMgr::readF32() {
239
71.1k
  if (Status != ErrCode::Value::Success) {
240
0
    return Unexpect(Status);
241
0
  }
242
  // Set the flag to the start offset.
243
71.1k
  LastPos = Pos;
244
245
71.1k
  uint32_t Buf = 0;
246
71.1k
  Byte Byte = 0x00;
247
  // Check whether reading exceeds the data or section boundary.
248
71.1k
  EXPECTED_TRY(testRead(4));
249
355k
  for (uint32_t I = 0; I < 4; I++) {
250
284k
    Byte = Data[Pos++];
251
284k
    Buf |= (Byte & UINT32_C(0xFF)) << (I * UINT32_C(8));
252
284k
  }
253
71.1k
  float Result;
254
71.1k
  static_assert(sizeof(Buf) == sizeof(Result));
255
71.1k
  std::memcpy(&Result, &Buf, sizeof(Result));
256
71.1k
  return Result;
257
71.1k
}
258
259
// Copy bytes to a double. See "include/loader/filemgr.h".
260
62.4k
Expect<double> FileMgr::readF64() {
261
62.4k
  if (Status != ErrCode::Value::Success) {
262
0
    return Unexpect(Status);
263
0
  }
264
  // Set the flag to the start offset.
265
62.4k
  LastPos = Pos;
266
267
62.4k
  uint64_t Buf = 0;
268
62.4k
  Byte Byte = 0x00;
269
  // Check whether reading exceeds the data or section boundary.
270
62.4k
  EXPECTED_TRY(testRead(8));
271
561k
  for (uint32_t I = 0; I < 8; I++) {
272
499k
    Byte = Data[Pos++];
273
499k
    Buf |= (Byte & UINT64_C(0xFF)) << (I * UINT64_C(8));
274
499k
  }
275
62.3k
  double Result;
276
62.3k
  static_assert(sizeof(Buf) == sizeof(Result));
277
62.3k
  std::memcpy(&Result, &Buf, sizeof(Result));
278
62.3k
  return Result;
279
62.4k
}
280
281
// Read a vector of bytes. See "include/loader/filemgr.h".
282
5.12M
Expect<std::string> FileMgr::readName() {
283
5.12M
  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
5.12M
  LastPos = Pos;
289
290
  // Read the name size.
291
5.12M
  EXPECTED_TRY(uint32_t SizeToRead, readU32());
292
293
  // Check whether the string length exceeds the data boundary.
294
5.12M
  if (auto Res = testRead(SizeToRead); unlikely(!Res)) {
295
226
    return Unexpect(ErrCode::Value::LengthOutOfBounds);
296
226
  }
297
298
  // Read the UTF-8 bytes.
299
5.12M
  std::string Str(SizeToRead, '\0');
300
5.12M
  EXPECTED_TRY(
301
5.12M
      readBytes(Span<Byte>(reinterpret_cast<Byte *>(Str.data()), Str.size())));
302
303
  // UTF-8 validation.
304
5.12M
  bool Valid = true;
305
9.07M
  for (uint32_t I = 0; I < Str.size() && Valid; ++I) {
306
3.94M
    char C = Str.data()[I];
307
3.94M
    uint32_t N = 0;
308
3.94M
    if ((C & '\x80') == 0) {
309
      // 0xxxxxxx, 7 bits UCS, ASCII
310
3.93M
      N = 0;
311
3.93M
    } else if ((C & '\xE0') == '\xC0') {
312
      // 110xxxxx, 11 bits UCS, U+80 to U+7FF
313
3.38k
      N = 1;
314
12.5k
    } else if ((C & '\xF0') == '\xE0') {
315
      // 1110xxxx, 16 bits UCS, U+800 to U+D7FF and U+E000 to U+FFFF
316
8.35k
      N = 2;
317
8.35k
    } else if ((C & '\xF8') == '\xF0') {
318
      // 11110xxx, 21 bits UCS, U+10000 to U+10FFFF
319
4.04k
      N = 3;
320
4.04k
    } else {
321
181
      Valid = false;
322
181
    }
323
324
    // Need N more bytes.
325
3.94M
    if (I + N >= Str.size()) {
326
47
      Valid = false;
327
47
    }
328
    // Invalid ranges
329
3.94M
    if (N == 1 && (C & '\xDE') == '\xC0') {
330
      // 11 bits UCS, U+0 to U+80, FAIL
331
5
      Valid = false;
332
3.94M
    } else if (N == 2 &&
333
8.35k
               ((C == '\xE0' && (Str.data()[I + 1] & '\xA0') == '\x80') ||
334
                // 16 bits UCS, U+0 to U+7FF, FAIL
335
8.35k
                (C == '\xED' && (Str.data()[I + 1] & '\xA0') == '\xA0')
336
                // 16 bits UCS, U+D800 to U+DFFF, FAIL
337
8.35k
                )) {
338
10
      Valid = false;
339
3.94M
    } else if (N == 3 &&
340
4.04k
               ((C == '\xF0' && (Str.data()[I + 1] & '\xB0') == '\x80') ||
341
                // 21 bits UCS, U+0 to U+FFFF, FAIL
342
4.03k
                (C == '\xF4' && (Str.data()[I + 1] & '\xB0') != '\x80') ||
343
                // 21 bits UCS, U+110000 to U+13FFFF, FAIL
344
4.02k
                (C != '\xF4' && (C & '\xF4') == '\xF4')
345
                // 21 bits UCS, U+140000 to U+1FFFFF, FAIL
346
4.04k
                )) {
347
20
      Valid = false;
348
20
    }
349
350
3.97M
    for (uint32_t J = 0; J < N && Valid; ++J) {
351
      // N bytes need to match 10xxxxxx
352
31.9k
      if ((Str.data()[I + J + 1] & '\xC0') != '\x80') {
353
133
        Valid = false;
354
133
      }
355
31.9k
    }
356
3.94M
    I += N;
357
3.94M
  }
358
359
5.12M
  if (!Valid) {
360
388
    Status = ErrCode::Value::MalformedUTF8;
361
388
    return Unexpect(Status);
362
388
  }
363
5.12M
  return Str;
364
5.12M
}
365
366
// Peek one byte. See "include/loader/filemgr.h".
367
2.88M
Expect<Byte> FileMgr::peekByte() {
368
2.88M
  EXPECTED_TRY(Byte B, readByte());
369
2.88M
  Pos--;
370
2.88M
  return B;
371
2.88M
}
372
373
// Get the file header type. See "include/loader/filemgr.h".
374
34.4k
FileMgr::FileHeader FileMgr::getHeaderType() {
375
34.4k
  if (Size >= 4) {
376
34.3k
    Byte WASMMagic[] = {0x00, 0x61, 0x73, 0x6D};
377
34.3k
    Byte ELFMagic[] = {0x7F, 0x45, 0x4C, 0x46};
378
34.3k
    Byte MAC32agic[] = {0xCE, 0xFA, 0xED, 0xFE};
379
34.3k
    Byte MAC64agic[] = {0xCF, 0xFA, 0xED, 0xFE};
380
34.3k
    if (std::equal(WASMMagic, WASMMagic + 4, Data)) {
381
34.2k
      return FileMgr::FileHeader::Wasm;
382
34.2k
    } else if (std::equal(ELFMagic, ELFMagic + 4, Data)) {
383
2
      return FileMgr::FileHeader::ELF;
384
82
    } else if (std::equal(MAC32agic, MAC32agic + 4, Data)) {
385
3
      return FileMgr::FileHeader::MachO_32;
386
79
    } else if (std::equal(MAC64agic, MAC64agic + 4, Data)) {
387
2
      return FileMgr::FileHeader::MachO_64;
388
2
    }
389
34.3k
  }
390
177
  if (Size >= 2) {
391
158
    Byte DLLMagic[] = {0x4D, 0x5A};
392
158
    if (std::equal(DLLMagic, DLLMagic + 2, Data)) {
393
4
      return FileMgr::FileHeader::DLL;
394
4
    }
395
158
  }
396
173
  return FileMgr::FileHeader::Unknown;
397
177
}
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
9.81M
Expect<void> FileMgr::readBytes(Span<Byte> Buffer) {
416
9.81M
  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
9.81M
  auto SizeToRead = Buffer.size();
421
9.81M
  if (likely(SizeToRead > 0)) {
422
    // Check whether reading exceeds the data boundary.
423
1.56M
    EXPECTED_TRY(testRead(SizeToRead));
424
1.56M
    std::copy_n(Data + Pos, SizeToRead, Buffer.begin());
425
1.56M
    Pos += SizeToRead;
426
1.56M
  }
427
9.81M
  return {};
428
9.81M
}
429
430
// Helper function for checking boundary. See "include/loader/filemgr.h".
431
139M
Expect<void> FileMgr::testRead(uint64_t Read) {
432
  // Check whether reading exceeds the data boundary.
433
139M
  if (unlikely(getRemainSize() < Read)) {
434
26.6k
    Pos = Size;
435
26.6k
    LastPos = Pos;
436
26.6k
    Status = ErrCode::Value::UnexpectedEnd;
437
26.6k
    return Unexpect(Status);
438
26.6k
  }
439
139M
  return {};
440
139M
}
441
442
} // namespace WasmEdge