Coverage Report

Created: 2026-11-12 06:35

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
14.6k
      : Data(D), Types(S) {}
40
41
14.6k
  Expect<ComponentValVariant> decode(const ComponentValType &Ty) noexcept {
42
14.6k
    EXPECTED_TRY(auto V, decodeVal(Ty));
43
13.7k
    if (Off != Data.size()) {
44
104
      return Unexpect(ErrCode::Value::ComponentMalformedValue);
45
104
    }
46
13.6k
    return V;
47
13.7k
  }
48
49
private:
50
59.1k
  Expect<Byte> readByte() noexcept {
51
59.1k
    if (Off >= Data.size()) {
52
479
      return Unexpect(ErrCode::Value::ComponentMalformedValue);
53
479
    }
54
58.7k
    return Data[Off++];
55
59.1k
  }
56
57
18.0k
  Expect<uint64_t> readULEB(uint32_t MaxBits) noexcept {
58
18.0k
    uint64_t Result = 0;
59
18.0k
    uint32_t Shift = 0;
60
22.4k
    while (true) {
61
22.4k
      EXPECTED_TRY(auto B, readByte());
62
22.1k
      if (Shift + 7 > MaxBits &&
63
160
          (B >> (MaxBits > Shift ? MaxBits - Shift : 0)) != 0) {
64
28
        return Unexpect(ErrCode::Value::ComponentMalformedValue);
65
28
      }
66
22.1k
      Result |= static_cast<uint64_t>(B & 0x7FU) << Shift;
67
22.1k
      if ((B & 0x80U) == 0) {
68
17.7k
        return Result;
69
17.7k
      }
70
4.38k
      Shift += 7;
71
4.38k
      if (Shift >= MaxBits + 7) {
72
0
        return Unexpect(ErrCode::Value::ComponentMalformedValue);
73
0
      }
74
4.38k
    }
75
18.0k
  }
76
77
13.0k
  Expect<int64_t> readSLEB(uint32_t MaxBits) noexcept {
78
13.0k
    uint64_t Result = 0;
79
13.0k
    uint32_t Shift = 0;
80
21.5k
    while (true) {
81
21.5k
      EXPECTED_TRY(auto B, readByte());
82
21.3k
      Result |= static_cast<uint64_t>(B & 0x7FU) << Shift;
83
21.3k
      if ((B & 0x80U) == 0) {
84
        // On the final byte, every bit above the value width repeats the sign.
85
12.9k
        const uint32_t Rest = MaxBits - Shift;
86
12.9k
        if (Rest <= 7) {
87
429
          const uint8_t Mask =
88
429
              static_cast<uint8_t>((0x7FU >> (Rest - 1)) << (Rest - 1));
89
429
          if ((B & Mask) != 0 && (B & Mask) != Mask) {
90
15
            return Unexpect(ErrCode::Value::ComponentMalformedValue);
91
15
          }
92
429
        }
93
12.9k
        Shift += 7;
94
12.9k
        if (Shift < 64 && (B & 0x40U) != 0) {
95
4.21k
          Result |= ~UINT64_C(0) << Shift;
96
4.21k
        }
97
12.9k
        return static_cast<int64_t>(Result);
98
12.9k
      }
99
8.45k
      Shift += 7;
100
8.45k
      if (Shift >= MaxBits) {
101
20
        return Unexpect(ErrCode::Value::ComponentMalformedValue);
102
20
      }
103
8.45k
    }
104
13.0k
  }
105
106
41.4k
  Expect<ComponentValVariant> decodeVal(const ComponentValType &Ty) noexcept {
107
41.4k
    if (Ty.isPrimValType()) {
108
27.8k
      return decodePrim(Ty.getPrimValType());
109
27.8k
    }
110
13.6k
    const auto *Entry = Types.getType(Ty.getTypeIndex());
111
13.6k
    const AST::Component::DefValType *D =
112
13.6k
        Entry != nullptr ? Entry->getDefValType() : nullptr;
113
13.6k
    if (D == nullptr) {
114
0
      return Unexpect(ErrCode::Value::ComponentMalformedValue);
115
0
    }
116
13.6k
    return decodeDef(*D);
117
13.6k
  }
118
119
28.1k
  Expect<ComponentValVariant> decodePrim(PrimValType P) noexcept {
120
28.1k
    switch (P) {
121
393
    case PrimValType::Bool: {
122
393
      EXPECTED_TRY(auto B, readByte());
123
382
      if (B > 1) {
124
15
        return Unexpect(ErrCode::Value::ComponentMalformedValue);
125
15
      }
126
367
      return ComponentValVariant{B != 0};
127
382
    }
128
855
    case PrimValType::U8: {
129
855
      EXPECTED_TRY(auto B, readByte());
130
838
      return ComponentValVariant{static_cast<uint8_t>(B)};
131
855
    }
132
495
    case PrimValType::S8: {
133
495
      EXPECTED_TRY(auto B, readByte());
134
481
      return ComponentValVariant{static_cast<int8_t>(B)};
135
495
    }
136
1.47k
    case PrimValType::U16: {
137
1.47k
      EXPECTED_TRY(auto V, readULEB(16));
138
1.37k
      return ComponentValVariant{static_cast<uint16_t>(V)};
139
1.47k
    }
140
2.03k
    case PrimValType::S16: {
141
2.03k
      EXPECTED_TRY(auto V, readSLEB(16));
142
1.99k
      return ComponentValVariant{static_cast<int16_t>(V)};
143
2.03k
    }
144
5.33k
    case PrimValType::U32: {
145
5.33k
      EXPECTED_TRY(auto V, readULEB(32));
146
5.29k
      return ComponentValVariant{static_cast<uint32_t>(V)};
147
5.33k
    }
148
4.34k
    case PrimValType::S32: {
149
4.34k
      EXPECTED_TRY(auto V, readSLEB(32));
150
4.29k
      return ComponentValVariant{static_cast<int32_t>(V)};
151
4.34k
    }
152
3.30k
    case PrimValType::U64: {
153
3.30k
      EXPECTED_TRY(auto V, readULEB(64));
154
3.28k
      return ComponentValVariant{V};
155
3.30k
    }
156
6.69k
    case PrimValType::S64: {
157
6.69k
      EXPECTED_TRY(auto V, readSLEB(64));
158
6.61k
      return ComponentValVariant{V};
159
6.69k
    }
160
597
    case PrimValType::F32: {
161
597
      uint32_t Bits = 0;
162
2.92k
      for (uint32_t I = 0; I < 4; ++I) {
163
2.34k
        EXPECTED_TRY(auto B, readByte());
164
2.32k
        Bits |= static_cast<uint32_t>(B) << (I * 8);
165
2.32k
      }
166
575
      float F;
167
575
      std::memcpy(&F, &Bits, sizeof(F));
168
575
      if (std::isnan(F) && Bits != UINT32_C(0x7FC00000)) {
169
12
        return Unexpect(ErrCode::Value::ComponentMalformedValue);
170
12
      }
171
563
      return ComponentValVariant{F};
172
575
    }
173
341
    case PrimValType::F64: {
174
341
      uint64_t Bits = 0;
175
2.95k
      for (uint32_t I = 0; I < 8; ++I) {
176
2.63k
        EXPECTED_TRY(auto B, readByte());
177
2.61k
        Bits |= static_cast<uint64_t>(B) << (I * 8);
178
2.61k
      }
179
322
      double D;
180
322
      std::memcpy(&D, &Bits, sizeof(D));
181
322
      if (std::isnan(D) && Bits != UINT64_C(0x7FF8000000000000)) {
182
71
        return Unexpect(ErrCode::Value::ComponentMalformedValue);
183
71
      }
184
251
      return ComponentValVariant{D};
185
322
    }
186
954
    case PrimValType::Char: {
187
954
      EXPECTED_TRY(auto CP, readUtf8Scalar());
188
900
      return ComponentValVariant{CP};
189
954
    }
190
1.35k
    case PrimValType::String: {
191
1.35k
      EXPECTED_TRY(auto Len, readULEB(32));
192
1.32k
      if (Len > Data.size() - Off) {
193
69
        return Unexpect(ErrCode::Value::ComponentMalformedValue);
194
69
      }
195
      // `val(string)` is a `core:name`, so the payload must be valid UTF-8.
196
1.25k
      const size_t Begin = Off;
197
1.25k
      const size_t End = Off + static_cast<size_t>(Len);
198
2.87k
      while (Off < End) {
199
1.65k
        EXPECTED_TRY(readUtf8Scalar());
200
1.65k
      }
201
1.21k
      if (Off != End) {
202
9
        return Unexpect(ErrCode::Value::ComponentMalformedValue);
203
9
      }
204
1.20k
      return ComponentValVariant{std::string(
205
1.20k
          reinterpret_cast<const char *>(Data.data()) + Begin, End - Begin)};
206
1.21k
    }
207
0
    default:
208
0
      return Unexpect(ErrCode::Value::ComponentMalformedValue);
209
28.1k
    }
210
28.1k
  }
211
212
2.61k
  Expect<uint32_t> readUtf8Scalar() noexcept {
213
2.61k
    EXPECTED_TRY(auto B0, readByte());
214
2.59k
    uint32_t CP = 0;
215
2.59k
    uint32_t Tail = 0;
216
    // The smallest scalar the sequence length is allowed to encode.
217
2.59k
    uint32_t Least = 0;
218
2.59k
    if (B0 < 0x80U) {
219
1.62k
      return static_cast<uint32_t>(B0);
220
1.62k
    }
221
974
    if ((B0 & 0xE0U) == 0xC0U) {
222
213
      CP = B0 & 0x1FU;
223
213
      Tail = 1;
224
213
      Least = 0x80U;
225
761
    } else if ((B0 & 0xF0U) == 0xE0U) {
226
634
      CP = B0 & 0x0FU;
227
634
      Tail = 2;
228
634
      Least = 0x800U;
229
634
    } else if ((B0 & 0xF8U) == 0xF0U) {
230
106
      CP = B0 & 0x07U;
231
106
      Tail = 3;
232
106
      Least = 0x10000U;
233
106
    } else {
234
21
      return Unexpect(ErrCode::Value::ComponentMalformedValue);
235
21
    }
236
2.66k
    for (uint32_t I = 0; I < Tail; ++I) {
237
1.76k
      EXPECTED_TRY(auto B, readByte());
238
1.73k
      if ((B & 0xC0U) != 0x80U) {
239
22
        return Unexpect(ErrCode::Value::ComponentMalformedValue);
240
22
      }
241
1.71k
      CP = (CP << 6) | (B & 0x3FU);
242
1.71k
    }
243
    // Reject overlong encodings, surrogates, and out-of-range scalars.
244
905
    if (CP < Least || CP >= 0x110000U || (CP >= 0xD800U && CP <= 0xDFFFU)) {
245
18
      return Unexpect(ErrCode::Value::ComponentMalformedValue);
246
18
    }
247
887
    return CP;
248
905
  }
249
250
  Expect<ComponentValVariant>
251
13.6k
  decodeDef(const AST::Component::DefValType &D) noexcept {
252
13.6k
    if (D.isPrimValType()) {
253
358
      return decodePrim(D.getPrimValType());
254
358
    }
255
13.2k
    if (D.isRecordTy()) {
256
1.34k
      RecordVal R;
257
1.34k
      for (const auto &LT : D.getRecord().LabelTypes) {
258
1.34k
        EXPECTED_TRY(auto V, decodeVal(LT.getValType()));
259
1.34k
        R.Fields.emplace_back(std::string(LT.getLabel()), std::move(V));
260
1.34k
      }
261
1.34k
      return makeComponentVal(std::move(R));
262
1.34k
    }
263
11.9k
    if (D.isVariantTy()) {
264
1.63k
      const auto &Cases = D.getVariant().Cases;
265
1.63k
      EXPECTED_TRY(auto Idx, readULEB(32));
266
1.61k
      if (Idx >= Cases.size()) {
267
42
        return Unexpect(ErrCode::Value::ComponentMalformedValue);
268
42
      }
269
1.57k
      VariantVal V;
270
1.57k
      V.Case = static_cast<uint32_t>(Idx);
271
1.57k
      V.Label = Cases[V.Case].first;
272
1.57k
      if (Cases[V.Case].second.has_value()) {
273
1.50k
        EXPECTED_TRY(auto P, decodeVal(*Cases[V.Case].second));
274
1.48k
        V.Payload = std::move(P);
275
1.48k
      }
276
1.55k
      return makeComponentVal(std::move(V));
277
1.57k
    }
278
10.3k
    if (D.isListTy()) {
279
1.37k
      const auto &L = D.getList();
280
1.37k
      ListVal LV;
281
1.37k
      uint64_t Count = 0;
282
1.37k
      if (L.Len.has_value()) {
283
851
        Count = *L.Len;
284
851
      } else {
285
524
        EXPECTED_TRY(Count, readULEB(32));
286
515
      }
287
7.73k
      for (uint64_t I = 0; I < Count; ++I) {
288
6.58k
        EXPECTED_TRY(auto V, decodeVal(L.ValTy));
289
6.36k
        LV.Elements.push_back(std::move(V));
290
6.36k
      }
291
1.14k
      return makeComponentVal(std::move(LV));
292
1.36k
    }
293
8.92k
    if (D.isMapTy()) {
294
      // (map k v) decodes like (list (tuple k v)).
295
4.06k
      ListVal LV;
296
4.06k
      EXPECTED_TRY(auto Count, readULEB(32));
297
10.8k
      for (uint64_t I = 0; I < Count; ++I) {
298
7.01k
        TupleVal Entry;
299
7.01k
        EXPECTED_TRY(auto K, decodeVal(D.getMap().KeyTy));
300
6.89k
        Entry.Values.push_back(std::move(K));
301
6.89k
        EXPECTED_TRY(auto V, decodeVal(D.getMap().ValTy));
302
6.82k
        Entry.Values.push_back(std::move(V));
303
6.82k
        LV.Elements.push_back(makeComponentVal(std::move(Entry)));
304
6.82k
      }
305
3.85k
      return makeComponentVal(std::move(LV));
306
4.04k
    }
307
4.86k
    if (D.isTupleTy()) {
308
361
      TupleVal T;
309
549
      for (const auto &Ty : D.getTuple().Types) {
310
549
        EXPECTED_TRY(auto V, decodeVal(Ty));
311
518
        T.Values.push_back(std::move(V));
312
518
      }
313
330
      return makeComponentVal(std::move(T));
314
361
    }
315
4.50k
    if (D.isFlagsTy()) {
316
835
      const auto &Labels = D.getFlags().Labels;
317
835
      FlagsVal F;
318
835
      F.Bits.resize(Labels.size(), false);
319
835
      const size_t Bytes = (Labels.size() + 7) / 8;
320
1.66k
      for (size_t I = 0; I < Bytes; ++I) {
321
835
        EXPECTED_TRY(auto B, readByte());
322
7.50k
        for (size_t Bit = 0; Bit < 8; ++Bit) {
323
6.67k
          const size_t Pos = I * 8 + Bit;
324
6.67k
          if (Pos < Labels.size() && (B & (1U << Bit)) != 0) {
325
603
            F.Bits[Pos] = true;
326
603
          }
327
6.67k
        }
328
834
      }
329
834
      return makeComponentVal(std::move(F));
330
835
    }
331
3.66k
    if (D.isEnumTy()) {
332
320
      const auto &Labels = D.getEnum().Labels;
333
320
      EXPECTED_TRY(auto Idx, readULEB(32));
334
315
      if (Idx >= Labels.size()) {
335
25
        return Unexpect(ErrCode::Value::ComponentMalformedValue);
336
25
      }
337
290
      return makeComponentVal(EnumVal{static_cast<uint32_t>(Idx), Labels[Idx]});
338
315
    }
339
3.34k
    if (D.isOptionTy()) {
340
2.62k
      EXPECTED_TRY(auto Disc, readByte());
341
2.62k
      OptionVal O;
342
2.62k
      if (Disc == 1) {
343
2.54k
        EXPECTED_TRY(auto V, decodeVal(D.getOption().ValTy));
344
2.53k
        O.Value = std::move(V);
345
2.53k
      } else if (Disc != 0) {
346
3
        return Unexpect(ErrCode::Value::ComponentMalformedValue);
347
3
      }
348
2.60k
      return makeComponentVal(std::move(O));
349
2.62k
    }
350
719
    if (D.isResultTy()) {
351
719
      EXPECTED_TRY(auto Disc, readByte());
352
717
      if (Disc > 1) {
353
3
        return Unexpect(ErrCode::Value::ComponentMalformedValue);
354
3
      }
355
714
      ResultVal R;
356
714
      R.IsOk = (Disc == 0);
357
714
      const auto &PT = R.IsOk ? D.getResult().ValTy : D.getResult().ErrTy;
358
714
      if (PT.has_value()) {
359
394
        EXPECTED_TRY(auto V, decodeVal(*PT));
360
389
        R.Payload = std::move(V);
361
389
      }
362
709
      return makeComponentVal(std::move(R));
363
714
    }
364
    // Handles, streams, and futures cannot appear in value definitions.
365
0
    return Unexpect(ErrCode::Value::ComponentMalformedValue);
366
719
  }
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