Coverage Report

Created: 2026-09-28 06:22

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/errcode.h"
21
#include "common/types.h"
22
#include "validator/component_types.h"
23
24
#include <cmath>
25
#include <cstring>
26
#include <string>
27
#include <utility>
28
29
namespace WasmEdge {
30
namespace Validator {
31
namespace Component {
32
33
/// Decoder over one value definition's payload, resolving types in its scope.
34
class ValueDecoder {
35
public:
36
  ValueDecoder(Span<const Byte> D, const Scope &S) noexcept
37
13.7k
      : Data(D), Types(S) {}
38
39
13.7k
  Expect<ComponentValVariant> decode(const ComponentValType &Ty) noexcept {
40
13.7k
    EXPECTED_TRY(auto V, decodeVal(Ty));
41
13.0k
    if (Off != Data.size()) {
42
90
      return Unexpect(ErrCode::Value::ComponentMalformedValue);
43
90
    }
44
12.9k
    return V;
45
13.0k
  }
46
47
private:
48
37.7k
  Expect<Byte> readByte() noexcept {
49
37.7k
    if (Off >= Data.size()) {
50
319
      return Unexpect(ErrCode::Value::ComponentMalformedValue);
51
319
    }
52
37.4k
    return Data[Off++];
53
37.7k
  }
54
55
14.6k
  Expect<uint64_t> readULEB(uint32_t MaxBits) noexcept {
56
14.6k
    uint64_t Result = 0;
57
14.6k
    uint32_t Shift = 0;
58
17.3k
    while (true) {
59
17.3k
      EXPECTED_TRY(auto B, readByte());
60
17.2k
      if (Shift + 7 > MaxBits &&
61
116
          (B >> (MaxBits > Shift ? MaxBits - Shift : 0)) != 0) {
62
22
        return Unexpect(ErrCode::Value::ComponentMalformedValue);
63
22
      }
64
17.1k
      Result |= static_cast<uint64_t>(B & 0x7FU) << Shift;
65
17.1k
      if ((B & 0x80U) == 0) {
66
14.4k
        return Result;
67
14.4k
      }
68
2.74k
      Shift += 7;
69
2.74k
      if (Shift >= MaxBits + 7) {
70
0
        return Unexpect(ErrCode::Value::ComponentMalformedValue);
71
0
      }
72
2.74k
    }
73
14.6k
  }
74
75
5.53k
  Expect<int64_t> readSLEB(uint32_t MaxBits) noexcept {
76
5.53k
    uint64_t Result = 0;
77
5.53k
    uint32_t Shift = 0;
78
9.27k
    while (true) {
79
9.27k
      EXPECTED_TRY(auto B, readByte());
80
9.18k
      Result |= static_cast<uint64_t>(B & 0x7FU) << Shift;
81
9.18k
      if ((B & 0x80U) == 0) {
82
        // On the final byte, every bit above the value width repeats the sign.
83
5.43k
        const uint32_t Rest = MaxBits - Shift;
84
5.43k
        if (Rest <= 7) {
85
264
          const uint8_t Mask =
86
264
              static_cast<uint8_t>((0x7FU >> (Rest - 1)) << (Rest - 1));
87
264
          if ((B & Mask) != 0 && (B & Mask) != Mask) {
88
12
            return Unexpect(ErrCode::Value::ComponentMalformedValue);
89
12
          }
90
264
        }
91
5.42k
        Shift += 7;
92
5.42k
        if (Shift < 64 && (B & 0x40U) != 0) {
93
1.56k
          Result |= ~UINT64_C(0) << Shift;
94
1.56k
        }
95
5.42k
        return static_cast<int64_t>(Result);
96
5.43k
      }
97
3.74k
      Shift += 7;
98
3.74k
      if (Shift >= MaxBits) {
99
8
        return Unexpect(ErrCode::Value::ComponentMalformedValue);
100
8
      }
101
3.74k
    }
102
5.53k
  }
103
104
29.8k
  Expect<ComponentValVariant> decodeVal(const ComponentValType &Ty) noexcept {
105
29.8k
    if (Ty.isPrimValType()) {
106
16.8k
      return decodePrim(static_cast<AST::Component::PrimValType>(Ty.getCode()));
107
16.8k
    }
108
13.0k
    const auto *Entry = Types.getType(Ty.getTypeIndex());
109
13.0k
    const AST::Component::DefValType *D =
110
13.0k
        Entry != nullptr ? Entry->getDefValType() : nullptr;
111
13.0k
    if (D == nullptr) {
112
0
      return Unexpect(ErrCode::Value::ComponentMalformedValue);
113
0
    }
114
13.0k
    return decodeDef(*D);
115
13.0k
  }
116
117
  Expect<ComponentValVariant>
118
17.0k
  decodePrim(AST::Component::PrimValType P) noexcept {
119
17.0k
    switch (P) {
120
275
    case AST::Component::PrimValType::Bool: {
121
275
      EXPECTED_TRY(auto B, readByte());
122
264
      if (B > 1) {
123
8
        return Unexpect(ErrCode::Value::ComponentMalformedValue);
124
8
      }
125
256
      return ComponentValVariant{B != 0};
126
264
    }
127
350
    case AST::Component::PrimValType::U8: {
128
350
      EXPECTED_TRY(auto B, readByte());
129
344
      return ComponentValVariant{static_cast<uint8_t>(B)};
130
350
    }
131
659
    case AST::Component::PrimValType::S8: {
132
659
      EXPECTED_TRY(auto B, readByte());
133
643
      return ComponentValVariant{static_cast<int8_t>(B)};
134
659
    }
135
1.16k
    case AST::Component::PrimValType::U16: {
136
1.16k
      EXPECTED_TRY(auto V, readULEB(16));
137
1.13k
      return ComponentValVariant{static_cast<uint16_t>(V)};
138
1.16k
    }
139
2.44k
    case AST::Component::PrimValType::S16: {
140
2.44k
      EXPECTED_TRY(auto V, readSLEB(16));
141
2.41k
      return ComponentValVariant{static_cast<int16_t>(V)};
142
2.44k
    }
143
2.33k
    case AST::Component::PrimValType::U32: {
144
2.33k
      EXPECTED_TRY(auto V, readULEB(32));
145
2.29k
      return ComponentValVariant{static_cast<uint32_t>(V)};
146
2.33k
    }
147
816
    case AST::Component::PrimValType::S32: {
148
816
      EXPECTED_TRY(auto V, readSLEB(32));
149
780
      return ComponentValVariant{static_cast<int32_t>(V)};
150
816
    }
151
4.59k
    case AST::Component::PrimValType::U64: {
152
4.59k
      EXPECTED_TRY(auto V, readULEB(64));
153
4.58k
      return ComponentValVariant{V};
154
4.59k
    }
155
2.27k
    case AST::Component::PrimValType::S64: {
156
2.27k
      EXPECTED_TRY(auto V, readSLEB(64));
157
2.22k
      return ComponentValVariant{V};
158
2.27k
    }
159
61
    case AST::Component::PrimValType::F32: {
160
61
      uint32_t Bits = 0;
161
274
      for (uint32_t I = 0; I < 4; ++I) {
162
225
        EXPECTED_TRY(auto B, readByte());
163
213
        Bits |= static_cast<uint32_t>(B) << (I * 8);
164
213
      }
165
49
      float F;
166
49
      std::memcpy(&F, &Bits, sizeof(F));
167
49
      if (std::isnan(F) && Bits != UINT32_C(0x7FC00000)) {
168
23
        return Unexpect(ErrCode::Value::ComponentMalformedValue);
169
23
      }
170
26
      return ComponentValVariant{F};
171
49
    }
172
297
    case AST::Component::PrimValType::F64: {
173
297
      uint64_t Bits = 0;
174
2.58k
      for (uint32_t I = 0; I < 8; ++I) {
175
2.30k
        EXPECTED_TRY(auto B, readByte());
176
2.28k
        Bits |= static_cast<uint64_t>(B) << (I * 8);
177
2.28k
      }
178
280
      double D;
179
280
      std::memcpy(&D, &Bits, sizeof(D));
180
280
      if (std::isnan(D) && Bits != UINT64_C(0x7FF8000000000000)) {
181
69
        return Unexpect(ErrCode::Value::ComponentMalformedValue);
182
69
      }
183
211
      return ComponentValVariant{D};
184
280
    }
185
531
    case AST::Component::PrimValType::Char: {
186
531
      EXPECTED_TRY(auto CP, readUtf8Scalar());
187
483
      return ComponentValVariant{CP};
188
531
    }
189
1.24k
    case AST::Component::PrimValType::String: {
190
1.24k
      EXPECTED_TRY(auto Len, readULEB(32));
191
1.21k
      if (Len > Data.size() - Off) {
192
51
        return Unexpect(ErrCode::Value::ComponentMalformedValue);
193
51
      }
194
      // `val(string)` is a `core:name`, so the payload must be valid UTF-8.
195
1.16k
      const size_t Begin = Off;
196
1.16k
      const size_t End = Off + static_cast<size_t>(Len);
197
2.63k
      while (Off < End) {
198
1.50k
        EXPECTED_TRY(readUtf8Scalar());
199
1.50k
      }
200
1.13k
      if (Off != End) {
201
5
        return Unexpect(ErrCode::Value::ComponentMalformedValue);
202
5
      }
203
1.12k
      return ComponentValVariant{std::string(
204
1.12k
          reinterpret_cast<const char *>(Data.data()) + Begin, End - Begin)};
205
1.13k
    }
206
5
    default:
207
5
      return Unexpect(ErrCode::Value::ComponentMalformedValue);
208
17.0k
    }
209
17.0k
  }
210
211
2.03k
  Expect<uint32_t> readUtf8Scalar() noexcept {
212
2.03k
    EXPECTED_TRY(auto B0, readByte());
213
2.02k
    uint32_t CP = 0;
214
2.02k
    uint32_t Tail = 0;
215
    // The smallest scalar the sequence length is allowed to encode.
216
2.02k
    uint32_t Least = 0;
217
2.02k
    if (B0 < 0x80U) {
218
1.72k
      return static_cast<uint32_t>(B0);
219
1.72k
    }
220
296
    if ((B0 & 0xE0U) == 0xC0U) {
221
113
      CP = B0 & 0x1FU;
222
113
      Tail = 1;
223
113
      Least = 0x80U;
224
183
    } else if ((B0 & 0xF0U) == 0xE0U) {
225
65
      CP = B0 & 0x0FU;
226
65
      Tail = 2;
227
65
      Least = 0x800U;
228
118
    } else if ((B0 & 0xF8U) == 0xF0U) {
229
101
      CP = B0 & 0x07U;
230
101
      Tail = 3;
231
101
      Least = 0x10000U;
232
101
    } else {
233
17
      return Unexpect(ErrCode::Value::ComponentMalformedValue);
234
17
    }
235
776
    for (uint32_t I = 0; I < Tail; ++I) {
236
534
      EXPECTED_TRY(auto B, readByte());
237
514
      if ((B & 0xC0U) != 0x80U) {
238
17
        return Unexpect(ErrCode::Value::ComponentMalformedValue);
239
17
      }
240
497
      CP = (CP << 6) | (B & 0x3FU);
241
497
    }
242
    // Reject overlong encodings, surrogates, and out-of-range scalars.
243
242
    if (CP < Least || CP >= 0x110000U || (CP >= 0xD800U && CP <= 0xDFFFU)) {
244
18
      return Unexpect(ErrCode::Value::ComponentMalformedValue);
245
18
    }
246
224
    return CP;
247
242
  }
248
249
  Expect<ComponentValVariant>
250
13.0k
  decodeDef(const AST::Component::DefValType &D) noexcept {
251
13.0k
    if (D.isPrimValType()) {
252
212
      return decodePrim(D.getPrimValType());
253
212
    }
254
12.7k
    if (D.isRecordTy()) {
255
2.31k
      RecordVal R;
256
2.31k
      for (const auto &LT : D.getRecord().LabelTypes) {
257
2.31k
        EXPECTED_TRY(auto V, decodeVal(LT.getValType()));
258
2.30k
        R.Fields.emplace_back(std::string(LT.getLabel()), std::move(V));
259
2.30k
      }
260
2.30k
      return makeComponentVal(std::move(R));
261
2.31k
    }
262
10.4k
    if (D.isVariantTy()) {
263
3.34k
      const auto &Cases = D.getVariant().Cases;
264
3.34k
      EXPECTED_TRY(auto Idx, readULEB(32));
265
3.33k
      if (Idx >= Cases.size()) {
266
62
        return Unexpect(ErrCode::Value::ComponentMalformedValue);
267
62
      }
268
3.26k
      VariantVal V;
269
3.26k
      V.Case = static_cast<uint32_t>(Idx);
270
3.26k
      V.Label = Cases[V.Case].first;
271
3.26k
      if (Cases[V.Case].second.has_value()) {
272
3.07k
        EXPECTED_TRY(auto P, decodeVal(*Cases[V.Case].second));
273
3.05k
        V.Payload = std::move(P);
274
3.05k
      }
275
3.25k
      return makeComponentVal(std::move(V));
276
3.26k
    }
277
7.13k
    if (D.isListTy()) {
278
362
      const auto &L = D.getList();
279
362
      ListVal LV;
280
362
      uint64_t Count = 0;
281
362
      if (L.Len.has_value()) {
282
315
        Count = *L.Len;
283
315
      } else {
284
47
        EXPECTED_TRY(Count, readULEB(32));
285
40
      }
286
2.17k
      for (uint64_t I = 0; I < Count; ++I) {
287
1.94k
        EXPECTED_TRY(auto V, decodeVal(L.ValTy));
288
1.81k
        LV.Elements.push_back(std::move(V));
289
1.81k
      }
290
227
      return makeComponentVal(std::move(LV));
291
355
    }
292
6.77k
    if (D.isMapTy()) {
293
      // (map k v) decodes like (list (tuple k v)).
294
1.51k
      ListVal LV;
295
1.51k
      EXPECTED_TRY(auto Count, readULEB(32));
296
3.75k
      for (uint64_t I = 0; I < Count; ++I) {
297
2.40k
        TupleVal Entry;
298
2.40k
        EXPECTED_TRY(auto K, decodeVal(D.getMap().KeyTy));
299
2.34k
        Entry.Values.push_back(std::move(K));
300
2.34k
        EXPECTED_TRY(auto V, decodeVal(D.getMap().ValTy));
301
2.26k
        Entry.Values.push_back(std::move(V));
302
2.26k
        LV.Elements.push_back(makeComponentVal(std::move(Entry)));
303
2.26k
      }
304
1.35k
      return makeComponentVal(std::move(LV));
305
1.49k
    }
306
5.26k
    if (D.isTupleTy()) {
307
178
      TupleVal T;
308
204
      for (const auto &Ty : D.getTuple().Types) {
309
204
        EXPECTED_TRY(auto V, decodeVal(Ty));
310
181
        T.Values.push_back(std::move(V));
311
181
      }
312
155
      return makeComponentVal(std::move(T));
313
178
    }
314
5.08k
    if (D.isFlagsTy()) {
315
407
      const auto &Labels = D.getFlags().Labels;
316
407
      FlagsVal F;
317
407
      F.Bits.resize(Labels.size(), false);
318
407
      const size_t Bytes = (Labels.size() + 7) / 8;
319
813
      for (size_t I = 0; I < Bytes; ++I) {
320
407
        EXPECTED_TRY(auto B, readByte());
321
3.65k
        for (size_t Bit = 0; Bit < 8; ++Bit) {
322
3.24k
          const size_t Pos = I * 8 + Bit;
323
3.24k
          if (Pos < Labels.size() && (B & (1U << Bit)) != 0) {
324
443
            F.Bits[Pos] = true;
325
443
          }
326
3.24k
        }
327
406
      }
328
406
      return makeComponentVal(std::move(F));
329
407
    }
330
4.67k
    if (D.isEnumTy()) {
331
362
      const auto &Labels = D.getEnum().Labels;
332
362
      EXPECTED_TRY(auto Idx, readULEB(32));
333
359
      if (Idx >= Labels.size()) {
334
31
        return Unexpect(ErrCode::Value::ComponentMalformedValue);
335
31
      }
336
328
      return makeComponentVal(EnumVal{static_cast<uint32_t>(Idx), Labels[Idx]});
337
359
    }
338
4.31k
    if (D.isOptionTy()) {
339
3.90k
      EXPECTED_TRY(auto Disc, readByte());
340
3.89k
      OptionVal O;
341
3.89k
      if (Disc == 1) {
342
3.56k
        EXPECTED_TRY(auto V, decodeVal(D.getOption().ValTy));
343
3.56k
        O.Value = std::move(V);
344
3.56k
      } else if (Disc != 0) {
345
14
        return Unexpect(ErrCode::Value::ComponentMalformedValue);
346
14
      }
347
3.88k
      return makeComponentVal(std::move(O));
348
3.89k
    }
349
413
    if (D.isResultTy()) {
350
407
      EXPECTED_TRY(auto Disc, readByte());
351
405
      if (Disc > 1) {
352
15
        return Unexpect(ErrCode::Value::ComponentMalformedValue);
353
15
      }
354
390
      ResultVal R;
355
390
      R.IsOk = (Disc == 0);
356
390
      const auto &PT = R.IsOk ? D.getResult().ValTy : D.getResult().ErrTy;
357
390
      if (PT.has_value()) {
358
201
        EXPECTED_TRY(auto V, decodeVal(*PT));
359
196
        R.Payload = std::move(V);
360
196
      }
361
385
      return makeComponentVal(std::move(R));
362
390
    }
363
    // Handles, streams, and futures cannot appear in value definitions.
364
6
    return Unexpect(ErrCode::Value::ComponentMalformedValue);
365
413
  }
366
367
  Span<const Byte> Data;
368
  const Scope &Types;
369
  size_t Off = 0;
370
};
371
372
} // namespace Component
373
} // namespace Validator
374
} // namespace WasmEdge