Coverage Report

Created: 2026-08-13 06:09

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