Coverage Report

Created: 2026-08-14 06:41

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