Coverage Report

Created: 2026-09-14 06:54

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
1.89k
#define FUZZ_MAX_INPUT (1024 * 64)
17
9.47k
#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
2
{
24
2
    fuzz_init_r();
25
26
2
    SEXP sym_as_numeric   = Rf_install("as.numeric");
27
2
    SEXP sym_as_complex   = Rf_install("as.complex");
28
2
    SEXP sym_as_logical   = Rf_install("as.logical");
29
2
    SEXP sym_type_convert = Rf_install("type.convert");
30
31
2
    SEXP true_val;
32
2
    Rf_protect(true_val = Rf_ScalarLogical(TRUE));
33
34
    /* Pre-build reusable string container and all call objects. */
35
2
    Rf_protect(x_str = Rf_allocVector(STRSXP, 1));
36
37
    /* as.numeric(x) -- exercises R_strtod4 */
38
2
    Rf_protect(calls[0] = Rf_lang2(sym_as_numeric, x_str));
39
40
    /* as.complex(x) -- exercises complex number parsing (a+bi) */
41
2
    Rf_protect(calls[1] = Rf_lang2(sym_as_complex, x_str));
42
43
    /* as.logical(x) -- exercises logical string matching */
44
2
    Rf_protect(calls[2] = Rf_lang2(sym_as_logical, x_str));
45
46
    /* type.convert(x, as.is=TRUE) -- auto-detection heuristic */
47
2
    Rf_protect(calls[3] = Rf_lang3(sym_type_convert, x_str, true_val));
48
2
    SET_TAG(CDDR(calls[3]), Rf_install("as.is"));
49
50
    /* Warmup: prime coercion code paths. */
51
2
    {
52
2
        int error = 0;
53
2
        SET_STRING_ELT(x_str, 0, Rf_mkChar("1"));
54
10
        for (int i = 0; i < N_CALLS; i++) {
55
8
            R_tryEval(calls[i], R_GlobalEnv, &error);
56
8
            error = 0;
57
8
        }
58
2
    }
59
60
2
    return 0;
61
2
}
62
63
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
64
1.89k
{
65
1.89k
    if (size == 0 || size > FUZZ_MAX_INPUT)
66
7
        return 0;
67
68
1.89k
    char buf[FUZZ_MAX_INPUT + 1];
69
1.89k
    memcpy(buf, data, size);
70
1.89k
    buf[size] = '\0';
71
72
1.89k
    if (!fuzz_set_string(x_str, buf))
73
0
        return 0;
74
75
1.89k
    fuzz_eval_data_t ed = { .env = R_GlobalEnv };
76
9.46k
    for (int i = 0; i < N_CALLS; i++) {
77
7.56k
        ed.call = calls[i];
78
7.56k
        R_ToplevelExec(fuzz_do_eval, &ed);
79
7.56k
    }
80
81
1.89k
    return 0;
82
1.89k
}