Coverage Report

Created: 2026-11-09 06:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/WasmEdge/lib/validator/validator.cpp
Line
Count
Source
1
// SPDX-License-Identifier: Apache-2.0
2
// SPDX-FileCopyrightText: Copyright The WasmEdge Authors
3
4
#include "validator/validator.h"
5
6
#include "ast/section.h"
7
#include "common/errinfo.h"
8
#include "common/hash.h"
9
10
#include <map>
11
#include <numeric>
12
#include <string>
13
#include <unordered_set>
14
#include <vector>
15
16
using namespace std::literals;
17
18
namespace WasmEdge {
19
namespace Validator {
20
21
namespace {
22
23
static constexpr uint32_t MaxSubtypeDepth = 63;
24
static constexpr uint32_t Unvisited = UINT32_MAX;
25
static constexpr uint32_t Visiting = UINT32_MAX - 1;
26
27
// TODO: make the super type depth table instead of recursively querying.
28
Expect<uint32_t>
29
checkSubtypeDepth(const uint32_t BaseIdx, uint32_t TestIdx, uint32_t Depth,
30
                  std::vector<uint32_t> &DepthMap,
31
4.29k
                  const std::vector<const WasmEdge::AST::SubType *> &TypeVec) {
32
4.29k
  if (TestIdx >= DepthMap.size()) {
33
0
    DepthMap.resize(TestIdx + 1, Unvisited);
34
4.29k
  } else if (DepthMap[TestIdx] == Visiting) {
35
0
    spdlog::error(ErrCode::Value::InvalidSubType);
36
0
    spdlog::error("    Cycle detected in subtype hierarchy for type {}."sv,
37
0
                  BaseIdx);
38
0
    return Unexpect(ErrCode::Value::InvalidSubType);
39
4.29k
  } else if (DepthMap[TestIdx] != Unvisited) {
40
3.20k
    return DepthMap[TestIdx];
41
3.20k
  }
42
43
1.08k
  if (Depth >= MaxSubtypeDepth) {
44
0
    spdlog::error(ErrCode::Value::InvalidSubType);
45
0
    spdlog::error("    Subtype depth for type {} exceeded the limits of {}"sv,
46
0
                  BaseIdx, MaxSubtypeDepth);
47
0
    return Unexpect(ErrCode::Value::InvalidSubType);
48
0
  }
49
50
1.08k
  DepthMap[TestIdx] = Visiting;
51
1.08k
  uint32_t MaxDepth = 0;
52
  // A component core:type index may name a module type, which is not a sub
53
  // type and holds no place in the hierarchy.
54
1.08k
  const auto *TestType = TypeVec[TestIdx];
55
1.08k
  if (unlikely(TestType == nullptr)) {
56
0
    spdlog::error(ErrCode::Value::InvalidSubType);
57
0
    spdlog::error("    Type index {} does not refer to a sub type."sv, TestIdx);
58
0
    return Unexpect(ErrCode::Value::InvalidSubType);
59
0
  }
60
1.08k
  for (const auto SuperIdx : TestType->getSuperTypeIndices()) {
61
475
    if (unlikely(SuperIdx >= TypeVec.size())) {
62
0
      spdlog::error(ErrCode::Value::InvalidSubType);
63
0
      spdlog::error(ErrInfo::InfoForbidIndex(
64
0
          ErrInfo::IndexCategory::DefinedType, SuperIdx,
65
0
          static_cast<uint32_t>(TypeVec.size())));
66
0
      return Unexpect(ErrCode::Value::InvalidSubType);
67
0
    }
68
950
    EXPECTED_TRY(
69
950
        auto RetDepth,
70
950
        checkSubtypeDepth(BaseIdx, SuperIdx, Depth + 1, DepthMap, TypeVec)
71
950
            .map_error([=](auto E) {
72
950
              spdlog::error(
73
950
                  "    When checking subtype hierarchy of super type {}."sv,
74
950
                  SuperIdx);
75
950
              return E;
76
950
            }));
77
950
    MaxDepth = std::max(MaxDepth, RetDepth + 1);
78
950
  }
79
80
1.08k
  if (MaxDepth >= MaxSubtypeDepth) {
81
0
    spdlog::error(ErrCode::Value::InvalidSubType);
82
0
    spdlog::error("    Subtype depth for type {} exceeded the limits of {}"sv,
83
0
                  BaseIdx, MaxSubtypeDepth);
84
0
    return Unexpect(ErrCode::Value::InvalidSubType);
85
0
  }
86
87
1.08k
  DepthMap[TestIdx] = MaxDepth;
88
1.08k
  return MaxDepth;
89
1.08k
}
90
91
// Set the canonical indices of a rec type from the first with the same key.
92
void setCanonicalIndices(Span<const AST::SubType> RecType, uint32_t BaseIdx,
93
                         const std::vector<const AST::SubType *> &TypeVec,
94
15.4k
                         std::map<std::vector<uint32_t>, uint32_t> &RecTypes) {
95
15.4k
  std::vector<uint32_t> Key;
96
15.4k
  auto AddTypeIdx = [&](uint32_t Idx) {
97
12.4k
    if (Idx >= BaseIdx && Idx - BaseIdx < RecType.size()) {
98
9.52k
      Key.push_back(0U);
99
9.52k
      Key.push_back(Idx - BaseIdx);
100
9.52k
    } else {
101
2.95k
      Key.push_back(1U);
102
2.95k
      Key.push_back(TypeVec[Idx]->getCanonicalIndex().value_or(Idx));
103
2.95k
    }
104
12.4k
  };
105
124k
  auto AddValType = [&](const ValType &VT) {
106
124k
    Key.push_back(static_cast<uint32_t>(VT.getCode()));
107
124k
    Key.push_back(static_cast<uint32_t>(VT.getHeapTypeCode()));
108
124k
    if (VT.getHeapTypeCode() == TypeCode::TypeIndex) {
109
9.95k
      AddTypeIdx(VT.getTypeIndex());
110
9.95k
    }
111
124k
  };
112
113
15.4k
  Key.push_back(static_cast<uint32_t>(RecType.size()));
114
30.2k
  for (const auto &Type : RecType) {
115
30.2k
    const auto &CompType = Type.getCompositeType();
116
30.2k
    Key.push_back(Type.isFinal() ? 1U : 0U);
117
30.2k
    Key.push_back(static_cast<uint32_t>(Type.getSuperTypeIndices().size()));
118
30.2k
    for (const auto Idx : Type.getSuperTypeIndices()) {
119
2.53k
      AddTypeIdx(Idx);
120
2.53k
    }
121
30.2k
    Key.push_back(static_cast<uint32_t>(CompType.getContentTypeCode()));
122
30.2k
    if (CompType.isFunc()) {
123
16.7k
      const auto &FType = CompType.getFuncType();
124
16.7k
      Key.push_back(static_cast<uint32_t>(FType.getParamTypes().size()));
125
47.4k
      for (const auto &VT : FType.getParamTypes()) {
126
47.4k
        AddValType(VT);
127
47.4k
      }
128
16.7k
      Key.push_back(static_cast<uint32_t>(FType.getReturnTypes().size()));
129
43.9k
      for (const auto &VT : FType.getReturnTypes()) {
130
43.9k
        AddValType(VT);
131
43.9k
      }
132
16.7k
    } else {
133
13.4k
      const auto &FTypes = CompType.getFieldTypes();
134
13.4k
      Key.push_back(static_cast<uint32_t>(FTypes.size()));
135
33.4k
      for (const auto &FType : FTypes) {
136
33.4k
        Key.push_back(static_cast<uint32_t>(FType.getValMut()));
137
33.4k
        AddValType(FType.getStorageType());
138
33.4k
      }
139
13.4k
    }
140
30.2k
  }
141
15.4k
  const uint32_t CanonIdx =
142
15.4k
      RecTypes.try_emplace(std::move(Key), BaseIdx).first->second;
143
45.6k
  for (uint32_t I = 0; I < RecType.size(); I++) {
144
30.2k
    const_cast<AST::SubType &>(RecType[I]).setCanonicalIndex(CanonIdx + I);
145
30.2k
  }
146
15.4k
}
147
148
} // namespace
149
150
// Validate Module. See "include/validator/validator.h".
151
8.22k
Expect<void> Validator::validate(const AST::Module &Mod) {
152
  // https://webassembly.github.io/spec/core/valid/modules.html
153
8.22k
  Checker.reset(true);
154
155
  // Validate and register type section.
156
8.22k
  EXPECTED_TRY(validate(Mod.getTypeSection()).map_error([](auto E) {
157
8.09k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Type));
158
8.09k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module));
159
8.09k
    return E;
160
8.09k
  }));
161
162
  // Validate and register the import section in FormChecker.
163
8.09k
  EXPECTED_TRY(validate(Mod.getImportSection()).map_error([](auto E) {
164
8.02k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Import));
165
8.02k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module));
166
8.02k
    return E;
167
8.02k
  }));
168
169
  // Validate the function section and register functions in FormChecker.
170
8.02k
  EXPECTED_TRY(validate(Mod.getFunctionSection()).map_error([](auto E) {
171
7.98k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Function));
172
7.98k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module));
173
7.98k
    return E;
174
7.98k
  }));
175
176
  // Validate the table section and register tables in FormChecker.
177
7.98k
  EXPECTED_TRY(validate(Mod.getTableSection()).map_error([](auto E) {
178
7.83k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Table));
179
7.83k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module));
180
7.83k
    return E;
181
7.83k
  }));
182
183
  // Validate the memory section and register memories in FormChecker.
184
7.83k
  EXPECTED_TRY(validate(Mod.getMemorySection()).map_error([](auto E) {
185
7.59k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Memory));
186
7.59k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module));
187
7.59k
    return E;
188
7.59k
  }));
189
190
  // Validate the global section and register globals in FormChecker.
191
7.59k
  EXPECTED_TRY(validate(Mod.getGlobalSection()).map_error([](auto E) {
192
7.30k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Global));
193
7.30k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module));
194
7.30k
    return E;
195
7.30k
  }));
196
197
  // Validate the tag section and register tags in FormChecker.
198
7.30k
  EXPECTED_TRY(validate(Mod.getTagSection()).map_error([](auto E) {
199
7.26k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Tag));
200
7.26k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module));
201
7.26k
    return E;
202
7.26k
  }));
203
204
  // Validate export section.
205
7.26k
  EXPECTED_TRY(validate(Mod.getExportSection()).map_error([](auto E) {
206
7.06k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Export));
207
7.06k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module));
208
7.06k
    return E;
209
7.06k
  }));
210
211
  // Validate start section.
212
7.06k
  EXPECTED_TRY(validate(Mod.getStartSection()).map_error([](auto E) {
213
7.02k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Start));
214
7.02k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module));
215
7.02k
    return E;
216
7.02k
  }));
217
218
  // Validate the element section that initializes tables.
219
7.02k
  EXPECTED_TRY(validate(Mod.getElementSection()).map_error([](auto E) {
220
6.88k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Element));
221
6.88k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module));
222
6.88k
    return E;
223
6.88k
  }));
224
225
  // Validate the data section that initializes memories.
226
6.88k
  EXPECTED_TRY(validate(Mod.getDataSection()).map_error([](auto E) {
227
6.86k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Data));
228
6.86k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module));
229
6.86k
    return E;
230
6.86k
  }));
231
232
  // Validate code section and expressions.
233
6.86k
  EXPECTED_TRY(validate(Mod.getCodeSection()).map_error([](auto E) {
234
2.78k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Code));
235
2.78k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module));
236
2.78k
    return E;
237
2.78k
  }));
238
239
  // Multiple tables are for the ReferenceTypes proposal.
240
2.78k
  if (Checker.getTables().size() > 1 &&
241
63
      !Conf.hasProposal(Proposal::ReferenceTypes)) {
242
0
    spdlog::error(ErrCode::Value::MultiTables);
243
0
    spdlog::error(ErrInfo::InfoProposal(Proposal::ReferenceTypes));
244
0
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module));
245
0
    return Unexpect(ErrCode::Value::MultiTables);
246
0
  }
247
248
  // Multiple memories are for the MultiMemories proposal.
249
2.78k
  if (Checker.getMemories().size() > 1 &&
250
77
      !Conf.hasProposal(Proposal::MultiMemories)) {
251
0
    spdlog::error(ErrCode::Value::MultiMemories);
252
0
    spdlog::error(ErrInfo::InfoProposal(Proposal::MultiMemories));
253
0
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module));
254
0
    return Unexpect(ErrCode::Value::MultiMemories);
255
0
  }
256
257
  // Set the validated flag.
258
2.78k
  const_cast<AST::Module &>(Mod).setIsValidated();
259
2.78k
  return {};
260
2.78k
}
261
262
// Validate Sub type. See "include/validator/validator.h".
263
Expect<void>
264
Validator::validate(const AST::SubType &Type, uint32_t OwnTypeIdx,
265
                    std::vector<uint32_t> &SubTypeDepthMap,
266
74.6k
                    const std::vector<const AST::SubType *> &TypeVec) {
267
74.6k
  const auto &CompType = Type.getCompositeType();
268
  // A concrete heap type reference must name a defined type of this space.
269
153k
  auto CheckValType = [&TypeVec](const ValType &VT) -> Expect<void> {
270
153k
    if (VT.isRefType() && VT.getHeapTypeCode() == TypeCode::TypeIndex &&
271
12.8k
        (VT.getTypeIndex() >= TypeVec.size() ||
272
12.7k
         TypeVec[VT.getTypeIndex()] == nullptr)) {
273
55
      spdlog::error(ErrCode::Value::InvalidFuncTypeIdx);
274
55
      spdlog::error(ErrInfo::InfoForbidIndex(
275
55
          ErrInfo::IndexCategory::FunctionType, VT.getTypeIndex(),
276
55
          static_cast<uint32_t>(TypeVec.size())));
277
55
      return Unexpect(ErrCode::Value::InvalidFuncTypeIdx);
278
55
    }
279
153k
    return {};
280
153k
  };
281
282
  // Check the validation of the composite type.
283
74.6k
  if (CompType.isFunc()) {
284
20.7k
    const auto &FType = CompType.getFuncType();
285
58.7k
    for (auto &PType : FType.getParamTypes()) {
286
58.7k
      EXPECTED_TRY(CheckValType(PType).map_error([](auto E) {
287
58.7k
        spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Function));
288
58.7k
        return E;
289
58.7k
      }));
290
58.7k
    }
291
20.7k
    if (unlikely(!Conf.hasProposal(Proposal::MultiValue)) &&
292
0
        FType.getReturnTypes().size() > 1) {
293
0
      spdlog::error(ErrCode::Value::InvalidResultArity);
294
0
      spdlog::error(ErrInfo::InfoProposal(Proposal::MultiValue));
295
0
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Function));
296
0
      return Unexpect(ErrCode::Value::InvalidResultArity);
297
0
    }
298
53.9k
    for (auto &RType : FType.getReturnTypes()) {
299
53.9k
      EXPECTED_TRY(CheckValType(RType).map_error([](auto E) {
300
53.9k
        spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Function));
301
53.9k
        return E;
302
53.9k
      }));
303
53.9k
    }
304
53.8k
  } else {
305
53.8k
    const auto &FTypes = CompType.getFieldTypes();
306
53.8k
    for (auto &FieldType : FTypes) {
307
40.9k
      EXPECTED_TRY(CheckValType(FieldType.getStorageType()));
308
40.9k
    }
309
53.8k
  }
310
311
  // In the current version, the length of the type index vector will be <= 1.
312
74.5k
  if (Type.getSuperTypeIndices().size() > 1) {
313
4
    spdlog::error(ErrCode::Value::MultipleSuperTypes);
314
4
    return Unexpect(ErrCode::Value::MultipleSuperTypes);
315
4
  }
316
317
74.5k
  for (const auto &Index : Type.getSuperTypeIndices()) {
318
    // A super type must be previously defined (smaller index than this sub
319
    // type), so OwnTypeIdx is the exclusive bound, subsuming the range check.
320
3.83k
    if (unlikely(Index >= OwnTypeIdx)) {
321
14
      spdlog::error(ErrCode::Value::InvalidSubType);
322
14
      spdlog::error("    Super type index {} must be smaller than the sub type "
323
14
                    "index {}."sv,
324
14
                    Index, OwnTypeIdx);
325
14
      return Unexpect(ErrCode::Value::InvalidSubType);
326
14
    }
327
328
3.81k
    EXPECTED_TRY(
329
3.81k
        checkSubtypeDepth(Index, Index, 0, SubTypeDepthMap, TypeVec)
330
3.81k
            .map_error([=](auto E) {
331
3.81k
              spdlog::error(
332
3.81k
                  "    When checking subtype hierarchy of super type {}."sv,
333
3.81k
                  Index);
334
3.81k
              return E;
335
3.81k
            }));
336
337
3.81k
    if (TypeVec[Index]->isFinal()) {
338
8
      spdlog::error(ErrCode::Value::InvalidSubType);
339
8
      spdlog::error("    Super type should not be final."sv);
340
8
      return Unexpect(ErrCode::Value::InvalidSubType);
341
8
    }
342
3.81k
  }
343
74.5k
  return {};
344
74.5k
}
345
346
// Validate Rec type. See "include/validator/validator.h".
347
Expect<void>
348
Validator::validate(Span<const AST::SubType> RecType, uint32_t BaseIdx,
349
                    std::vector<uint32_t> &SubTypeDepthMap,
350
56.0k
                    const std::vector<const AST::SubType *> &TypeVec) {
351
  // Check all the members before matching, which walks their super types.
352
130k
  for (uint32_t I = 0; I < RecType.size(); I++) {
353
74.6k
    EXPECTED_TRY(validate(RecType[I], BaseIdx + I, SubTypeDepthMap, TypeVec));
354
74.6k
  }
355
71.6k
  for (const auto &Type : RecType) {
356
71.6k
    for (const auto &Index : Type.getSuperTypeIndices()) {
357
2.79k
      if (!AST::TypeMatcher::matchType(TypeVec,
358
2.79k
                                       TypeVec[Index]->getCompositeType(),
359
2.79k
                                       Type.getCompositeType())) {
360
60
        spdlog::error(ErrCode::Value::InvalidSubType);
361
60
        spdlog::error("    Super type not matched."sv);
362
60
        return Unexpect(ErrCode::Value::InvalidSubType);
363
60
      }
364
2.79k
    }
365
71.6k
  }
366
55.8k
  return {};
367
55.9k
}
368
369
// Validate Limit type. See "include/validator/validator.h".
370
12.1k
Expect<void> Validator::validate(const AST::Limit &Lim) {
371
12.1k
  if (Lim.hasMax() && Lim.getMin() > Lim.getMax()) {
372
98
    spdlog::error(ErrCode::Value::InvalidLimit);
373
98
    spdlog::error(ErrInfo::InfoLimit(Lim.hasMax(), Lim.getMin(), Lim.getMax()));
374
98
    return Unexpect(ErrCode::Value::InvalidLimit);
375
98
  }
376
12.0k
  if (Lim.isShared() && unlikely(!Lim.hasMax())) {
377
0
    spdlog::error(ErrCode::Value::SharedMemoryNoMax);
378
0
    return Unexpect(ErrCode::Value::SharedMemoryNoMax);
379
0
  }
380
12.0k
  return {};
381
12.0k
}
382
383
// Validate Table type. See "include/validator/validator.h".
384
5.69k
Expect<void> Validator::validate(const AST::TableType &Tab) {
385
  // Validate value type.
386
5.69k
  EXPECTED_TRY(Checker.validate(Tab.getRefType()));
387
  // Validate table limits.
388
5.66k
  const auto &Lim = Tab.getLimit();
389
5.66k
  EXPECTED_TRY(validate(Lim).map_error([](auto E) {
390
5.62k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Limit));
391
5.62k
    return E;
392
5.62k
  }));
393
5.62k
  uint64_t Range = getMaxAddress(Lim.getAddrType());
394
5.62k
  if (Lim.getMin() > Range || (Lim.hasMax() && Lim.getMax() > Range)) {
395
    // Since spec test has no related error message, use this error instead.
396
100
    auto Code = Conf.hasProposal(Proposal::Memory64)
397
100
                    ? ErrCode::Value::InvalidTableSize64
398
100
                    : ErrCode::Value::InvalidLimit;
399
100
    spdlog::error(Code);
400
100
    spdlog::error(ErrInfo::InfoLimit(Lim.hasMax(), Lim.getMin(), Lim.getMax()));
401
100
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Limit));
402
100
    return Unexpect(Code);
403
100
  }
404
5.52k
  return {};
405
5.62k
}
406
407
// Validate Memory type. See "include/validator/validator.h".
408
6.48k
Expect<void> Validator::validate(const AST::MemoryType &Mem) {
409
  // Validate memory limits.
410
6.48k
  const auto &Lim = Mem.getLimit();
411
6.48k
  EXPECTED_TRY(validate(Lim).map_error([](auto E) {
412
6.42k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Limit));
413
6.42k
    return E;
414
6.42k
  }));
415
6.42k
  if (!Conf.hasProposal(Proposal::Memory64) && Lim.is64()) {
416
0
    spdlog::error(ErrCode::Value::InvalidLimit);
417
0
    spdlog::error(ErrInfo::InfoProposal(Proposal::Memory64));
418
0
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Limit));
419
0
    return Unexpect(ErrCode::Value::InvalidLimit);
420
0
  }
421
6.42k
  uint64_t Range = Lim.is32() ? (static_cast<uint64_t>(1) << 16)
422
6.42k
                              : (static_cast<uint64_t>(1) << 48);
423
6.42k
  if (Lim.getMin() > Range || (Lim.hasMax() && Lim.getMax() > Range)) {
424
182
    auto Code = Conf.hasProposal(Proposal::Memory64)
425
182
                    ? ErrCode::Value::InvalidMemPages64
426
182
                    : ErrCode::Value::InvalidMemPages;
427
182
    spdlog::error(Code);
428
182
    spdlog::error(ErrInfo::InfoLimit(Lim.hasMax(), Lim.getMin(), Lim.getMax()));
429
182
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Limit));
430
182
    return Unexpect(Code);
431
182
  }
432
6.23k
  return {};
433
6.42k
}
434
435
// Validate Global type. See "include/validator/validator.h".
436
2.70k
Expect<void> Validator::validate(const AST::GlobalType &Glob) {
437
  // Validate value type.
438
2.70k
  return Checker.validate(Glob.getValType());
439
2.70k
}
440
441
// Validate Table segment. See "include/validator/validator.h".
442
5.27k
Expect<void> Validator::validate(const AST::TableSegment &TabSeg) {
443
5.27k
  if (TabSeg.getExpr().getInstrs().size() > 0) {
444
    // Check ref initialization is a const expression.
445
161
    EXPECTED_TRY(
446
161
        validateConstExpr(TabSeg.getExpr().getInstrs(),
447
161
                          {ValType(TabSeg.getTableType().getRefType())})
448
161
            .map_error([](auto E) {
449
161
              spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Expression));
450
161
              return E;
451
161
            }));
452
5.11k
  } else {
453
    // No init expression. Check that the reference type is nullable.
454
5.11k
    if (!TabSeg.getTableType().getRefType().isNullableRefType()) {
455
3
      spdlog::error(ErrCode::Value::TypeCheckFailed);
456
3
      spdlog::error(ErrInfo::InfoMismatch(
457
3
          ValType(TypeCode::RefNull,
458
3
                  TabSeg.getTableType().getRefType().getHeapTypeCode(),
459
3
                  TabSeg.getTableType().getRefType().getTypeIndex()),
460
3
          TabSeg.getTableType().getRefType()));
461
3
      return Unexpect(ErrCode::Value::TypeCheckFailed);
462
3
    }
463
5.11k
  }
464
  // Validate table type.
465
5.26k
  return validate(TabSeg.getTableType()).map_error([](auto E) {
466
156
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Table));
467
156
    return E;
468
156
  });
469
5.27k
}
470
471
// Validate Global segment. See "include/validator/validator.h".
472
2.13k
Expect<void> Validator::validate(const AST::GlobalSegment &GlobSeg) {
473
  // Check global initialization is a const expression.
474
2.13k
  EXPECTED_TRY(validateConstExpr(GlobSeg.getExpr().getInstrs(),
475
1.83k
                                 {GlobSeg.getGlobalType().getValType()})
476
1.83k
                   .map_error([](auto E) {
477
1.83k
                     spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Expression));
478
1.83k
                     return E;
479
1.83k
                   }));
480
  // Validate global type.
481
1.83k
  return validate(GlobSeg.getGlobalType()).map_error([](auto E) {
482
0
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Global));
483
0
    return E;
484
0
  });
485
2.13k
}
486
487
// Validate Element segment. See "include/validator/validator.h".
488
1.29k
Expect<void> Validator::validate(const AST::ElementSegment &ElemSeg) {
489
  // Check that initialization expressions are const expressions.
490
2.57k
  for (auto &Expr : ElemSeg.getInitExprs()) {
491
2.57k
    EXPECTED_TRY(
492
2.57k
        validateConstExpr(Expr.getInstrs(), {ValType(ElemSeg.getRefType())})
493
2.57k
            .map_error([](auto E) {
494
2.57k
              spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Expression));
495
2.57k
              return E;
496
2.57k
            }));
497
2.57k
  }
498
499
  // The reference type should be valid.
500
1.20k
  EXPECTED_TRY(Checker.validate(ElemSeg.getRefType()));
501
502
  // Passive and declarative cases are valid with a valid reference type.
503
1.19k
  if (ElemSeg.getMode() == AST::ElementSegment::ElemMode::Active) {
504
    // Check table index and reference type in context.
505
529
    const auto &TableVec = Checker.getTables();
506
529
    if (ElemSeg.getIdx() >= TableVec.size()) {
507
21
      spdlog::error(ErrCode::Value::InvalidTableIdx);
508
21
      spdlog::error(ErrInfo::InfoForbidIndex(
509
21
          ErrInfo::IndexCategory::Table, ElemSeg.getIdx(),
510
21
          static_cast<uint32_t>(TableVec.size())));
511
21
      return Unexpect(ErrCode::Value::InvalidTableIdx);
512
21
    }
513
508
    if (!AST::TypeMatcher::matchType(Checker.getTypes(),
514
508
                                     TableVec[ElemSeg.getIdx()].second,
515
508
                                     ElemSeg.getRefType())) {
516
      // Reference type does not match.
517
8
      spdlog::error(ErrCode::Value::TypeCheckFailed);
518
8
      spdlog::error(ErrInfo::InfoMismatch(TableVec[ElemSeg.getIdx()].second,
519
8
                                          ElemSeg.getRefType()));
520
8
      return Unexpect(ErrCode::Value::TypeCheckFailed);
521
8
    }
522
    // Check table initialization is a const expression.
523
500
    return validateConstExpr(ElemSeg.getExpr().getInstrs(),
524
500
                             {ValType(TableVec[ElemSeg.getIdx()].first)})
525
500
        .map_error([](auto E) {
526
9
          spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Expression));
527
9
          return E;
528
9
        });
529
508
  }
530
663
  return {};
531
1.19k
}
532
533
// Validate Code segment. See "include/validator/validator.h".
534
Expect<void> Validator::validate(const AST::CodeSegment &CodeSeg,
535
19.3k
                                 const uint32_t TypeIdx) {
536
  // Due to validation of the function section, the type at this index must
537
  // be a function type.
538
19.3k
  const auto &FuncType =
539
19.3k
      Checker.getTypes()[TypeIdx]->getCompositeType().getFuncType();
540
  // Reset stack in FormChecker.
541
19.3k
  Checker.reset();
542
  // Add parameters to this frame.
543
53.9k
  for (auto &Type : FuncType.getParamTypes()) {
544
    // Local passed by function parameters must have been initialized.
545
53.9k
    Checker.addLocal(Type, true);
546
53.9k
  }
547
  // Add locals to this frame.
548
19.3k
  for (auto Val : CodeSeg.getLocals()) {
549
506M
    for (uint32_t Cnt = 0; Cnt < Val.first; ++Cnt) {
550
      // The local value type should be valid.
551
506M
      EXPECTED_TRY(Checker.validate(Val.second));
552
506M
      Checker.addLocal(Val.second, false);
553
506M
    }
554
12.7k
  }
555
  // Validate function body expression.
556
19.2k
  return Checker
557
19.2k
      .validate(CodeSeg.getExpr().getInstrs(), FuncType.getReturnTypes())
558
19.2k
      .map_error([](auto E) {
559
4.05k
        spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Expression));
560
4.05k
        return E;
561
4.05k
      });
562
19.3k
}
563
564
// Validate Data segment. See "include/validator/validator.h".
565
2.47k
Expect<void> Validator::validate(const AST::DataSegment &DataSeg) {
566
2.47k
  switch (DataSeg.getMode()) {
567
287
  case AST::DataSegment::DataMode::Active: {
568
    // Check memory index in context.
569
287
    const auto &MemVec = Checker.getMemories();
570
287
    if (DataSeg.getIdx() >= MemVec.size()) {
571
21
      spdlog::error(ErrCode::Value::InvalidMemoryIdx);
572
21
      spdlog::error(ErrInfo::InfoForbidIndex(
573
21
          ErrInfo::IndexCategory::Memory, DataSeg.getIdx(),
574
21
          static_cast<uint32_t>(MemVec.size())));
575
21
      return Unexpect(ErrCode::Value::InvalidMemoryIdx);
576
21
    }
577
    // Check memory initialization is a const expression.
578
266
    return validateConstExpr(DataSeg.getExpr().getInstrs(),
579
266
                             {ValType(MemVec[DataSeg.getIdx()])})
580
266
        .map_error([](auto E) {
581
8
          spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Expression));
582
8
          return E;
583
8
        });
584
287
  }
585
2.18k
  case AST::DataSegment::DataMode::Passive:
586
    // Passive case is always valid.
587
2.18k
    return {};
588
0
  default:
589
0
    return {};
590
2.47k
  }
591
2.47k
}
592
593
// Validate Import description. See "include/validator/validator.h".
594
4.31k
Expect<void> Validator::validate(const AST::ImportDesc &ImpDesc) {
595
4.31k
  switch (ImpDesc.getExternalType()) {
596
  // External type and external content are ensured to match in the loader
597
  // phase.
598
1.16k
  case ExternalType::Function: {
599
1.16k
    const auto TId = ImpDesc.getExternalFuncTypeIdx();
600
    // Function type index must exist in context and be valid.
601
1.16k
    if (TId >= Checker.getTypes().size()) {
602
31
      spdlog::error(ErrCode::Value::InvalidFuncTypeIdx);
603
31
      spdlog::error(ErrInfo::InfoForbidIndex(
604
31
          ErrInfo::IndexCategory::FunctionType, TId,
605
31
          static_cast<uint32_t>(Checker.getTypes().size())));
606
31
      return Unexpect(ErrCode::Value::InvalidFuncTypeIdx);
607
31
    }
608
1.13k
    if (!Checker.getTypes()[TId]->getCompositeType().isFunc()) {
609
4
      spdlog::error(ErrCode::Value::InvalidFuncTypeIdx);
610
4
      spdlog::error("    Defined type index {} is not a function type."sv, TId);
611
4
      return Unexpect(ErrCode::Value::InvalidFuncTypeIdx);
612
4
    }
613
1.12k
    Checker.addFunc(TId, true);
614
1.12k
    return {};
615
1.13k
  }
616
378
  case ExternalType::Table: {
617
378
    const auto &TabType = ImpDesc.getExternalTableType();
618
    // Table type must be valid.
619
378
    EXPECTED_TRY(validate(TabType).map_error([](auto E) {
620
373
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Table));
621
373
      return E;
622
373
    }));
623
373
    Checker.addTable(TabType);
624
373
    return {};
625
378
  }
626
1.24k
  case ExternalType::Memory: {
627
1.24k
    const auto &MemType = ImpDesc.getExternalMemoryType();
628
    // Memory type must be valid.
629
1.24k
    EXPECTED_TRY(validate(MemType).map_error([](auto E) {
630
1.24k
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Memory));
631
1.24k
      return E;
632
1.24k
    }));
633
1.24k
    Checker.addMemory(MemType);
634
1.24k
    return {};
635
1.24k
  }
636
723
  case ExternalType::Tag: {
637
723
    const auto &T = ImpDesc.getExternalTagType();
638
    // Tag type index must exist in context.
639
723
    auto TagTypeIdx = T.getTypeIdx();
640
723
    if (TagTypeIdx >= Checker.getTypes().size()) {
641
22
      spdlog::error(ErrCode::Value::InvalidTagIdx);
642
22
      spdlog::error(ErrInfo::InfoForbidIndex(
643
22
          ErrInfo::IndexCategory::TagType, TagTypeIdx,
644
22
          static_cast<uint32_t>(Checker.getTypes().size())));
645
22
      return Unexpect(ErrCode::Value::InvalidTagIdx);
646
22
    }
647
    // Tag type must be valid.
648
701
    auto &CompType = Checker.getTypes()[TagTypeIdx]->getCompositeType();
649
701
    if (!CompType.isFunc()) {
650
3
      spdlog::error(ErrCode::Value::InvalidTagIdx);
651
3
      spdlog::error("    Defined type index {} is not a function type."sv,
652
3
                    TagTypeIdx);
653
3
      return Unexpect(ErrCode::Value::InvalidTagIdx);
654
3
    }
655
698
    if (!CompType.getFuncType().getReturnTypes().empty()) {
656
2
      spdlog::error(ErrCode::Value::InvalidTagResultType);
657
2
      return Unexpect(ErrCode::Value::InvalidTagResultType);
658
2
    }
659
696
    Checker.addTag(TagTypeIdx);
660
696
    return {};
661
698
  }
662
802
  case ExternalType::Global: {
663
802
    const auto &GlobType = ImpDesc.getExternalGlobalType();
664
    // Global type must be valid.
665
802
    EXPECTED_TRY(validate(GlobType).map_error([](auto E) {
666
795
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Global));
667
795
      return E;
668
795
    }));
669
795
    Checker.addGlobal(GlobType, true);
670
795
    return {};
671
802
  }
672
0
  default:
673
0
    return {};
674
4.31k
  }
675
4.31k
}
676
677
// Validate Export description. See "include/validator/validator.h".
678
14.8k
Expect<void> Validator::validate(const AST::ExportDesc &ExpDesc) {
679
14.8k
  auto Id = ExpDesc.getExternalIndex();
680
14.8k
  switch (ExpDesc.getExternalType()) {
681
10.5k
  case ExternalType::Function:
682
10.5k
    if (Id >= Checker.getFunctions().size()) {
683
59
      spdlog::error(ErrCode::Value::InvalidFuncIdx);
684
59
      spdlog::error(ErrInfo::InfoForbidIndex(
685
59
          ErrInfo::IndexCategory::Function, Id,
686
59
          static_cast<uint32_t>(Checker.getFunctions().size())));
687
59
      return Unexpect(ErrCode::Value::InvalidFuncIdx);
688
59
    }
689
10.4k
    Checker.addRef(Id);
690
10.4k
    return {};
691
1.42k
  case ExternalType::Table:
692
1.42k
    if (Id >= Checker.getTables().size()) {
693
37
      spdlog::error(ErrCode::Value::InvalidTableIdx);
694
37
      spdlog::error(ErrInfo::InfoForbidIndex(
695
37
          ErrInfo::IndexCategory::Table, Id,
696
37
          static_cast<uint32_t>(Checker.getTables().size())));
697
37
      return Unexpect(ErrCode::Value::InvalidTableIdx);
698
37
    }
699
1.38k
    return {};
700
168
  case ExternalType::Memory:
701
168
    if (Id >= Checker.getMemories().size()) {
702
31
      spdlog::error(ErrCode::Value::InvalidMemoryIdx);
703
31
      spdlog::error(ErrInfo::InfoForbidIndex(
704
31
          ErrInfo::IndexCategory::Memory, Id,
705
31
          static_cast<uint32_t>(Checker.getMemories().size())));
706
31
      return Unexpect(ErrCode::Value::InvalidMemoryIdx);
707
31
    }
708
137
    return {};
709
50
  case ExternalType::Tag:
710
50
    if (Id >= Checker.getTags().size()) {
711
27
      spdlog::error(ErrCode::Value::InvalidTagIdx);
712
27
      spdlog::error(ErrInfo::InfoForbidIndex(
713
27
          ErrInfo::IndexCategory::Tag, Id,
714
27
          static_cast<uint32_t>(Checker.getTags().size())));
715
27
      return Unexpect(ErrCode::Value::InvalidTagIdx);
716
27
    }
717
23
    return {};
718
2.63k
  case ExternalType::Global:
719
2.63k
    if (Id >= Checker.getGlobals().size()) {
720
34
      spdlog::error(ErrCode::Value::InvalidGlobalIdx);
721
34
      spdlog::error(ErrInfo::InfoForbidIndex(
722
34
          ErrInfo::IndexCategory::Global, Id,
723
34
          static_cast<uint32_t>(Checker.getGlobals().size())));
724
34
      return Unexpect(ErrCode::Value::InvalidGlobalIdx);
725
34
    }
726
2.60k
    return {};
727
0
  default:
728
0
    return {};
729
14.8k
  }
730
14.8k
}
731
732
13.9k
Expect<void> Validator::validate(const AST::TypeSection &TypeSec) {
733
13.9k
  const auto STypeList = TypeSec.getContent();
734
13.9k
  std::vector<uint32_t> SubTypeDepthMap(STypeList.size(), Unvisited);
735
13.9k
  std::map<std::vector<uint32_t>, uint32_t> RecTypes;
736
13.9k
  uint32_t Idx = 0;
737
29.3k
  while (Idx < STypeList.size()) {
738
15.5k
    const auto &SType = STypeList[Idx];
739
    // The next type to add takes this index in the type index space.
740
15.5k
    const uint32_t BaseIdx = static_cast<uint32_t>(Checker.getTypes().size());
741
15.5k
    if (Conf.hasProposal(Proposal::GC)) {
742
      // With GC a type is (self-)recursive (a singleton is a rec group of 1):
743
      // add the whole group before validating so members can reference it.
744
15.5k
      const uint32_t RecSize = SType.getRecursiveInfo().RecTypeSize;
745
50.1k
      for (uint32_t I = Idx; I < Idx + RecSize; I++) {
746
34.5k
        Checker.addType(STypeList[I]);
747
34.5k
      }
748
15.5k
      EXPECTED_TRY(validate(STypeList.subspan(Idx, RecSize), BaseIdx,
749
15.4k
                            SubTypeDepthMap, Checker.getTypes())
750
15.4k
                       .map_error([](auto E) {
751
15.4k
                         spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Rec));
752
15.4k
                         return E;
753
15.4k
                       }));
754
15.4k
      setCanonicalIndices(STypeList.subspan(Idx, RecSize), BaseIdx,
755
15.4k
                          Checker.getTypes(), RecTypes);
756
15.4k
      Idx += RecSize;
757
15.4k
    } else {
758
      // Without GC there are no rec groups: a type may reference only earlier
759
      // ones, so validate it before registering.
760
0
      EXPECTED_TRY(
761
0
          validate(SType, BaseIdx, SubTypeDepthMap, Checker.getTypes()));
762
0
      Checker.addType(SType);
763
0
      setCanonicalIndices(STypeList.subspan(Idx, 1), BaseIdx,
764
0
                          Checker.getTypes(), RecTypes);
765
0
      Idx++;
766
0
    }
767
15.5k
  }
768
13.8k
  return {};
769
13.9k
}
770
771
// Validate Import section. See "include/validator/validator.h".
772
13.8k
Expect<void> Validator::validate(const AST::ImportSection &ImportSec) {
773
13.8k
  for (auto &ImportDesc : ImportSec.getContent()) {
774
4.31k
    EXPECTED_TRY(validate(ImportDesc).map_error([](auto E) {
775
4.31k
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Desc_Import));
776
4.31k
      return E;
777
4.31k
    }));
778
4.31k
  }
779
13.7k
  return {};
780
13.8k
}
781
782
// Validate Function section. See "include/validator/validator.h".
783
13.7k
Expect<void> Validator::validate(const AST::FunctionSection &FuncSec) {
784
13.7k
  const auto &FuncVec = FuncSec.getContent();
785
13.7k
  const auto &TypeVec = Checker.getTypes();
786
787
  // Check whether the function type ID is valid in context.
788
28.3k
  for (auto &TId : FuncVec) {
789
28.3k
    if (TId >= TypeVec.size()) {
790
35
      spdlog::error(ErrCode::Value::InvalidFuncTypeIdx);
791
35
      spdlog::error(
792
35
          ErrInfo::InfoForbidIndex(ErrInfo::IndexCategory::FunctionType, TId,
793
35
                                   static_cast<uint32_t>(TypeVec.size())));
794
35
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Function));
795
35
      return Unexpect(ErrCode::Value::InvalidFuncTypeIdx);
796
35
    }
797
28.2k
    if (!TypeVec[TId]->getCompositeType().isFunc()) {
798
8
      spdlog::error(ErrCode::Value::InvalidFuncTypeIdx);
799
8
      spdlog::error("    Defined type index {} is not a function type."sv, TId);
800
8
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Function));
801
8
      return Unexpect(ErrCode::Value::InvalidFuncTypeIdx);
802
8
    }
803
28.2k
    Checker.addFunc(TId);
804
28.2k
  }
805
13.6k
  return {};
806
13.7k
}
807
808
// Validate Table section. See "include/validator/validator.h".
809
13.6k
Expect<void> Validator::validate(const AST::TableSection &TabSec) {
810
13.6k
  for (auto &Tab : TabSec.getContent()) {
811
5.27k
    EXPECTED_TRY(validate(Tab).map_error([](auto E) {
812
5.10k
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Table));
813
5.10k
      return E;
814
5.10k
    }));
815
5.10k
    Checker.addTable(Tab.getTableType());
816
5.10k
  }
817
13.5k
  return {};
818
13.6k
}
819
820
// Validate Memory section. See "include/validator/validator.h".
821
13.5k
Expect<void> Validator::validate(const AST::MemorySection &MemSec) {
822
13.5k
  for (auto &Mem : MemSec.getContent()) {
823
4.31k
    EXPECTED_TRY(validate(Mem).map_error([](auto E) {
824
4.07k
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Memory));
825
4.07k
      return E;
826
4.07k
    }));
827
4.07k
    Checker.addMemory(Mem);
828
4.07k
  }
829
13.2k
  return {};
830
13.5k
}
831
832
// Validate Global section. See "include/validator/validator.h".
833
13.2k
Expect<void> Validator::validate(const AST::GlobalSection &GlobSec) {
834
13.2k
  for (auto &GlobSeg : GlobSec.getContent()) {
835
2.13k
    EXPECTED_TRY(validate(GlobSeg).map_error([](auto E) {
836
1.83k
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Global));
837
1.83k
      return E;
838
1.83k
    }));
839
1.83k
    Checker.addGlobal(GlobSeg.getGlobalType());
840
1.83k
  }
841
12.9k
  return {};
842
13.2k
}
843
844
// Validate Element section. See "include/validator/validator.h".
845
12.6k
Expect<void> Validator::validate(const AST::ElementSection &ElemSec) {
846
12.6k
  for (auto &ElemSeg : ElemSec.getContent()) {
847
1.29k
    EXPECTED_TRY(validate(ElemSeg).map_error([](auto E) {
848
1.15k
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Element));
849
1.15k
      return E;
850
1.15k
    }));
851
1.15k
    Checker.addElem(ElemSeg);
852
1.15k
  }
853
12.5k
  return {};
854
12.6k
}
855
856
// Validate Code section. See "include/validator/validator.h".
857
10.9k
Expect<void> Validator::validate(const AST::CodeSection &CodeSec) {
858
10.9k
  const auto &CodeVec = CodeSec.getContent();
859
10.9k
  const auto &FuncVec = Checker.getFunctions();
860
861
  // Validate function body.
862
26.1k
  for (uint32_t Id = 0; Id < static_cast<uint32_t>(CodeVec.size()); ++Id) {
863
    // Added functions contain imported functions.
864
19.3k
    uint32_t TId = Id + static_cast<uint32_t>(Checker.getNumImportFuncs());
865
19.3k
    if (TId >= static_cast<uint32_t>(FuncVec.size())) {
866
0
      spdlog::error(ErrCode::Value::InvalidFuncIdx);
867
0
      spdlog::error(
868
0
          ErrInfo::InfoForbidIndex(ErrInfo::IndexCategory::Function, TId,
869
0
                                   static_cast<uint32_t>(FuncVec.size())));
870
0
      return Unexpect(ErrCode::Value::InvalidFuncIdx);
871
0
    }
872
19.3k
    EXPECTED_TRY(validate(CodeVec[Id], FuncVec[TId]).map_error([](auto E) {
873
19.3k
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Code));
874
19.3k
      return E;
875
19.3k
    }));
876
19.3k
  }
877
6.82k
  return {};
878
10.9k
}
879
880
// Validate Data section. See "include/validator/validator.h".
881
12.5k
Expect<void> Validator::validate(const AST::DataSection &DataSec) {
882
12.5k
  for (auto &DataSeg : DataSec.getContent()) {
883
2.47k
    EXPECTED_TRY(validate(DataSeg).map_error([](auto E) {
884
2.44k
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Data));
885
2.44k
      return E;
886
2.44k
    }));
887
2.44k
    Checker.addData(DataSeg);
888
2.44k
  }
889
12.5k
  return {};
890
12.5k
}
891
892
// Validate Start section. See "include/validator/validator.h".
893
12.7k
Expect<void> Validator::validate(const AST::StartSection &StartSec) {
894
12.7k
  if (StartSec.getContent()) {
895
81
    auto FId = *StartSec.getContent();
896
81
    if (FId >= Checker.getFunctions().size()) {
897
33
      spdlog::error(ErrCode::Value::InvalidFuncIdx);
898
33
      spdlog::error(ErrInfo::InfoForbidIndex(
899
33
          ErrInfo::IndexCategory::Function, FId,
900
33
          static_cast<uint32_t>(Checker.getFunctions().size())));
901
33
      return Unexpect(ErrCode::Value::InvalidFuncIdx);
902
33
    }
903
48
    auto TId = Checker.getFunctions()[FId];
904
48
    assuming(TId < Checker.getTypes().size());
905
48
    if (!Checker.getTypes()[TId]->getCompositeType().isFunc()) {
906
0
      spdlog::error(ErrCode::Value::InvalidStartFunc);
907
0
      spdlog::error("    Defined type index {} is not a function type."sv, TId);
908
0
      return Unexpect(ErrCode::Value::InvalidStartFunc);
909
0
    }
910
48
    auto &Type = Checker.getTypes()[TId]->getCompositeType().getFuncType();
911
48
    if (Type.getParamTypes().size() != 0 || Type.getReturnTypes().size() != 0) {
912
      // Start function signature should be {}->{}
913
9
      spdlog::error(ErrCode::Value::InvalidStartFunc);
914
9
      spdlog::error(ErrInfo::InfoMismatch({}, {}, Type.getParamTypes(),
915
9
                                          Type.getReturnTypes()));
916
9
      return Unexpect(ErrCode::Value::InvalidStartFunc);
917
9
    }
918
48
  }
919
12.6k
  return {};
920
12.7k
}
921
922
// Validate Export section. See "include/validator/validator.h".
923
12.9k
Expect<void> Validator::validate(const AST::ExportSection &ExportSec) {
924
12.9k
  std::unordered_set<std::string_view, Hash::Hash> ExportNames;
925
14.8k
  for (auto &ExportDesc : ExportSec.getContent()) {
926
14.8k
    auto Result = ExportNames.emplace(ExportDesc.getExternalName());
927
14.8k
    if (!Result.second) {
928
      // Duplicated export name.
929
18
      spdlog::error(ErrCode::Value::DupExportName);
930
18
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Desc_Export));
931
18
      return Unexpect(ErrCode::Value::DupExportName);
932
18
    }
933
14.8k
    EXPECTED_TRY(validate(ExportDesc).map_error([](auto E) {
934
14.8k
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Desc_Export));
935
14.8k
      return E;
936
14.8k
    }));
937
14.8k
  }
938
12.7k
  return {};
939
12.9k
}
940
941
// Validate Tag section. See "include/validator/validator.h".
942
12.9k
Expect<void> Validator::validate(const AST::TagSection &TagSec) {
943
12.9k
  const auto &TagVec = TagSec.getContent();
944
12.9k
  const auto &TypeVec = Checker.getTypes();
945
946
  // Check whether the tag type ID is valid in context.
947
12.9k
  for (auto &TagType : TagVec) {
948
3.01k
    auto TagTypeIdx = TagType.getTypeIdx();
949
3.01k
    if (TagTypeIdx >= TypeVec.size()) {
950
37
      spdlog::error(ErrCode::Value::InvalidTagIdx);
951
37
      spdlog::error(
952
37
          ErrInfo::InfoForbidIndex(ErrInfo::IndexCategory::TagType, TagTypeIdx,
953
37
                                   static_cast<uint32_t>(TypeVec.size())));
954
37
      return Unexpect(ErrCode::Value::InvalidTagIdx);
955
37
    }
956
2.98k
    auto &CompType = TypeVec[TagTypeIdx]->getCompositeType();
957
2.98k
    if (!CompType.isFunc()) {
958
3
      spdlog::error(ErrCode::Value::InvalidTagIdx);
959
3
      spdlog::error("    Defined type index {} is not a function type."sv,
960
3
                    TagTypeIdx);
961
3
      return Unexpect(ErrCode::Value::InvalidTagIdx);
962
3
    }
963
2.97k
    if (!CompType.getFuncType().getReturnTypes().empty()) {
964
2
      spdlog::error(ErrCode::Value::InvalidTagResultType);
965
2
      return Unexpect(ErrCode::Value::InvalidTagResultType);
966
2
    }
967
2.97k
    Checker.addTag(TagTypeIdx);
968
2.97k
  }
969
12.9k
  return {};
970
12.9k
}
971
972
// Validate constant expression. See "include/validator/validator.h".
973
Expect<void> Validator::validateConstExpr(AST::InstrView Instrs,
974
5.64k
                                          Span<const ValType> Returns) {
975
14.3k
  for (auto &Instr : Instrs) {
976
    // Only these instructions are accepted.
977
14.3k
    switch (Instr.getOpCode()) {
978
109
    case OpCode::Global__get: {
979
      // For the initialization case, global indices must be imported globals.
980
109
      auto GlobIdx = Instr.getTargetIndex();
981
109
      uint32_t ValidGlobalSize = Checker.getNumImportGlobals();
982
109
      if (Conf.hasProposal(Proposal::FunctionReferences)) {
983
109
        ValidGlobalSize = static_cast<uint32_t>(Checker.getGlobals().size());
984
109
      }
985
109
      if (GlobIdx >= ValidGlobalSize) {
986
46
        spdlog::error(ErrCode::Value::InvalidGlobalIdx);
987
46
        spdlog::error(ErrInfo::InfoForbidIndex(ErrInfo::IndexCategory::Global,
988
46
                                               GlobIdx, ValidGlobalSize));
989
46
        spdlog::error(
990
46
            ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset()));
991
46
        return Unexpect(ErrCode::Value::InvalidGlobalIdx);
992
46
      }
993
63
      if (Checker.getGlobals()[GlobIdx].second != ValMut::Const) {
994
2
        spdlog::error(ErrCode::Value::ConstExprRequired);
995
2
        spdlog::error(
996
2
            ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset()));
997
2
        return Unexpect(ErrCode::Value::ConstExprRequired);
998
2
      }
999
61
      break;
1000
63
    }
1001
1.97k
    case OpCode::Ref__func: {
1002
      // In a const expression, add the reference to the context.
1003
1.97k
      auto FuncIdx = Instr.getTargetIndex();
1004
1.97k
      if (FuncIdx >= Checker.getFunctions().size()) {
1005
        // Function index out of range.
1006
59
        spdlog::error(ErrCode::Value::InvalidFuncIdx);
1007
59
        spdlog::error(ErrInfo::InfoForbidIndex(
1008
59
            ErrInfo::IndexCategory::Function, FuncIdx,
1009
59
            static_cast<uint32_t>(Checker.getFunctions().size())));
1010
59
        spdlog::error(
1011
59
            ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset()));
1012
59
        return Unexpect(ErrCode::Value::InvalidFuncIdx);
1013
59
      }
1014
1.91k
      Checker.addRef(Instr.getTargetIndex());
1015
1.91k
      break;
1016
1.97k
    }
1017
2.30k
    case OpCode::I32__const:
1018
2.96k
    case OpCode::I64__const:
1019
3.13k
    case OpCode::F32__const:
1020
3.24k
    case OpCode::F64__const:
1021
4.60k
    case OpCode::Ref__null:
1022
4.77k
    case OpCode::V128__const:
1023
10.1k
    case OpCode::End:
1024
10.2k
    case OpCode::Struct__new:
1025
10.3k
    case OpCode::Struct__new_default:
1026
10.3k
    case OpCode::Array__new:
1027
10.3k
    case OpCode::Array__new_default:
1028
10.4k
    case OpCode::Array__new_fixed:
1029
10.4k
    case OpCode::Any__convert_extern:
1030
10.5k
    case OpCode::Extern__convert_any:
1031
10.6k
    case OpCode::Ref__i31:
1032
10.6k
      break;
1033
1034
    // For the Extended-const proposal, these instructions are accepted.
1035
190
    case OpCode::I32__add:
1036
490
    case OpCode::I32__sub:
1037
864
    case OpCode::I32__mul:
1038
1.05k
    case OpCode::I64__add:
1039
1.32k
    case OpCode::I64__sub:
1040
1.53k
    case OpCode::I64__mul:
1041
1.53k
      if (Conf.hasProposal(Proposal::ExtendedConst)) {
1042
1.53k
        break;
1043
1.53k
      }
1044
0
      spdlog::error(ErrCode::Value::ConstExprRequired);
1045
0
      spdlog::error(ErrInfo::InfoProposal(Proposal::ExtendedConst));
1046
0
      spdlog::error(
1047
0
          ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset()));
1048
0
      return Unexpect(ErrCode::Value::ConstExprRequired);
1049
1050
124
    default:
1051
124
      spdlog::error(ErrCode::Value::ConstExprRequired);
1052
124
      spdlog::error(
1053
124
          ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset()));
1054
124
      return Unexpect(ErrCode::Value::ConstExprRequired);
1055
14.3k
    }
1056
14.3k
  }
1057
  // Validate expression with result types.
1058
5.41k
  Checker.reset();
1059
5.41k
  return Checker.validate(Instrs, Returns);
1060
5.64k
}
1061
1062
} // namespace Validator
1063
} // namespace WasmEdge