Coverage Report

Created: 2026-11-12 06:35

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.46k
                  const std::vector<const WasmEdge::AST::SubType *> &TypeVec) {
32
4.46k
  if (TestIdx >= DepthMap.size()) {
33
0
    DepthMap.resize(TestIdx + 1, Unvisited);
34
4.46k
  } 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.46k
  } else if (DepthMap[TestIdx] != Unvisited) {
40
3.41k
    return DepthMap[TestIdx];
41
3.41k
  }
42
43
1.05k
  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.05k
  DepthMap[TestIdx] = Visiting;
51
1.05k
  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.05k
  const auto *TestType = TypeVec[TestIdx];
55
1.05k
  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.05k
  for (const auto SuperIdx : TestType->getSuperTypeIndices()) {
61
469
    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
938
    EXPECTED_TRY(
69
938
        auto RetDepth,
70
938
        checkSubtypeDepth(BaseIdx, SuperIdx, Depth + 1, DepthMap, TypeVec)
71
938
            .map_error([=](auto E) {
72
938
              spdlog::error(
73
938
                  "    When checking subtype hierarchy of super type {}."sv,
74
938
                  SuperIdx);
75
938
              return E;
76
938
            }));
77
938
    MaxDepth = std::max(MaxDepth, RetDepth + 1);
78
938
  }
79
80
1.05k
  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.05k
  DepthMap[TestIdx] = MaxDepth;
88
1.05k
  return MaxDepth;
89
1.05k
}
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
16.3k
                         std::map<std::vector<uint32_t>, uint32_t> &RecTypes) {
95
16.3k
  std::vector<uint32_t> Key;
96
16.3k
  auto AddTypeIdx = [&](uint32_t Idx) {
97
13.4k
    if (Idx >= BaseIdx && Idx - BaseIdx < RecType.size()) {
98
10.0k
      Key.push_back(0U);
99
10.0k
      Key.push_back(Idx - BaseIdx);
100
10.0k
    } else {
101
3.34k
      Key.push_back(1U);
102
3.34k
      Key.push_back(TypeVec[Idx]->getCanonicalIndex().value_or(Idx));
103
3.34k
    }
104
13.4k
  };
105
122k
  auto AddValType = [&](const ValType &VT) {
106
122k
    Key.push_back(static_cast<uint32_t>(VT.getCode()));
107
122k
    Key.push_back(static_cast<uint32_t>(VT.getHeapTypeCode()));
108
122k
    if (VT.getHeapTypeCode() == TypeCode::TypeIndex) {
109
11.0k
      AddTypeIdx(VT.getTypeIndex());
110
11.0k
    }
111
122k
  };
112
113
16.3k
  Key.push_back(static_cast<uint32_t>(RecType.size()));
114
31.0k
  for (const auto &Type : RecType) {
115
31.0k
    const auto &CompType = Type.getCompositeType();
116
31.0k
    Key.push_back(Type.isFinal() ? 1U : 0U);
117
31.0k
    Key.push_back(static_cast<uint32_t>(Type.getSuperTypeIndices().size()));
118
31.0k
    for (const auto Idx : Type.getSuperTypeIndices()) {
119
2.40k
      AddTypeIdx(Idx);
120
2.40k
    }
121
31.0k
    Key.push_back(static_cast<uint32_t>(CompType.getContentTypeCode()));
122
31.0k
    if (CompType.isFunc()) {
123
17.1k
      const auto &FType = CompType.getFuncType();
124
17.1k
      Key.push_back(static_cast<uint32_t>(FType.getParamTypes().size()));
125
45.7k
      for (const auto &VT : FType.getParamTypes()) {
126
45.7k
        AddValType(VT);
127
45.7k
      }
128
17.1k
      Key.push_back(static_cast<uint32_t>(FType.getReturnTypes().size()));
129
43.5k
      for (const auto &VT : FType.getReturnTypes()) {
130
43.5k
        AddValType(VT);
131
43.5k
      }
132
17.1k
    } else {
133
13.8k
      const auto &FTypes = CompType.getFieldTypes();
134
13.8k
      Key.push_back(static_cast<uint32_t>(FTypes.size()));
135
33.5k
      for (const auto &FType : FTypes) {
136
33.5k
        Key.push_back(static_cast<uint32_t>(FType.getValMut()));
137
33.5k
        AddValType(FType.getStorageType());
138
33.5k
      }
139
13.8k
    }
140
31.0k
  }
141
16.3k
  const uint32_t CanonIdx =
142
16.3k
      RecTypes.try_emplace(std::move(Key), BaseIdx).first->second;
143
47.4k
  for (uint32_t I = 0; I < RecType.size(); I++) {
144
31.0k
    const_cast<AST::SubType &>(RecType[I]).setCanonicalIndex(CanonIdx + I);
145
31.0k
  }
146
16.3k
}
147
148
} // namespace
149
150
// Validate Module. See "include/validator/validator.h".
151
8.74k
Expect<void> Validator::validate(const AST::Module &Mod) {
152
  // https://webassembly.github.io/spec/core/valid/modules.html
153
8.74k
  Checker.reset(true);
154
155
  // Validate and register type section.
156
8.74k
  EXPECTED_TRY(validate(Mod.getTypeSection()).map_error([](auto E) {
157
8.58k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Type));
158
8.58k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module));
159
8.58k
    return E;
160
8.58k
  }));
161
162
  // Validate and register the import section in FormChecker.
163
8.58k
  EXPECTED_TRY(validate(Mod.getImportSection()).map_error([](auto E) {
164
8.50k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Import));
165
8.50k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module));
166
8.50k
    return E;
167
8.50k
  }));
168
169
  // Validate the function section and register functions in FormChecker.
170
8.50k
  EXPECTED_TRY(validate(Mod.getFunctionSection()).map_error([](auto E) {
171
8.46k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Function));
172
8.46k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module));
173
8.46k
    return E;
174
8.46k
  }));
175
176
  // Validate the table section and register tables in FormChecker.
177
8.46k
  EXPECTED_TRY(validate(Mod.getTableSection()).map_error([](auto E) {
178
8.28k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Table));
179
8.28k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module));
180
8.28k
    return E;
181
8.28k
  }));
182
183
  // Validate the memory section and register memories in FormChecker.
184
8.28k
  EXPECTED_TRY(validate(Mod.getMemorySection()).map_error([](auto E) {
185
8.01k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Memory));
186
8.01k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module));
187
8.01k
    return E;
188
8.01k
  }));
189
190
  // Validate the global section and register globals in FormChecker.
191
8.01k
  EXPECTED_TRY(validate(Mod.getGlobalSection()).map_error([](auto E) {
192
7.69k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Global));
193
7.69k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module));
194
7.69k
    return E;
195
7.69k
  }));
196
197
  // Validate the tag section and register tags in FormChecker.
198
7.69k
  EXPECTED_TRY(validate(Mod.getTagSection()).map_error([](auto E) {
199
7.65k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Tag));
200
7.65k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module));
201
7.65k
    return E;
202
7.65k
  }));
203
204
  // Validate export section.
205
7.65k
  EXPECTED_TRY(validate(Mod.getExportSection()).map_error([](auto E) {
206
7.39k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Export));
207
7.39k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module));
208
7.39k
    return E;
209
7.39k
  }));
210
211
  // Validate start section.
212
7.39k
  EXPECTED_TRY(validate(Mod.getStartSection()).map_error([](auto E) {
213
7.33k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Start));
214
7.33k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module));
215
7.33k
    return E;
216
7.33k
  }));
217
218
  // Validate the element section that initializes tables.
219
7.33k
  EXPECTED_TRY(validate(Mod.getElementSection()).map_error([](auto E) {
220
7.18k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Element));
221
7.18k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module));
222
7.18k
    return E;
223
7.18k
  }));
224
225
  // Validate the data section that initializes memories.
226
7.18k
  EXPECTED_TRY(validate(Mod.getDataSection()).map_error([](auto E) {
227
7.15k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Data));
228
7.15k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module));
229
7.15k
    return E;
230
7.15k
  }));
231
232
  // Validate code section and expressions.
233
7.15k
  EXPECTED_TRY(validate(Mod.getCodeSection()).map_error([](auto E) {
234
2.92k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Code));
235
2.92k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module));
236
2.92k
    return E;
237
2.92k
  }));
238
239
  // Multiple tables are for the ReferenceTypes proposal.
240
2.92k
  if (Checker.getTables().size() > 1 &&
241
66
      !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.92k
  if (Checker.getMemories().size() > 1 &&
250
82
      !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.92k
  const_cast<AST::Module &>(Mod).setIsValidated();
259
2.92k
  return {};
260
2.92k
}
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
84.7k
                    const std::vector<const AST::SubType *> &TypeVec) {
267
84.7k
  const auto &CompType = Type.getCompositeType();
268
  // A concrete heap type reference must name a defined type of this space.
269
147k
  auto CheckValType = [&TypeVec](const ValType &VT) -> Expect<void> {
270
147k
    if (VT.isRefType() && VT.getHeapTypeCode() == TypeCode::TypeIndex &&
271
14.3k
        (VT.getTypeIndex() >= TypeVec.size() ||
272
14.3k
         TypeVec[VT.getTypeIndex()] == nullptr)) {
273
73
      spdlog::error(ErrCode::Value::InvalidFuncTypeIdx);
274
73
      spdlog::error(ErrInfo::InfoForbidIndex(
275
73
          ErrInfo::IndexCategory::FunctionType, VT.getTypeIndex(),
276
73
          static_cast<uint32_t>(TypeVec.size())));
277
73
      return Unexpect(ErrCode::Value::InvalidFuncTypeIdx);
278
73
    }
279
147k
    return {};
280
147k
  };
281
282
  // Check the validation of the composite type.
283
84.7k
  if (CompType.isFunc()) {
284
20.9k
    const auto &FType = CompType.getFuncType();
285
54.3k
    for (auto &PType : FType.getParamTypes()) {
286
54.3k
      EXPECTED_TRY(CheckValType(PType).map_error([](auto E) {
287
54.3k
        spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Function));
288
54.3k
        return E;
289
54.3k
      }));
290
54.3k
    }
291
20.9k
    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
51.1k
    for (auto &RType : FType.getReturnTypes()) {
299
51.1k
      EXPECTED_TRY(CheckValType(RType).map_error([](auto E) {
300
51.1k
        spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Function));
301
51.1k
        return E;
302
51.1k
      }));
303
51.1k
    }
304
63.8k
  } else {
305
63.8k
    const auto &FTypes = CompType.getFieldTypes();
306
63.8k
    for (auto &FieldType : FTypes) {
307
42.0k
      EXPECTED_TRY(CheckValType(FieldType.getStorageType()));
308
42.0k
    }
309
63.8k
  }
310
311
  // In the current version, the length of the type index vector will be <= 1.
312
84.7k
  if (Type.getSuperTypeIndices().size() > 1) {
313
4
    spdlog::error(ErrCode::Value::MultipleSuperTypes);
314
4
    return Unexpect(ErrCode::Value::MultipleSuperTypes);
315
4
  }
316
317
84.7k
  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
4.00k
    if (unlikely(Index >= OwnTypeIdx)) {
321
13
      spdlog::error(ErrCode::Value::InvalidSubType);
322
13
      spdlog::error("    Super type index {} must be smaller than the sub type "
323
13
                    "index {}."sv,
324
13
                    Index, OwnTypeIdx);
325
13
      return Unexpect(ErrCode::Value::InvalidSubType);
326
13
    }
327
328
3.99k
    EXPECTED_TRY(
329
3.99k
        checkSubtypeDepth(Index, Index, 0, SubTypeDepthMap, TypeVec)
330
3.99k
            .map_error([=](auto E) {
331
3.99k
              spdlog::error(
332
3.99k
                  "    When checking subtype hierarchy of super type {}."sv,
333
3.99k
                  Index);
334
3.99k
              return E;
335
3.99k
            }));
336
337
3.99k
    if (TypeVec[Index]->isFinal()) {
338
9
      spdlog::error(ErrCode::Value::InvalidSubType);
339
9
      spdlog::error("    Super type should not be final."sv);
340
9
      return Unexpect(ErrCode::Value::InvalidSubType);
341
9
    }
342
3.99k
  }
343
84.6k
  return {};
344
84.7k
}
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
66.3k
                    const std::vector<const AST::SubType *> &TypeVec) {
351
  // Check all the members before matching, which walks their super types.
352
151k
  for (uint32_t I = 0; I < RecType.size(); I++) {
353
84.7k
    EXPECTED_TRY(validate(RecType[I], BaseIdx + I, SubTypeDepthMap, TypeVec));
354
84.7k
  }
355
82.0k
  for (const auto &Type : RecType) {
356
82.0k
    for (const auto &Index : Type.getSuperTypeIndices()) {
357
2.70k
      if (!AST::TypeMatcher::matchType(TypeVec,
358
2.70k
                                       TypeVec[Index]->getCompositeType(),
359
2.70k
                                       Type.getCompositeType())) {
360
63
        spdlog::error(ErrCode::Value::InvalidSubType);
361
63
        spdlog::error("    Super type not matched."sv);
362
63
        return Unexpect(ErrCode::Value::InvalidSubType);
363
63
      }
364
2.70k
    }
365
82.0k
  }
366
66.1k
  return {};
367
66.2k
}
368
369
// Validate Limit type. See "include/validator/validator.h".
370
13.5k
Expect<void> Validator::validate(const AST::Limit &Lim) {
371
13.5k
  if (Lim.hasMax() && Lim.getMin() > Lim.getMax()) {
372
95
    spdlog::error(ErrCode::Value::InvalidLimit);
373
95
    spdlog::error(ErrInfo::InfoLimit(Lim.hasMax(), Lim.getMin(), Lim.getMax()));
374
95
    return Unexpect(ErrCode::Value::InvalidLimit);
375
95
  }
376
13.4k
  if (Lim.isShared() && unlikely(!Lim.hasMax())) {
377
0
    spdlog::error(ErrCode::Value::SharedMemoryNoMax);
378
0
    return Unexpect(ErrCode::Value::SharedMemoryNoMax);
379
0
  }
380
13.4k
  return {};
381
13.4k
}
382
383
// Validate Table type. See "include/validator/validator.h".
384
5.65k
Expect<void> Validator::validate(const AST::TableType &Tab) {
385
  // Validate value type.
386
5.65k
  EXPECTED_TRY(Checker.validate(Tab.getRefType()));
387
  // Validate table limits.
388
5.61k
  const auto &Lim = Tab.getLimit();
389
5.61k
  EXPECTED_TRY(validate(Lim).map_error([](auto E) {
390
5.58k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Limit));
391
5.58k
    return E;
392
5.58k
  }));
393
5.58k
  uint64_t Range = getMaxAddress(Lim.getAddrType());
394
5.58k
  if (Lim.getMin() > Range || (Lim.hasMax() && Lim.getMax() > Range)) {
395
    // Since spec test has no related error message, use this error instead.
396
123
    auto Code = Conf.hasProposal(Proposal::Memory64)
397
123
                    ? ErrCode::Value::InvalidTableSize64
398
123
                    : ErrCode::Value::InvalidLimit;
399
123
    spdlog::error(Code);
400
123
    spdlog::error(ErrInfo::InfoLimit(Lim.hasMax(), Lim.getMin(), Lim.getMax()));
401
123
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Limit));
402
123
    return Unexpect(Code);
403
123
  }
404
5.46k
  return {};
405
5.58k
}
406
407
// Validate Memory type. See "include/validator/validator.h".
408
7.96k
Expect<void> Validator::validate(const AST::MemoryType &Mem) {
409
  // Validate memory limits.
410
7.96k
  const auto &Lim = Mem.getLimit();
411
7.96k
  EXPECTED_TRY(validate(Lim).map_error([](auto E) {
412
7.89k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Limit));
413
7.89k
    return E;
414
7.89k
  }));
415
7.89k
  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
7.89k
  uint64_t Range = Lim.is32() ? (static_cast<uint64_t>(1) << 16)
422
7.89k
                              : (static_cast<uint64_t>(1) << 48);
423
7.89k
  if (Lim.getMin() > Range || (Lim.hasMax() && Lim.getMax() > Range)) {
424
209
    auto Code = Conf.hasProposal(Proposal::Memory64)
425
209
                    ? ErrCode::Value::InvalidMemPages64
426
209
                    : ErrCode::Value::InvalidMemPages;
427
209
    spdlog::error(Code);
428
209
    spdlog::error(ErrInfo::InfoLimit(Lim.hasMax(), Lim.getMin(), Lim.getMax()));
429
209
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Limit));
430
209
    return Unexpect(Code);
431
209
  }
432
7.68k
  return {};
433
7.89k
}
434
435
// Validate Global type. See "include/validator/validator.h".
436
2.87k
Expect<void> Validator::validate(const AST::GlobalType &Glob) {
437
  // Validate value type.
438
2.87k
  return Checker.validate(Glob.getValType());
439
2.87k
}
440
441
// Validate Table segment. See "include/validator/validator.h".
442
5.21k
Expect<void> Validator::validate(const AST::TableSegment &TabSeg) {
443
5.21k
  if (TabSeg.getExpr().getInstrs().size() > 0) {
444
    // Check ref initialization is a const expression.
445
158
    EXPECTED_TRY(
446
158
        validateConstExpr(TabSeg.getExpr().getInstrs(),
447
158
                          {ValType(TabSeg.getTableType().getRefType())})
448
158
            .map_error([](auto E) {
449
158
              spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Expression));
450
158
              return E;
451
158
            }));
452
5.05k
  } else {
453
    // No init expression. Check that the reference type is nullable.
454
5.05k
    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.05k
  }
464
  // Validate table type.
465
5.20k
  return validate(TabSeg.getTableType()).map_error([](auto E) {
466
179
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Table));
467
179
    return E;
468
179
  });
469
5.21k
}
470
471
// Validate Global segment. See "include/validator/validator.h".
472
2.28k
Expect<void> Validator::validate(const AST::GlobalSegment &GlobSeg) {
473
  // Check global initialization is a const expression.
474
2.28k
  EXPECTED_TRY(validateConstExpr(GlobSeg.getExpr().getInstrs(),
475
1.95k
                                 {GlobSeg.getGlobalType().getValType()})
476
1.95k
                   .map_error([](auto E) {
477
1.95k
                     spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Expression));
478
1.95k
                     return E;
479
1.95k
                   }));
480
  // Validate global type.
481
1.95k
  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.28k
}
486
487
// Validate Element segment. See "include/validator/validator.h".
488
1.30k
Expect<void> Validator::validate(const AST::ElementSegment &ElemSeg) {
489
  // Check that initialization expressions are const expressions.
490
2.61k
  for (auto &Expr : ElemSeg.getInitExprs()) {
491
2.61k
    EXPECTED_TRY(
492
2.61k
        validateConstExpr(Expr.getInstrs(), {ValType(ElemSeg.getRefType())})
493
2.61k
            .map_error([](auto E) {
494
2.61k
              spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Expression));
495
2.61k
              return E;
496
2.61k
            }));
497
2.61k
  }
498
499
  // The reference type should be valid.
500
1.21k
  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
542
    const auto &TableVec = Checker.getTables();
506
542
    if (ElemSeg.getIdx() >= TableVec.size()) {
507
25
      spdlog::error(ErrCode::Value::InvalidTableIdx);
508
25
      spdlog::error(ErrInfo::InfoForbidIndex(
509
25
          ErrInfo::IndexCategory::Table, ElemSeg.getIdx(),
510
25
          static_cast<uint32_t>(TableVec.size())));
511
25
      return Unexpect(ErrCode::Value::InvalidTableIdx);
512
25
    }
513
517
    if (!AST::TypeMatcher::matchType(Checker.getTypes(),
514
517
                                     TableVec[ElemSeg.getIdx()].second,
515
517
                                     ElemSeg.getRefType())) {
516
      // Reference type does not match.
517
10
      spdlog::error(ErrCode::Value::TypeCheckFailed);
518
10
      spdlog::error(ErrInfo::InfoMismatch(TableVec[ElemSeg.getIdx()].second,
519
10
                                          ElemSeg.getRefType()));
520
10
      return Unexpect(ErrCode::Value::TypeCheckFailed);
521
10
    }
522
    // Check table initialization is a const expression.
523
507
    return validateConstExpr(ElemSeg.getExpr().getInstrs(),
524
507
                             {ValType(TableVec[ElemSeg.getIdx()].first)})
525
507
        .map_error([](auto E) {
526
10
          spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Expression));
527
10
          return E;
528
10
        });
529
517
  }
530
656
  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.5k
                                 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.5k
  const auto &FuncType =
539
19.5k
      Checker.getTypes()[TypeIdx]->getCompositeType().getFuncType();
540
  // Reset stack in FormChecker.
541
19.5k
  Checker.reset();
542
  // Add parameters to this frame.
543
49.3k
  for (auto &Type : FuncType.getParamTypes()) {
544
    // Local passed by function parameters must have been initialized.
545
49.3k
    Checker.addLocal(Type, true);
546
49.3k
  }
547
  // Add locals to this frame.
548
19.5k
  for (auto Val : CodeSeg.getLocals()) {
549
825M
    for (uint32_t Cnt = 0; Cnt < Val.first; ++Cnt) {
550
      // The local value type should be valid.
551
825M
      EXPECTED_TRY(Checker.validate(Val.second));
552
825M
      Checker.addLocal(Val.second, false);
553
825M
    }
554
13.9k
  }
555
  // Validate function body expression.
556
19.5k
  return Checker
557
19.5k
      .validate(CodeSeg.getExpr().getInstrs(), FuncType.getReturnTypes())
558
19.5k
      .map_error([](auto E) {
559
4.20k
        spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Expression));
560
4.20k
        return E;
561
4.20k
      });
562
19.5k
}
563
564
// Validate Data segment. See "include/validator/validator.h".
565
2.33k
Expect<void> Validator::validate(const AST::DataSegment &DataSeg) {
566
2.33k
  switch (DataSeg.getMode()) {
567
289
  case AST::DataSegment::DataMode::Active: {
568
    // Check memory index in context.
569
289
    const auto &MemVec = Checker.getMemories();
570
289
    if (DataSeg.getIdx() >= MemVec.size()) {
571
24
      spdlog::error(ErrCode::Value::InvalidMemoryIdx);
572
24
      spdlog::error(ErrInfo::InfoForbidIndex(
573
24
          ErrInfo::IndexCategory::Memory, DataSeg.getIdx(),
574
24
          static_cast<uint32_t>(MemVec.size())));
575
24
      return Unexpect(ErrCode::Value::InvalidMemoryIdx);
576
24
    }
577
    // Check memory initialization is a const expression.
578
265
    return validateConstExpr(DataSeg.getExpr().getInstrs(),
579
265
                             {ValType(MemVec[DataSeg.getIdx()])})
580
265
        .map_error([](auto E) {
581
11
          spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Expression));
582
11
          return E;
583
11
        });
584
289
  }
585
2.04k
  case AST::DataSegment::DataMode::Passive:
586
    // Passive case is always valid.
587
2.04k
    return {};
588
0
  default:
589
0
    return {};
590
2.33k
  }
591
2.33k
}
592
593
// Validate Import description. See "include/validator/validator.h".
594
4.52k
Expect<void> Validator::validate(const AST::ImportDesc &ImpDesc) {
595
4.52k
  switch (ImpDesc.getExternalType()) {
596
  // External type and external content are ensured to match in the loader
597
  // phase.
598
1.07k
  case ExternalType::Function: {
599
1.07k
    const auto TId = ImpDesc.getExternalFuncTypeIdx();
600
    // Function type index must exist in context and be valid.
601
1.07k
    if (TId >= Checker.getTypes().size()) {
602
48
      spdlog::error(ErrCode::Value::InvalidFuncTypeIdx);
603
48
      spdlog::error(ErrInfo::InfoForbidIndex(
604
48
          ErrInfo::IndexCategory::FunctionType, TId,
605
48
          static_cast<uint32_t>(Checker.getTypes().size())));
606
48
      return Unexpect(ErrCode::Value::InvalidFuncTypeIdx);
607
48
    }
608
1.02k
    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.02k
    Checker.addFunc(TId, true);
614
1.02k
    return {};
615
1.02k
  }
616
401
  case ExternalType::Table: {
617
401
    const auto &TabType = ImpDesc.getExternalTableType();
618
    // Table type must be valid.
619
401
    EXPECTED_TRY(validate(TabType).map_error([](auto E) {
620
396
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Table));
621
396
      return E;
622
396
    }));
623
396
    Checker.addTable(TabType);
624
396
    return {};
625
401
  }
626
1.43k
  case ExternalType::Memory: {
627
1.43k
    const auto &MemType = ImpDesc.getExternalMemoryType();
628
    // Memory type must be valid.
629
1.43k
    EXPECTED_TRY(validate(MemType).map_error([](auto E) {
630
1.43k
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Memory));
631
1.43k
      return E;
632
1.43k
    }));
633
1.43k
    Checker.addMemory(MemType);
634
1.43k
    return {};
635
1.43k
  }
636
741
  case ExternalType::Tag: {
637
741
    const auto &T = ImpDesc.getExternalTagType();
638
    // Tag type index must exist in context.
639
741
    auto TagTypeIdx = T.getTypeIdx();
640
741
    if (TagTypeIdx >= Checker.getTypes().size()) {
641
28
      spdlog::error(ErrCode::Value::InvalidTagIdx);
642
28
      spdlog::error(ErrInfo::InfoForbidIndex(
643
28
          ErrInfo::IndexCategory::TagType, TagTypeIdx,
644
28
          static_cast<uint32_t>(Checker.getTypes().size())));
645
28
      return Unexpect(ErrCode::Value::InvalidTagIdx);
646
28
    }
647
    // Tag type must be valid.
648
713
    auto &CompType = Checker.getTypes()[TagTypeIdx]->getCompositeType();
649
713
    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
710
    if (!CompType.getFuncType().getReturnTypes().empty()) {
656
4
      spdlog::error(ErrCode::Value::InvalidTagResultType);
657
4
      return Unexpect(ErrCode::Value::InvalidTagResultType);
658
4
    }
659
706
    Checker.addTag(TagTypeIdx);
660
706
    return {};
661
710
  }
662
874
  case ExternalType::Global: {
663
874
    const auto &GlobType = ImpDesc.getExternalGlobalType();
664
    // Global type must be valid.
665
874
    EXPECTED_TRY(validate(GlobType).map_error([](auto E) {
666
868
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Global));
667
868
      return E;
668
868
    }));
669
868
    Checker.addGlobal(GlobType, true);
670
868
    return {};
671
874
  }
672
0
  default:
673
0
    return {};
674
4.52k
  }
675
4.52k
}
676
677
// Validate Export description. See "include/validator/validator.h".
678
16.3k
Expect<void> Validator::validate(const AST::ExportDesc &ExpDesc) {
679
16.3k
  auto Id = ExpDesc.getExternalIndex();
680
16.3k
  switch (ExpDesc.getExternalType()) {
681
11.8k
  case ExternalType::Function:
682
11.8k
    if (Id >= Checker.getFunctions().size()) {
683
69
      spdlog::error(ErrCode::Value::InvalidFuncIdx);
684
69
      spdlog::error(ErrInfo::InfoForbidIndex(
685
69
          ErrInfo::IndexCategory::Function, Id,
686
69
          static_cast<uint32_t>(Checker.getFunctions().size())));
687
69
      return Unexpect(ErrCode::Value::InvalidFuncIdx);
688
69
    }
689
11.7k
    Checker.addRef(Id);
690
11.7k
    return {};
691
1.53k
  case ExternalType::Table:
692
1.53k
    if (Id >= Checker.getTables().size()) {
693
43
      spdlog::error(ErrCode::Value::InvalidTableIdx);
694
43
      spdlog::error(ErrInfo::InfoForbidIndex(
695
43
          ErrInfo::IndexCategory::Table, Id,
696
43
          static_cast<uint32_t>(Checker.getTables().size())));
697
43
      return Unexpect(ErrCode::Value::InvalidTableIdx);
698
43
    }
699
1.48k
    return {};
700
197
  case ExternalType::Memory:
701
197
    if (Id >= Checker.getMemories().size()) {
702
40
      spdlog::error(ErrCode::Value::InvalidMemoryIdx);
703
40
      spdlog::error(ErrInfo::InfoForbidIndex(
704
40
          ErrInfo::IndexCategory::Memory, Id,
705
40
          static_cast<uint32_t>(Checker.getMemories().size())));
706
40
      return Unexpect(ErrCode::Value::InvalidMemoryIdx);
707
40
    }
708
157
    return {};
709
65
  case ExternalType::Tag:
710
65
    if (Id >= Checker.getTags().size()) {
711
41
      spdlog::error(ErrCode::Value::InvalidTagIdx);
712
41
      spdlog::error(ErrInfo::InfoForbidIndex(
713
41
          ErrInfo::IndexCategory::Tag, Id,
714
41
          static_cast<uint32_t>(Checker.getTags().size())));
715
41
      return Unexpect(ErrCode::Value::InvalidTagIdx);
716
41
    }
717
24
    return {};
718
2.65k
  case ExternalType::Global:
719
2.65k
    if (Id >= Checker.getGlobals().size()) {
720
56
      spdlog::error(ErrCode::Value::InvalidGlobalIdx);
721
56
      spdlog::error(ErrInfo::InfoForbidIndex(
722
56
          ErrInfo::IndexCategory::Global, Id,
723
56
          static_cast<uint32_t>(Checker.getGlobals().size())));
724
56
      return Unexpect(ErrCode::Value::InvalidGlobalIdx);
725
56
    }
726
2.60k
    return {};
727
0
  default:
728
0
    return {};
729
16.3k
  }
730
16.3k
}
731
732
15.3k
Expect<void> Validator::validate(const AST::TypeSection &TypeSec) {
733
15.3k
  const auto STypeList = TypeSec.getContent();
734
15.3k
  std::vector<uint32_t> SubTypeDepthMap(STypeList.size(), Unvisited);
735
15.3k
  std::map<std::vector<uint32_t>, uint32_t> RecTypes;
736
15.3k
  uint32_t Idx = 0;
737
31.7k
  while (Idx < STypeList.size()) {
738
16.5k
    const auto &SType = STypeList[Idx];
739
    // The next type to add takes this index in the type index space.
740
16.5k
    const uint32_t BaseIdx = static_cast<uint32_t>(Checker.getTypes().size());
741
16.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
16.5k
      const uint32_t RecSize = SType.getRecursiveInfo().RecTypeSize;
745
51.8k
      for (uint32_t I = Idx; I < Idx + RecSize; I++) {
746
35.3k
        Checker.addType(STypeList[I]);
747
35.3k
      }
748
16.5k
      EXPECTED_TRY(validate(STypeList.subspan(Idx, RecSize), BaseIdx,
749
16.3k
                            SubTypeDepthMap, Checker.getTypes())
750
16.3k
                       .map_error([](auto E) {
751
16.3k
                         spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Rec));
752
16.3k
                         return E;
753
16.3k
                       }));
754
16.3k
      setCanonicalIndices(STypeList.subspan(Idx, RecSize), BaseIdx,
755
16.3k
                          Checker.getTypes(), RecTypes);
756
16.3k
      Idx += RecSize;
757
16.3k
    } 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
16.5k
  }
768
15.1k
  return {};
769
15.3k
}
770
771
// Validate Import section. See "include/validator/validator.h".
772
15.1k
Expect<void> Validator::validate(const AST::ImportSection &ImportSec) {
773
15.1k
  for (auto &ImportDesc : ImportSec.getContent()) {
774
4.52k
    EXPECTED_TRY(validate(ImportDesc).map_error([](auto E) {
775
4.52k
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Desc_Import));
776
4.52k
      return E;
777
4.52k
    }));
778
4.52k
  }
779
15.0k
  return {};
780
15.1k
}
781
782
// Validate Function section. See "include/validator/validator.h".
783
15.0k
Expect<void> Validator::validate(const AST::FunctionSection &FuncSec) {
784
15.0k
  const auto &FuncVec = FuncSec.getContent();
785
15.0k
  const auto &TypeVec = Checker.getTypes();
786
787
  // Check whether the function type ID is valid in context.
788
29.8k
  for (auto &TId : FuncVec) {
789
29.8k
    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
29.8k
    if (!TypeVec[TId]->getCompositeType().isFunc()) {
798
9
      spdlog::error(ErrCode::Value::InvalidFuncTypeIdx);
799
9
      spdlog::error("    Defined type index {} is not a function type."sv, TId);
800
9
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Function));
801
9
      return Unexpect(ErrCode::Value::InvalidFuncTypeIdx);
802
9
    }
803
29.8k
    Checker.addFunc(TId);
804
29.8k
  }
805
15.0k
  return {};
806
15.0k
}
807
808
// Validate Table section. See "include/validator/validator.h".
809
15.0k
Expect<void> Validator::validate(const AST::TableSection &TabSec) {
810
15.0k
  for (auto &Tab : TabSec.getContent()) {
811
5.21k
    EXPECTED_TRY(validate(Tab).map_error([](auto E) {
812
5.02k
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Table));
813
5.02k
      return E;
814
5.02k
    }));
815
5.02k
    Checker.addTable(Tab.getTableType());
816
5.02k
  }
817
14.8k
  return {};
818
15.0k
}
819
820
// Validate Memory section. See "include/validator/validator.h".
821
14.8k
Expect<void> Validator::validate(const AST::MemorySection &MemSec) {
822
14.8k
  for (auto &Mem : MemSec.getContent()) {
823
5.63k
    EXPECTED_TRY(validate(Mem).map_error([](auto E) {
824
5.35k
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Memory));
825
5.35k
      return E;
826
5.35k
    }));
827
5.35k
    Checker.addMemory(Mem);
828
5.35k
  }
829
14.5k
  return {};
830
14.8k
}
831
832
// Validate Global section. See "include/validator/validator.h".
833
14.5k
Expect<void> Validator::validate(const AST::GlobalSection &GlobSec) {
834
14.5k
  for (auto &GlobSeg : GlobSec.getContent()) {
835
2.28k
    EXPECTED_TRY(validate(GlobSeg).map_error([](auto E) {
836
1.95k
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Global));
837
1.95k
      return E;
838
1.95k
    }));
839
1.95k
    Checker.addGlobal(GlobSeg.getGlobalType());
840
1.95k
  }
841
14.2k
  return {};
842
14.5k
}
843
844
// Validate Element section. See "include/validator/validator.h".
845
13.8k
Expect<void> Validator::validate(const AST::ElementSection &ElemSec) {
846
13.8k
  for (auto &ElemSeg : ElemSec.getContent()) {
847
1.30k
    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
13.7k
  return {};
854
13.8k
}
855
856
// Validate Code section. See "include/validator/validator.h".
857
11.9k
Expect<void> Validator::validate(const AST::CodeSection &CodeSec) {
858
11.9k
  const auto &CodeVec = CodeSec.getContent();
859
11.9k
  const auto &FuncVec = Checker.getFunctions();
860
861
  // Validate function body.
862
27.2k
  for (uint32_t Id = 0; Id < static_cast<uint32_t>(CodeVec.size()); ++Id) {
863
    // Added functions contain imported functions.
864
19.5k
    uint32_t TId = Id + static_cast<uint32_t>(Checker.getNumImportFuncs());
865
19.5k
    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.5k
    EXPECTED_TRY(validate(CodeVec[Id], FuncVec[TId]).map_error([](auto E) {
873
19.5k
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Code));
874
19.5k
      return E;
875
19.5k
    }));
876
19.5k
  }
877
7.69k
  return {};
878
11.9k
}
879
880
// Validate Data section. See "include/validator/validator.h".
881
13.7k
Expect<void> Validator::validate(const AST::DataSection &DataSec) {
882
13.7k
  for (auto &DataSeg : DataSec.getContent()) {
883
2.33k
    EXPECTED_TRY(validate(DataSeg).map_error([](auto E) {
884
2.30k
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Data));
885
2.30k
      return E;
886
2.30k
    }));
887
2.30k
    Checker.addData(DataSeg);
888
2.30k
  }
889
13.6k
  return {};
890
13.7k
}
891
892
// Validate Start section. See "include/validator/validator.h".
893
13.9k
Expect<void> Validator::validate(const AST::StartSection &StartSec) {
894
13.9k
  if (StartSec.getContent()) {
895
97
    auto FId = *StartSec.getContent();
896
97
    if (FId >= Checker.getFunctions().size()) {
897
51
      spdlog::error(ErrCode::Value::InvalidFuncIdx);
898
51
      spdlog::error(ErrInfo::InfoForbidIndex(
899
51
          ErrInfo::IndexCategory::Function, FId,
900
51
          static_cast<uint32_t>(Checker.getFunctions().size())));
901
51
      return Unexpect(ErrCode::Value::InvalidFuncIdx);
902
51
    }
903
46
    auto TId = Checker.getFunctions()[FId];
904
46
    assuming(TId < Checker.getTypes().size());
905
46
    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
46
    auto &Type = Checker.getTypes()[TId]->getCompositeType().getFuncType();
911
46
    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
46
  }
919
13.8k
  return {};
920
13.9k
}
921
922
// Validate Export section. See "include/validator/validator.h".
923
14.1k
Expect<void> Validator::validate(const AST::ExportSection &ExportSec) {
924
14.1k
  std::unordered_set<std::string_view, Hash::Hash> ExportNames;
925
16.3k
  for (auto &ExportDesc : ExportSec.getContent()) {
926
16.3k
    auto Result = ExportNames.emplace(ExportDesc.getExternalName());
927
16.3k
    if (!Result.second) {
928
      // Duplicated export name.
929
14
      spdlog::error(ErrCode::Value::DupExportName);
930
14
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Desc_Export));
931
14
      return Unexpect(ErrCode::Value::DupExportName);
932
14
    }
933
16.3k
    EXPECTED_TRY(validate(ExportDesc).map_error([](auto E) {
934
16.3k
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Desc_Export));
935
16.3k
      return E;
936
16.3k
    }));
937
16.3k
  }
938
13.9k
  return {};
939
14.1k
}
940
941
// Validate Tag section. See "include/validator/validator.h".
942
14.2k
Expect<void> Validator::validate(const AST::TagSection &TagSec) {
943
14.2k
  const auto &TagVec = TagSec.getContent();
944
14.2k
  const auto &TypeVec = Checker.getTypes();
945
946
  // Check whether the tag type ID is valid in context.
947
14.2k
  for (auto &TagType : TagVec) {
948
2.69k
    auto TagTypeIdx = TagType.getTypeIdx();
949
2.69k
    if (TagTypeIdx >= TypeVec.size()) {
950
41
      spdlog::error(ErrCode::Value::InvalidTagIdx);
951
41
      spdlog::error(
952
41
          ErrInfo::InfoForbidIndex(ErrInfo::IndexCategory::TagType, TagTypeIdx,
953
41
                                   static_cast<uint32_t>(TypeVec.size())));
954
41
      return Unexpect(ErrCode::Value::InvalidTagIdx);
955
41
    }
956
2.65k
    auto &CompType = TypeVec[TagTypeIdx]->getCompositeType();
957
2.65k
    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.64k
    if (!CompType.getFuncType().getReturnTypes().empty()) {
964
2
      spdlog::error(ErrCode::Value::InvalidTagResultType);
965
2
      return Unexpect(ErrCode::Value::InvalidTagResultType);
966
2
    }
967
2.64k
    Checker.addTag(TagTypeIdx);
968
2.64k
  }
969
14.1k
  return {};
970
14.2k
}
971
972
// Validate constant expression. See "include/validator/validator.h".
973
Expect<void> Validator::validateConstExpr(AST::InstrView Instrs,
974
5.82k
                                          Span<const ValType> Returns) {
975
14.6k
  for (auto &Instr : Instrs) {
976
    // Only these instructions are accepted.
977
14.6k
    switch (Instr.getOpCode()) {
978
104
    case OpCode::Global__get: {
979
      // For the initialization case, global indices must be imported globals.
980
104
      auto GlobIdx = Instr.getTargetIndex();
981
104
      uint32_t ValidGlobalSize = Checker.getNumImportGlobals();
982
104
      if (Conf.hasProposal(Proposal::FunctionReferences)) {
983
104
        ValidGlobalSize = static_cast<uint32_t>(Checker.getGlobals().size());
984
104
      }
985
104
      if (GlobIdx >= ValidGlobalSize) {
986
52
        spdlog::error(ErrCode::Value::InvalidGlobalIdx);
987
52
        spdlog::error(ErrInfo::InfoForbidIndex(ErrInfo::IndexCategory::Global,
988
52
                                               GlobIdx, ValidGlobalSize));
989
52
        spdlog::error(
990
52
            ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset()));
991
52
        return Unexpect(ErrCode::Value::InvalidGlobalIdx);
992
52
      }
993
52
      if (Checker.getGlobals()[GlobIdx].second != ValMut::Const) {
994
3
        spdlog::error(ErrCode::Value::ConstExprRequired);
995
3
        spdlog::error(
996
3
            ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset()));
997
3
        return Unexpect(ErrCode::Value::ConstExprRequired);
998
3
      }
999
49
      break;
1000
52
    }
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
61
        spdlog::error(ErrCode::Value::InvalidFuncIdx);
1007
61
        spdlog::error(ErrInfo::InfoForbidIndex(
1008
61
            ErrInfo::IndexCategory::Function, FuncIdx,
1009
61
            static_cast<uint32_t>(Checker.getFunctions().size())));
1010
61
        spdlog::error(
1011
61
            ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset()));
1012
61
        return Unexpect(ErrCode::Value::InvalidFuncIdx);
1013
61
      }
1014
1.91k
      Checker.addRef(Instr.getTargetIndex());
1015
1.91k
      break;
1016
1.97k
    }
1017
2.23k
    case OpCode::I32__const:
1018
2.85k
    case OpCode::I64__const:
1019
3.01k
    case OpCode::F32__const:
1020
3.13k
    case OpCode::F64__const:
1021
4.76k
    case OpCode::Ref__null:
1022
4.91k
    case OpCode::V128__const:
1023
10.4k
    case OpCode::End:
1024
10.5k
    case OpCode::Struct__new:
1025
10.6k
    case OpCode::Struct__new_default:
1026
10.6k
    case OpCode::Array__new:
1027
10.7k
    case OpCode::Array__new_default:
1028
10.7k
    case OpCode::Array__new_fixed:
1029
10.7k
    case OpCode::Any__convert_extern:
1030
10.8k
    case OpCode::Extern__convert_any:
1031
10.9k
    case OpCode::Ref__i31:
1032
10.9k
      break;
1033
1034
    // For the Extended-const proposal, these instructions are accepted.
1035
194
    case OpCode::I32__add:
1036
470
    case OpCode::I32__sub:
1037
827
    case OpCode::I32__mul:
1038
1.02k
    case OpCode::I64__add:
1039
1.29k
    case OpCode::I64__sub:
1040
1.49k
    case OpCode::I64__mul:
1041
1.49k
      if (Conf.hasProposal(Proposal::ExtendedConst)) {
1042
1.49k
        break;
1043
1.49k
      }
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
129
    default:
1051
129
      spdlog::error(ErrCode::Value::ConstExprRequired);
1052
129
      spdlog::error(
1053
129
          ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset()));
1054
129
      return Unexpect(ErrCode::Value::ConstExprRequired);
1055
14.6k
    }
1056
14.6k
  }
1057
  // Validate expression with result types.
1058
5.58k
  Checker.reset();
1059
5.58k
  return Checker.validate(Instrs, Returns);
1060
5.82k
}
1061
1062
} // namespace Validator
1063
} // namespace WasmEdge