Coverage Report

Created: 2026-09-14 06:56

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/r-oss-fuzz/harnesses/coerce.c
Line
Count
Source
1
/*
2
 * libFuzzer harness for R's type coercion / string-to-X parsing.
3
 *
4
 * Passes fuzzed input as a character string through R's type conversion
5
 * functions: as.numeric (R_strtod4), as.complex (complex number parsing),
6
 * as.logical, and type.convert (auto-detection).
7
 *
8
 * Adapted from r-afl's coerce harness.
9
 */
10
11
#include <stdint.h>
12
#include <string.h>
13
14
#include "common.h"
15
16
5.96k
#define FUZZ_MAX_INPUT (1024 * 64)
17
38.9k
#define N_CALLS 4
18
19
static SEXP x_str;
20
static SEXP calls[N_CALLS];
21
22
int LLVMFuzzerInitialize(int *argc, char ***argv)
23
4
{
24
4
    fuzz_init_r();
25
26
4
    SEXP sym_as_numeric   = Rf_install("as.numeric");
27
4
    SEXP sym_as_complex   = Rf_install("as.complex");
28
4
    SEXP sym_as_logical   = Rf_install("as.logical");
29
4
    SEXP sym_type_convert = Rf_install("type.convert");
30
31
4
    SEXP true_val;
32
4
    Rf_protect(true_val = Rf_ScalarLogical(TRUE));
33
34
    /* Pre-build reusable string container and all call objects. */
35
4
    Rf_protect(x_str = Rf_allocVector(STRSXP, 1));
36
37
    /* as.numeric(x) -- exercises R_strtod4 */
38
4
    Rf_protect(calls[0] = Rf_lang2(sym_as_numeric, x_str));
39
40
    /* as.complex(x) -- exercises complex number parsing (a+bi) */
41
4
    Rf_protect(calls[1] = Rf_lang2(sym_as_complex, x_str));
42
43
    /* as.logical(x) -- exercises logical string matching */
44
4
    Rf_protect(calls[2] = Rf_lang2(sym_as_logical, x_str));
45
46
    /* type.convert(x, as.is=TRUE) -- auto-detection heuristic */
47
4
    Rf_protect(calls[3] = Rf_lang3(sym_type_convert, x_str, true_val));
48
4
    SET_TAG(CDDR(calls[3]), Rf_install("as.is"));
49
50
    /* Warmup: prime coercion code paths. */
51
4
    {
52
4
        int error = 0;
53
4
        SET_STRING_ELT(x_str, 0, Rf_mkChar("1"));
54
20
        for (int i = 0; i < N_CALLS; i++) {
55
16
            R_tryEval(calls[i], R_GlobalEnv, &error);
56
16
            error = 0;
57
16
        }
58
4
    }
59
60
4
    return 0;
61
4
}
62
63
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
64
5.96k
{
65
5.96k
    if (size == 0 || size > FUZZ_MAX_INPUT)
66
17
        return 0;
67
68
5.94k
    char buf[FUZZ_MAX_INPUT + 1];
69
5.94k
    memcpy(buf, data, size);
70
5.94k
    buf[size] = '\0';
71
72
5.94k
    if (!fuzz_set_string(x_str, buf))
73
0
        return 0;
74
75
5.94k
    fuzz_eval_data_t ed = { .env = R_GlobalEnv };
76
38.9k
    for (int i = 0; i < N_CALLS; i++) {
77
32.9k
        ed.call = calls[i];
78
32.9k
        R_ToplevelExec(fuzz_do_eval, &ed);
79
32.9k
    }
80
81
5.94k
    return 0;
82
5.94k
}