Coverage Report

Created: 2026-10-17 06:58

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wasm3/platforms/app_fuzz/fuzzer.c
Line
Count
Source
1
//
2
//  Wasm3 - high performance WebAssembly interpreter written in C.
3
//
4
//  Copyright © 2019 Steven Massey, Volodymyr Shymanskyy.
5
//  All rights reserved.
6
//
7
8
#include <stdint.h>
9
#include <stddef.h>
10
11
#include "wasm3.h"
12
#include "m3_env.h"    // for IM3Runtime::memoryLimit
13
14
#define FATAL(...) __builtin_trap()
15
16
// A module may declare up to 4 GiB of linear memory, and wasm3 allocates the
17
// initial pages eagerly at load, so a handful of bytes can ask for more than
18
// the fuzzing engine allows and get killed as an OOM rather than exercising
19
// anything. Cap what is actually allocated: memory accesses and data segment
20
// loads are bounded by the allocated length, not the declared page count.
21
33.5k
#define d_m3FuzzMemoryLimit  (4*1024*1024)
22
23
// A table element is a pointer, so 1M of them are 8 MiB on a 64-bit host: the same
24
// order as the memory budget, and far below what d_m3MaxSaneTableSize allows.
25
33.5k
#define d_m3FuzzTableLimit   (1024*1024)
26
27
// Nothing stops a few fuzzed bytes from describing a loop that never ends.
28
// Fuzzer timeout is an error => let's use gas metering to limit the number
29
// of instructions that can run.
30
33.5k
#define d_m3FuzzGasLimit     (1000 * M3_GAS_UNITS_PER_GAS)
31
32
// Each active continuation holds a value stack of 8 KiB, so 256 of them are 2 MiB.
33
33.5k
#define d_m3FuzzContinuationLimit  256
34
35
int LLVMFuzzerTestOneInput (const uint8_t* data, size_t size)
36
33.5k
{
37
33.5k
    M3Result result = m3Err_none;
38
39
33.5k
    if (size < 8 || size > 256 * 1024) {
40
4
        return 0;
41
4
    }
42
43
33.5k
    IM3Environment env = m3_NewEnvironment();
44
33.5k
    if (env) {
45
33.5k
        IM3Runtime runtime = m3_NewRuntime(env, 4096, NULL);
46
33.5k
        if (runtime) {
47
33.5k
            IM3Module module = NULL;
48
49
33.5k
            runtime->memoryLimit = d_m3FuzzMemoryLimit;
50
51
33.5k
            const struct {
52
33.5k
                M3ResourceLimit limit;
53
33.5k
                uint64_t        value;
54
33.5k
            } limits[] = {
55
33.5k
                { c_m3Limit_TableElements, d_m3FuzzTableLimit        },
56
33.5k
                { c_m3Limit_GasUnits,      d_m3FuzzGasLimit          },
57
33.5k
                { c_m3Limit_Continuations, d_m3FuzzContinuationLimit },
58
33.5k
            };
59
134k
            for (unsigned i = 0; i < sizeof(limits) / sizeof(limits[0]); ++i) {
60
100k
                result = m3_SetResourceLimit(runtime, limits[i].limit, limits[i].value);
61
100k
                if (result && result != m3Err_resourceLimitNotSupported) {
62
0
                    m3_FreeRuntime(runtime);
63
0
                    m3_FreeEnvironment(env);
64
0
                    return 0;
65
0
                }
66
100k
            }
67
68
33.5k
            result = m3_ParseModule(env, &module, data, size);
69
33.5k
            if (module) {
70
28.8k
                result = m3_LoadModule(runtime, module);
71
28.8k
                if (result == 0) {
72
28.2k
                    IM3Function f = NULL;
73
74
28.2k
                    result = m3_FindFunction(&f, runtime, "fib");
75
28.2k
                    if (f) {
76
23.8k
                        if (m3_GetArgCount(f) == 1 && m3_GetArgType(f, 0) == c_m3Type_i32) {
77
22
                            m3_CallV(f, 10);
78
23.7k
                        } else if (m3_GetArgCount(f) == 0) {
79
23.5k
                            m3_CallV(f);
80
23.5k
                        }
81
23.8k
                    }
82
28.2k
                }
83
                // on failure too, the runtime owns the module now
84
28.8k
            }
85
86
33.5k
            m3_FreeRuntime(runtime);
87
33.5k
        }
88
33.5k
        m3_FreeEnvironment(env);
89
33.5k
    }
90
91
33.5k
    return 0;
92
33.5k
}