Coverage Report

Created: 2026-07-16 07:09

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
26.1k
Expect<void> FileMgr::setCode(Span<const Byte> CodeData) {
49
26.1k
  reset();
50
26.1k
  Data = CodeData.data();
51
26.1k
  Size = CodeData.size();
52
26.1k
  Status = ErrCode::Value::Success;
53
26.1k
  return {};
54
26.1k
}
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
42.2M
Expect<Byte> FileMgr::readByte() {
73
42.2M
  if (unlikely(Status != ErrCode::Value::Success)) {
74
0
    return Unexpect(Status);
75
0
  }
76
  // Set the flag to the start offset.
77
42.2M
  LastPos = Pos;
78
  // Check whether reading exceeds the data or section boundary.
79
42.2M
  EXPECTED_TRY(testRead(1));
80
42.2M
  return Data[Pos++];
81
42.2M
}
82
83
// Read bytes. See "include/loader/filemgr.h".
84
459k
Expect<std::vector<Byte>> FileMgr::readBytes(size_t SizeToRead) {
85
  // Set the flag to the start offset.
86
459k
  LastPos = Pos;
87
  // Read bytes into vector.
88
459k
  std::vector<Byte> Buf(SizeToRead);
89
459k
  EXPECTED_TRY(readBytes(Buf));
90
459k
  return Buf;
91
459k
}
92
93
// Decode and read an unsigned int. See "include/loader/filemgr.h".
94
9.79M
Expect<uint32_t> FileMgr::readU32() {
95
9.79M
  if (unlikely(Status != ErrCode::Value::Success)) {
96
0
    return Unexpect(Status);
97
0
  }
98
  // Set the flag to the start offset.
99
9.79M
  LastPos = Pos;
100
101
  // Read and decode U32.
102
9.79M
  uint32_t Result = 0;
103
9.79M
  uint32_t Offset = 0;
104
9.79M
  Byte Byte = 0x80;
105
20.9M
  while (Byte & 0x80) {
106
11.2M
    if (unlikely(Offset >= 32)) {
107
19
      Status = ErrCode::Value::IntegerTooLong;
108
19
      return Unexpect(Status);
109
19
    }
110
11.2M
    EXPECTED_TRY(testRead(1));
111
11.2M
    Byte = Data[Pos++];
112
11.2M
    Result |= (Byte & UINT32_C(0x7F)) << Offset;
113
11.2M
    if (Offset == 28 && unlikely((Byte & UINT32_C(0x70)) != 0)) {
114
161
      Status = ErrCode::Value::IntegerTooLarge;
115
161
      return Unexpect(Status);
116
161
    }
117
11.2M
    Offset += 7;
118
11.2M
  }
119
9.78M
  return Result;
120
9.79M
}
121
122
// Decode and read an unsigned long long int. See "include/loader/filemgr.h".
123
805k
Expect<uint64_t> FileMgr::readU64() {
124
805k
  if (Status != ErrCode::Value::Success) {
125
0
    return Unexpect(Status);
126
0
  }
127
  // Set the flag to the start offset.
128
805k
  LastPos = Pos;
129
130
  // Read and decode U64.
131
805k
  uint64_t Result = 0;
132
805k
  uint64_t Offset = 0;
133
805k
  Byte Byte = 0x80;
134
1.70M
  while (Byte & 0x80) {
135
895k
    if (unlikely(Offset >= 64)) {
136
2
      Status = ErrCode::Value::IntegerTooLong;
137
2
      return Unexpect(Status);
138
2
    }
139
895k
    EXPECTED_TRY(testRead(1));
140
894k
    Byte = Data[Pos++];
141
894k
    Result |= (Byte & UINT64_C(0x7F)) << Offset;
142
894k
    if (Offset == 63 && unlikely((Byte & UINT32_C(0x7E)) != 0)) {
143
7
      Status = ErrCode::Value::IntegerTooLarge;
144
7
      return Unexpect(Status);
145
7
    }
146
894k
    Offset += 7;
147
894k
  }
148
805k
  return Result;
149
805k
}
150
151
6.15M
template <typename RetType, size_t N> Expect<RetType> FileMgr::readSN() {
152
6.15M
  static_assert(N >= 8, "The N of S_N must have at least length of a byte");
153
6.15M
  static_assert(8 * sizeof(RetType) >= N,
154
6.15M
                "RetType cannot hold the full range of S_N");
155
6.15M
  static_assert(std::is_signed_v<RetType>,
156
6.15M
                "RetType of S_N must be signed type");
157
158
6.15M
  if (Status != ErrCode::Value::Success) {
159
0
    return Unexpect(Status);
160
0
  }
161
  // Set the flag to the start offset.
162
6.15M
  LastPos = Pos;
163
164
  // Read and decode S_N.
165
6.15M
  RetType Result = 0;
166
6.15M
  size_t Offset = 0;
167
6.15M
  size_t RemainingBits = N;
168
7.32M
  while (true) {
169
7.32M
    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
7.32M
    EXPECTED_TRY(testRead(1));
176
7.32M
    WasmEdge::Byte Byte = Data[Pos++];
177
178
7.32M
    const WasmEdge::Byte HighestBitMask = 1 << 7;
179
7.32M
    const WasmEdge::Byte SecondHighestBitMask = 1 << 6;
180
7.32M
    if (Byte & HighestBitMask) {
181
      // The byte has a leading 1. It contains a 7-bit payload.
182
183
1.16M
      if (unlikely(RemainingBits < 7)) {
184
94
        Status = ErrCode::Value::IntegerTooLong;
185
94
        return Unexpect(Status);
186
94
      }
187
188
1.16M
      std::make_unsigned_t<RetType> Payload =
189
1.16M
          Byte & (~HighestBitMask); // & 0b01111111
190
1.16M
      Result |= (Payload << Offset);
191
1.16M
      Offset += 7;
192
1.16M
      RemainingBits -= 7;
193
6.15M
    } 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
6.15M
      size_t EffectiveBits = RemainingBits < 7 ? RemainingBits : 7;
200
6.15M
      std::make_unsigned_t<RetType> Payload = Byte;
201
6.15M
      if (Byte & SecondHighestBitMask) {
202
        // The byte is signed.
203
4.18M
        if (Byte >= (1 << 7) - (1 << (EffectiveBits - 1))) {
204
4.18M
          Payload -= (1 << 7);
205
4.18M
        } else {
206
36
          Status = ErrCode::Value::IntegerTooLarge;
207
36
          return Unexpect(Status);
208
36
        }
209
4.18M
      } else {
210
        // The byte is unsigned.
211
1.96M
        if (Byte >= (1 << (EffectiveBits - 1))) {
212
34
          Status = ErrCode::Value::IntegerTooLarge;
213
34
          return Unexpect(Status);
214
34
        }
215
1.96M
      }
216
6.15M
      Result |= (Payload << Offset);
217
6.15M
      break;
218
6.15M
    }
219
7.32M
  }
220
221
6.15M
  return Result;
222
6.15M
}
cxx20::expected<long, WasmEdge::ErrCode> WasmEdge::FileMgr::readSN<long, 33ul>()
Line
Count
Source
151
1.82M
template <typename RetType, size_t N> Expect<RetType> FileMgr::readSN() {
152
1.82M
  static_assert(N >= 8, "The N of S_N must have at least length of a byte");
153
1.82M
  static_assert(8 * sizeof(RetType) >= N,
154
1.82M
                "RetType cannot hold the full range of S_N");
155
1.82M
  static_assert(std::is_signed_v<RetType>,
156
1.82M
                "RetType of S_N must be signed type");
157
158
1.82M
  if (Status != ErrCode::Value::Success) {
159
0
    return Unexpect(Status);
160
0
  }
161
  // Set the flag to the start offset.
162
1.82M
  LastPos = Pos;
163
164
  // Read and decode S_N.
165
1.82M
  RetType Result = 0;
166
1.82M
  size_t Offset = 0;
167
1.82M
  size_t RemainingBits = N;
168
1.92M
  while (true) {
169
1.92M
    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.92M
    EXPECTED_TRY(testRead(1));
176
1.92M
    WasmEdge::Byte Byte = Data[Pos++];
177
178
1.92M
    const WasmEdge::Byte HighestBitMask = 1 << 7;
179
1.92M
    const WasmEdge::Byte SecondHighestBitMask = 1 << 6;
180
1.92M
    if (Byte & HighestBitMask) {
181
      // The byte has a leading 1. It contains a 7-bit payload.
182
183
101k
      if (unlikely(RemainingBits < 7)) {
184
34
        Status = ErrCode::Value::IntegerTooLong;
185
34
        return Unexpect(Status);
186
34
      }
187
188
101k
      std::make_unsigned_t<RetType> Payload =
189
101k
          Byte & (~HighestBitMask); // & 0b01111111
190
101k
      Result |= (Payload << Offset);
191
101k
      Offset += 7;
192
101k
      RemainingBits -= 7;
193
1.82M
    } 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
1.82M
      size_t EffectiveBits = RemainingBits < 7 ? RemainingBits : 7;
200
1.82M
      std::make_unsigned_t<RetType> Payload = Byte;
201
1.82M
      if (Byte & SecondHighestBitMask) {
202
        // The byte is signed.
203
558k
        if (Byte >= (1 << 7) - (1 << (EffectiveBits - 1))) {
204
558k
          Payload -= (1 << 7);
205
558k
        } else {
206
13
          Status = ErrCode::Value::IntegerTooLarge;
207
13
          return Unexpect(Status);
208
13
        }
209
1.26M
      } else {
210
        // The byte is unsigned.
211
1.26M
        if (Byte >= (1 << (EffectiveBits - 1))) {
212
7
          Status = ErrCode::Value::IntegerTooLarge;
213
7
          return Unexpect(Status);
214
7
        }
215
1.26M
      }
216
1.82M
      Result |= (Payload << Offset);
217
1.82M
      break;
218
1.82M
    }
219
1.92M
  }
220
221
1.82M
  return Result;
222
1.82M
}
cxx20::expected<int, WasmEdge::ErrCode> WasmEdge::FileMgr::readSN<int, 32ul>()
Line
Count
Source
151
2.49M
template <typename RetType, size_t N> Expect<RetType> FileMgr::readSN() {
152
2.49M
  static_assert(N >= 8, "The N of S_N must have at least length of a byte");
153
2.49M
  static_assert(8 * sizeof(RetType) >= N,
154
2.49M
                "RetType cannot hold the full range of S_N");
155
2.49M
  static_assert(std::is_signed_v<RetType>,
156
2.49M
                "RetType of S_N must be signed type");
157
158
2.49M
  if (Status != ErrCode::Value::Success) {
159
0
    return Unexpect(Status);
160
0
  }
161
  // Set the flag to the start offset.
162
2.49M
  LastPos = Pos;
163
164
  // Read and decode S_N.
165
2.49M
  RetType Result = 0;
166
2.49M
  size_t Offset = 0;
167
2.49M
  size_t RemainingBits = N;
168
2.66M
  while (true) {
169
2.66M
    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.66M
    EXPECTED_TRY(testRead(1));
176
2.66M
    WasmEdge::Byte Byte = Data[Pos++];
177
178
2.66M
    const WasmEdge::Byte HighestBitMask = 1 << 7;
179
2.66M
    const WasmEdge::Byte SecondHighestBitMask = 1 << 6;
180
2.66M
    if (Byte & HighestBitMask) {
181
      // The byte has a leading 1. It contains a 7-bit payload.
182
183
178k
      if (unlikely(RemainingBits < 7)) {
184
16
        Status = ErrCode::Value::IntegerTooLong;
185
16
        return Unexpect(Status);
186
16
      }
187
188
178k
      std::make_unsigned_t<RetType> Payload =
189
178k
          Byte & (~HighestBitMask); // & 0b01111111
190
178k
      Result |= (Payload << Offset);
191
178k
      Offset += 7;
192
178k
      RemainingBits -= 7;
193
2.49M
    } 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.49M
      size_t EffectiveBits = RemainingBits < 7 ? RemainingBits : 7;
200
2.49M
      std::make_unsigned_t<RetType> Payload = Byte;
201
2.49M
      if (Byte & SecondHighestBitMask) {
202
        // The byte is signed.
203
1.98M
        if (Byte >= (1 << 7) - (1 << (EffectiveBits - 1))) {
204
1.98M
          Payload -= (1 << 7);
205
1.98M
        } else {
206
9
          Status = ErrCode::Value::IntegerTooLarge;
207
9
          return Unexpect(Status);
208
9
        }
209
1.98M
      } else {
210
        // The byte is unsigned.
211
507k
        if (Byte >= (1 << (EffectiveBits - 1))) {
212
9
          Status = ErrCode::Value::IntegerTooLarge;
213
9
          return Unexpect(Status);
214
9
        }
215
507k
      }
216
2.49M
      Result |= (Payload << Offset);
217
2.49M
      break;
218
2.49M
    }
219
2.66M
  }
220
221
2.49M
  return Result;
222
2.49M
}
cxx20::expected<long, WasmEdge::ErrCode> WasmEdge::FileMgr::readSN<long, 64ul>()
Line
Count
Source
151
1.84M
template <typename RetType, size_t N> Expect<RetType> FileMgr::readSN() {
152
1.84M
  static_assert(N >= 8, "The N of S_N must have at least length of a byte");
153
1.84M
  static_assert(8 * sizeof(RetType) >= N,
154
1.84M
                "RetType cannot hold the full range of S_N");
155
1.84M
  static_assert(std::is_signed_v<RetType>,
156
1.84M
                "RetType of S_N must be signed type");
157
158
1.84M
  if (Status != ErrCode::Value::Success) {
159
0
    return Unexpect(Status);
160
0
  }
161
  // Set the flag to the start offset.
162
1.84M
  LastPos = Pos;
163
164
  // Read and decode S_N.
165
1.84M
  RetType Result = 0;
166
1.84M
  size_t Offset = 0;
167
1.84M
  size_t RemainingBits = N;
168
2.73M
  while (true) {
169
2.73M
    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.73M
    EXPECTED_TRY(testRead(1));
176
2.73M
    WasmEdge::Byte Byte = Data[Pos++];
177
178
2.73M
    const WasmEdge::Byte HighestBitMask = 1 << 7;
179
2.73M
    const WasmEdge::Byte SecondHighestBitMask = 1 << 6;
180
2.73M
    if (Byte & HighestBitMask) {
181
      // The byte has a leading 1. It contains a 7-bit payload.
182
183
884k
      if (unlikely(RemainingBits < 7)) {
184
44
        Status = ErrCode::Value::IntegerTooLong;
185
44
        return Unexpect(Status);
186
44
      }
187
188
884k
      std::make_unsigned_t<RetType> Payload =
189
884k
          Byte & (~HighestBitMask); // & 0b01111111
190
884k
      Result |= (Payload << Offset);
191
884k
      Offset += 7;
192
884k
      RemainingBits -= 7;
193
1.84M
    } 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
1.84M
      size_t EffectiveBits = RemainingBits < 7 ? RemainingBits : 7;
200
1.84M
      std::make_unsigned_t<RetType> Payload = Byte;
201
1.84M
      if (Byte & SecondHighestBitMask) {
202
        // The byte is signed.
203
1.64M
        if (Byte >= (1 << 7) - (1 << (EffectiveBits - 1))) {
204
1.64M
          Payload -= (1 << 7);
205
1.64M
        } else {
206
14
          Status = ErrCode::Value::IntegerTooLarge;
207
14
          return Unexpect(Status);
208
14
        }
209
1.64M
      } else {
210
        // The byte is unsigned.
211
200k
        if (Byte >= (1 << (EffectiveBits - 1))) {
212
18
          Status = ErrCode::Value::IntegerTooLarge;
213
18
          return Unexpect(Status);
214
18
        }
215
200k
      }
216
1.84M
      Result |= (Payload << Offset);
217
1.84M
      break;
218
1.84M
    }
219
2.73M
  }
220
221
1.84M
  return Result;
222
1.84M
}
223
224
1.82M
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.49M
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
1.84M
Expect<int64_t> FileMgr::readS64() { return readSN<int64_t, 64>(); }
231
232
// Copy bytes to a float. See "include/loader/filemgr.h".
233
41.0k
Expect<float> FileMgr::readF32() {
234
41.0k
  if (Status != ErrCode::Value::Success) {
235
0
    return Unexpect(Status);
236
0
  }
237
  // Set the flag to the start offset.
238
41.0k
  LastPos = Pos;
239
240
41.0k
  uint32_t Buf = 0;
241
41.0k
  Byte Byte = 0x00;
242
  // Check whether reading exceeds the data or section boundary.
243
41.0k
  EXPECTED_TRY(testRead(4));
244
205k
  for (uint32_t I = 0; I < 4; I++) {
245
164k
    Byte = Data[Pos++];
246
164k
    Buf |= (Byte & UINT32_C(0xFF)) << (I * UINT32_C(8));
247
164k
  }
248
41.0k
  float Result;
249
41.0k
  static_assert(sizeof(Buf) == sizeof(Result));
250
41.0k
  std::memcpy(&Result, &Buf, sizeof(Result));
251
41.0k
  return Result;
252
41.0k
}
253
254
// Copy bytes to a double. See "include/loader/filemgr.h".
255
23.3k
Expect<double> FileMgr::readF64() {
256
23.3k
  if (Status != ErrCode::Value::Success) {
257
0
    return Unexpect(Status);
258
0
  }
259
  // Set the flag to the start offset.
260
23.3k
  LastPos = Pos;
261
262
23.3k
  uint64_t Buf = 0;
263
23.3k
  Byte Byte = 0x00;
264
  // Check whether reading exceeds the data or section boundary.
265
23.3k
  EXPECTED_TRY(testRead(8));
266
209k
  for (uint32_t I = 0; I < 8; I++) {
267
186k
    Byte = Data[Pos++];
268
186k
    Buf |= (Byte & UINT64_C(0xFF)) << (I * UINT64_C(8));
269
186k
  }
270
23.2k
  double Result;
271
23.2k
  static_assert(sizeof(Buf) == sizeof(Result));
272
23.2k
  std::memcpy(&Result, &Buf, sizeof(Result));
273
23.2k
  return Result;
274
23.3k
}
275
276
// Read a vector of bytes. See "include/loader/filemgr.h".
277
536k
Expect<std::string> FileMgr::readName() {
278
536k
  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
536k
  LastPos = Pos;
284
285
  // Read the name size.
286
536k
  EXPECTED_TRY(uint32_t SizeToRead, readU32());
287
288
  // Check whether the string length exceeds the data boundary.
289
536k
  if (auto Res = testRead(SizeToRead); unlikely(!Res)) {
290
325
    return Unexpect(ErrCode::Value::LengthOutOfBounds);
291
325
  }
292
293
  // Read the UTF-8 bytes.
294
536k
  std::string Str(SizeToRead, '\0');
295
536k
  EXPECTED_TRY(
296
536k
      readBytes(Span<Byte>(reinterpret_cast<Byte *>(Str.data()), Str.size())));
297
298
  // UTF-8 validation.
299
536k
  bool Valid = true;
300
2.47M
  for (uint32_t I = 0; I < Str.size() && Valid; ++I) {
301
1.93M
    char C = Str.data()[I];
302
1.93M
    uint32_t N = 0;
303
1.93M
    if ((C & '\x80') == 0) {
304
      // 0xxxxxxx, 7 bits UCS, ASCII
305
1.92M
      N = 0;
306
1.92M
    } else if ((C & '\xE0') == '\xC0') {
307
      // 110xxxxx, 11 bits UCS, U+80 to U+7FF
308
2.67k
      N = 1;
309
11.1k
    } else if ((C & '\xF0') == '\xE0') {
310
      // 1110xxxx, 16 bits UCS, U+800 to U+D7FF and U+E000 to U+FFFF
311
7.59k
      N = 2;
312
7.59k
    } else if ((C & '\xF8') == '\xF0') {
313
      // 11110xxx, 21 bits UCS, U+10000 to U+10FFFF
314
3.37k
      N = 3;
315
3.37k
    } else {
316
187
      Valid = false;
317
187
    }
318
319
    // Need N more bytes.
320
1.93M
    if (I + N >= Str.size()) {
321
51
      Valid = false;
322
51
    }
323
    // Invalid ranges
324
1.93M
    if (N == 1 && (C & '\xDE') == '\xC0') {
325
      // 11 bits UCS, U+0 to U+80, FAIL
326
12
      Valid = false;
327
1.93M
    } else if (N == 2 &&
328
7.59k
               ((C == '\xE0' && (Str.data()[I + 1] & '\xA0') == '\x80') ||
329
                // 16 bits UCS, U+0 to U+7FF, FAIL
330
7.59k
                (C == '\xED' && (Str.data()[I + 1] & '\xA0') == '\xA0')
331
                // 16 bits UCS, U+D800 to U+DFFF, FAIL
332
7.59k
                )) {
333
12
      Valid = false;
334
1.93M
    } else if (N == 3 &&
335
3.37k
               ((C == '\xF0' && (Str.data()[I + 1] & '\xB0') == '\x80') ||
336
                // 21 bits UCS, U+0 to U+FFFF, FAIL
337
3.37k
                (C == '\xF4' && (Str.data()[I + 1] & '\xB0') != '\x80') ||
338
                // 21 bits UCS, U+110000 to U+13FFFF, FAIL
339
3.35k
                (C != '\xF4' && (C & '\xF4') == '\xF4')
340
                // 21 bits UCS, U+140000 to U+1FFFFF, FAIL
341
3.37k
                )) {
342
35
      Valid = false;
343
35
    }
344
345
1.96M
    for (uint32_t J = 0; J < N && Valid; ++J) {
346
      // N bytes need to match 10xxxxxx
347
27.7k
      if ((Str.data()[I + J + 1] & '\xC0') != '\x80') {
348
108
        Valid = false;
349
108
      }
350
27.7k
    }
351
1.93M
    I += N;
352
1.93M
  }
353
354
536k
  if (!Valid) {
355
397
    Status = ErrCode::Value::MalformedUTF8;
356
397
    return Unexpect(Status);
357
397
  }
358
535k
  return Str;
359
536k
}
360
361
// Peek one byte. See "include/loader/filemgr.h".
362
951k
Expect<Byte> FileMgr::peekByte() {
363
951k
  EXPECTED_TRY(Byte B, readByte());
364
950k
  Pos--;
365
950k
  return B;
366
951k
}
367
368
// Get the file header type. See "include/loader/filemgr.h".
369
26.1k
FileMgr::FileHeader FileMgr::getHeaderType() {
370
26.1k
  if (Size >= 4) {
371
26.0k
    Byte WASMMagic[] = {0x00, 0x61, 0x73, 0x6D};
372
26.0k
    Byte ELFMagic[] = {0x7F, 0x45, 0x4C, 0x46};
373
26.0k
    Byte MAC32agic[] = {0xCE, 0xFA, 0xED, 0xFE};
374
26.0k
    Byte MAC64agic[] = {0xCF, 0xFA, 0xED, 0xFE};
375
26.0k
    if (std::equal(WASMMagic, WASMMagic + 4, Data)) {
376
25.9k
      return FileMgr::FileHeader::Wasm;
377
25.9k
    } else if (std::equal(ELFMagic, ELFMagic + 4, Data)) {
378
2
      return FileMgr::FileHeader::ELF;
379
99
    } else if (std::equal(MAC32agic, MAC32agic + 4, Data)) {
380
2
      return FileMgr::FileHeader::MachO_32;
381
97
    } else if (std::equal(MAC64agic, MAC64agic + 4, Data)) {
382
2
      return FileMgr::FileHeader::MachO_64;
383
2
    }
384
26.0k
  }
385
175
  if (Size >= 2) {
386
158
    Byte DLLMagic[] = {0x4D, 0x5A};
387
158
    if (std::equal(DLLMagic, DLLMagic + 2, Data)) {
388
7
      return FileMgr::FileHeader::DLL;
389
7
    }
390
158
  }
391
168
  return FileMgr::FileHeader::Unknown;
392
175
}
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
995k
Expect<void> FileMgr::readBytes(Span<Byte> Buffer) {
411
995k
  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
995k
  auto SizeToRead = Buffer.size();
416
995k
  if (likely(SizeToRead > 0)) {
417
    // Check whether reading exceeds the data boundary.
418
308k
    EXPECTED_TRY(testRead(SizeToRead));
419
308k
    std::copy_n(Data + Pos, SizeToRead, Buffer.begin());
420
308k
    Pos += SizeToRead;
421
308k
  }
422
995k
  return {};
423
995k
}
424
425
// Helper function for checking boundary. See "include/loader/filemgr.h".
426
62.6M
Expect<void> FileMgr::testRead(uint64_t Read) {
427
  // Check whether reading exceeds the data boundary.
428
62.6M
  if (unlikely(getRemainSize() < Read)) {
429
18.0k
    Pos = Size;
430
18.0k
    LastPos = Pos;
431
18.0k
    Status = ErrCode::Value::UnexpectedEnd;
432
18.0k
    return Unexpect(Status);
433
18.0k
  }
434
62.5M
  return {};
435
62.6M
}
436
437
} // namespace WasmEdge