Coverage Report

Created: 2026-11-09 06:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/WasmEdge/include/validator/component_value_decode.h
Line
Count
Source
1
// SPDX-License-Identifier: Apache-2.0
2
// SPDX-FileCopyrightText: Copyright The WasmEdge Authors
3
4
//===-- wasmedge/validator/component_value_decode.h - Value decoding ------===//
5
//
6
// Part of the WasmEdge Project.
7
//
8
//===----------------------------------------------------------------------===//
9
///
10
/// \file
11
/// This file contains the decoder of the binary `val(t)` payload of a value
12
/// definition. The validator decodes each payload while checking it against
13
/// the declared type and caches the decoded value on the AST node, which
14
/// instantiation later consumes.
15
///
16
//===----------------------------------------------------------------------===//
17
#pragma once
18
19
#include "ast/component/type.h"
20
#include "common/component_valtype.h"
21
#include "common/component_variant.h"
22
#include "common/errcode.h"
23
#include "common/types.h"
24
#include "validator/component_types.h"
25
26
#include <cmath>
27
#include <cstring>
28
#include <string>
29
#include <utility>
30
31
namespace WasmEdge {
32
namespace Validator {
33
namespace Component {
34
35
/// Decoder over one value definition's payload, resolving types in its scope.
36
class ValueDecoder {
37
public:
38
  ValueDecoder(Span<const Byte> D, const Scope &S) noexcept
39
15.1k
      : Data(D), Types(S) {}
40
41
15.1k
  Expect<ComponentValVariant> decode(const ComponentValType &Ty) noexcept {
42
15.1k
    EXPECTED_TRY(auto V, decodeVal(Ty));
43
14.2k
    if (Off != Data.size()) {
44
107
      return Unexpect(ErrCode::Value::ComponentMalformedValue);
45
107
    }
46
14.1k
    return V;
47
14.2k
  }
48
49
private:
50
58.2k
  Expect<Byte> readByte() noexcept {
51
58.2k
    if (Off >= Data.size()) {
52
467
      return Unexpect(ErrCode::Value::ComponentMalformedValue);
53
467
    }
54
57.8k
    return Data[Off++];
55
58.2k
  }
56
57
17.2k
  Expect<uint64_t> readULEB(uint32_t MaxBits) noexcept {
58
17.2k
    uint64_t Result = 0;
59
17.2k
    uint32_t Shift = 0;
60
23.3k
    while (true) {
61
23.3k
      EXPECTED_TRY(auto B, readByte());
62
23.1k
      if (Shift + 7 > MaxBits &&
63
164
          (B >> (MaxBits > Shift ? MaxBits - Shift : 0)) != 0) {
64
26
        return Unexpect(ErrCode::Value::ComponentMalformedValue);
65
26
      }
66
23.0k
      Result |= static_cast<uint64_t>(B & 0x7FU) << Shift;
67
23.0k
      if ((B & 0x80U) == 0) {
68
17.0k
        return Result;
69
17.0k
      }
70
6.05k
      Shift += 7;
71
6.05k
      if (Shift >= MaxBits + 7) {
72
0
        return Unexpect(ErrCode::Value::ComponentMalformedValue);
73
0
      }
74
6.05k
    }
75
17.2k
  }
76
77
10.9k
  Expect<int64_t> readSLEB(uint32_t MaxBits) noexcept {
78
10.9k
    uint64_t Result = 0;
79
10.9k
    uint32_t Shift = 0;
80
19.5k
    while (true) {
81
19.5k
      EXPECTED_TRY(auto B, readByte());
82
19.4k
      Result |= static_cast<uint64_t>(B & 0x7FU) << Shift;
83
19.4k
      if ((B & 0x80U) == 0) {
84
        // On the final byte, every bit above the value width repeats the sign.
85
10.8k
        const uint32_t Rest = MaxBits - Shift;
86
10.8k
        if (Rest <= 7) {
87
435
          const uint8_t Mask =
88
435
              static_cast<uint8_t>((0x7FU >> (Rest - 1)) << (Rest - 1));
89
435
          if ((B & Mask) != 0 && (B & Mask) != Mask) {
90
13
            return Unexpect(ErrCode::Value::ComponentMalformedValue);
91
13
          }
92
435
        }
93
10.7k
        Shift += 7;
94
10.7k
        if (Shift < 64 && (B & 0x40U) != 0) {
95
3.98k
          Result |= ~UINT64_C(0) << Shift;
96
3.98k
        }
97
10.7k
        return static_cast<int64_t>(Result);
98
10.8k
      }
99
8.60k
      Shift += 7;
100
8.60k
      if (Shift >= MaxBits) {
101
19
        return Unexpect(ErrCode::Value::ComponentMalformedValue);
102
19
      }
103
8.60k
    }
104
10.9k
  }
105
106
38.0k
  Expect<ComponentValVariant> decodeVal(const ComponentValType &Ty) noexcept {
107
38.0k
    if (Ty.isPrimValType()) {
108
23.6k
      return decodePrim(Ty.getPrimValType());
109
23.6k
    }
110
14.4k
    const auto *Entry = Types.getType(Ty.getTypeIndex());
111
14.4k
    const AST::Component::DefValType *D =
112
14.4k
        Entry != nullptr ? Entry->getDefValType() : nullptr;
113
14.4k
    if (D == nullptr) {
114
0
      return Unexpect(ErrCode::Value::ComponentMalformedValue);
115
0
    }
116
14.4k
    return decodeDef(*D);
117
14.4k
  }
118
119
23.9k
  Expect<ComponentValVariant> decodePrim(PrimValType P) noexcept {
120
23.9k
    switch (P) {
121
367
    case PrimValType::Bool: {
122
367
      EXPECTED_TRY(auto B, readByte());
123
354
      if (B > 1) {
124
19
        return Unexpect(ErrCode::Value::ComponentMalformedValue);
125
19
      }
126
335
      return ComponentValVariant{B != 0};
127
354
    }
128
676
    case PrimValType::U8: {
129
676
      EXPECTED_TRY(auto B, readByte());
130
654
      return ComponentValVariant{static_cast<uint8_t>(B)};
131
676
    }
132
391
    case PrimValType::S8: {
133
391
      EXPECTED_TRY(auto B, readByte());
134
378
      return ComponentValVariant{static_cast<int8_t>(B)};
135
391
    }
136
926
    case PrimValType::U16: {
137
926
      EXPECTED_TRY(auto V, readULEB(16));
138
818
      return ComponentValVariant{static_cast<uint16_t>(V)};
139
926
    }
140
1.73k
    case PrimValType::S16: {
141
1.73k
      EXPECTED_TRY(auto V, readSLEB(16));
142
1.69k
      return ComponentValVariant{static_cast<int16_t>(V)};
143
1.73k
    }
144
4.62k
    case PrimValType::U32: {
145
4.62k
      EXPECTED_TRY(auto V, readULEB(32));
146
4.57k
      return ComponentValVariant{static_cast<uint32_t>(V)};
147
4.62k
    }
148
3.95k
    case PrimValType::S32: {
149
3.95k
      EXPECTED_TRY(auto V, readSLEB(32));
150
3.90k
      return ComponentValVariant{static_cast<int32_t>(V)};
151
3.95k
    }
152
2.65k
    case PrimValType::U64: {
153
2.65k
      EXPECTED_TRY(auto V, readULEB(64));
154
2.63k
      return ComponentValVariant{V};
155
2.65k
    }
156
5.26k
    case PrimValType::S64: {
157
5.26k
      EXPECTED_TRY(auto V, readSLEB(64));
158
5.19k
      return ComponentValVariant{V};
159
5.26k
    }
160
721
    case PrimValType::F32: {
161
721
      uint32_t Bits = 0;
162
3.52k
      for (uint32_t I = 0; I < 4; ++I) {
163
2.83k
        EXPECTED_TRY(auto B, readByte());
164
2.80k
        Bits |= static_cast<uint32_t>(B) << (I * 8);
165
2.80k
      }
166
695
      float F;
167
695
      std::memcpy(&F, &Bits, sizeof(F));
168
695
      if (std::isnan(F) && Bits != UINT32_C(0x7FC00000)) {
169
15
        return Unexpect(ErrCode::Value::ComponentMalformedValue);
170
15
      }
171
680
      return ComponentValVariant{F};
172
695
    }
173
328
    case PrimValType::F64: {
174
328
      uint64_t Bits = 0;
175
2.85k
      for (uint32_t I = 0; I < 8; ++I) {
176
2.54k
        EXPECTED_TRY(auto B, readByte());
177
2.52k
        Bits |= static_cast<uint64_t>(B) << (I * 8);
178
2.52k
      }
179
311
      double D;
180
311
      std::memcpy(&D, &Bits, sizeof(D));
181
311
      if (std::isnan(D) && Bits != UINT64_C(0x7FF8000000000000)) {
182
68
        return Unexpect(ErrCode::Value::ComponentMalformedValue);
183
68
      }
184
243
      return ComponentValVariant{D};
185
311
    }
186
1.06k
    case PrimValType::Char: {
187
1.06k
      EXPECTED_TRY(auto CP, readUtf8Scalar());
188
1.01k
      return ComponentValVariant{CP};
189
1.06k
    }
190
1.24k
    case PrimValType::String: {
191
1.24k
      EXPECTED_TRY(auto Len, readULEB(32));
192
1.21k
      if (Len > Data.size() - Off) {
193
61
        return Unexpect(ErrCode::Value::ComponentMalformedValue);
194
61
      }
195
      // `val(string)` is a `core:name`, so the payload must be valid UTF-8.
196
1.15k
      const size_t Begin = Off;
197
1.15k
      const size_t End = Off + static_cast<size_t>(Len);
198
2.74k
      while (Off < End) {
199
1.62k
        EXPECTED_TRY(readUtf8Scalar());
200
1.62k
      }
201
1.11k
      if (Off != End) {
202
7
        return Unexpect(ErrCode::Value::ComponentMalformedValue);
203
7
      }
204
1.10k
      return ComponentValVariant{std::string(
205
1.10k
          reinterpret_cast<const char *>(Data.data()) + Begin, End - Begin)};
206
1.11k
    }
207
0
    default:
208
0
      return Unexpect(ErrCode::Value::ComponentMalformedValue);
209
23.9k
    }
210
23.9k
  }
211
212
2.68k
  Expect<uint32_t> readUtf8Scalar() noexcept {
213
2.68k
    EXPECTED_TRY(auto B0, readByte());
214
2.67k
    uint32_t CP = 0;
215
2.67k
    uint32_t Tail = 0;
216
    // The smallest scalar the sequence length is allowed to encode.
217
2.67k
    uint32_t Least = 0;
218
2.67k
    if (B0 < 0x80U) {
219
1.54k
      return static_cast<uint32_t>(B0);
220
1.54k
    }
221
1.13k
    if ((B0 & 0xE0U) == 0xC0U) {
222
206
      CP = B0 & 0x1FU;
223
206
      Tail = 1;
224
206
      Least = 0x80U;
225
928
    } else if ((B0 & 0xF0U) == 0xE0U) {
226
814
      CP = B0 & 0x0FU;
227
814
      Tail = 2;
228
814
      Least = 0x800U;
229
814
    } else if ((B0 & 0xF8U) == 0xF0U) {
230
88
      CP = B0 & 0x07U;
231
88
      Tail = 3;
232
88
      Least = 0x10000U;
233
88
    } else {
234
26
      return Unexpect(ErrCode::Value::ComponentMalformedValue);
235
26
    }
236
3.13k
    for (uint32_t I = 0; I < Tail; ++I) {
237
2.07k
      EXPECTED_TRY(auto B, readByte());
238
2.05k
      if ((B & 0xC0U) != 0x80U) {
239
24
        return Unexpect(ErrCode::Value::ComponentMalformedValue);
240
24
      }
241
2.02k
      CP = (CP << 6) | (B & 0x3FU);
242
2.02k
    }
243
    // Reject overlong encodings, surrogates, and out-of-range scalars.
244
1.06k
    if (CP < Least || CP >= 0x110000U || (CP >= 0xD800U && CP <= 0xDFFFU)) {
245
10
      return Unexpect(ErrCode::Value::ComponentMalformedValue);
246
10
    }
247
1.05k
    return CP;
248
1.06k
  }
249
250
  Expect<ComponentValVariant>
251
14.4k
  decodeDef(const AST::Component::DefValType &D) noexcept {
252
14.4k
    if (D.isPrimValType()) {
253
325
      return decodePrim(D.getPrimValType());
254
325
    }
255
14.0k
    if (D.isRecordTy()) {
256
1.60k
      RecordVal R;
257
1.60k
      for (const auto &LT : D.getRecord().LabelTypes) {
258
1.60k
        EXPECTED_TRY(auto V, decodeVal(LT.getValType()));
259
1.59k
        R.Fields.emplace_back(std::string(LT.getLabel()), std::move(V));
260
1.59k
      }
261
1.59k
      return makeComponentVal(std::move(R));
262
1.60k
    }
263
12.4k
    if (D.isVariantTy()) {
264
1.70k
      const auto &Cases = D.getVariant().Cases;
265
1.70k
      EXPECTED_TRY(auto Idx, readULEB(32));
266
1.68k
      if (Idx >= Cases.size()) {
267
50
        return Unexpect(ErrCode::Value::ComponentMalformedValue);
268
50
      }
269
1.63k
      VariantVal V;
270
1.63k
      V.Case = static_cast<uint32_t>(Idx);
271
1.63k
      V.Label = Cases[V.Case].first;
272
1.63k
      if (Cases[V.Case].second.has_value()) {
273
1.56k
        EXPECTED_TRY(auto P, decodeVal(*Cases[V.Case].second));
274
1.55k
        V.Payload = std::move(P);
275
1.55k
      }
276
1.62k
      return makeComponentVal(std::move(V));
277
1.63k
    }
278
10.7k
    if (D.isListTy()) {
279
997
      const auto &L = D.getList();
280
997
      ListVal LV;
281
997
      uint64_t Count = 0;
282
997
      if (L.Len.has_value()) {
283
429
        Count = *L.Len;
284
568
      } else {
285
568
        EXPECTED_TRY(Count, readULEB(32));
286
561
      }
287
4.15k
      for (uint64_t I = 0; I < Count; ++I) {
288
3.33k
        EXPECTED_TRY(auto V, decodeVal(L.ValTy));
289
3.16k
        LV.Elements.push_back(std::move(V));
290
3.16k
      }
291
817
      return makeComponentVal(std::move(LV));
292
990
    }
293
9.78k
    if (D.isMapTy()) {
294
      // (map k v) decodes like (list (tuple k v)).
295
5.22k
      ListVal LV;
296
5.22k
      EXPECTED_TRY(auto Count, readULEB(32));
297
11.7k
      for (uint64_t I = 0; I < Count; ++I) {
298
6.76k
        TupleVal Entry;
299
6.76k
        EXPECTED_TRY(auto K, decodeVal(D.getMap().KeyTy));
300
6.61k
        Entry.Values.push_back(std::move(K));
301
6.61k
        EXPECTED_TRY(auto V, decodeVal(D.getMap().ValTy));
302
6.51k
        Entry.Values.push_back(std::move(V));
303
6.51k
        LV.Elements.push_back(makeComponentVal(std::move(Entry)));
304
6.51k
      }
305
4.95k
      return makeComponentVal(std::move(LV));
306
5.20k
    }
307
4.56k
    if (D.isTupleTy()) {
308
390
      TupleVal T;
309
548
      for (const auto &Ty : D.getTuple().Types) {
310
548
        EXPECTED_TRY(auto V, decodeVal(Ty));
311
509
        T.Values.push_back(std::move(V));
312
509
      }
313
351
      return makeComponentVal(std::move(T));
314
390
    }
315
4.17k
    if (D.isFlagsTy()) {
316
817
      const auto &Labels = D.getFlags().Labels;
317
817
      FlagsVal F;
318
817
      F.Bits.resize(Labels.size(), false);
319
817
      const size_t Bytes = (Labels.size() + 7) / 8;
320
1.63k
      for (size_t I = 0; I < Bytes; ++I) {
321
817
        EXPECTED_TRY(auto B, readByte());
322
7.32k
        for (size_t Bit = 0; Bit < 8; ++Bit) {
323
6.51k
          const size_t Pos = I * 8 + Bit;
324
6.51k
          if (Pos < Labels.size() && (B & (1U << Bit)) != 0) {
325
804
            F.Bits[Pos] = true;
326
804
          }
327
6.51k
        }
328
814
      }
329
814
      return makeComponentVal(std::move(F));
330
817
    }
331
3.35k
    if (D.isEnumTy()) {
332
329
      const auto &Labels = D.getEnum().Labels;
333
329
      EXPECTED_TRY(auto Idx, readULEB(32));
334
325
      if (Idx >= Labels.size()) {
335
18
        return Unexpect(ErrCode::Value::ComponentMalformedValue);
336
18
      }
337
307
      return makeComponentVal(EnumVal{static_cast<uint32_t>(Idx), Labels[Idx]});
338
325
    }
339
3.02k
    if (D.isOptionTy()) {
340
2.01k
      EXPECTED_TRY(auto Disc, readByte());
341
2.00k
      OptionVal O;
342
2.00k
      if (Disc == 1) {
343
1.92k
        EXPECTED_TRY(auto V, decodeVal(D.getOption().ValTy));
344
1.91k
        O.Value = std::move(V);
345
1.91k
      } else if (Disc != 0) {
346
9
        return Unexpect(ErrCode::Value::ComponentMalformedValue);
347
9
      }
348
1.98k
      return makeComponentVal(std::move(O));
349
2.00k
    }
350
1.01k
    if (D.isResultTy()) {
351
1.01k
      EXPECTED_TRY(auto Disc, readByte());
352
1.01k
      if (Disc > 1) {
353
9
        return Unexpect(ErrCode::Value::ComponentMalformedValue);
354
9
      }
355
1.00k
      ResultVal R;
356
1.00k
      R.IsOk = (Disc == 0);
357
1.00k
      const auto &PT = R.IsOk ? D.getResult().ValTy : D.getResult().ErrTy;
358
1.00k
      if (PT.has_value()) {
359
541
        EXPECTED_TRY(auto V, decodeVal(*PT));
360
531
        R.Payload = std::move(V);
361
531
      }
362
993
      return makeComponentVal(std::move(R));
363
1.00k
    }
364
    // Handles, streams, and futures cannot appear in value definitions.
365
0
    return Unexpect(ErrCode::Value::ComponentMalformedValue);
366
1.01k
  }
367
368
  Span<const Byte> Data;
369
  const Scope &Types;
370
  size_t Off = 0;
371
};
372
373
} // namespace Component
374
} // namespace Validator
375
} // namespace WasmEdge