Coverage Report

Created: 2026-10-28 06:40

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/r-oss-fuzz/harnesses/common.h
Line
Count
Source
1
/*
2
 * Shared helpers for R fuzzing harnesses (libFuzzer).
3
 *
4
 * Provides:
5
 *   fuzz_suppress_warnings() - Suppress R warnings to avoid buffer overflow
6
 *   fuzz_run_on_r_thread()   - Run a function on the R thread (1 GiB stack)
7
 *   fuzz_init_r()            - Full R initialization sequence
8
 *   fuzz_set_string()        - Stage a string input under a toplevel context
9
 *   fuzz_set_string_ce()     - Stage a string with an explicit encoding mark
10
 *   fuzz_set_raw_arg()       - Stage a raw-vector input likewise
11
 *   fuzz_make_wrapper()      - Parse an R closure that implements a call slot
12
 *   fuzz_scratch_file()      - Per-process temp file for path-only entry points
13
 *   fuzz_write_scratch()     - Rewrite that file with the current input
14
 *   fuzz_repeat_product_excessive() - Guard against TRE repeat blowup
15
 *   LLVMFuzzerInitialize / LLVMFuzzerTestOneInput - forward to the
16
 *       harness's fuzz_target_init / fuzz_target_run on the R thread
17
 *
18
 * Adapted from r-afl's fuzz.h for use with libFuzzer instead of AFL++.
19
 */
20
21
#ifndef FUZZ_COMMON_H
22
#define FUZZ_COMMON_H
23
24
#include <limits.h>
25
#include <pthread.h>
26
#include <signal.h>
27
#include <stdint.h>
28
#include <stdio.h>
29
#include <stdlib.h>
30
#include <string.h>
31
#include <unistd.h>
32
33
#define R_NO_REMAP 1
34
#include <Rembedded.h>
35
#include <Rinternals.h>
36
#define CSTACK_DEFNS 1    /* R_CStackStart, R_CStackLimit */
37
#define HAVE_UINTPTR_T 1
38
#include <Rinterface.h>   /* R_SignalHandlers */
39
#include <R_ext/Parse.h>
40
41
/*
42
 * Suppress R warnings globally.
43
 *
44
 * Many R functions emit warnings on invalid input (e.g., "NAs introduced
45
 * by coercion").  In persistent fuzzing, these accumulate and can overflow
46
 * R's warning buffer, triggering fatal errors.  Setting warn = -1
47
 * suppresses all warnings.
48
 */
49
static void fuzz_suppress_warnings(void)
50
38
{
51
38
    int error = 0;
52
38
    SEXP warn_call;
53
38
    Rf_protect(warn_call = Rf_lang2(Rf_install("options"),
54
38
                                    Rf_ScalarInteger(-1)));
55
38
    SET_TAG(CDR(warn_call), Rf_install("warn"));
56
38
    R_tryEval(warn_call, R_GlobalEnv, &error);
57
38
    Rf_unprotect(1);
58
38
}
io.c:fuzz_suppress_warnings
Line
Count
Source
50
2
{
51
2
    int error = 0;
52
2
    SEXP warn_call;
53
2
    Rf_protect(warn_call = Rf_lang2(Rf_install("options"),
54
2
                                    Rf_ScalarInteger(-1)));
55
2
    SET_TAG(CDR(warn_call), Rf_install("warn"));
56
2
    R_tryEval(warn_call, R_GlobalEnv, &error);
57
2
    Rf_unprotect(1);
58
2
}
dcf.c:fuzz_suppress_warnings
Line
Count
Source
50
2
{
51
2
    int error = 0;
52
2
    SEXP warn_call;
53
2
    Rf_protect(warn_call = Rf_lang2(Rf_install("options"),
54
2
                                    Rf_ScalarInteger(-1)));
55
2
    SET_TAG(CDR(warn_call), Rf_install("warn"));
56
2
    R_tryEval(warn_call, R_GlobalEnv, &error);
57
2
    Rf_unprotect(1);
58
2
}
character.c:fuzz_suppress_warnings
Line
Count
Source
50
2
{
51
2
    int error = 0;
52
2
    SEXP warn_call;
53
2
    Rf_protect(warn_call = Rf_lang2(Rf_install("options"),
54
2
                                    Rf_ScalarInteger(-1)));
55
2
    SET_TAG(CDR(warn_call), Rf_install("warn"));
56
2
    R_tryEval(warn_call, R_GlobalEnv, &error);
57
2
    Rf_unprotect(1);
58
2
}
encoding.c:fuzz_suppress_warnings
Line
Count
Source
50
2
{
51
2
    int error = 0;
52
2
    SEXP warn_call;
53
2
    Rf_protect(warn_call = Rf_lang2(Rf_install("options"),
54
2
                                    Rf_ScalarInteger(-1)));
55
2
    SET_TAG(CDR(warn_call), Rf_install("warn"));
56
2
    R_tryEval(warn_call, R_GlobalEnv, &error);
57
2
    Rf_unprotect(1);
58
2
}
sort.c:fuzz_suppress_warnings
Line
Count
Source
50
2
{
51
2
    int error = 0;
52
2
    SEXP warn_call;
53
2
    Rf_protect(warn_call = Rf_lang2(Rf_install("options"),
54
2
                                    Rf_ScalarInteger(-1)));
55
2
    SET_TAG(CDR(warn_call), Rf_install("warn"));
56
2
    R_tryEval(warn_call, R_GlobalEnv, &error);
57
2
    Rf_unprotect(1);
58
2
}
connections.c:fuzz_suppress_warnings
Line
Count
Source
50
2
{
51
2
    int error = 0;
52
2
    SEXP warn_call;
53
2
    Rf_protect(warn_call = Rf_lang2(Rf_install("options"),
54
2
                                    Rf_ScalarInteger(-1)));
55
2
    SET_TAG(CDR(warn_call), Rf_install("warn"));
56
2
    R_tryEval(warn_call, R_GlobalEnv, &error);
57
2
    Rf_unprotect(1);
58
2
}
unserialize.c:fuzz_suppress_warnings
Line
Count
Source
50
2
{
51
2
    int error = 0;
52
2
    SEXP warn_call;
53
2
    Rf_protect(warn_call = Rf_lang2(Rf_install("options"),
54
2
                                    Rf_ScalarInteger(-1)));
55
2
    SET_TAG(CDR(warn_call), Rf_install("warn"));
56
2
    R_tryEval(warn_call, R_GlobalEnv, &error);
57
2
    Rf_unprotect(1);
58
2
}
decompress.c:fuzz_suppress_warnings
Line
Count
Source
50
2
{
51
2
    int error = 0;
52
2
    SEXP warn_call;
53
2
    Rf_protect(warn_call = Rf_lang2(Rf_install("options"),
54
2
                                    Rf_ScalarInteger(-1)));
55
2
    SET_TAG(CDR(warn_call), Rf_install("warn"));
56
2
    R_tryEval(warn_call, R_GlobalEnv, &error);
57
2
    Rf_unprotect(1);
58
2
}
readtable.c:fuzz_suppress_warnings
Line
Count
Source
50
2
{
51
2
    int error = 0;
52
2
    SEXP warn_call;
53
2
    Rf_protect(warn_call = Rf_lang2(Rf_install("options"),
54
2
                                    Rf_ScalarInteger(-1)));
55
2
    SET_TAG(CDR(warn_call), Rf_install("warn"));
56
2
    R_tryEval(warn_call, R_GlobalEnv, &error);
57
2
    Rf_unprotect(1);
58
2
}
format.c:fuzz_suppress_warnings
Line
Count
Source
50
2
{
51
2
    int error = 0;
52
2
    SEXP warn_call;
53
2
    Rf_protect(warn_call = Rf_lang2(Rf_install("options"),
54
2
                                    Rf_ScalarInteger(-1)));
55
2
    SET_TAG(CDR(warn_call), Rf_install("warn"));
56
2
    R_tryEval(warn_call, R_GlobalEnv, &error);
57
2
    Rf_unprotect(1);
58
2
}
datetime.c:fuzz_suppress_warnings
Line
Count
Source
50
2
{
51
2
    int error = 0;
52
2
    SEXP warn_call;
53
2
    Rf_protect(warn_call = Rf_lang2(Rf_install("options"),
54
2
                                    Rf_ScalarInteger(-1)));
55
2
    SET_TAG(CDR(warn_call), Rf_install("warn"));
56
2
    R_tryEval(warn_call, R_GlobalEnv, &error);
57
2
    Rf_unprotect(1);
58
2
}
coerce.c:fuzz_suppress_warnings
Line
Count
Source
50
2
{
51
2
    int error = 0;
52
2
    SEXP warn_call;
53
2
    Rf_protect(warn_call = Rf_lang2(Rf_install("options"),
54
2
                                    Rf_ScalarInteger(-1)));
55
2
    SET_TAG(CDR(warn_call), Rf_install("warn"));
56
2
    R_tryEval(warn_call, R_GlobalEnv, &error);
57
2
    Rf_unprotect(1);
58
2
}
load.c:fuzz_suppress_warnings
Line
Count
Source
50
2
{
51
2
    int error = 0;
52
2
    SEXP warn_call;
53
2
    Rf_protect(warn_call = Rf_lang2(Rf_install("options"),
54
2
                                    Rf_ScalarInteger(-1)));
55
2
    SET_TAG(CDR(warn_call), Rf_install("warn"));
56
2
    R_tryEval(warn_call, R_GlobalEnv, &error);
57
2
    Rf_unprotect(1);
58
2
}
scan.c:fuzz_suppress_warnings
Line
Count
Source
50
2
{
51
2
    int error = 0;
52
2
    SEXP warn_call;
53
2
    Rf_protect(warn_call = Rf_lang2(Rf_install("options"),
54
2
                                    Rf_ScalarInteger(-1)));
55
2
    SET_TAG(CDR(warn_call), Rf_install("warn"));
56
2
    R_tryEval(warn_call, R_GlobalEnv, &error);
57
2
    Rf_unprotect(1);
58
2
}
colors.c:fuzz_suppress_warnings
Line
Count
Source
50
2
{
51
2
    int error = 0;
52
2
    SEXP warn_call;
53
2
    Rf_protect(warn_call = Rf_lang2(Rf_install("options"),
54
2
                                    Rf_ScalarInteger(-1)));
55
2
    SET_TAG(CDR(warn_call), Rf_install("warn"));
56
2
    R_tryEval(warn_call, R_GlobalEnv, &error);
57
2
    Rf_unprotect(1);
58
2
}
parse.c:fuzz_suppress_warnings
Line
Count
Source
50
2
{
51
2
    int error = 0;
52
2
    SEXP warn_call;
53
2
    Rf_protect(warn_call = Rf_lang2(Rf_install("options"),
54
2
                                    Rf_ScalarInteger(-1)));
55
2
    SET_TAG(CDR(warn_call), Rf_install("warn"));
56
2
    R_tryEval(warn_call, R_GlobalEnv, &error);
57
2
    Rf_unprotect(1);
58
2
}
sprintf.c:fuzz_suppress_warnings
Line
Count
Source
50
2
{
51
2
    int error = 0;
52
2
    SEXP warn_call;
53
2
    Rf_protect(warn_call = Rf_lang2(Rf_install("options"),
54
2
                                    Rf_ScalarInteger(-1)));
55
2
    SET_TAG(CDR(warn_call), Rf_install("warn"));
56
2
    R_tryEval(warn_call, R_GlobalEnv, &error);
57
2
    Rf_unprotect(1);
58
2
}
eval.c:fuzz_suppress_warnings
Line
Count
Source
50
2
{
51
2
    int error = 0;
52
2
    SEXP warn_call;
53
2
    Rf_protect(warn_call = Rf_lang2(Rf_install("options"),
54
2
                                    Rf_ScalarInteger(-1)));
55
2
    SET_TAG(CDR(warn_call), Rf_install("warn"));
56
2
    R_tryEval(warn_call, R_GlobalEnv, &error);
57
2
    Rf_unprotect(1);
58
2
}
zip.c:fuzz_suppress_warnings
Line
Count
Source
50
2
{
51
2
    int error = 0;
52
2
    SEXP warn_call;
53
2
    Rf_protect(warn_call = Rf_lang2(Rf_install("options"),
54
2
                                    Rf_ScalarInteger(-1)));
55
2
    SET_TAG(CDR(warn_call), Rf_install("warn"));
56
2
    R_tryEval(warn_call, R_GlobalEnv, &error);
57
2
    Rf_unprotect(1);
58
2
}
59
60
/*
61
 * Set R_HOME based on the fuzzer binary's location.
62
 *
63
 * OSS-Fuzz places everything in $OUT.  The build.sh installs R to
64
 * $OUT/r-install, so R_HOME is at $OUT/r-install/lib/R.  We derive
65
 * this from /proc/self/exe so it works regardless of the mount path.
66
 */
67
static void fuzz_set_r_home(void)
68
38
{
69
    /* Skip if R_HOME is already set (e.g., for local testing) */
70
38
    if (getenv("R_HOME") != NULL)
71
19
        return;
72
73
19
    char exe[PATH_MAX];
74
19
    ssize_t len = readlink("/proc/self/exe", exe, sizeof(exe) - 1);
75
19
    if (len <= 0)
76
0
        return;
77
19
    exe[len] = '\0';
78
79
    /* Find the directory containing the binary */
80
19
    char *slash = strrchr(exe, '/');
81
19
    if (slash == NULL)
82
0
        return;
83
19
    *slash = '\0';
84
85
19
    char r_home[PATH_MAX];
86
19
    snprintf(r_home, sizeof(r_home), "%s/r-install/lib/R", exe);
87
19
    setenv("R_HOME", r_home, 1);
88
19
}
io.c:fuzz_set_r_home
Line
Count
Source
68
2
{
69
    /* Skip if R_HOME is already set (e.g., for local testing) */
70
2
    if (getenv("R_HOME") != NULL)
71
1
        return;
72
73
1
    char exe[PATH_MAX];
74
1
    ssize_t len = readlink("/proc/self/exe", exe, sizeof(exe) - 1);
75
1
    if (len <= 0)
76
0
        return;
77
1
    exe[len] = '\0';
78
79
    /* Find the directory containing the binary */
80
1
    char *slash = strrchr(exe, '/');
81
1
    if (slash == NULL)
82
0
        return;
83
1
    *slash = '\0';
84
85
1
    char r_home[PATH_MAX];
86
1
    snprintf(r_home, sizeof(r_home), "%s/r-install/lib/R", exe);
87
1
    setenv("R_HOME", r_home, 1);
88
1
}
dcf.c:fuzz_set_r_home
Line
Count
Source
68
2
{
69
    /* Skip if R_HOME is already set (e.g., for local testing) */
70
2
    if (getenv("R_HOME") != NULL)
71
1
        return;
72
73
1
    char exe[PATH_MAX];
74
1
    ssize_t len = readlink("/proc/self/exe", exe, sizeof(exe) - 1);
75
1
    if (len <= 0)
76
0
        return;
77
1
    exe[len] = '\0';
78
79
    /* Find the directory containing the binary */
80
1
    char *slash = strrchr(exe, '/');
81
1
    if (slash == NULL)
82
0
        return;
83
1
    *slash = '\0';
84
85
1
    char r_home[PATH_MAX];
86
1
    snprintf(r_home, sizeof(r_home), "%s/r-install/lib/R", exe);
87
1
    setenv("R_HOME", r_home, 1);
88
1
}
character.c:fuzz_set_r_home
Line
Count
Source
68
2
{
69
    /* Skip if R_HOME is already set (e.g., for local testing) */
70
2
    if (getenv("R_HOME") != NULL)
71
1
        return;
72
73
1
    char exe[PATH_MAX];
74
1
    ssize_t len = readlink("/proc/self/exe", exe, sizeof(exe) - 1);
75
1
    if (len <= 0)
76
0
        return;
77
1
    exe[len] = '\0';
78
79
    /* Find the directory containing the binary */
80
1
    char *slash = strrchr(exe, '/');
81
1
    if (slash == NULL)
82
0
        return;
83
1
    *slash = '\0';
84
85
1
    char r_home[PATH_MAX];
86
1
    snprintf(r_home, sizeof(r_home), "%s/r-install/lib/R", exe);
87
1
    setenv("R_HOME", r_home, 1);
88
1
}
encoding.c:fuzz_set_r_home
Line
Count
Source
68
2
{
69
    /* Skip if R_HOME is already set (e.g., for local testing) */
70
2
    if (getenv("R_HOME") != NULL)
71
1
        return;
72
73
1
    char exe[PATH_MAX];
74
1
    ssize_t len = readlink("/proc/self/exe", exe, sizeof(exe) - 1);
75
1
    if (len <= 0)
76
0
        return;
77
1
    exe[len] = '\0';
78
79
    /* Find the directory containing the binary */
80
1
    char *slash = strrchr(exe, '/');
81
1
    if (slash == NULL)
82
0
        return;
83
1
    *slash = '\0';
84
85
1
    char r_home[PATH_MAX];
86
1
    snprintf(r_home, sizeof(r_home), "%s/r-install/lib/R", exe);
87
1
    setenv("R_HOME", r_home, 1);
88
1
}
sort.c:fuzz_set_r_home
Line
Count
Source
68
2
{
69
    /* Skip if R_HOME is already set (e.g., for local testing) */
70
2
    if (getenv("R_HOME") != NULL)
71
1
        return;
72
73
1
    char exe[PATH_MAX];
74
1
    ssize_t len = readlink("/proc/self/exe", exe, sizeof(exe) - 1);
75
1
    if (len <= 0)
76
0
        return;
77
1
    exe[len] = '\0';
78
79
    /* Find the directory containing the binary */
80
1
    char *slash = strrchr(exe, '/');
81
1
    if (slash == NULL)
82
0
        return;
83
1
    *slash = '\0';
84
85
1
    char r_home[PATH_MAX];
86
1
    snprintf(r_home, sizeof(r_home), "%s/r-install/lib/R", exe);
87
1
    setenv("R_HOME", r_home, 1);
88
1
}
connections.c:fuzz_set_r_home
Line
Count
Source
68
2
{
69
    /* Skip if R_HOME is already set (e.g., for local testing) */
70
2
    if (getenv("R_HOME") != NULL)
71
1
        return;
72
73
1
    char exe[PATH_MAX];
74
1
    ssize_t len = readlink("/proc/self/exe", exe, sizeof(exe) - 1);
75
1
    if (len <= 0)
76
0
        return;
77
1
    exe[len] = '\0';
78
79
    /* Find the directory containing the binary */
80
1
    char *slash = strrchr(exe, '/');
81
1
    if (slash == NULL)
82
0
        return;
83
1
    *slash = '\0';
84
85
1
    char r_home[PATH_MAX];
86
1
    snprintf(r_home, sizeof(r_home), "%s/r-install/lib/R", exe);
87
1
    setenv("R_HOME", r_home, 1);
88
1
}
unserialize.c:fuzz_set_r_home
Line
Count
Source
68
2
{
69
    /* Skip if R_HOME is already set (e.g., for local testing) */
70
2
    if (getenv("R_HOME") != NULL)
71
1
        return;
72
73
1
    char exe[PATH_MAX];
74
1
    ssize_t len = readlink("/proc/self/exe", exe, sizeof(exe) - 1);
75
1
    if (len <= 0)
76
0
        return;
77
1
    exe[len] = '\0';
78
79
    /* Find the directory containing the binary */
80
1
    char *slash = strrchr(exe, '/');
81
1
    if (slash == NULL)
82
0
        return;
83
1
    *slash = '\0';
84
85
1
    char r_home[PATH_MAX];
86
1
    snprintf(r_home, sizeof(r_home), "%s/r-install/lib/R", exe);
87
1
    setenv("R_HOME", r_home, 1);
88
1
}
decompress.c:fuzz_set_r_home
Line
Count
Source
68
2
{
69
    /* Skip if R_HOME is already set (e.g., for local testing) */
70
2
    if (getenv("R_HOME") != NULL)
71
1
        return;
72
73
1
    char exe[PATH_MAX];
74
1
    ssize_t len = readlink("/proc/self/exe", exe, sizeof(exe) - 1);
75
1
    if (len <= 0)
76
0
        return;
77
1
    exe[len] = '\0';
78
79
    /* Find the directory containing the binary */
80
1
    char *slash = strrchr(exe, '/');
81
1
    if (slash == NULL)
82
0
        return;
83
1
    *slash = '\0';
84
85
1
    char r_home[PATH_MAX];
86
1
    snprintf(r_home, sizeof(r_home), "%s/r-install/lib/R", exe);
87
1
    setenv("R_HOME", r_home, 1);
88
1
}
readtable.c:fuzz_set_r_home
Line
Count
Source
68
2
{
69
    /* Skip if R_HOME is already set (e.g., for local testing) */
70
2
    if (getenv("R_HOME") != NULL)
71
1
        return;
72
73
1
    char exe[PATH_MAX];
74
1
    ssize_t len = readlink("/proc/self/exe", exe, sizeof(exe) - 1);
75
1
    if (len <= 0)
76
0
        return;
77
1
    exe[len] = '\0';
78
79
    /* Find the directory containing the binary */
80
1
    char *slash = strrchr(exe, '/');
81
1
    if (slash == NULL)
82
0
        return;
83
1
    *slash = '\0';
84
85
1
    char r_home[PATH_MAX];
86
1
    snprintf(r_home, sizeof(r_home), "%s/r-install/lib/R", exe);
87
1
    setenv("R_HOME", r_home, 1);
88
1
}
format.c:fuzz_set_r_home
Line
Count
Source
68
2
{
69
    /* Skip if R_HOME is already set (e.g., for local testing) */
70
2
    if (getenv("R_HOME") != NULL)
71
1
        return;
72
73
1
    char exe[PATH_MAX];
74
1
    ssize_t len = readlink("/proc/self/exe", exe, sizeof(exe) - 1);
75
1
    if (len <= 0)
76
0
        return;
77
1
    exe[len] = '\0';
78
79
    /* Find the directory containing the binary */
80
1
    char *slash = strrchr(exe, '/');
81
1
    if (slash == NULL)
82
0
        return;
83
1
    *slash = '\0';
84
85
1
    char r_home[PATH_MAX];
86
1
    snprintf(r_home, sizeof(r_home), "%s/r-install/lib/R", exe);
87
1
    setenv("R_HOME", r_home, 1);
88
1
}
datetime.c:fuzz_set_r_home
Line
Count
Source
68
2
{
69
    /* Skip if R_HOME is already set (e.g., for local testing) */
70
2
    if (getenv("R_HOME") != NULL)
71
1
        return;
72
73
1
    char exe[PATH_MAX];
74
1
    ssize_t len = readlink("/proc/self/exe", exe, sizeof(exe) - 1);
75
1
    if (len <= 0)
76
0
        return;
77
1
    exe[len] = '\0';
78
79
    /* Find the directory containing the binary */
80
1
    char *slash = strrchr(exe, '/');
81
1
    if (slash == NULL)
82
0
        return;
83
1
    *slash = '\0';
84
85
1
    char r_home[PATH_MAX];
86
1
    snprintf(r_home, sizeof(r_home), "%s/r-install/lib/R", exe);
87
1
    setenv("R_HOME", r_home, 1);
88
1
}
coerce.c:fuzz_set_r_home
Line
Count
Source
68
2
{
69
    /* Skip if R_HOME is already set (e.g., for local testing) */
70
2
    if (getenv("R_HOME") != NULL)
71
1
        return;
72
73
1
    char exe[PATH_MAX];
74
1
    ssize_t len = readlink("/proc/self/exe", exe, sizeof(exe) - 1);
75
1
    if (len <= 0)
76
0
        return;
77
1
    exe[len] = '\0';
78
79
    /* Find the directory containing the binary */
80
1
    char *slash = strrchr(exe, '/');
81
1
    if (slash == NULL)
82
0
        return;
83
1
    *slash = '\0';
84
85
1
    char r_home[PATH_MAX];
86
1
    snprintf(r_home, sizeof(r_home), "%s/r-install/lib/R", exe);
87
1
    setenv("R_HOME", r_home, 1);
88
1
}
load.c:fuzz_set_r_home
Line
Count
Source
68
2
{
69
    /* Skip if R_HOME is already set (e.g., for local testing) */
70
2
    if (getenv("R_HOME") != NULL)
71
1
        return;
72
73
1
    char exe[PATH_MAX];
74
1
    ssize_t len = readlink("/proc/self/exe", exe, sizeof(exe) - 1);
75
1
    if (len <= 0)
76
0
        return;
77
1
    exe[len] = '\0';
78
79
    /* Find the directory containing the binary */
80
1
    char *slash = strrchr(exe, '/');
81
1
    if (slash == NULL)
82
0
        return;
83
1
    *slash = '\0';
84
85
1
    char r_home[PATH_MAX];
86
1
    snprintf(r_home, sizeof(r_home), "%s/r-install/lib/R", exe);
87
1
    setenv("R_HOME", r_home, 1);
88
1
}
scan.c:fuzz_set_r_home
Line
Count
Source
68
2
{
69
    /* Skip if R_HOME is already set (e.g., for local testing) */
70
2
    if (getenv("R_HOME") != NULL)
71
1
        return;
72
73
1
    char exe[PATH_MAX];
74
1
    ssize_t len = readlink("/proc/self/exe", exe, sizeof(exe) - 1);
75
1
    if (len <= 0)
76
0
        return;
77
1
    exe[len] = '\0';
78
79
    /* Find the directory containing the binary */
80
1
    char *slash = strrchr(exe, '/');
81
1
    if (slash == NULL)
82
0
        return;
83
1
    *slash = '\0';
84
85
1
    char r_home[PATH_MAX];
86
1
    snprintf(r_home, sizeof(r_home), "%s/r-install/lib/R", exe);
87
1
    setenv("R_HOME", r_home, 1);
88
1
}
colors.c:fuzz_set_r_home
Line
Count
Source
68
2
{
69
    /* Skip if R_HOME is already set (e.g., for local testing) */
70
2
    if (getenv("R_HOME") != NULL)
71
1
        return;
72
73
1
    char exe[PATH_MAX];
74
1
    ssize_t len = readlink("/proc/self/exe", exe, sizeof(exe) - 1);
75
1
    if (len <= 0)
76
0
        return;
77
1
    exe[len] = '\0';
78
79
    /* Find the directory containing the binary */
80
1
    char *slash = strrchr(exe, '/');
81
1
    if (slash == NULL)
82
0
        return;
83
1
    *slash = '\0';
84
85
1
    char r_home[PATH_MAX];
86
1
    snprintf(r_home, sizeof(r_home), "%s/r-install/lib/R", exe);
87
1
    setenv("R_HOME", r_home, 1);
88
1
}
parse.c:fuzz_set_r_home
Line
Count
Source
68
2
{
69
    /* Skip if R_HOME is already set (e.g., for local testing) */
70
2
    if (getenv("R_HOME") != NULL)
71
1
        return;
72
73
1
    char exe[PATH_MAX];
74
1
    ssize_t len = readlink("/proc/self/exe", exe, sizeof(exe) - 1);
75
1
    if (len <= 0)
76
0
        return;
77
1
    exe[len] = '\0';
78
79
    /* Find the directory containing the binary */
80
1
    char *slash = strrchr(exe, '/');
81
1
    if (slash == NULL)
82
0
        return;
83
1
    *slash = '\0';
84
85
1
    char r_home[PATH_MAX];
86
1
    snprintf(r_home, sizeof(r_home), "%s/r-install/lib/R", exe);
87
1
    setenv("R_HOME", r_home, 1);
88
1
}
sprintf.c:fuzz_set_r_home
Line
Count
Source
68
2
{
69
    /* Skip if R_HOME is already set (e.g., for local testing) */
70
2
    if (getenv("R_HOME") != NULL)
71
1
        return;
72
73
1
    char exe[PATH_MAX];
74
1
    ssize_t len = readlink("/proc/self/exe", exe, sizeof(exe) - 1);
75
1
    if (len <= 0)
76
0
        return;
77
1
    exe[len] = '\0';
78
79
    /* Find the directory containing the binary */
80
1
    char *slash = strrchr(exe, '/');
81
1
    if (slash == NULL)
82
0
        return;
83
1
    *slash = '\0';
84
85
1
    char r_home[PATH_MAX];
86
1
    snprintf(r_home, sizeof(r_home), "%s/r-install/lib/R", exe);
87
1
    setenv("R_HOME", r_home, 1);
88
1
}
eval.c:fuzz_set_r_home
Line
Count
Source
68
2
{
69
    /* Skip if R_HOME is already set (e.g., for local testing) */
70
2
    if (getenv("R_HOME") != NULL)
71
1
        return;
72
73
1
    char exe[PATH_MAX];
74
1
    ssize_t len = readlink("/proc/self/exe", exe, sizeof(exe) - 1);
75
1
    if (len <= 0)
76
0
        return;
77
1
    exe[len] = '\0';
78
79
    /* Find the directory containing the binary */
80
1
    char *slash = strrchr(exe, '/');
81
1
    if (slash == NULL)
82
0
        return;
83
1
    *slash = '\0';
84
85
1
    char r_home[PATH_MAX];
86
1
    snprintf(r_home, sizeof(r_home), "%s/r-install/lib/R", exe);
87
1
    setenv("R_HOME", r_home, 1);
88
1
}
zip.c:fuzz_set_r_home
Line
Count
Source
68
2
{
69
    /* Skip if R_HOME is already set (e.g., for local testing) */
70
2
    if (getenv("R_HOME") != NULL)
71
1
        return;
72
73
1
    char exe[PATH_MAX];
74
1
    ssize_t len = readlink("/proc/self/exe", exe, sizeof(exe) - 1);
75
1
    if (len <= 0)
76
0
        return;
77
1
    exe[len] = '\0';
78
79
    /* Find the directory containing the binary */
80
1
    char *slash = strrchr(exe, '/');
81
1
    if (slash == NULL)
82
0
        return;
83
1
    *slash = '\0';
84
85
1
    char r_home[PATH_MAX];
86
1
    snprintf(r_home, sizeof(r_home), "%s/r-install/lib/R", exe);
87
1
    setenv("R_HOME", r_home, 1);
88
1
}
89
90
/*
91
 * Cap R's vector heap.
92
 *
93
 * Hostile input reaches R's allocator directly -- a serialized vector can
94
 * declare any length it likes, and coercion or scanning can be talked into
95
 * asking for one -- so a 64KB input can request gigabytes.
96
 *
97
 * R enforces R_MAX_VSIZE in allocVector and signals an ordinary R error
98
 * ("vector memory limit of N reached").  When it fires inside R_ToplevelExec
99
 * the iteration is discarded and fuzzing carries on; every per-iteration
100
 * allocation must therefore go through fuzz_set_string / fuzz_set_raw_arg
101
 * below, which run under such a context.  That catchability is the reason
102
 * to prefer this over a sanitizer-level RSS limit: ASAN's soft_rss_limit_mb
103
 * either aborts the process or starts handing NULL back to allocators that
104
 * never expected it, and both look like crashes.
105
 *
106
 * Caveats:
107
 *   - The cap bounds R's cumulative LIVE vector heap, not one input's
108
 *     allocations.  Interned symbols are never collected, so the parse and
109
 *     unserialize targets ratchet toward the cap over a long run.
110
 *   - It bounds R's vector heap ONLY.  malloc-based allocations, like TRE
111
 *     compiling a pattern, bypass it entirely; see
112
 *     fuzz_repeat_product_excessive for that guard.
113
 *   - It does cost coverage of code paths that need larger results.
114
 *     Targets with legitimately large outputs (decompress: a 64KB bzip2
115
 *     stream of zeros expands past 1GB) raise the default by defining
116
 *     FUZZ_R_MAX_VSIZE before including this header.
117
 *   - R's suffix parsing is case-sensitive: "4Gb" works, "4gb" silently
118
 *     leaves the heap uncapped (R only warns on stderr at startup).  The
119
 *     env override is for local runs; the CI runner does not forward
120
 *     arbitrary environment variables.
121
 *
122
 * Local reproduction of vector-limit findings under plain Rscript needs
123
 * the same value exported; see README.md.
124
 */
125
#ifndef FUZZ_R_MAX_VSIZE
126
16
# define FUZZ_R_MAX_VSIZE "1Gb"
127
#endif
128
129
static void fuzz_set_vsize_limit(void)
130
38
{
131
38
    if (getenv("R_MAX_VSIZE") == NULL)
132
19
        setenv("R_MAX_VSIZE", FUZZ_R_MAX_VSIZE, 1);
133
38
}
io.c:fuzz_set_vsize_limit
Line
Count
Source
130
2
{
131
2
    if (getenv("R_MAX_VSIZE") == NULL)
132
1
        setenv("R_MAX_VSIZE", FUZZ_R_MAX_VSIZE, 1);
133
2
}
dcf.c:fuzz_set_vsize_limit
Line
Count
Source
130
2
{
131
2
    if (getenv("R_MAX_VSIZE") == NULL)
132
1
        setenv("R_MAX_VSIZE", FUZZ_R_MAX_VSIZE, 1);
133
2
}
character.c:fuzz_set_vsize_limit
Line
Count
Source
130
2
{
131
2
    if (getenv("R_MAX_VSIZE") == NULL)
132
1
        setenv("R_MAX_VSIZE", FUZZ_R_MAX_VSIZE, 1);
133
2
}
encoding.c:fuzz_set_vsize_limit
Line
Count
Source
130
2
{
131
2
    if (getenv("R_MAX_VSIZE") == NULL)
132
1
        setenv("R_MAX_VSIZE", FUZZ_R_MAX_VSIZE, 1);
133
2
}
sort.c:fuzz_set_vsize_limit
Line
Count
Source
130
2
{
131
2
    if (getenv("R_MAX_VSIZE") == NULL)
132
1
        setenv("R_MAX_VSIZE", FUZZ_R_MAX_VSIZE, 1);
133
2
}
connections.c:fuzz_set_vsize_limit
Line
Count
Source
130
2
{
131
2
    if (getenv("R_MAX_VSIZE") == NULL)
132
1
        setenv("R_MAX_VSIZE", FUZZ_R_MAX_VSIZE, 1);
133
2
}
unserialize.c:fuzz_set_vsize_limit
Line
Count
Source
130
2
{
131
2
    if (getenv("R_MAX_VSIZE") == NULL)
132
1
        setenv("R_MAX_VSIZE", FUZZ_R_MAX_VSIZE, 1);
133
2
}
decompress.c:fuzz_set_vsize_limit
Line
Count
Source
130
2
{
131
2
    if (getenv("R_MAX_VSIZE") == NULL)
132
1
        setenv("R_MAX_VSIZE", FUZZ_R_MAX_VSIZE, 1);
133
2
}
readtable.c:fuzz_set_vsize_limit
Line
Count
Source
130
2
{
131
2
    if (getenv("R_MAX_VSIZE") == NULL)
132
1
        setenv("R_MAX_VSIZE", FUZZ_R_MAX_VSIZE, 1);
133
2
}
format.c:fuzz_set_vsize_limit
Line
Count
Source
130
2
{
131
2
    if (getenv("R_MAX_VSIZE") == NULL)
132
1
        setenv("R_MAX_VSIZE", FUZZ_R_MAX_VSIZE, 1);
133
2
}
datetime.c:fuzz_set_vsize_limit
Line
Count
Source
130
2
{
131
2
    if (getenv("R_MAX_VSIZE") == NULL)
132
1
        setenv("R_MAX_VSIZE", FUZZ_R_MAX_VSIZE, 1);
133
2
}
coerce.c:fuzz_set_vsize_limit
Line
Count
Source
130
2
{
131
2
    if (getenv("R_MAX_VSIZE") == NULL)
132
1
        setenv("R_MAX_VSIZE", FUZZ_R_MAX_VSIZE, 1);
133
2
}
load.c:fuzz_set_vsize_limit
Line
Count
Source
130
2
{
131
2
    if (getenv("R_MAX_VSIZE") == NULL)
132
1
        setenv("R_MAX_VSIZE", FUZZ_R_MAX_VSIZE, 1);
133
2
}
scan.c:fuzz_set_vsize_limit
Line
Count
Source
130
2
{
131
2
    if (getenv("R_MAX_VSIZE") == NULL)
132
1
        setenv("R_MAX_VSIZE", FUZZ_R_MAX_VSIZE, 1);
133
2
}
colors.c:fuzz_set_vsize_limit
Line
Count
Source
130
2
{
131
2
    if (getenv("R_MAX_VSIZE") == NULL)
132
1
        setenv("R_MAX_VSIZE", FUZZ_R_MAX_VSIZE, 1);
133
2
}
parse.c:fuzz_set_vsize_limit
Line
Count
Source
130
2
{
131
2
    if (getenv("R_MAX_VSIZE") == NULL)
132
1
        setenv("R_MAX_VSIZE", FUZZ_R_MAX_VSIZE, 1);
133
2
}
sprintf.c:fuzz_set_vsize_limit
Line
Count
Source
130
2
{
131
2
    if (getenv("R_MAX_VSIZE") == NULL)
132
1
        setenv("R_MAX_VSIZE", FUZZ_R_MAX_VSIZE, 1);
133
2
}
eval.c:fuzz_set_vsize_limit
Line
Count
Source
130
2
{
131
2
    if (getenv("R_MAX_VSIZE") == NULL)
132
1
        setenv("R_MAX_VSIZE", FUZZ_R_MAX_VSIZE, 1);
133
2
}
zip.c:fuzz_set_vsize_limit
Line
Count
Source
130
2
{
131
2
    if (getenv("R_MAX_VSIZE") == NULL)
132
1
        setenv("R_MAX_VSIZE", FUZZ_R_MAX_VSIZE, 1);
133
2
}
134
135
/*
136
 * Run R on its own thread with a large stack.
137
 *
138
 * Several of R's recursive C walkers never call R_CheckStack(): bind.c's
139
 * AnswerType behind c(recursive = TRUE), deparse.c behind
140
 * as.character(<list>), and the coerce, duplicate, identical and subassign
141
 * walkers.  A list some tens of thousands deep, which an input can build
142
 * at run time, overflows the 8 MiB main-thread stack in them.  Plain R
143
 * reports "segfault from C stack overflow" and recovers, long-standing
144
 * behaviour rather than a defect to report; under the sanitizers it is a
145
 * stack-overflow crash that every target walking a nested value would
146
 * keep rediscovering.
147
 *
148
 * The main thread's stack is fixed before the process starts, so R runs
149
 * on a worker thread created with FUZZ_R_STACK_SIZE of stack instead:
150
 * deep enough that any recursion an input can afford within the per-input
151
 * limits completes, and virtual until touched, so it costs an idle target
152
 * nothing.
153
 *
154
 * Everything that touches R -- initialization, every input, the checks
155
 * under tests/ -- must run on that thread: R records its stack bounds
156
 * once, and R_CheckStack() measures against them.  The libFuzzer entry
157
 * points at the end of this header forward to fuzz_target_init and
158
 * fuzz_target_run there, and fuzz_init_r() refuses to run anywhere else.
159
 *
160
 * The thread does not survive a fork, and AFL++'s driver forks: its
161
 * forkserver starts after LLVMFuzzerInitialize, so every input runs in a
162
 * child that inherited the initialized R but no thread to run it on.
163
 * An atfork handler forgets the thread in the child, and the next job
164
 * starts a fresh one, which points R's stack check at its own stack.
165
 */
166
#ifndef FUZZ_R_STACK_SIZE
167
76
# define FUZZ_R_STACK_SIZE ((size_t)1 << 30)
168
#endif
169
170
typedef struct {
171
    void (*fn)(void *);
172
    void *arg;
173
} fuzz_job_t;
174
175
static struct {
176
    pthread_t thread;
177
    int started;
178
    pthread_mutex_t mutex;
179
    pthread_cond_t cond;
180
    fuzz_job_t *job;        /* set by the caller, cleared by the thread */
181
    uintptr_t stack_top;    /* where the thread's frames begin */
182
} fuzz_r_thread = {
183
    .mutex = PTHREAD_MUTEX_INITIALIZER,
184
    .cond = PTHREAD_COND_INITIALIZER
185
};
186
187
static void *fuzz_r_thread_main(void *unused)
188
38
{
189
38
    (void)unused;
190
    /* The frame address rather than a local's: under ASAN an address-taken
191
     * local may sit on the fake stack, nowhere near this thread's stack.
192
     * R_CStackStart matters only once R is initialized; fuzz_init_r()
193
     * sets it again after Rf_initialize_R has overwritten it. */
194
38
    fuzz_r_thread.stack_top = (uintptr_t)__builtin_frame_address(0);
195
38
    R_CStackStart = fuzz_r_thread.stack_top;
196
197
    /* libFuzzer's -timeout alarm is acted on only by the thread running
198
     * its loop (the main thread); delivered here it would be ignored and
199
     * the input would run on.  Block it so the kernel cannot pick this
200
     * thread.  A timeout report therefore shows the main thread waiting
201
     * rather than where R is; the testcase it writes still reproduces. */
202
38
    sigset_t alarm;
203
38
    sigemptyset(&alarm);
204
38
    sigaddset(&alarm, SIGALRM);
205
38
    pthread_sigmask(SIG_BLOCK, &alarm, NULL);
206
207
38
    pthread_mutex_lock(&fuzz_r_thread.mutex);
208
69.1k
    for (;;) {
209
138k
        while (fuzz_r_thread.job == NULL)
210
69.1k
            pthread_cond_wait(&fuzz_r_thread.cond, &fuzz_r_thread.mutex);
211
69.1k
        fuzz_job_t *job = fuzz_r_thread.job;
212
69.1k
        pthread_mutex_unlock(&fuzz_r_thread.mutex);
213
214
69.1k
        job->fn(job->arg);
215
216
69.1k
        pthread_mutex_lock(&fuzz_r_thread.mutex);
217
69.1k
        fuzz_r_thread.job = NULL;
218
69.1k
        pthread_cond_broadcast(&fuzz_r_thread.cond);
219
69.1k
    }
220
38
    return NULL;
221
38
}
io.c:fuzz_r_thread_main
Line
Count
Source
188
2
{
189
2
    (void)unused;
190
    /* The frame address rather than a local's: under ASAN an address-taken
191
     * local may sit on the fake stack, nowhere near this thread's stack.
192
     * R_CStackStart matters only once R is initialized; fuzz_init_r()
193
     * sets it again after Rf_initialize_R has overwritten it. */
194
2
    fuzz_r_thread.stack_top = (uintptr_t)__builtin_frame_address(0);
195
2
    R_CStackStart = fuzz_r_thread.stack_top;
196
197
    /* libFuzzer's -timeout alarm is acted on only by the thread running
198
     * its loop (the main thread); delivered here it would be ignored and
199
     * the input would run on.  Block it so the kernel cannot pick this
200
     * thread.  A timeout report therefore shows the main thread waiting
201
     * rather than where R is; the testcase it writes still reproduces. */
202
2
    sigset_t alarm;
203
2
    sigemptyset(&alarm);
204
2
    sigaddset(&alarm, SIGALRM);
205
2
    pthread_sigmask(SIG_BLOCK, &alarm, NULL);
206
207
2
    pthread_mutex_lock(&fuzz_r_thread.mutex);
208
1.57k
    for (;;) {
209
3.14k
        while (fuzz_r_thread.job == NULL)
210
1.57k
            pthread_cond_wait(&fuzz_r_thread.cond, &fuzz_r_thread.mutex);
211
1.57k
        fuzz_job_t *job = fuzz_r_thread.job;
212
1.57k
        pthread_mutex_unlock(&fuzz_r_thread.mutex);
213
214
1.57k
        job->fn(job->arg);
215
216
1.57k
        pthread_mutex_lock(&fuzz_r_thread.mutex);
217
1.57k
        fuzz_r_thread.job = NULL;
218
1.57k
        pthread_cond_broadcast(&fuzz_r_thread.cond);
219
1.57k
    }
220
    return NULL;
221
2
}
dcf.c:fuzz_r_thread_main
Line
Count
Source
188
2
{
189
2
    (void)unused;
190
    /* The frame address rather than a local's: under ASAN an address-taken
191
     * local may sit on the fake stack, nowhere near this thread's stack.
192
     * R_CStackStart matters only once R is initialized; fuzz_init_r()
193
     * sets it again after Rf_initialize_R has overwritten it. */
194
2
    fuzz_r_thread.stack_top = (uintptr_t)__builtin_frame_address(0);
195
2
    R_CStackStart = fuzz_r_thread.stack_top;
196
197
    /* libFuzzer's -timeout alarm is acted on only by the thread running
198
     * its loop (the main thread); delivered here it would be ignored and
199
     * the input would run on.  Block it so the kernel cannot pick this
200
     * thread.  A timeout report therefore shows the main thread waiting
201
     * rather than where R is; the testcase it writes still reproduces. */
202
2
    sigset_t alarm;
203
2
    sigemptyset(&alarm);
204
2
    sigaddset(&alarm, SIGALRM);
205
2
    pthread_sigmask(SIG_BLOCK, &alarm, NULL);
206
207
2
    pthread_mutex_lock(&fuzz_r_thread.mutex);
208
4.76k
    for (;;) {
209
9.53k
        while (fuzz_r_thread.job == NULL)
210
4.76k
            pthread_cond_wait(&fuzz_r_thread.cond, &fuzz_r_thread.mutex);
211
4.76k
        fuzz_job_t *job = fuzz_r_thread.job;
212
4.76k
        pthread_mutex_unlock(&fuzz_r_thread.mutex);
213
214
4.76k
        job->fn(job->arg);
215
216
4.76k
        pthread_mutex_lock(&fuzz_r_thread.mutex);
217
4.76k
        fuzz_r_thread.job = NULL;
218
4.76k
        pthread_cond_broadcast(&fuzz_r_thread.cond);
219
4.76k
    }
220
    return NULL;
221
2
}
character.c:fuzz_r_thread_main
Line
Count
Source
188
2
{
189
2
    (void)unused;
190
    /* The frame address rather than a local's: under ASAN an address-taken
191
     * local may sit on the fake stack, nowhere near this thread's stack.
192
     * R_CStackStart matters only once R is initialized; fuzz_init_r()
193
     * sets it again after Rf_initialize_R has overwritten it. */
194
2
    fuzz_r_thread.stack_top = (uintptr_t)__builtin_frame_address(0);
195
2
    R_CStackStart = fuzz_r_thread.stack_top;
196
197
    /* libFuzzer's -timeout alarm is acted on only by the thread running
198
     * its loop (the main thread); delivered here it would be ignored and
199
     * the input would run on.  Block it so the kernel cannot pick this
200
     * thread.  A timeout report therefore shows the main thread waiting
201
     * rather than where R is; the testcase it writes still reproduces. */
202
2
    sigset_t alarm;
203
2
    sigemptyset(&alarm);
204
2
    sigaddset(&alarm, SIGALRM);
205
2
    pthread_sigmask(SIG_BLOCK, &alarm, NULL);
206
207
2
    pthread_mutex_lock(&fuzz_r_thread.mutex);
208
3.59k
    for (;;) {
209
7.17k
        while (fuzz_r_thread.job == NULL)
210
3.58k
            pthread_cond_wait(&fuzz_r_thread.cond, &fuzz_r_thread.mutex);
211
3.59k
        fuzz_job_t *job = fuzz_r_thread.job;
212
3.59k
        pthread_mutex_unlock(&fuzz_r_thread.mutex);
213
214
3.59k
        job->fn(job->arg);
215
216
3.59k
        pthread_mutex_lock(&fuzz_r_thread.mutex);
217
3.59k
        fuzz_r_thread.job = NULL;
218
3.59k
        pthread_cond_broadcast(&fuzz_r_thread.cond);
219
3.59k
    }
220
    return NULL;
221
2
}
encoding.c:fuzz_r_thread_main
Line
Count
Source
188
2
{
189
2
    (void)unused;
190
    /* The frame address rather than a local's: under ASAN an address-taken
191
     * local may sit on the fake stack, nowhere near this thread's stack.
192
     * R_CStackStart matters only once R is initialized; fuzz_init_r()
193
     * sets it again after Rf_initialize_R has overwritten it. */
194
2
    fuzz_r_thread.stack_top = (uintptr_t)__builtin_frame_address(0);
195
2
    R_CStackStart = fuzz_r_thread.stack_top;
196
197
    /* libFuzzer's -timeout alarm is acted on only by the thread running
198
     * its loop (the main thread); delivered here it would be ignored and
199
     * the input would run on.  Block it so the kernel cannot pick this
200
     * thread.  A timeout report therefore shows the main thread waiting
201
     * rather than where R is; the testcase it writes still reproduces. */
202
2
    sigset_t alarm;
203
2
    sigemptyset(&alarm);
204
2
    sigaddset(&alarm, SIGALRM);
205
2
    pthread_sigmask(SIG_BLOCK, &alarm, NULL);
206
207
2
    pthread_mutex_lock(&fuzz_r_thread.mutex);
208
1.53k
    for (;;) {
209
3.06k
        while (fuzz_r_thread.job == NULL)
210
1.52k
            pthread_cond_wait(&fuzz_r_thread.cond, &fuzz_r_thread.mutex);
211
1.53k
        fuzz_job_t *job = fuzz_r_thread.job;
212
1.53k
        pthread_mutex_unlock(&fuzz_r_thread.mutex);
213
214
1.53k
        job->fn(job->arg);
215
216
1.53k
        pthread_mutex_lock(&fuzz_r_thread.mutex);
217
1.53k
        fuzz_r_thread.job = NULL;
218
1.53k
        pthread_cond_broadcast(&fuzz_r_thread.cond);
219
1.53k
    }
220
    return NULL;
221
2
}
sort.c:fuzz_r_thread_main
Line
Count
Source
188
2
{
189
2
    (void)unused;
190
    /* The frame address rather than a local's: under ASAN an address-taken
191
     * local may sit on the fake stack, nowhere near this thread's stack.
192
     * R_CStackStart matters only once R is initialized; fuzz_init_r()
193
     * sets it again after Rf_initialize_R has overwritten it. */
194
2
    fuzz_r_thread.stack_top = (uintptr_t)__builtin_frame_address(0);
195
2
    R_CStackStart = fuzz_r_thread.stack_top;
196
197
    /* libFuzzer's -timeout alarm is acted on only by the thread running
198
     * its loop (the main thread); delivered here it would be ignored and
199
     * the input would run on.  Block it so the kernel cannot pick this
200
     * thread.  A timeout report therefore shows the main thread waiting
201
     * rather than where R is; the testcase it writes still reproduces. */
202
2
    sigset_t alarm;
203
2
    sigemptyset(&alarm);
204
2
    sigaddset(&alarm, SIGALRM);
205
2
    pthread_sigmask(SIG_BLOCK, &alarm, NULL);
206
207
2
    pthread_mutex_lock(&fuzz_r_thread.mutex);
208
6.34k
    for (;;) {
209
12.6k
        while (fuzz_r_thread.job == NULL)
210
6.33k
            pthread_cond_wait(&fuzz_r_thread.cond, &fuzz_r_thread.mutex);
211
6.34k
        fuzz_job_t *job = fuzz_r_thread.job;
212
6.34k
        pthread_mutex_unlock(&fuzz_r_thread.mutex);
213
214
6.34k
        job->fn(job->arg);
215
216
6.34k
        pthread_mutex_lock(&fuzz_r_thread.mutex);
217
6.34k
        fuzz_r_thread.job = NULL;
218
6.34k
        pthread_cond_broadcast(&fuzz_r_thread.cond);
219
6.34k
    }
220
    return NULL;
221
2
}
connections.c:fuzz_r_thread_main
Line
Count
Source
188
2
{
189
2
    (void)unused;
190
    /* The frame address rather than a local's: under ASAN an address-taken
191
     * local may sit on the fake stack, nowhere near this thread's stack.
192
     * R_CStackStart matters only once R is initialized; fuzz_init_r()
193
     * sets it again after Rf_initialize_R has overwritten it. */
194
2
    fuzz_r_thread.stack_top = (uintptr_t)__builtin_frame_address(0);
195
2
    R_CStackStart = fuzz_r_thread.stack_top;
196
197
    /* libFuzzer's -timeout alarm is acted on only by the thread running
198
     * its loop (the main thread); delivered here it would be ignored and
199
     * the input would run on.  Block it so the kernel cannot pick this
200
     * thread.  A timeout report therefore shows the main thread waiting
201
     * rather than where R is; the testcase it writes still reproduces. */
202
2
    sigset_t alarm;
203
2
    sigemptyset(&alarm);
204
2
    sigaddset(&alarm, SIGALRM);
205
2
    pthread_sigmask(SIG_BLOCK, &alarm, NULL);
206
207
2
    pthread_mutex_lock(&fuzz_r_thread.mutex);
208
2.43k
    for (;;) {
209
4.86k
        while (fuzz_r_thread.job == NULL)
210
2.43k
            pthread_cond_wait(&fuzz_r_thread.cond, &fuzz_r_thread.mutex);
211
2.43k
        fuzz_job_t *job = fuzz_r_thread.job;
212
2.43k
        pthread_mutex_unlock(&fuzz_r_thread.mutex);
213
214
2.43k
        job->fn(job->arg);
215
216
2.43k
        pthread_mutex_lock(&fuzz_r_thread.mutex);
217
2.43k
        fuzz_r_thread.job = NULL;
218
2.43k
        pthread_cond_broadcast(&fuzz_r_thread.cond);
219
2.43k
    }
220
    return NULL;
221
2
}
unserialize.c:fuzz_r_thread_main
Line
Count
Source
188
2
{
189
2
    (void)unused;
190
    /* The frame address rather than a local's: under ASAN an address-taken
191
     * local may sit on the fake stack, nowhere near this thread's stack.
192
     * R_CStackStart matters only once R is initialized; fuzz_init_r()
193
     * sets it again after Rf_initialize_R has overwritten it. */
194
2
    fuzz_r_thread.stack_top = (uintptr_t)__builtin_frame_address(0);
195
2
    R_CStackStart = fuzz_r_thread.stack_top;
196
197
    /* libFuzzer's -timeout alarm is acted on only by the thread running
198
     * its loop (the main thread); delivered here it would be ignored and
199
     * the input would run on.  Block it so the kernel cannot pick this
200
     * thread.  A timeout report therefore shows the main thread waiting
201
     * rather than where R is; the testcase it writes still reproduces. */
202
2
    sigset_t alarm;
203
2
    sigemptyset(&alarm);
204
2
    sigaddset(&alarm, SIGALRM);
205
2
    pthread_sigmask(SIG_BLOCK, &alarm, NULL);
206
207
2
    pthread_mutex_lock(&fuzz_r_thread.mutex);
208
4.94k
    for (;;) {
209
9.88k
        while (fuzz_r_thread.job == NULL)
210
4.94k
            pthread_cond_wait(&fuzz_r_thread.cond, &fuzz_r_thread.mutex);
211
4.94k
        fuzz_job_t *job = fuzz_r_thread.job;
212
4.94k
        pthread_mutex_unlock(&fuzz_r_thread.mutex);
213
214
4.94k
        job->fn(job->arg);
215
216
4.94k
        pthread_mutex_lock(&fuzz_r_thread.mutex);
217
4.94k
        fuzz_r_thread.job = NULL;
218
4.94k
        pthread_cond_broadcast(&fuzz_r_thread.cond);
219
4.94k
    }
220
    return NULL;
221
2
}
decompress.c:fuzz_r_thread_main
Line
Count
Source
188
2
{
189
2
    (void)unused;
190
    /* The frame address rather than a local's: under ASAN an address-taken
191
     * local may sit on the fake stack, nowhere near this thread's stack.
192
     * R_CStackStart matters only once R is initialized; fuzz_init_r()
193
     * sets it again after Rf_initialize_R has overwritten it. */
194
2
    fuzz_r_thread.stack_top = (uintptr_t)__builtin_frame_address(0);
195
2
    R_CStackStart = fuzz_r_thread.stack_top;
196
197
    /* libFuzzer's -timeout alarm is acted on only by the thread running
198
     * its loop (the main thread); delivered here it would be ignored and
199
     * the input would run on.  Block it so the kernel cannot pick this
200
     * thread.  A timeout report therefore shows the main thread waiting
201
     * rather than where R is; the testcase it writes still reproduces. */
202
2
    sigset_t alarm;
203
2
    sigemptyset(&alarm);
204
2
    sigaddset(&alarm, SIGALRM);
205
2
    pthread_sigmask(SIG_BLOCK, &alarm, NULL);
206
207
2
    pthread_mutex_lock(&fuzz_r_thread.mutex);
208
1.62k
    for (;;) {
209
3.25k
        while (fuzz_r_thread.job == NULL)
210
1.62k
            pthread_cond_wait(&fuzz_r_thread.cond, &fuzz_r_thread.mutex);
211
1.62k
        fuzz_job_t *job = fuzz_r_thread.job;
212
1.62k
        pthread_mutex_unlock(&fuzz_r_thread.mutex);
213
214
1.62k
        job->fn(job->arg);
215
216
1.62k
        pthread_mutex_lock(&fuzz_r_thread.mutex);
217
1.62k
        fuzz_r_thread.job = NULL;
218
1.62k
        pthread_cond_broadcast(&fuzz_r_thread.cond);
219
1.62k
    }
220
    return NULL;
221
2
}
readtable.c:fuzz_r_thread_main
Line
Count
Source
188
2
{
189
2
    (void)unused;
190
    /* The frame address rather than a local's: under ASAN an address-taken
191
     * local may sit on the fake stack, nowhere near this thread's stack.
192
     * R_CStackStart matters only once R is initialized; fuzz_init_r()
193
     * sets it again after Rf_initialize_R has overwritten it. */
194
2
    fuzz_r_thread.stack_top = (uintptr_t)__builtin_frame_address(0);
195
2
    R_CStackStart = fuzz_r_thread.stack_top;
196
197
    /* libFuzzer's -timeout alarm is acted on only by the thread running
198
     * its loop (the main thread); delivered here it would be ignored and
199
     * the input would run on.  Block it so the kernel cannot pick this
200
     * thread.  A timeout report therefore shows the main thread waiting
201
     * rather than where R is; the testcase it writes still reproduces. */
202
2
    sigset_t alarm;
203
2
    sigemptyset(&alarm);
204
2
    sigaddset(&alarm, SIGALRM);
205
2
    pthread_sigmask(SIG_BLOCK, &alarm, NULL);
206
207
2
    pthread_mutex_lock(&fuzz_r_thread.mutex);
208
351
    for (;;) {
209
700
        while (fuzz_r_thread.job == NULL)
210
349
            pthread_cond_wait(&fuzz_r_thread.cond, &fuzz_r_thread.mutex);
211
351
        fuzz_job_t *job = fuzz_r_thread.job;
212
351
        pthread_mutex_unlock(&fuzz_r_thread.mutex);
213
214
351
        job->fn(job->arg);
215
216
351
        pthread_mutex_lock(&fuzz_r_thread.mutex);
217
351
        fuzz_r_thread.job = NULL;
218
351
        pthread_cond_broadcast(&fuzz_r_thread.cond);
219
351
    }
220
    return NULL;
221
2
}
format.c:fuzz_r_thread_main
Line
Count
Source
188
2
{
189
2
    (void)unused;
190
    /* The frame address rather than a local's: under ASAN an address-taken
191
     * local may sit on the fake stack, nowhere near this thread's stack.
192
     * R_CStackStart matters only once R is initialized; fuzz_init_r()
193
     * sets it again after Rf_initialize_R has overwritten it. */
194
2
    fuzz_r_thread.stack_top = (uintptr_t)__builtin_frame_address(0);
195
2
    R_CStackStart = fuzz_r_thread.stack_top;
196
197
    /* libFuzzer's -timeout alarm is acted on only by the thread running
198
     * its loop (the main thread); delivered here it would be ignored and
199
     * the input would run on.  Block it so the kernel cannot pick this
200
     * thread.  A timeout report therefore shows the main thread waiting
201
     * rather than where R is; the testcase it writes still reproduces. */
202
2
    sigset_t alarm;
203
2
    sigemptyset(&alarm);
204
2
    sigaddset(&alarm, SIGALRM);
205
2
    pthread_sigmask(SIG_BLOCK, &alarm, NULL);
206
207
2
    pthread_mutex_lock(&fuzz_r_thread.mutex);
208
5.16k
    for (;;) {
209
10.3k
        while (fuzz_r_thread.job == NULL)
210
5.16k
            pthread_cond_wait(&fuzz_r_thread.cond, &fuzz_r_thread.mutex);
211
5.16k
        fuzz_job_t *job = fuzz_r_thread.job;
212
5.16k
        pthread_mutex_unlock(&fuzz_r_thread.mutex);
213
214
5.16k
        job->fn(job->arg);
215
216
5.16k
        pthread_mutex_lock(&fuzz_r_thread.mutex);
217
5.16k
        fuzz_r_thread.job = NULL;
218
5.16k
        pthread_cond_broadcast(&fuzz_r_thread.cond);
219
5.16k
    }
220
    return NULL;
221
2
}
datetime.c:fuzz_r_thread_main
Line
Count
Source
188
2
{
189
2
    (void)unused;
190
    /* The frame address rather than a local's: under ASAN an address-taken
191
     * local may sit on the fake stack, nowhere near this thread's stack.
192
     * R_CStackStart matters only once R is initialized; fuzz_init_r()
193
     * sets it again after Rf_initialize_R has overwritten it. */
194
2
    fuzz_r_thread.stack_top = (uintptr_t)__builtin_frame_address(0);
195
2
    R_CStackStart = fuzz_r_thread.stack_top;
196
197
    /* libFuzzer's -timeout alarm is acted on only by the thread running
198
     * its loop (the main thread); delivered here it would be ignored and
199
     * the input would run on.  Block it so the kernel cannot pick this
200
     * thread.  A timeout report therefore shows the main thread waiting
201
     * rather than where R is; the testcase it writes still reproduces. */
202
2
    sigset_t alarm;
203
2
    sigemptyset(&alarm);
204
2
    sigaddset(&alarm, SIGALRM);
205
2
    pthread_sigmask(SIG_BLOCK, &alarm, NULL);
206
207
2
    pthread_mutex_lock(&fuzz_r_thread.mutex);
208
5.07k
    for (;;) {
209
10.1k
        while (fuzz_r_thread.job == NULL)
210
5.06k
            pthread_cond_wait(&fuzz_r_thread.cond, &fuzz_r_thread.mutex);
211
5.07k
        fuzz_job_t *job = fuzz_r_thread.job;
212
5.07k
        pthread_mutex_unlock(&fuzz_r_thread.mutex);
213
214
5.07k
        job->fn(job->arg);
215
216
5.07k
        pthread_mutex_lock(&fuzz_r_thread.mutex);
217
5.07k
        fuzz_r_thread.job = NULL;
218
5.07k
        pthread_cond_broadcast(&fuzz_r_thread.cond);
219
5.07k
    }
220
    return NULL;
221
2
}
coerce.c:fuzz_r_thread_main
Line
Count
Source
188
2
{
189
2
    (void)unused;
190
    /* The frame address rather than a local's: under ASAN an address-taken
191
     * local may sit on the fake stack, nowhere near this thread's stack.
192
     * R_CStackStart matters only once R is initialized; fuzz_init_r()
193
     * sets it again after Rf_initialize_R has overwritten it. */
194
2
    fuzz_r_thread.stack_top = (uintptr_t)__builtin_frame_address(0);
195
2
    R_CStackStart = fuzz_r_thread.stack_top;
196
197
    /* libFuzzer's -timeout alarm is acted on only by the thread running
198
     * its loop (the main thread); delivered here it would be ignored and
199
     * the input would run on.  Block it so the kernel cannot pick this
200
     * thread.  A timeout report therefore shows the main thread waiting
201
     * rather than where R is; the testcase it writes still reproduces. */
202
2
    sigset_t alarm;
203
2
    sigemptyset(&alarm);
204
2
    sigaddset(&alarm, SIGALRM);
205
2
    pthread_sigmask(SIG_BLOCK, &alarm, NULL);
206
207
2
    pthread_mutex_lock(&fuzz_r_thread.mutex);
208
1.72k
    for (;;) {
209
3.44k
        while (fuzz_r_thread.job == NULL)
210
1.72k
            pthread_cond_wait(&fuzz_r_thread.cond, &fuzz_r_thread.mutex);
211
1.72k
        fuzz_job_t *job = fuzz_r_thread.job;
212
1.72k
        pthread_mutex_unlock(&fuzz_r_thread.mutex);
213
214
1.72k
        job->fn(job->arg);
215
216
1.72k
        pthread_mutex_lock(&fuzz_r_thread.mutex);
217
1.72k
        fuzz_r_thread.job = NULL;
218
1.72k
        pthread_cond_broadcast(&fuzz_r_thread.cond);
219
1.72k
    }
220
    return NULL;
221
2
}
load.c:fuzz_r_thread_main
Line
Count
Source
188
2
{
189
2
    (void)unused;
190
    /* The frame address rather than a local's: under ASAN an address-taken
191
     * local may sit on the fake stack, nowhere near this thread's stack.
192
     * R_CStackStart matters only once R is initialized; fuzz_init_r()
193
     * sets it again after Rf_initialize_R has overwritten it. */
194
2
    fuzz_r_thread.stack_top = (uintptr_t)__builtin_frame_address(0);
195
2
    R_CStackStart = fuzz_r_thread.stack_top;
196
197
    /* libFuzzer's -timeout alarm is acted on only by the thread running
198
     * its loop (the main thread); delivered here it would be ignored and
199
     * the input would run on.  Block it so the kernel cannot pick this
200
     * thread.  A timeout report therefore shows the main thread waiting
201
     * rather than where R is; the testcase it writes still reproduces. */
202
2
    sigset_t alarm;
203
2
    sigemptyset(&alarm);
204
2
    sigaddset(&alarm, SIGALRM);
205
2
    pthread_sigmask(SIG_BLOCK, &alarm, NULL);
206
207
2
    pthread_mutex_lock(&fuzz_r_thread.mutex);
208
5.34k
    for (;;) {
209
10.6k
        while (fuzz_r_thread.job == NULL)
210
5.33k
            pthread_cond_wait(&fuzz_r_thread.cond, &fuzz_r_thread.mutex);
211
5.34k
        fuzz_job_t *job = fuzz_r_thread.job;
212
5.34k
        pthread_mutex_unlock(&fuzz_r_thread.mutex);
213
214
5.34k
        job->fn(job->arg);
215
216
5.34k
        pthread_mutex_lock(&fuzz_r_thread.mutex);
217
5.34k
        fuzz_r_thread.job = NULL;
218
5.34k
        pthread_cond_broadcast(&fuzz_r_thread.cond);
219
5.34k
    }
220
    return NULL;
221
2
}
scan.c:fuzz_r_thread_main
Line
Count
Source
188
2
{
189
2
    (void)unused;
190
    /* The frame address rather than a local's: under ASAN an address-taken
191
     * local may sit on the fake stack, nowhere near this thread's stack.
192
     * R_CStackStart matters only once R is initialized; fuzz_init_r()
193
     * sets it again after Rf_initialize_R has overwritten it. */
194
2
    fuzz_r_thread.stack_top = (uintptr_t)__builtin_frame_address(0);
195
2
    R_CStackStart = fuzz_r_thread.stack_top;
196
197
    /* libFuzzer's -timeout alarm is acted on only by the thread running
198
     * its loop (the main thread); delivered here it would be ignored and
199
     * the input would run on.  Block it so the kernel cannot pick this
200
     * thread.  A timeout report therefore shows the main thread waiting
201
     * rather than where R is; the testcase it writes still reproduces. */
202
2
    sigset_t alarm;
203
2
    sigemptyset(&alarm);
204
2
    sigaddset(&alarm, SIGALRM);
205
2
    pthread_sigmask(SIG_BLOCK, &alarm, NULL);
206
207
2
    pthread_mutex_lock(&fuzz_r_thread.mutex);
208
2.82k
    for (;;) {
209
5.64k
        while (fuzz_r_thread.job == NULL)
210
2.81k
            pthread_cond_wait(&fuzz_r_thread.cond, &fuzz_r_thread.mutex);
211
2.82k
        fuzz_job_t *job = fuzz_r_thread.job;
212
2.82k
        pthread_mutex_unlock(&fuzz_r_thread.mutex);
213
214
2.82k
        job->fn(job->arg);
215
216
2.82k
        pthread_mutex_lock(&fuzz_r_thread.mutex);
217
2.82k
        fuzz_r_thread.job = NULL;
218
2.82k
        pthread_cond_broadcast(&fuzz_r_thread.cond);
219
2.82k
    }
220
    return NULL;
221
2
}
colors.c:fuzz_r_thread_main
Line
Count
Source
188
2
{
189
2
    (void)unused;
190
    /* The frame address rather than a local's: under ASAN an address-taken
191
     * local may sit on the fake stack, nowhere near this thread's stack.
192
     * R_CStackStart matters only once R is initialized; fuzz_init_r()
193
     * sets it again after Rf_initialize_R has overwritten it. */
194
2
    fuzz_r_thread.stack_top = (uintptr_t)__builtin_frame_address(0);
195
2
    R_CStackStart = fuzz_r_thread.stack_top;
196
197
    /* libFuzzer's -timeout alarm is acted on only by the thread running
198
     * its loop (the main thread); delivered here it would be ignored and
199
     * the input would run on.  Block it so the kernel cannot pick this
200
     * thread.  A timeout report therefore shows the main thread waiting
201
     * rather than where R is; the testcase it writes still reproduces. */
202
2
    sigset_t alarm;
203
2
    sigemptyset(&alarm);
204
2
    sigaddset(&alarm, SIGALRM);
205
2
    pthread_sigmask(SIG_BLOCK, &alarm, NULL);
206
207
2
    pthread_mutex_lock(&fuzz_r_thread.mutex);
208
1.88k
    for (;;) {
209
3.77k
        while (fuzz_r_thread.job == NULL)
210
1.88k
            pthread_cond_wait(&fuzz_r_thread.cond, &fuzz_r_thread.mutex);
211
1.88k
        fuzz_job_t *job = fuzz_r_thread.job;
212
1.88k
        pthread_mutex_unlock(&fuzz_r_thread.mutex);
213
214
1.88k
        job->fn(job->arg);
215
216
1.88k
        pthread_mutex_lock(&fuzz_r_thread.mutex);
217
1.88k
        fuzz_r_thread.job = NULL;
218
1.88k
        pthread_cond_broadcast(&fuzz_r_thread.cond);
219
1.88k
    }
220
    return NULL;
221
2
}
parse.c:fuzz_r_thread_main
Line
Count
Source
188
2
{
189
2
    (void)unused;
190
    /* The frame address rather than a local's: under ASAN an address-taken
191
     * local may sit on the fake stack, nowhere near this thread's stack.
192
     * R_CStackStart matters only once R is initialized; fuzz_init_r()
193
     * sets it again after Rf_initialize_R has overwritten it. */
194
2
    fuzz_r_thread.stack_top = (uintptr_t)__builtin_frame_address(0);
195
2
    R_CStackStart = fuzz_r_thread.stack_top;
196
197
    /* libFuzzer's -timeout alarm is acted on only by the thread running
198
     * its loop (the main thread); delivered here it would be ignored and
199
     * the input would run on.  Block it so the kernel cannot pick this
200
     * thread.  A timeout report therefore shows the main thread waiting
201
     * rather than where R is; the testcase it writes still reproduces. */
202
2
    sigset_t alarm;
203
2
    sigemptyset(&alarm);
204
2
    sigaddset(&alarm, SIGALRM);
205
2
    pthread_sigmask(SIG_BLOCK, &alarm, NULL);
206
207
2
    pthread_mutex_lock(&fuzz_r_thread.mutex);
208
7.03k
    for (;;) {
209
14.0k
        while (fuzz_r_thread.job == NULL)
210
7.02k
            pthread_cond_wait(&fuzz_r_thread.cond, &fuzz_r_thread.mutex);
211
7.03k
        fuzz_job_t *job = fuzz_r_thread.job;
212
7.03k
        pthread_mutex_unlock(&fuzz_r_thread.mutex);
213
214
7.03k
        job->fn(job->arg);
215
216
7.03k
        pthread_mutex_lock(&fuzz_r_thread.mutex);
217
7.03k
        fuzz_r_thread.job = NULL;
218
7.03k
        pthread_cond_broadcast(&fuzz_r_thread.cond);
219
7.03k
    }
220
    return NULL;
221
2
}
sprintf.c:fuzz_r_thread_main
Line
Count
Source
188
2
{
189
2
    (void)unused;
190
    /* The frame address rather than a local's: under ASAN an address-taken
191
     * local may sit on the fake stack, nowhere near this thread's stack.
192
     * R_CStackStart matters only once R is initialized; fuzz_init_r()
193
     * sets it again after Rf_initialize_R has overwritten it. */
194
2
    fuzz_r_thread.stack_top = (uintptr_t)__builtin_frame_address(0);
195
2
    R_CStackStart = fuzz_r_thread.stack_top;
196
197
    /* libFuzzer's -timeout alarm is acted on only by the thread running
198
     * its loop (the main thread); delivered here it would be ignored and
199
     * the input would run on.  Block it so the kernel cannot pick this
200
     * thread.  A timeout report therefore shows the main thread waiting
201
     * rather than where R is; the testcase it writes still reproduces. */
202
2
    sigset_t alarm;
203
2
    sigemptyset(&alarm);
204
2
    sigaddset(&alarm, SIGALRM);
205
2
    pthread_sigmask(SIG_BLOCK, &alarm, NULL);
206
207
2
    pthread_mutex_lock(&fuzz_r_thread.mutex);
208
1.97k
    for (;;) {
209
3.95k
        while (fuzz_r_thread.job == NULL)
210
1.97k
            pthread_cond_wait(&fuzz_r_thread.cond, &fuzz_r_thread.mutex);
211
1.97k
        fuzz_job_t *job = fuzz_r_thread.job;
212
1.97k
        pthread_mutex_unlock(&fuzz_r_thread.mutex);
213
214
1.97k
        job->fn(job->arg);
215
216
1.97k
        pthread_mutex_lock(&fuzz_r_thread.mutex);
217
1.97k
        fuzz_r_thread.job = NULL;
218
1.97k
        pthread_cond_broadcast(&fuzz_r_thread.cond);
219
1.97k
    }
220
    return NULL;
221
2
}
eval.c:fuzz_r_thread_main
Line
Count
Source
188
2
{
189
2
    (void)unused;
190
    /* The frame address rather than a local's: under ASAN an address-taken
191
     * local may sit on the fake stack, nowhere near this thread's stack.
192
     * R_CStackStart matters only once R is initialized; fuzz_init_r()
193
     * sets it again after Rf_initialize_R has overwritten it. */
194
2
    fuzz_r_thread.stack_top = (uintptr_t)__builtin_frame_address(0);
195
2
    R_CStackStart = fuzz_r_thread.stack_top;
196
197
    /* libFuzzer's -timeout alarm is acted on only by the thread running
198
     * its loop (the main thread); delivered here it would be ignored and
199
     * the input would run on.  Block it so the kernel cannot pick this
200
     * thread.  A timeout report therefore shows the main thread waiting
201
     * rather than where R is; the testcase it writes still reproduces. */
202
2
    sigset_t alarm;
203
2
    sigemptyset(&alarm);
204
2
    sigaddset(&alarm, SIGALRM);
205
2
    pthread_sigmask(SIG_BLOCK, &alarm, NULL);
206
207
2
    pthread_mutex_lock(&fuzz_r_thread.mutex);
208
9.20k
    for (;;) {
209
18.4k
        while (fuzz_r_thread.job == NULL)
210
9.20k
            pthread_cond_wait(&fuzz_r_thread.cond, &fuzz_r_thread.mutex);
211
9.20k
        fuzz_job_t *job = fuzz_r_thread.job;
212
9.20k
        pthread_mutex_unlock(&fuzz_r_thread.mutex);
213
214
9.20k
        job->fn(job->arg);
215
216
9.20k
        pthread_mutex_lock(&fuzz_r_thread.mutex);
217
9.20k
        fuzz_r_thread.job = NULL;
218
9.20k
        pthread_cond_broadcast(&fuzz_r_thread.cond);
219
9.20k
    }
220
    return NULL;
221
2
}
zip.c:fuzz_r_thread_main
Line
Count
Source
188
2
{
189
2
    (void)unused;
190
    /* The frame address rather than a local's: under ASAN an address-taken
191
     * local may sit on the fake stack, nowhere near this thread's stack.
192
     * R_CStackStart matters only once R is initialized; fuzz_init_r()
193
     * sets it again after Rf_initialize_R has overwritten it. */
194
2
    fuzz_r_thread.stack_top = (uintptr_t)__builtin_frame_address(0);
195
2
    R_CStackStart = fuzz_r_thread.stack_top;
196
197
    /* libFuzzer's -timeout alarm is acted on only by the thread running
198
     * its loop (the main thread); delivered here it would be ignored and
199
     * the input would run on.  Block it so the kernel cannot pick this
200
     * thread.  A timeout report therefore shows the main thread waiting
201
     * rather than where R is; the testcase it writes still reproduces. */
202
2
    sigset_t alarm;
203
2
    sigemptyset(&alarm);
204
2
    sigaddset(&alarm, SIGALRM);
205
2
    pthread_sigmask(SIG_BLOCK, &alarm, NULL);
206
207
2
    pthread_mutex_lock(&fuzz_r_thread.mutex);
208
1.81k
    for (;;) {
209
3.63k
        while (fuzz_r_thread.job == NULL)
210
1.81k
            pthread_cond_wait(&fuzz_r_thread.cond, &fuzz_r_thread.mutex);
211
1.81k
        fuzz_job_t *job = fuzz_r_thread.job;
212
1.81k
        pthread_mutex_unlock(&fuzz_r_thread.mutex);
213
214
1.81k
        job->fn(job->arg);
215
216
1.81k
        pthread_mutex_lock(&fuzz_r_thread.mutex);
217
1.81k
        fuzz_r_thread.job = NULL;
218
1.81k
        pthread_cond_broadcast(&fuzz_r_thread.cond);
219
1.81k
    }
220
    return NULL;
221
2
}
222
223
static int fuzz_on_r_thread(void)
224
69.1k
{
225
69.1k
    return fuzz_r_thread.started &&
226
69.1k
           pthread_equal(pthread_self(), fuzz_r_thread.thread);
227
69.1k
}
io.c:fuzz_on_r_thread
Line
Count
Source
224
1.57k
{
225
1.57k
    return fuzz_r_thread.started &&
226
1.57k
           pthread_equal(pthread_self(), fuzz_r_thread.thread);
227
1.57k
}
dcf.c:fuzz_on_r_thread
Line
Count
Source
224
4.76k
{
225
4.76k
    return fuzz_r_thread.started &&
226
4.76k
           pthread_equal(pthread_self(), fuzz_r_thread.thread);
227
4.76k
}
character.c:fuzz_on_r_thread
Line
Count
Source
224
3.59k
{
225
3.59k
    return fuzz_r_thread.started &&
226
3.59k
           pthread_equal(pthread_self(), fuzz_r_thread.thread);
227
3.59k
}
encoding.c:fuzz_on_r_thread
Line
Count
Source
224
1.53k
{
225
1.53k
    return fuzz_r_thread.started &&
226
1.53k
           pthread_equal(pthread_self(), fuzz_r_thread.thread);
227
1.53k
}
sort.c:fuzz_on_r_thread
Line
Count
Source
224
6.34k
{
225
6.34k
    return fuzz_r_thread.started &&
226
6.34k
           pthread_equal(pthread_self(), fuzz_r_thread.thread);
227
6.34k
}
connections.c:fuzz_on_r_thread
Line
Count
Source
224
2.43k
{
225
2.43k
    return fuzz_r_thread.started &&
226
2.43k
           pthread_equal(pthread_self(), fuzz_r_thread.thread);
227
2.43k
}
unserialize.c:fuzz_on_r_thread
Line
Count
Source
224
4.94k
{
225
4.94k
    return fuzz_r_thread.started &&
226
4.94k
           pthread_equal(pthread_self(), fuzz_r_thread.thread);
227
4.94k
}
decompress.c:fuzz_on_r_thread
Line
Count
Source
224
1.62k
{
225
1.62k
    return fuzz_r_thread.started &&
226
1.62k
           pthread_equal(pthread_self(), fuzz_r_thread.thread);
227
1.62k
}
readtable.c:fuzz_on_r_thread
Line
Count
Source
224
351
{
225
351
    return fuzz_r_thread.started &&
226
351
           pthread_equal(pthread_self(), fuzz_r_thread.thread);
227
351
}
format.c:fuzz_on_r_thread
Line
Count
Source
224
5.16k
{
225
5.16k
    return fuzz_r_thread.started &&
226
5.16k
           pthread_equal(pthread_self(), fuzz_r_thread.thread);
227
5.16k
}
datetime.c:fuzz_on_r_thread
Line
Count
Source
224
5.07k
{
225
5.07k
    return fuzz_r_thread.started &&
226
5.07k
           pthread_equal(pthread_self(), fuzz_r_thread.thread);
227
5.07k
}
coerce.c:fuzz_on_r_thread
Line
Count
Source
224
1.72k
{
225
1.72k
    return fuzz_r_thread.started &&
226
1.72k
           pthread_equal(pthread_self(), fuzz_r_thread.thread);
227
1.72k
}
load.c:fuzz_on_r_thread
Line
Count
Source
224
5.34k
{
225
5.34k
    return fuzz_r_thread.started &&
226
5.34k
           pthread_equal(pthread_self(), fuzz_r_thread.thread);
227
5.34k
}
scan.c:fuzz_on_r_thread
Line
Count
Source
224
2.82k
{
225
2.82k
    return fuzz_r_thread.started &&
226
2.82k
           pthread_equal(pthread_self(), fuzz_r_thread.thread);
227
2.82k
}
colors.c:fuzz_on_r_thread
Line
Count
Source
224
1.88k
{
225
1.88k
    return fuzz_r_thread.started &&
226
1.88k
           pthread_equal(pthread_self(), fuzz_r_thread.thread);
227
1.88k
}
parse.c:fuzz_on_r_thread
Line
Count
Source
224
7.03k
{
225
7.03k
    return fuzz_r_thread.started &&
226
7.03k
           pthread_equal(pthread_self(), fuzz_r_thread.thread);
227
7.03k
}
sprintf.c:fuzz_on_r_thread
Line
Count
Source
224
1.97k
{
225
1.97k
    return fuzz_r_thread.started &&
226
1.97k
           pthread_equal(pthread_self(), fuzz_r_thread.thread);
227
1.97k
}
eval.c:fuzz_on_r_thread
Line
Count
Source
224
9.20k
{
225
9.20k
    return fuzz_r_thread.started &&
226
9.20k
           pthread_equal(pthread_self(), fuzz_r_thread.thread);
227
9.20k
}
zip.c:fuzz_on_r_thread
Line
Count
Source
224
1.81k
{
225
1.81k
    return fuzz_r_thread.started &&
226
1.81k
           pthread_equal(pthread_self(), fuzz_r_thread.thread);
227
1.81k
}
228
229
/* Child side of fork: only the forking thread survives, so the R thread
230
 * is gone, and if it was the one waiting in pthread_cond_wait the
231
 * condition variable still counts it.  Nothing holds the mutex during a
232
 * fork from either side of the handoff, so resetting both is safe;
233
 * pthread_cond_destroy would wait for the phantom waiter instead. */
234
static void fuzz_r_thread_forget(void)
235
0
{
236
0
    fuzz_r_thread.started = 0;
237
0
    fuzz_r_thread.job = NULL;
238
0
    fuzz_r_thread.mutex = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;
239
0
    fuzz_r_thread.cond = (pthread_cond_t)PTHREAD_COND_INITIALIZER;
240
0
}
Unexecuted instantiation: io.c:fuzz_r_thread_forget
Unexecuted instantiation: dcf.c:fuzz_r_thread_forget
Unexecuted instantiation: character.c:fuzz_r_thread_forget
Unexecuted instantiation: encoding.c:fuzz_r_thread_forget
Unexecuted instantiation: sort.c:fuzz_r_thread_forget
Unexecuted instantiation: connections.c:fuzz_r_thread_forget
Unexecuted instantiation: unserialize.c:fuzz_r_thread_forget
Unexecuted instantiation: decompress.c:fuzz_r_thread_forget
Unexecuted instantiation: readtable.c:fuzz_r_thread_forget
Unexecuted instantiation: format.c:fuzz_r_thread_forget
Unexecuted instantiation: datetime.c:fuzz_r_thread_forget
Unexecuted instantiation: coerce.c:fuzz_r_thread_forget
Unexecuted instantiation: load.c:fuzz_r_thread_forget
Unexecuted instantiation: scan.c:fuzz_r_thread_forget
Unexecuted instantiation: colors.c:fuzz_r_thread_forget
Unexecuted instantiation: parse.c:fuzz_r_thread_forget
Unexecuted instantiation: sprintf.c:fuzz_r_thread_forget
Unexecuted instantiation: eval.c:fuzz_r_thread_forget
Unexecuted instantiation: zip.c:fuzz_r_thread_forget
241
242
/* Run fn(arg) on the R thread and wait for it to return, starting the
243
 * thread on first use.  From the R thread itself this is a plain call. */
244
static void fuzz_run_on_r_thread(void (*fn)(void *), void *arg)
245
69.1k
{
246
69.1k
    if (!fuzz_r_thread.started) {
247
38
        static int atfork_registered = 0;
248
38
        if (!atfork_registered) {
249
38
            if (pthread_atfork(NULL, NULL, fuzz_r_thread_forget) != 0) {
250
0
                fprintf(stderr, "fuzz: cannot register the fork handler\n");
251
0
                abort();
252
0
            }
253
38
            atfork_registered = 1;
254
38
        }
255
256
38
        pthread_attr_t attr;
257
38
        if (pthread_attr_init(&attr) != 0 ||
258
38
            pthread_attr_setstacksize(&attr, FUZZ_R_STACK_SIZE) != 0 ||
259
38
            pthread_create(&fuzz_r_thread.thread, &attr,
260
38
                           fuzz_r_thread_main, NULL) != 0) {
261
0
            fprintf(stderr, "fuzz: cannot start the R thread\n");
262
0
            abort();
263
0
        }
264
38
        pthread_attr_destroy(&attr);
265
38
        fuzz_r_thread.started = 1;
266
38
    }
267
268
69.1k
    if (fuzz_on_r_thread()) {
269
0
        fn(arg);
270
0
        return;
271
0
    }
272
273
69.1k
    fuzz_job_t job = { fn, arg };
274
69.1k
    pthread_mutex_lock(&fuzz_r_thread.mutex);
275
69.1k
    fuzz_r_thread.job = &job;
276
69.1k
    pthread_cond_broadcast(&fuzz_r_thread.cond);
277
138k
    while (fuzz_r_thread.job != NULL)
278
69.1k
        pthread_cond_wait(&fuzz_r_thread.cond, &fuzz_r_thread.mutex);
279
69.1k
    pthread_mutex_unlock(&fuzz_r_thread.mutex);
280
69.1k
}
io.c:fuzz_run_on_r_thread
Line
Count
Source
245
1.57k
{
246
1.57k
    if (!fuzz_r_thread.started) {
247
2
        static int atfork_registered = 0;
248
2
        if (!atfork_registered) {
249
2
            if (pthread_atfork(NULL, NULL, fuzz_r_thread_forget) != 0) {
250
0
                fprintf(stderr, "fuzz: cannot register the fork handler\n");
251
0
                abort();
252
0
            }
253
2
            atfork_registered = 1;
254
2
        }
255
256
2
        pthread_attr_t attr;
257
2
        if (pthread_attr_init(&attr) != 0 ||
258
2
            pthread_attr_setstacksize(&attr, FUZZ_R_STACK_SIZE) != 0 ||
259
2
            pthread_create(&fuzz_r_thread.thread, &attr,
260
2
                           fuzz_r_thread_main, NULL) != 0) {
261
0
            fprintf(stderr, "fuzz: cannot start the R thread\n");
262
0
            abort();
263
0
        }
264
2
        pthread_attr_destroy(&attr);
265
2
        fuzz_r_thread.started = 1;
266
2
    }
267
268
1.57k
    if (fuzz_on_r_thread()) {
269
0
        fn(arg);
270
0
        return;
271
0
    }
272
273
1.57k
    fuzz_job_t job = { fn, arg };
274
1.57k
    pthread_mutex_lock(&fuzz_r_thread.mutex);
275
1.57k
    fuzz_r_thread.job = &job;
276
1.57k
    pthread_cond_broadcast(&fuzz_r_thread.cond);
277
3.14k
    while (fuzz_r_thread.job != NULL)
278
1.57k
        pthread_cond_wait(&fuzz_r_thread.cond, &fuzz_r_thread.mutex);
279
1.57k
    pthread_mutex_unlock(&fuzz_r_thread.mutex);
280
1.57k
}
dcf.c:fuzz_run_on_r_thread
Line
Count
Source
245
4.76k
{
246
4.76k
    if (!fuzz_r_thread.started) {
247
2
        static int atfork_registered = 0;
248
2
        if (!atfork_registered) {
249
2
            if (pthread_atfork(NULL, NULL, fuzz_r_thread_forget) != 0) {
250
0
                fprintf(stderr, "fuzz: cannot register the fork handler\n");
251
0
                abort();
252
0
            }
253
2
            atfork_registered = 1;
254
2
        }
255
256
2
        pthread_attr_t attr;
257
2
        if (pthread_attr_init(&attr) != 0 ||
258
2
            pthread_attr_setstacksize(&attr, FUZZ_R_STACK_SIZE) != 0 ||
259
2
            pthread_create(&fuzz_r_thread.thread, &attr,
260
2
                           fuzz_r_thread_main, NULL) != 0) {
261
0
            fprintf(stderr, "fuzz: cannot start the R thread\n");
262
0
            abort();
263
0
        }
264
2
        pthread_attr_destroy(&attr);
265
2
        fuzz_r_thread.started = 1;
266
2
    }
267
268
4.76k
    if (fuzz_on_r_thread()) {
269
0
        fn(arg);
270
0
        return;
271
0
    }
272
273
4.76k
    fuzz_job_t job = { fn, arg };
274
4.76k
    pthread_mutex_lock(&fuzz_r_thread.mutex);
275
4.76k
    fuzz_r_thread.job = &job;
276
4.76k
    pthread_cond_broadcast(&fuzz_r_thread.cond);
277
9.53k
    while (fuzz_r_thread.job != NULL)
278
4.76k
        pthread_cond_wait(&fuzz_r_thread.cond, &fuzz_r_thread.mutex);
279
4.76k
    pthread_mutex_unlock(&fuzz_r_thread.mutex);
280
4.76k
}
character.c:fuzz_run_on_r_thread
Line
Count
Source
245
3.58k
{
246
3.58k
    if (!fuzz_r_thread.started) {
247
2
        static int atfork_registered = 0;
248
2
        if (!atfork_registered) {
249
2
            if (pthread_atfork(NULL, NULL, fuzz_r_thread_forget) != 0) {
250
0
                fprintf(stderr, "fuzz: cannot register the fork handler\n");
251
0
                abort();
252
0
            }
253
2
            atfork_registered = 1;
254
2
        }
255
256
2
        pthread_attr_t attr;
257
2
        if (pthread_attr_init(&attr) != 0 ||
258
2
            pthread_attr_setstacksize(&attr, FUZZ_R_STACK_SIZE) != 0 ||
259
2
            pthread_create(&fuzz_r_thread.thread, &attr,
260
2
                           fuzz_r_thread_main, NULL) != 0) {
261
0
            fprintf(stderr, "fuzz: cannot start the R thread\n");
262
0
            abort();
263
0
        }
264
2
        pthread_attr_destroy(&attr);
265
2
        fuzz_r_thread.started = 1;
266
2
    }
267
268
3.58k
    if (fuzz_on_r_thread()) {
269
0
        fn(arg);
270
0
        return;
271
0
    }
272
273
3.58k
    fuzz_job_t job = { fn, arg };
274
3.58k
    pthread_mutex_lock(&fuzz_r_thread.mutex);
275
3.58k
    fuzz_r_thread.job = &job;
276
3.58k
    pthread_cond_broadcast(&fuzz_r_thread.cond);
277
7.17k
    while (fuzz_r_thread.job != NULL)
278
3.58k
        pthread_cond_wait(&fuzz_r_thread.cond, &fuzz_r_thread.mutex);
279
3.58k
    pthread_mutex_unlock(&fuzz_r_thread.mutex);
280
3.58k
}
encoding.c:fuzz_run_on_r_thread
Line
Count
Source
245
1.52k
{
246
1.52k
    if (!fuzz_r_thread.started) {
247
2
        static int atfork_registered = 0;
248
2
        if (!atfork_registered) {
249
2
            if (pthread_atfork(NULL, NULL, fuzz_r_thread_forget) != 0) {
250
0
                fprintf(stderr, "fuzz: cannot register the fork handler\n");
251
0
                abort();
252
0
            }
253
2
            atfork_registered = 1;
254
2
        }
255
256
2
        pthread_attr_t attr;
257
2
        if (pthread_attr_init(&attr) != 0 ||
258
2
            pthread_attr_setstacksize(&attr, FUZZ_R_STACK_SIZE) != 0 ||
259
2
            pthread_create(&fuzz_r_thread.thread, &attr,
260
2
                           fuzz_r_thread_main, NULL) != 0) {
261
0
            fprintf(stderr, "fuzz: cannot start the R thread\n");
262
0
            abort();
263
0
        }
264
2
        pthread_attr_destroy(&attr);
265
2
        fuzz_r_thread.started = 1;
266
2
    }
267
268
1.52k
    if (fuzz_on_r_thread()) {
269
0
        fn(arg);
270
0
        return;
271
0
    }
272
273
1.52k
    fuzz_job_t job = { fn, arg };
274
1.52k
    pthread_mutex_lock(&fuzz_r_thread.mutex);
275
1.52k
    fuzz_r_thread.job = &job;
276
1.52k
    pthread_cond_broadcast(&fuzz_r_thread.cond);
277
3.05k
    while (fuzz_r_thread.job != NULL)
278
1.52k
        pthread_cond_wait(&fuzz_r_thread.cond, &fuzz_r_thread.mutex);
279
1.52k
    pthread_mutex_unlock(&fuzz_r_thread.mutex);
280
1.52k
}
sort.c:fuzz_run_on_r_thread
Line
Count
Source
245
6.33k
{
246
6.33k
    if (!fuzz_r_thread.started) {
247
2
        static int atfork_registered = 0;
248
2
        if (!atfork_registered) {
249
2
            if (pthread_atfork(NULL, NULL, fuzz_r_thread_forget) != 0) {
250
0
                fprintf(stderr, "fuzz: cannot register the fork handler\n");
251
0
                abort();
252
0
            }
253
2
            atfork_registered = 1;
254
2
        }
255
256
2
        pthread_attr_t attr;
257
2
        if (pthread_attr_init(&attr) != 0 ||
258
2
            pthread_attr_setstacksize(&attr, FUZZ_R_STACK_SIZE) != 0 ||
259
2
            pthread_create(&fuzz_r_thread.thread, &attr,
260
2
                           fuzz_r_thread_main, NULL) != 0) {
261
0
            fprintf(stderr, "fuzz: cannot start the R thread\n");
262
0
            abort();
263
0
        }
264
2
        pthread_attr_destroy(&attr);
265
2
        fuzz_r_thread.started = 1;
266
2
    }
267
268
6.33k
    if (fuzz_on_r_thread()) {
269
0
        fn(arg);
270
0
        return;
271
0
    }
272
273
6.33k
    fuzz_job_t job = { fn, arg };
274
6.33k
    pthread_mutex_lock(&fuzz_r_thread.mutex);
275
6.33k
    fuzz_r_thread.job = &job;
276
6.33k
    pthread_cond_broadcast(&fuzz_r_thread.cond);
277
12.6k
    while (fuzz_r_thread.job != NULL)
278
6.33k
        pthread_cond_wait(&fuzz_r_thread.cond, &fuzz_r_thread.mutex);
279
6.33k
    pthread_mutex_unlock(&fuzz_r_thread.mutex);
280
6.33k
}
connections.c:fuzz_run_on_r_thread
Line
Count
Source
245
2.43k
{
246
2.43k
    if (!fuzz_r_thread.started) {
247
2
        static int atfork_registered = 0;
248
2
        if (!atfork_registered) {
249
2
            if (pthread_atfork(NULL, NULL, fuzz_r_thread_forget) != 0) {
250
0
                fprintf(stderr, "fuzz: cannot register the fork handler\n");
251
0
                abort();
252
0
            }
253
2
            atfork_registered = 1;
254
2
        }
255
256
2
        pthread_attr_t attr;
257
2
        if (pthread_attr_init(&attr) != 0 ||
258
2
            pthread_attr_setstacksize(&attr, FUZZ_R_STACK_SIZE) != 0 ||
259
2
            pthread_create(&fuzz_r_thread.thread, &attr,
260
2
                           fuzz_r_thread_main, NULL) != 0) {
261
0
            fprintf(stderr, "fuzz: cannot start the R thread\n");
262
0
            abort();
263
0
        }
264
2
        pthread_attr_destroy(&attr);
265
2
        fuzz_r_thread.started = 1;
266
2
    }
267
268
2.43k
    if (fuzz_on_r_thread()) {
269
0
        fn(arg);
270
0
        return;
271
0
    }
272
273
2.43k
    fuzz_job_t job = { fn, arg };
274
2.43k
    pthread_mutex_lock(&fuzz_r_thread.mutex);
275
2.43k
    fuzz_r_thread.job = &job;
276
2.43k
    pthread_cond_broadcast(&fuzz_r_thread.cond);
277
4.86k
    while (fuzz_r_thread.job != NULL)
278
2.43k
        pthread_cond_wait(&fuzz_r_thread.cond, &fuzz_r_thread.mutex);
279
2.43k
    pthread_mutex_unlock(&fuzz_r_thread.mutex);
280
2.43k
}
unserialize.c:fuzz_run_on_r_thread
Line
Count
Source
245
4.94k
{
246
4.94k
    if (!fuzz_r_thread.started) {
247
2
        static int atfork_registered = 0;
248
2
        if (!atfork_registered) {
249
2
            if (pthread_atfork(NULL, NULL, fuzz_r_thread_forget) != 0) {
250
0
                fprintf(stderr, "fuzz: cannot register the fork handler\n");
251
0
                abort();
252
0
            }
253
2
            atfork_registered = 1;
254
2
        }
255
256
2
        pthread_attr_t attr;
257
2
        if (pthread_attr_init(&attr) != 0 ||
258
2
            pthread_attr_setstacksize(&attr, FUZZ_R_STACK_SIZE) != 0 ||
259
2
            pthread_create(&fuzz_r_thread.thread, &attr,
260
2
                           fuzz_r_thread_main, NULL) != 0) {
261
0
            fprintf(stderr, "fuzz: cannot start the R thread\n");
262
0
            abort();
263
0
        }
264
2
        pthread_attr_destroy(&attr);
265
2
        fuzz_r_thread.started = 1;
266
2
    }
267
268
4.94k
    if (fuzz_on_r_thread()) {
269
0
        fn(arg);
270
0
        return;
271
0
    }
272
273
4.94k
    fuzz_job_t job = { fn, arg };
274
4.94k
    pthread_mutex_lock(&fuzz_r_thread.mutex);
275
4.94k
    fuzz_r_thread.job = &job;
276
4.94k
    pthread_cond_broadcast(&fuzz_r_thread.cond);
277
9.88k
    while (fuzz_r_thread.job != NULL)
278
4.94k
        pthread_cond_wait(&fuzz_r_thread.cond, &fuzz_r_thread.mutex);
279
4.94k
    pthread_mutex_unlock(&fuzz_r_thread.mutex);
280
4.94k
}
decompress.c:fuzz_run_on_r_thread
Line
Count
Source
245
1.62k
{
246
1.62k
    if (!fuzz_r_thread.started) {
247
2
        static int atfork_registered = 0;
248
2
        if (!atfork_registered) {
249
2
            if (pthread_atfork(NULL, NULL, fuzz_r_thread_forget) != 0) {
250
0
                fprintf(stderr, "fuzz: cannot register the fork handler\n");
251
0
                abort();
252
0
            }
253
2
            atfork_registered = 1;
254
2
        }
255
256
2
        pthread_attr_t attr;
257
2
        if (pthread_attr_init(&attr) != 0 ||
258
2
            pthread_attr_setstacksize(&attr, FUZZ_R_STACK_SIZE) != 0 ||
259
2
            pthread_create(&fuzz_r_thread.thread, &attr,
260
2
                           fuzz_r_thread_main, NULL) != 0) {
261
0
            fprintf(stderr, "fuzz: cannot start the R thread\n");
262
0
            abort();
263
0
        }
264
2
        pthread_attr_destroy(&attr);
265
2
        fuzz_r_thread.started = 1;
266
2
    }
267
268
1.62k
    if (fuzz_on_r_thread()) {
269
0
        fn(arg);
270
0
        return;
271
0
    }
272
273
1.62k
    fuzz_job_t job = { fn, arg };
274
1.62k
    pthread_mutex_lock(&fuzz_r_thread.mutex);
275
1.62k
    fuzz_r_thread.job = &job;
276
1.62k
    pthread_cond_broadcast(&fuzz_r_thread.cond);
277
3.24k
    while (fuzz_r_thread.job != NULL)
278
1.62k
        pthread_cond_wait(&fuzz_r_thread.cond, &fuzz_r_thread.mutex);
279
1.62k
    pthread_mutex_unlock(&fuzz_r_thread.mutex);
280
1.62k
}
readtable.c:fuzz_run_on_r_thread
Line
Count
Source
245
349
{
246
349
    if (!fuzz_r_thread.started) {
247
2
        static int atfork_registered = 0;
248
2
        if (!atfork_registered) {
249
2
            if (pthread_atfork(NULL, NULL, fuzz_r_thread_forget) != 0) {
250
0
                fprintf(stderr, "fuzz: cannot register the fork handler\n");
251
0
                abort();
252
0
            }
253
2
            atfork_registered = 1;
254
2
        }
255
256
2
        pthread_attr_t attr;
257
2
        if (pthread_attr_init(&attr) != 0 ||
258
2
            pthread_attr_setstacksize(&attr, FUZZ_R_STACK_SIZE) != 0 ||
259
2
            pthread_create(&fuzz_r_thread.thread, &attr,
260
2
                           fuzz_r_thread_main, NULL) != 0) {
261
0
            fprintf(stderr, "fuzz: cannot start the R thread\n");
262
0
            abort();
263
0
        }
264
2
        pthread_attr_destroy(&attr);
265
2
        fuzz_r_thread.started = 1;
266
2
    }
267
268
349
    if (fuzz_on_r_thread()) {
269
0
        fn(arg);
270
0
        return;
271
0
    }
272
273
349
    fuzz_job_t job = { fn, arg };
274
349
    pthread_mutex_lock(&fuzz_r_thread.mutex);
275
349
    fuzz_r_thread.job = &job;
276
349
    pthread_cond_broadcast(&fuzz_r_thread.cond);
277
698
    while (fuzz_r_thread.job != NULL)
278
349
        pthread_cond_wait(&fuzz_r_thread.cond, &fuzz_r_thread.mutex);
279
349
    pthread_mutex_unlock(&fuzz_r_thread.mutex);
280
349
}
format.c:fuzz_run_on_r_thread
Line
Count
Source
245
5.16k
{
246
5.16k
    if (!fuzz_r_thread.started) {
247
2
        static int atfork_registered = 0;
248
2
        if (!atfork_registered) {
249
2
            if (pthread_atfork(NULL, NULL, fuzz_r_thread_forget) != 0) {
250
0
                fprintf(stderr, "fuzz: cannot register the fork handler\n");
251
0
                abort();
252
0
            }
253
2
            atfork_registered = 1;
254
2
        }
255
256
2
        pthread_attr_t attr;
257
2
        if (pthread_attr_init(&attr) != 0 ||
258
2
            pthread_attr_setstacksize(&attr, FUZZ_R_STACK_SIZE) != 0 ||
259
2
            pthread_create(&fuzz_r_thread.thread, &attr,
260
2
                           fuzz_r_thread_main, NULL) != 0) {
261
0
            fprintf(stderr, "fuzz: cannot start the R thread\n");
262
0
            abort();
263
0
        }
264
2
        pthread_attr_destroy(&attr);
265
2
        fuzz_r_thread.started = 1;
266
2
    }
267
268
5.16k
    if (fuzz_on_r_thread()) {
269
0
        fn(arg);
270
0
        return;
271
0
    }
272
273
5.16k
    fuzz_job_t job = { fn, arg };
274
5.16k
    pthread_mutex_lock(&fuzz_r_thread.mutex);
275
5.16k
    fuzz_r_thread.job = &job;
276
5.16k
    pthread_cond_broadcast(&fuzz_r_thread.cond);
277
10.3k
    while (fuzz_r_thread.job != NULL)
278
5.16k
        pthread_cond_wait(&fuzz_r_thread.cond, &fuzz_r_thread.mutex);
279
5.16k
    pthread_mutex_unlock(&fuzz_r_thread.mutex);
280
5.16k
}
datetime.c:fuzz_run_on_r_thread
Line
Count
Source
245
5.06k
{
246
5.06k
    if (!fuzz_r_thread.started) {
247
2
        static int atfork_registered = 0;
248
2
        if (!atfork_registered) {
249
2
            if (pthread_atfork(NULL, NULL, fuzz_r_thread_forget) != 0) {
250
0
                fprintf(stderr, "fuzz: cannot register the fork handler\n");
251
0
                abort();
252
0
            }
253
2
            atfork_registered = 1;
254
2
        }
255
256
2
        pthread_attr_t attr;
257
2
        if (pthread_attr_init(&attr) != 0 ||
258
2
            pthread_attr_setstacksize(&attr, FUZZ_R_STACK_SIZE) != 0 ||
259
2
            pthread_create(&fuzz_r_thread.thread, &attr,
260
2
                           fuzz_r_thread_main, NULL) != 0) {
261
0
            fprintf(stderr, "fuzz: cannot start the R thread\n");
262
0
            abort();
263
0
        }
264
2
        pthread_attr_destroy(&attr);
265
2
        fuzz_r_thread.started = 1;
266
2
    }
267
268
5.06k
    if (fuzz_on_r_thread()) {
269
0
        fn(arg);
270
0
        return;
271
0
    }
272
273
5.06k
    fuzz_job_t job = { fn, arg };
274
5.06k
    pthread_mutex_lock(&fuzz_r_thread.mutex);
275
5.06k
    fuzz_r_thread.job = &job;
276
5.06k
    pthread_cond_broadcast(&fuzz_r_thread.cond);
277
10.1k
    while (fuzz_r_thread.job != NULL)
278
5.06k
        pthread_cond_wait(&fuzz_r_thread.cond, &fuzz_r_thread.mutex);
279
5.06k
    pthread_mutex_unlock(&fuzz_r_thread.mutex);
280
5.06k
}
coerce.c:fuzz_run_on_r_thread
Line
Count
Source
245
1.72k
{
246
1.72k
    if (!fuzz_r_thread.started) {
247
2
        static int atfork_registered = 0;
248
2
        if (!atfork_registered) {
249
2
            if (pthread_atfork(NULL, NULL, fuzz_r_thread_forget) != 0) {
250
0
                fprintf(stderr, "fuzz: cannot register the fork handler\n");
251
0
                abort();
252
0
            }
253
2
            atfork_registered = 1;
254
2
        }
255
256
2
        pthread_attr_t attr;
257
2
        if (pthread_attr_init(&attr) != 0 ||
258
2
            pthread_attr_setstacksize(&attr, FUZZ_R_STACK_SIZE) != 0 ||
259
2
            pthread_create(&fuzz_r_thread.thread, &attr,
260
2
                           fuzz_r_thread_main, NULL) != 0) {
261
0
            fprintf(stderr, "fuzz: cannot start the R thread\n");
262
0
            abort();
263
0
        }
264
2
        pthread_attr_destroy(&attr);
265
2
        fuzz_r_thread.started = 1;
266
2
    }
267
268
1.72k
    if (fuzz_on_r_thread()) {
269
0
        fn(arg);
270
0
        return;
271
0
    }
272
273
1.72k
    fuzz_job_t job = { fn, arg };
274
1.72k
    pthread_mutex_lock(&fuzz_r_thread.mutex);
275
1.72k
    fuzz_r_thread.job = &job;
276
1.72k
    pthread_cond_broadcast(&fuzz_r_thread.cond);
277
3.44k
    while (fuzz_r_thread.job != NULL)
278
1.72k
        pthread_cond_wait(&fuzz_r_thread.cond, &fuzz_r_thread.mutex);
279
1.72k
    pthread_mutex_unlock(&fuzz_r_thread.mutex);
280
1.72k
}
load.c:fuzz_run_on_r_thread
Line
Count
Source
245
5.33k
{
246
5.33k
    if (!fuzz_r_thread.started) {
247
2
        static int atfork_registered = 0;
248
2
        if (!atfork_registered) {
249
2
            if (pthread_atfork(NULL, NULL, fuzz_r_thread_forget) != 0) {
250
0
                fprintf(stderr, "fuzz: cannot register the fork handler\n");
251
0
                abort();
252
0
            }
253
2
            atfork_registered = 1;
254
2
        }
255
256
2
        pthread_attr_t attr;
257
2
        if (pthread_attr_init(&attr) != 0 ||
258
2
            pthread_attr_setstacksize(&attr, FUZZ_R_STACK_SIZE) != 0 ||
259
2
            pthread_create(&fuzz_r_thread.thread, &attr,
260
2
                           fuzz_r_thread_main, NULL) != 0) {
261
0
            fprintf(stderr, "fuzz: cannot start the R thread\n");
262
0
            abort();
263
0
        }
264
2
        pthread_attr_destroy(&attr);
265
2
        fuzz_r_thread.started = 1;
266
2
    }
267
268
5.33k
    if (fuzz_on_r_thread()) {
269
0
        fn(arg);
270
0
        return;
271
0
    }
272
273
5.33k
    fuzz_job_t job = { fn, arg };
274
5.33k
    pthread_mutex_lock(&fuzz_r_thread.mutex);
275
5.33k
    fuzz_r_thread.job = &job;
276
5.33k
    pthread_cond_broadcast(&fuzz_r_thread.cond);
277
10.6k
    while (fuzz_r_thread.job != NULL)
278
5.33k
        pthread_cond_wait(&fuzz_r_thread.cond, &fuzz_r_thread.mutex);
279
5.33k
    pthread_mutex_unlock(&fuzz_r_thread.mutex);
280
5.33k
}
scan.c:fuzz_run_on_r_thread
Line
Count
Source
245
2.81k
{
246
2.81k
    if (!fuzz_r_thread.started) {
247
2
        static int atfork_registered = 0;
248
2
        if (!atfork_registered) {
249
2
            if (pthread_atfork(NULL, NULL, fuzz_r_thread_forget) != 0) {
250
0
                fprintf(stderr, "fuzz: cannot register the fork handler\n");
251
0
                abort();
252
0
            }
253
2
            atfork_registered = 1;
254
2
        }
255
256
2
        pthread_attr_t attr;
257
2
        if (pthread_attr_init(&attr) != 0 ||
258
2
            pthread_attr_setstacksize(&attr, FUZZ_R_STACK_SIZE) != 0 ||
259
2
            pthread_create(&fuzz_r_thread.thread, &attr,
260
2
                           fuzz_r_thread_main, NULL) != 0) {
261
0
            fprintf(stderr, "fuzz: cannot start the R thread\n");
262
0
            abort();
263
0
        }
264
2
        pthread_attr_destroy(&attr);
265
2
        fuzz_r_thread.started = 1;
266
2
    }
267
268
2.81k
    if (fuzz_on_r_thread()) {
269
0
        fn(arg);
270
0
        return;
271
0
    }
272
273
2.81k
    fuzz_job_t job = { fn, arg };
274
2.81k
    pthread_mutex_lock(&fuzz_r_thread.mutex);
275
2.81k
    fuzz_r_thread.job = &job;
276
2.81k
    pthread_cond_broadcast(&fuzz_r_thread.cond);
277
5.63k
    while (fuzz_r_thread.job != NULL)
278
2.81k
        pthread_cond_wait(&fuzz_r_thread.cond, &fuzz_r_thread.mutex);
279
2.81k
    pthread_mutex_unlock(&fuzz_r_thread.mutex);
280
2.81k
}
colors.c:fuzz_run_on_r_thread
Line
Count
Source
245
1.88k
{
246
1.88k
    if (!fuzz_r_thread.started) {
247
2
        static int atfork_registered = 0;
248
2
        if (!atfork_registered) {
249
2
            if (pthread_atfork(NULL, NULL, fuzz_r_thread_forget) != 0) {
250
0
                fprintf(stderr, "fuzz: cannot register the fork handler\n");
251
0
                abort();
252
0
            }
253
2
            atfork_registered = 1;
254
2
        }
255
256
2
        pthread_attr_t attr;
257
2
        if (pthread_attr_init(&attr) != 0 ||
258
2
            pthread_attr_setstacksize(&attr, FUZZ_R_STACK_SIZE) != 0 ||
259
2
            pthread_create(&fuzz_r_thread.thread, &attr,
260
2
                           fuzz_r_thread_main, NULL) != 0) {
261
0
            fprintf(stderr, "fuzz: cannot start the R thread\n");
262
0
            abort();
263
0
        }
264
2
        pthread_attr_destroy(&attr);
265
2
        fuzz_r_thread.started = 1;
266
2
    }
267
268
1.88k
    if (fuzz_on_r_thread()) {
269
0
        fn(arg);
270
0
        return;
271
0
    }
272
273
1.88k
    fuzz_job_t job = { fn, arg };
274
1.88k
    pthread_mutex_lock(&fuzz_r_thread.mutex);
275
1.88k
    fuzz_r_thread.job = &job;
276
1.88k
    pthread_cond_broadcast(&fuzz_r_thread.cond);
277
3.77k
    while (fuzz_r_thread.job != NULL)
278
1.88k
        pthread_cond_wait(&fuzz_r_thread.cond, &fuzz_r_thread.mutex);
279
1.88k
    pthread_mutex_unlock(&fuzz_r_thread.mutex);
280
1.88k
}
parse.c:fuzz_run_on_r_thread
Line
Count
Source
245
7.02k
{
246
7.02k
    if (!fuzz_r_thread.started) {
247
2
        static int atfork_registered = 0;
248
2
        if (!atfork_registered) {
249
2
            if (pthread_atfork(NULL, NULL, fuzz_r_thread_forget) != 0) {
250
0
                fprintf(stderr, "fuzz: cannot register the fork handler\n");
251
0
                abort();
252
0
            }
253
2
            atfork_registered = 1;
254
2
        }
255
256
2
        pthread_attr_t attr;
257
2
        if (pthread_attr_init(&attr) != 0 ||
258
2
            pthread_attr_setstacksize(&attr, FUZZ_R_STACK_SIZE) != 0 ||
259
2
            pthread_create(&fuzz_r_thread.thread, &attr,
260
2
                           fuzz_r_thread_main, NULL) != 0) {
261
0
            fprintf(stderr, "fuzz: cannot start the R thread\n");
262
0
            abort();
263
0
        }
264
2
        pthread_attr_destroy(&attr);
265
2
        fuzz_r_thread.started = 1;
266
2
    }
267
268
7.02k
    if (fuzz_on_r_thread()) {
269
0
        fn(arg);
270
0
        return;
271
0
    }
272
273
7.02k
    fuzz_job_t job = { fn, arg };
274
7.02k
    pthread_mutex_lock(&fuzz_r_thread.mutex);
275
7.02k
    fuzz_r_thread.job = &job;
276
7.02k
    pthread_cond_broadcast(&fuzz_r_thread.cond);
277
14.0k
    while (fuzz_r_thread.job != NULL)
278
7.02k
        pthread_cond_wait(&fuzz_r_thread.cond, &fuzz_r_thread.mutex);
279
7.02k
    pthread_mutex_unlock(&fuzz_r_thread.mutex);
280
7.02k
}
sprintf.c:fuzz_run_on_r_thread
Line
Count
Source
245
1.97k
{
246
1.97k
    if (!fuzz_r_thread.started) {
247
2
        static int atfork_registered = 0;
248
2
        if (!atfork_registered) {
249
2
            if (pthread_atfork(NULL, NULL, fuzz_r_thread_forget) != 0) {
250
0
                fprintf(stderr, "fuzz: cannot register the fork handler\n");
251
0
                abort();
252
0
            }
253
2
            atfork_registered = 1;
254
2
        }
255
256
2
        pthread_attr_t attr;
257
2
        if (pthread_attr_init(&attr) != 0 ||
258
2
            pthread_attr_setstacksize(&attr, FUZZ_R_STACK_SIZE) != 0 ||
259
2
            pthread_create(&fuzz_r_thread.thread, &attr,
260
2
                           fuzz_r_thread_main, NULL) != 0) {
261
0
            fprintf(stderr, "fuzz: cannot start the R thread\n");
262
0
            abort();
263
0
        }
264
2
        pthread_attr_destroy(&attr);
265
2
        fuzz_r_thread.started = 1;
266
2
    }
267
268
1.97k
    if (fuzz_on_r_thread()) {
269
0
        fn(arg);
270
0
        return;
271
0
    }
272
273
1.97k
    fuzz_job_t job = { fn, arg };
274
1.97k
    pthread_mutex_lock(&fuzz_r_thread.mutex);
275
1.97k
    fuzz_r_thread.job = &job;
276
1.97k
    pthread_cond_broadcast(&fuzz_r_thread.cond);
277
3.95k
    while (fuzz_r_thread.job != NULL)
278
1.97k
        pthread_cond_wait(&fuzz_r_thread.cond, &fuzz_r_thread.mutex);
279
1.97k
    pthread_mutex_unlock(&fuzz_r_thread.mutex);
280
1.97k
}
eval.c:fuzz_run_on_r_thread
Line
Count
Source
245
9.20k
{
246
9.20k
    if (!fuzz_r_thread.started) {
247
2
        static int atfork_registered = 0;
248
2
        if (!atfork_registered) {
249
2
            if (pthread_atfork(NULL, NULL, fuzz_r_thread_forget) != 0) {
250
0
                fprintf(stderr, "fuzz: cannot register the fork handler\n");
251
0
                abort();
252
0
            }
253
2
            atfork_registered = 1;
254
2
        }
255
256
2
        pthread_attr_t attr;
257
2
        if (pthread_attr_init(&attr) != 0 ||
258
2
            pthread_attr_setstacksize(&attr, FUZZ_R_STACK_SIZE) != 0 ||
259
2
            pthread_create(&fuzz_r_thread.thread, &attr,
260
2
                           fuzz_r_thread_main, NULL) != 0) {
261
0
            fprintf(stderr, "fuzz: cannot start the R thread\n");
262
0
            abort();
263
0
        }
264
2
        pthread_attr_destroy(&attr);
265
2
        fuzz_r_thread.started = 1;
266
2
    }
267
268
9.20k
    if (fuzz_on_r_thread()) {
269
0
        fn(arg);
270
0
        return;
271
0
    }
272
273
9.20k
    fuzz_job_t job = { fn, arg };
274
9.20k
    pthread_mutex_lock(&fuzz_r_thread.mutex);
275
9.20k
    fuzz_r_thread.job = &job;
276
9.20k
    pthread_cond_broadcast(&fuzz_r_thread.cond);
277
18.4k
    while (fuzz_r_thread.job != NULL)
278
9.20k
        pthread_cond_wait(&fuzz_r_thread.cond, &fuzz_r_thread.mutex);
279
9.20k
    pthread_mutex_unlock(&fuzz_r_thread.mutex);
280
9.20k
}
zip.c:fuzz_run_on_r_thread
Line
Count
Source
245
1.81k
{
246
1.81k
    if (!fuzz_r_thread.started) {
247
2
        static int atfork_registered = 0;
248
2
        if (!atfork_registered) {
249
2
            if (pthread_atfork(NULL, NULL, fuzz_r_thread_forget) != 0) {
250
0
                fprintf(stderr, "fuzz: cannot register the fork handler\n");
251
0
                abort();
252
0
            }
253
2
            atfork_registered = 1;
254
2
        }
255
256
2
        pthread_attr_t attr;
257
2
        if (pthread_attr_init(&attr) != 0 ||
258
2
            pthread_attr_setstacksize(&attr, FUZZ_R_STACK_SIZE) != 0 ||
259
2
            pthread_create(&fuzz_r_thread.thread, &attr,
260
2
                           fuzz_r_thread_main, NULL) != 0) {
261
0
            fprintf(stderr, "fuzz: cannot start the R thread\n");
262
0
            abort();
263
0
        }
264
2
        pthread_attr_destroy(&attr);
265
2
        fuzz_r_thread.started = 1;
266
2
    }
267
268
1.81k
    if (fuzz_on_r_thread()) {
269
0
        fn(arg);
270
0
        return;
271
0
    }
272
273
1.81k
    fuzz_job_t job = { fn, arg };
274
1.81k
    pthread_mutex_lock(&fuzz_r_thread.mutex);
275
1.81k
    fuzz_r_thread.job = &job;
276
1.81k
    pthread_cond_broadcast(&fuzz_r_thread.cond);
277
3.63k
    while (fuzz_r_thread.job != NULL)
278
1.81k
        pthread_cond_wait(&fuzz_r_thread.cond, &fuzz_r_thread.mutex);
279
1.81k
    pthread_mutex_unlock(&fuzz_r_thread.mutex);
280
1.81k
}
281
282
/*
283
 * Initialize R for fuzzing.  Call once from fuzz_target_init.
284
 *
285
 * Performs:
286
 *   1. Set R_HOME from binary location
287
 *   2. Cap the vector heap (must precede R's startup, which reads it)
288
 *   3. Initialize embedded R, without R's signal handlers
289
 *   4. Point R's C stack check at the R thread's stack
290
 *   5. Suppress warnings
291
 */
292
static void fuzz_init_r(void)
293
38
{
294
38
    if (!fuzz_on_r_thread()) {
295
0
        fprintf(stderr, "fuzz_init_r: must run on the R thread "
296
0
                        "(define fuzz_target_init, not LLVMFuzzerInitialize)\n");
297
0
        abort();
298
0
    }
299
300
38
    fuzz_set_r_home();
301
38
    fuzz_set_vsize_limit();
302
303
    /* GC consistency failures ("untraced old-to-new reference", a node
304
     * with a bad type) are memory corruption, not input errors.  R's
305
     * default is to report and carry on; this makes gc_error() fatal
306
     * (through R_Suicide, which instrumentation/0004 turns into abort)
307
     * so they surface as crashes at the collection that found them. */
308
38
    if (getenv("_R_GC_FAIL_ON_ERROR_") == NULL)
309
19
        setenv("_R_GC_FAIL_ON_ERROR_", "yes", 1);
310
311
    /* R's SIGSEGV/SIGILL/etc. handlers enter an interactive recovery
312
     * prompt instead of crashing, which would hang the fuzzer.  Telling
313
     * R not to install them (rather than resetting to SIG_DFL after
314
     * init) keeps the sanitizers' own handlers in place, so wild-pointer
315
     * faults still get full ASAN reports and clean deduplication. */
316
38
    R_SignalHandlers = 0;
317
318
    /* The two halves of Rf_initEmbeddedR, with the C stack check fixed
319
     * up in between.  On Linux Rf_initialize_R takes R_CStackStart from
320
     * __libc_stack_end, the main thread's stack, so from this thread
321
     * every R_CheckStack() while setup_Rmainloop loads base would see
322
     * terabytes of usage and R would abort ("unable to initialize the
323
     * JIT").  macOS never sets it when embedded, which hides this
324
     * locally.  Switch the check off for startup, then measure against
325
     * this thread with R's own 5% of headroom for handling the overflow
326
     * error: R_CheckStack() fires as an ordinary R error at
327
     * 0.95 * FUZZ_R_STACK_SIZE rather than the sanitizer catching a fault.
328
     * setup_Rmainloop itself would turn any limit above 100 MB into
329
     * "unlimited", hence setting it after. */
330
38
    char *r_argv[] = {"R", "--vanilla", "--no-echo", "--no-restore"};
331
38
    int r_argc = sizeof(r_argv) / sizeof(r_argv[0]);
332
38
    Rf_initialize_R(r_argc, r_argv);
333
38
    R_CStackStart = fuzz_r_thread.stack_top;
334
38
    R_CStackLimit = (uintptr_t)-1;
335
38
    R_Interactive = TRUE;   /* as Rf_initEmbeddedR */
336
38
    setup_Rmainloop();
337
38
    R_CStackLimit = (uintptr_t)(0.95 * FUZZ_R_STACK_SIZE);
338
339
38
    fuzz_suppress_warnings();
340
38
}
io.c:fuzz_init_r
Line
Count
Source
293
2
{
294
2
    if (!fuzz_on_r_thread()) {
295
0
        fprintf(stderr, "fuzz_init_r: must run on the R thread "
296
0
                        "(define fuzz_target_init, not LLVMFuzzerInitialize)\n");
297
0
        abort();
298
0
    }
299
300
2
    fuzz_set_r_home();
301
2
    fuzz_set_vsize_limit();
302
303
    /* GC consistency failures ("untraced old-to-new reference", a node
304
     * with a bad type) are memory corruption, not input errors.  R's
305
     * default is to report and carry on; this makes gc_error() fatal
306
     * (through R_Suicide, which instrumentation/0004 turns into abort)
307
     * so they surface as crashes at the collection that found them. */
308
2
    if (getenv("_R_GC_FAIL_ON_ERROR_") == NULL)
309
1
        setenv("_R_GC_FAIL_ON_ERROR_", "yes", 1);
310
311
    /* R's SIGSEGV/SIGILL/etc. handlers enter an interactive recovery
312
     * prompt instead of crashing, which would hang the fuzzer.  Telling
313
     * R not to install them (rather than resetting to SIG_DFL after
314
     * init) keeps the sanitizers' own handlers in place, so wild-pointer
315
     * faults still get full ASAN reports and clean deduplication. */
316
2
    R_SignalHandlers = 0;
317
318
    /* The two halves of Rf_initEmbeddedR, with the C stack check fixed
319
     * up in between.  On Linux Rf_initialize_R takes R_CStackStart from
320
     * __libc_stack_end, the main thread's stack, so from this thread
321
     * every R_CheckStack() while setup_Rmainloop loads base would see
322
     * terabytes of usage and R would abort ("unable to initialize the
323
     * JIT").  macOS never sets it when embedded, which hides this
324
     * locally.  Switch the check off for startup, then measure against
325
     * this thread with R's own 5% of headroom for handling the overflow
326
     * error: R_CheckStack() fires as an ordinary R error at
327
     * 0.95 * FUZZ_R_STACK_SIZE rather than the sanitizer catching a fault.
328
     * setup_Rmainloop itself would turn any limit above 100 MB into
329
     * "unlimited", hence setting it after. */
330
2
    char *r_argv[] = {"R", "--vanilla", "--no-echo", "--no-restore"};
331
2
    int r_argc = sizeof(r_argv) / sizeof(r_argv[0]);
332
2
    Rf_initialize_R(r_argc, r_argv);
333
2
    R_CStackStart = fuzz_r_thread.stack_top;
334
2
    R_CStackLimit = (uintptr_t)-1;
335
2
    R_Interactive = TRUE;   /* as Rf_initEmbeddedR */
336
2
    setup_Rmainloop();
337
2
    R_CStackLimit = (uintptr_t)(0.95 * FUZZ_R_STACK_SIZE);
338
339
2
    fuzz_suppress_warnings();
340
2
}
dcf.c:fuzz_init_r
Line
Count
Source
293
2
{
294
2
    if (!fuzz_on_r_thread()) {
295
0
        fprintf(stderr, "fuzz_init_r: must run on the R thread "
296
0
                        "(define fuzz_target_init, not LLVMFuzzerInitialize)\n");
297
0
        abort();
298
0
    }
299
300
2
    fuzz_set_r_home();
301
2
    fuzz_set_vsize_limit();
302
303
    /* GC consistency failures ("untraced old-to-new reference", a node
304
     * with a bad type) are memory corruption, not input errors.  R's
305
     * default is to report and carry on; this makes gc_error() fatal
306
     * (through R_Suicide, which instrumentation/0004 turns into abort)
307
     * so they surface as crashes at the collection that found them. */
308
2
    if (getenv("_R_GC_FAIL_ON_ERROR_") == NULL)
309
1
        setenv("_R_GC_FAIL_ON_ERROR_", "yes", 1);
310
311
    /* R's SIGSEGV/SIGILL/etc. handlers enter an interactive recovery
312
     * prompt instead of crashing, which would hang the fuzzer.  Telling
313
     * R not to install them (rather than resetting to SIG_DFL after
314
     * init) keeps the sanitizers' own handlers in place, so wild-pointer
315
     * faults still get full ASAN reports and clean deduplication. */
316
2
    R_SignalHandlers = 0;
317
318
    /* The two halves of Rf_initEmbeddedR, with the C stack check fixed
319
     * up in between.  On Linux Rf_initialize_R takes R_CStackStart from
320
     * __libc_stack_end, the main thread's stack, so from this thread
321
     * every R_CheckStack() while setup_Rmainloop loads base would see
322
     * terabytes of usage and R would abort ("unable to initialize the
323
     * JIT").  macOS never sets it when embedded, which hides this
324
     * locally.  Switch the check off for startup, then measure against
325
     * this thread with R's own 5% of headroom for handling the overflow
326
     * error: R_CheckStack() fires as an ordinary R error at
327
     * 0.95 * FUZZ_R_STACK_SIZE rather than the sanitizer catching a fault.
328
     * setup_Rmainloop itself would turn any limit above 100 MB into
329
     * "unlimited", hence setting it after. */
330
2
    char *r_argv[] = {"R", "--vanilla", "--no-echo", "--no-restore"};
331
2
    int r_argc = sizeof(r_argv) / sizeof(r_argv[0]);
332
2
    Rf_initialize_R(r_argc, r_argv);
333
2
    R_CStackStart = fuzz_r_thread.stack_top;
334
2
    R_CStackLimit = (uintptr_t)-1;
335
2
    R_Interactive = TRUE;   /* as Rf_initEmbeddedR */
336
2
    setup_Rmainloop();
337
2
    R_CStackLimit = (uintptr_t)(0.95 * FUZZ_R_STACK_SIZE);
338
339
2
    fuzz_suppress_warnings();
340
2
}
character.c:fuzz_init_r
Line
Count
Source
293
2
{
294
2
    if (!fuzz_on_r_thread()) {
295
0
        fprintf(stderr, "fuzz_init_r: must run on the R thread "
296
0
                        "(define fuzz_target_init, not LLVMFuzzerInitialize)\n");
297
0
        abort();
298
0
    }
299
300
2
    fuzz_set_r_home();
301
2
    fuzz_set_vsize_limit();
302
303
    /* GC consistency failures ("untraced old-to-new reference", a node
304
     * with a bad type) are memory corruption, not input errors.  R's
305
     * default is to report and carry on; this makes gc_error() fatal
306
     * (through R_Suicide, which instrumentation/0004 turns into abort)
307
     * so they surface as crashes at the collection that found them. */
308
2
    if (getenv("_R_GC_FAIL_ON_ERROR_") == NULL)
309
1
        setenv("_R_GC_FAIL_ON_ERROR_", "yes", 1);
310
311
    /* R's SIGSEGV/SIGILL/etc. handlers enter an interactive recovery
312
     * prompt instead of crashing, which would hang the fuzzer.  Telling
313
     * R not to install them (rather than resetting to SIG_DFL after
314
     * init) keeps the sanitizers' own handlers in place, so wild-pointer
315
     * faults still get full ASAN reports and clean deduplication. */
316
2
    R_SignalHandlers = 0;
317
318
    /* The two halves of Rf_initEmbeddedR, with the C stack check fixed
319
     * up in between.  On Linux Rf_initialize_R takes R_CStackStart from
320
     * __libc_stack_end, the main thread's stack, so from this thread
321
     * every R_CheckStack() while setup_Rmainloop loads base would see
322
     * terabytes of usage and R would abort ("unable to initialize the
323
     * JIT").  macOS never sets it when embedded, which hides this
324
     * locally.  Switch the check off for startup, then measure against
325
     * this thread with R's own 5% of headroom for handling the overflow
326
     * error: R_CheckStack() fires as an ordinary R error at
327
     * 0.95 * FUZZ_R_STACK_SIZE rather than the sanitizer catching a fault.
328
     * setup_Rmainloop itself would turn any limit above 100 MB into
329
     * "unlimited", hence setting it after. */
330
2
    char *r_argv[] = {"R", "--vanilla", "--no-echo", "--no-restore"};
331
2
    int r_argc = sizeof(r_argv) / sizeof(r_argv[0]);
332
2
    Rf_initialize_R(r_argc, r_argv);
333
2
    R_CStackStart = fuzz_r_thread.stack_top;
334
2
    R_CStackLimit = (uintptr_t)-1;
335
2
    R_Interactive = TRUE;   /* as Rf_initEmbeddedR */
336
2
    setup_Rmainloop();
337
2
    R_CStackLimit = (uintptr_t)(0.95 * FUZZ_R_STACK_SIZE);
338
339
2
    fuzz_suppress_warnings();
340
2
}
encoding.c:fuzz_init_r
Line
Count
Source
293
2
{
294
2
    if (!fuzz_on_r_thread()) {
295
0
        fprintf(stderr, "fuzz_init_r: must run on the R thread "
296
0
                        "(define fuzz_target_init, not LLVMFuzzerInitialize)\n");
297
0
        abort();
298
0
    }
299
300
2
    fuzz_set_r_home();
301
2
    fuzz_set_vsize_limit();
302
303
    /* GC consistency failures ("untraced old-to-new reference", a node
304
     * with a bad type) are memory corruption, not input errors.  R's
305
     * default is to report and carry on; this makes gc_error() fatal
306
     * (through R_Suicide, which instrumentation/0004 turns into abort)
307
     * so they surface as crashes at the collection that found them. */
308
2
    if (getenv("_R_GC_FAIL_ON_ERROR_") == NULL)
309
1
        setenv("_R_GC_FAIL_ON_ERROR_", "yes", 1);
310
311
    /* R's SIGSEGV/SIGILL/etc. handlers enter an interactive recovery
312
     * prompt instead of crashing, which would hang the fuzzer.  Telling
313
     * R not to install them (rather than resetting to SIG_DFL after
314
     * init) keeps the sanitizers' own handlers in place, so wild-pointer
315
     * faults still get full ASAN reports and clean deduplication. */
316
2
    R_SignalHandlers = 0;
317
318
    /* The two halves of Rf_initEmbeddedR, with the C stack check fixed
319
     * up in between.  On Linux Rf_initialize_R takes R_CStackStart from
320
     * __libc_stack_end, the main thread's stack, so from this thread
321
     * every R_CheckStack() while setup_Rmainloop loads base would see
322
     * terabytes of usage and R would abort ("unable to initialize the
323
     * JIT").  macOS never sets it when embedded, which hides this
324
     * locally.  Switch the check off for startup, then measure against
325
     * this thread with R's own 5% of headroom for handling the overflow
326
     * error: R_CheckStack() fires as an ordinary R error at
327
     * 0.95 * FUZZ_R_STACK_SIZE rather than the sanitizer catching a fault.
328
     * setup_Rmainloop itself would turn any limit above 100 MB into
329
     * "unlimited", hence setting it after. */
330
2
    char *r_argv[] = {"R", "--vanilla", "--no-echo", "--no-restore"};
331
2
    int r_argc = sizeof(r_argv) / sizeof(r_argv[0]);
332
2
    Rf_initialize_R(r_argc, r_argv);
333
2
    R_CStackStart = fuzz_r_thread.stack_top;
334
2
    R_CStackLimit = (uintptr_t)-1;
335
2
    R_Interactive = TRUE;   /* as Rf_initEmbeddedR */
336
2
    setup_Rmainloop();
337
2
    R_CStackLimit = (uintptr_t)(0.95 * FUZZ_R_STACK_SIZE);
338
339
2
    fuzz_suppress_warnings();
340
2
}
sort.c:fuzz_init_r
Line
Count
Source
293
2
{
294
2
    if (!fuzz_on_r_thread()) {
295
0
        fprintf(stderr, "fuzz_init_r: must run on the R thread "
296
0
                        "(define fuzz_target_init, not LLVMFuzzerInitialize)\n");
297
0
        abort();
298
0
    }
299
300
2
    fuzz_set_r_home();
301
2
    fuzz_set_vsize_limit();
302
303
    /* GC consistency failures ("untraced old-to-new reference", a node
304
     * with a bad type) are memory corruption, not input errors.  R's
305
     * default is to report and carry on; this makes gc_error() fatal
306
     * (through R_Suicide, which instrumentation/0004 turns into abort)
307
     * so they surface as crashes at the collection that found them. */
308
2
    if (getenv("_R_GC_FAIL_ON_ERROR_") == NULL)
309
1
        setenv("_R_GC_FAIL_ON_ERROR_", "yes", 1);
310
311
    /* R's SIGSEGV/SIGILL/etc. handlers enter an interactive recovery
312
     * prompt instead of crashing, which would hang the fuzzer.  Telling
313
     * R not to install them (rather than resetting to SIG_DFL after
314
     * init) keeps the sanitizers' own handlers in place, so wild-pointer
315
     * faults still get full ASAN reports and clean deduplication. */
316
2
    R_SignalHandlers = 0;
317
318
    /* The two halves of Rf_initEmbeddedR, with the C stack check fixed
319
     * up in between.  On Linux Rf_initialize_R takes R_CStackStart from
320
     * __libc_stack_end, the main thread's stack, so from this thread
321
     * every R_CheckStack() while setup_Rmainloop loads base would see
322
     * terabytes of usage and R would abort ("unable to initialize the
323
     * JIT").  macOS never sets it when embedded, which hides this
324
     * locally.  Switch the check off for startup, then measure against
325
     * this thread with R's own 5% of headroom for handling the overflow
326
     * error: R_CheckStack() fires as an ordinary R error at
327
     * 0.95 * FUZZ_R_STACK_SIZE rather than the sanitizer catching a fault.
328
     * setup_Rmainloop itself would turn any limit above 100 MB into
329
     * "unlimited", hence setting it after. */
330
2
    char *r_argv[] = {"R", "--vanilla", "--no-echo", "--no-restore"};
331
2
    int r_argc = sizeof(r_argv) / sizeof(r_argv[0]);
332
2
    Rf_initialize_R(r_argc, r_argv);
333
2
    R_CStackStart = fuzz_r_thread.stack_top;
334
2
    R_CStackLimit = (uintptr_t)-1;
335
2
    R_Interactive = TRUE;   /* as Rf_initEmbeddedR */
336
2
    setup_Rmainloop();
337
2
    R_CStackLimit = (uintptr_t)(0.95 * FUZZ_R_STACK_SIZE);
338
339
2
    fuzz_suppress_warnings();
340
2
}
connections.c:fuzz_init_r
Line
Count
Source
293
2
{
294
2
    if (!fuzz_on_r_thread()) {
295
0
        fprintf(stderr, "fuzz_init_r: must run on the R thread "
296
0
                        "(define fuzz_target_init, not LLVMFuzzerInitialize)\n");
297
0
        abort();
298
0
    }
299
300
2
    fuzz_set_r_home();
301
2
    fuzz_set_vsize_limit();
302
303
    /* GC consistency failures ("untraced old-to-new reference", a node
304
     * with a bad type) are memory corruption, not input errors.  R's
305
     * default is to report and carry on; this makes gc_error() fatal
306
     * (through R_Suicide, which instrumentation/0004 turns into abort)
307
     * so they surface as crashes at the collection that found them. */
308
2
    if (getenv("_R_GC_FAIL_ON_ERROR_") == NULL)
309
1
        setenv("_R_GC_FAIL_ON_ERROR_", "yes", 1);
310
311
    /* R's SIGSEGV/SIGILL/etc. handlers enter an interactive recovery
312
     * prompt instead of crashing, which would hang the fuzzer.  Telling
313
     * R not to install them (rather than resetting to SIG_DFL after
314
     * init) keeps the sanitizers' own handlers in place, so wild-pointer
315
     * faults still get full ASAN reports and clean deduplication. */
316
2
    R_SignalHandlers = 0;
317
318
    /* The two halves of Rf_initEmbeddedR, with the C stack check fixed
319
     * up in between.  On Linux Rf_initialize_R takes R_CStackStart from
320
     * __libc_stack_end, the main thread's stack, so from this thread
321
     * every R_CheckStack() while setup_Rmainloop loads base would see
322
     * terabytes of usage and R would abort ("unable to initialize the
323
     * JIT").  macOS never sets it when embedded, which hides this
324
     * locally.  Switch the check off for startup, then measure against
325
     * this thread with R's own 5% of headroom for handling the overflow
326
     * error: R_CheckStack() fires as an ordinary R error at
327
     * 0.95 * FUZZ_R_STACK_SIZE rather than the sanitizer catching a fault.
328
     * setup_Rmainloop itself would turn any limit above 100 MB into
329
     * "unlimited", hence setting it after. */
330
2
    char *r_argv[] = {"R", "--vanilla", "--no-echo", "--no-restore"};
331
2
    int r_argc = sizeof(r_argv) / sizeof(r_argv[0]);
332
2
    Rf_initialize_R(r_argc, r_argv);
333
2
    R_CStackStart = fuzz_r_thread.stack_top;
334
2
    R_CStackLimit = (uintptr_t)-1;
335
2
    R_Interactive = TRUE;   /* as Rf_initEmbeddedR */
336
2
    setup_Rmainloop();
337
2
    R_CStackLimit = (uintptr_t)(0.95 * FUZZ_R_STACK_SIZE);
338
339
2
    fuzz_suppress_warnings();
340
2
}
unserialize.c:fuzz_init_r
Line
Count
Source
293
2
{
294
2
    if (!fuzz_on_r_thread()) {
295
0
        fprintf(stderr, "fuzz_init_r: must run on the R thread "
296
0
                        "(define fuzz_target_init, not LLVMFuzzerInitialize)\n");
297
0
        abort();
298
0
    }
299
300
2
    fuzz_set_r_home();
301
2
    fuzz_set_vsize_limit();
302
303
    /* GC consistency failures ("untraced old-to-new reference", a node
304
     * with a bad type) are memory corruption, not input errors.  R's
305
     * default is to report and carry on; this makes gc_error() fatal
306
     * (through R_Suicide, which instrumentation/0004 turns into abort)
307
     * so they surface as crashes at the collection that found them. */
308
2
    if (getenv("_R_GC_FAIL_ON_ERROR_") == NULL)
309
1
        setenv("_R_GC_FAIL_ON_ERROR_", "yes", 1);
310
311
    /* R's SIGSEGV/SIGILL/etc. handlers enter an interactive recovery
312
     * prompt instead of crashing, which would hang the fuzzer.  Telling
313
     * R not to install them (rather than resetting to SIG_DFL after
314
     * init) keeps the sanitizers' own handlers in place, so wild-pointer
315
     * faults still get full ASAN reports and clean deduplication. */
316
2
    R_SignalHandlers = 0;
317
318
    /* The two halves of Rf_initEmbeddedR, with the C stack check fixed
319
     * up in between.  On Linux Rf_initialize_R takes R_CStackStart from
320
     * __libc_stack_end, the main thread's stack, so from this thread
321
     * every R_CheckStack() while setup_Rmainloop loads base would see
322
     * terabytes of usage and R would abort ("unable to initialize the
323
     * JIT").  macOS never sets it when embedded, which hides this
324
     * locally.  Switch the check off for startup, then measure against
325
     * this thread with R's own 5% of headroom for handling the overflow
326
     * error: R_CheckStack() fires as an ordinary R error at
327
     * 0.95 * FUZZ_R_STACK_SIZE rather than the sanitizer catching a fault.
328
     * setup_Rmainloop itself would turn any limit above 100 MB into
329
     * "unlimited", hence setting it after. */
330
2
    char *r_argv[] = {"R", "--vanilla", "--no-echo", "--no-restore"};
331
2
    int r_argc = sizeof(r_argv) / sizeof(r_argv[0]);
332
2
    Rf_initialize_R(r_argc, r_argv);
333
2
    R_CStackStart = fuzz_r_thread.stack_top;
334
2
    R_CStackLimit = (uintptr_t)-1;
335
2
    R_Interactive = TRUE;   /* as Rf_initEmbeddedR */
336
2
    setup_Rmainloop();
337
2
    R_CStackLimit = (uintptr_t)(0.95 * FUZZ_R_STACK_SIZE);
338
339
2
    fuzz_suppress_warnings();
340
2
}
decompress.c:fuzz_init_r
Line
Count
Source
293
2
{
294
2
    if (!fuzz_on_r_thread()) {
295
0
        fprintf(stderr, "fuzz_init_r: must run on the R thread "
296
0
                        "(define fuzz_target_init, not LLVMFuzzerInitialize)\n");
297
0
        abort();
298
0
    }
299
300
2
    fuzz_set_r_home();
301
2
    fuzz_set_vsize_limit();
302
303
    /* GC consistency failures ("untraced old-to-new reference", a node
304
     * with a bad type) are memory corruption, not input errors.  R's
305
     * default is to report and carry on; this makes gc_error() fatal
306
     * (through R_Suicide, which instrumentation/0004 turns into abort)
307
     * so they surface as crashes at the collection that found them. */
308
2
    if (getenv("_R_GC_FAIL_ON_ERROR_") == NULL)
309
1
        setenv("_R_GC_FAIL_ON_ERROR_", "yes", 1);
310
311
    /* R's SIGSEGV/SIGILL/etc. handlers enter an interactive recovery
312
     * prompt instead of crashing, which would hang the fuzzer.  Telling
313
     * R not to install them (rather than resetting to SIG_DFL after
314
     * init) keeps the sanitizers' own handlers in place, so wild-pointer
315
     * faults still get full ASAN reports and clean deduplication. */
316
2
    R_SignalHandlers = 0;
317
318
    /* The two halves of Rf_initEmbeddedR, with the C stack check fixed
319
     * up in between.  On Linux Rf_initialize_R takes R_CStackStart from
320
     * __libc_stack_end, the main thread's stack, so from this thread
321
     * every R_CheckStack() while setup_Rmainloop loads base would see
322
     * terabytes of usage and R would abort ("unable to initialize the
323
     * JIT").  macOS never sets it when embedded, which hides this
324
     * locally.  Switch the check off for startup, then measure against
325
     * this thread with R's own 5% of headroom for handling the overflow
326
     * error: R_CheckStack() fires as an ordinary R error at
327
     * 0.95 * FUZZ_R_STACK_SIZE rather than the sanitizer catching a fault.
328
     * setup_Rmainloop itself would turn any limit above 100 MB into
329
     * "unlimited", hence setting it after. */
330
2
    char *r_argv[] = {"R", "--vanilla", "--no-echo", "--no-restore"};
331
2
    int r_argc = sizeof(r_argv) / sizeof(r_argv[0]);
332
2
    Rf_initialize_R(r_argc, r_argv);
333
2
    R_CStackStart = fuzz_r_thread.stack_top;
334
2
    R_CStackLimit = (uintptr_t)-1;
335
2
    R_Interactive = TRUE;   /* as Rf_initEmbeddedR */
336
2
    setup_Rmainloop();
337
2
    R_CStackLimit = (uintptr_t)(0.95 * FUZZ_R_STACK_SIZE);
338
339
2
    fuzz_suppress_warnings();
340
2
}
readtable.c:fuzz_init_r
Line
Count
Source
293
2
{
294
2
    if (!fuzz_on_r_thread()) {
295
0
        fprintf(stderr, "fuzz_init_r: must run on the R thread "
296
0
                        "(define fuzz_target_init, not LLVMFuzzerInitialize)\n");
297
0
        abort();
298
0
    }
299
300
2
    fuzz_set_r_home();
301
2
    fuzz_set_vsize_limit();
302
303
    /* GC consistency failures ("untraced old-to-new reference", a node
304
     * with a bad type) are memory corruption, not input errors.  R's
305
     * default is to report and carry on; this makes gc_error() fatal
306
     * (through R_Suicide, which instrumentation/0004 turns into abort)
307
     * so they surface as crashes at the collection that found them. */
308
2
    if (getenv("_R_GC_FAIL_ON_ERROR_") == NULL)
309
1
        setenv("_R_GC_FAIL_ON_ERROR_", "yes", 1);
310
311
    /* R's SIGSEGV/SIGILL/etc. handlers enter an interactive recovery
312
     * prompt instead of crashing, which would hang the fuzzer.  Telling
313
     * R not to install them (rather than resetting to SIG_DFL after
314
     * init) keeps the sanitizers' own handlers in place, so wild-pointer
315
     * faults still get full ASAN reports and clean deduplication. */
316
2
    R_SignalHandlers = 0;
317
318
    /* The two halves of Rf_initEmbeddedR, with the C stack check fixed
319
     * up in between.  On Linux Rf_initialize_R takes R_CStackStart from
320
     * __libc_stack_end, the main thread's stack, so from this thread
321
     * every R_CheckStack() while setup_Rmainloop loads base would see
322
     * terabytes of usage and R would abort ("unable to initialize the
323
     * JIT").  macOS never sets it when embedded, which hides this
324
     * locally.  Switch the check off for startup, then measure against
325
     * this thread with R's own 5% of headroom for handling the overflow
326
     * error: R_CheckStack() fires as an ordinary R error at
327
     * 0.95 * FUZZ_R_STACK_SIZE rather than the sanitizer catching a fault.
328
     * setup_Rmainloop itself would turn any limit above 100 MB into
329
     * "unlimited", hence setting it after. */
330
2
    char *r_argv[] = {"R", "--vanilla", "--no-echo", "--no-restore"};
331
2
    int r_argc = sizeof(r_argv) / sizeof(r_argv[0]);
332
2
    Rf_initialize_R(r_argc, r_argv);
333
2
    R_CStackStart = fuzz_r_thread.stack_top;
334
2
    R_CStackLimit = (uintptr_t)-1;
335
2
    R_Interactive = TRUE;   /* as Rf_initEmbeddedR */
336
2
    setup_Rmainloop();
337
2
    R_CStackLimit = (uintptr_t)(0.95 * FUZZ_R_STACK_SIZE);
338
339
2
    fuzz_suppress_warnings();
340
2
}
format.c:fuzz_init_r
Line
Count
Source
293
2
{
294
2
    if (!fuzz_on_r_thread()) {
295
0
        fprintf(stderr, "fuzz_init_r: must run on the R thread "
296
0
                        "(define fuzz_target_init, not LLVMFuzzerInitialize)\n");
297
0
        abort();
298
0
    }
299
300
2
    fuzz_set_r_home();
301
2
    fuzz_set_vsize_limit();
302
303
    /* GC consistency failures ("untraced old-to-new reference", a node
304
     * with a bad type) are memory corruption, not input errors.  R's
305
     * default is to report and carry on; this makes gc_error() fatal
306
     * (through R_Suicide, which instrumentation/0004 turns into abort)
307
     * so they surface as crashes at the collection that found them. */
308
2
    if (getenv("_R_GC_FAIL_ON_ERROR_") == NULL)
309
1
        setenv("_R_GC_FAIL_ON_ERROR_", "yes", 1);
310
311
    /* R's SIGSEGV/SIGILL/etc. handlers enter an interactive recovery
312
     * prompt instead of crashing, which would hang the fuzzer.  Telling
313
     * R not to install them (rather than resetting to SIG_DFL after
314
     * init) keeps the sanitizers' own handlers in place, so wild-pointer
315
     * faults still get full ASAN reports and clean deduplication. */
316
2
    R_SignalHandlers = 0;
317
318
    /* The two halves of Rf_initEmbeddedR, with the C stack check fixed
319
     * up in between.  On Linux Rf_initialize_R takes R_CStackStart from
320
     * __libc_stack_end, the main thread's stack, so from this thread
321
     * every R_CheckStack() while setup_Rmainloop loads base would see
322
     * terabytes of usage and R would abort ("unable to initialize the
323
     * JIT").  macOS never sets it when embedded, which hides this
324
     * locally.  Switch the check off for startup, then measure against
325
     * this thread with R's own 5% of headroom for handling the overflow
326
     * error: R_CheckStack() fires as an ordinary R error at
327
     * 0.95 * FUZZ_R_STACK_SIZE rather than the sanitizer catching a fault.
328
     * setup_Rmainloop itself would turn any limit above 100 MB into
329
     * "unlimited", hence setting it after. */
330
2
    char *r_argv[] = {"R", "--vanilla", "--no-echo", "--no-restore"};
331
2
    int r_argc = sizeof(r_argv) / sizeof(r_argv[0]);
332
2
    Rf_initialize_R(r_argc, r_argv);
333
2
    R_CStackStart = fuzz_r_thread.stack_top;
334
2
    R_CStackLimit = (uintptr_t)-1;
335
2
    R_Interactive = TRUE;   /* as Rf_initEmbeddedR */
336
2
    setup_Rmainloop();
337
2
    R_CStackLimit = (uintptr_t)(0.95 * FUZZ_R_STACK_SIZE);
338
339
2
    fuzz_suppress_warnings();
340
2
}
datetime.c:fuzz_init_r
Line
Count
Source
293
2
{
294
2
    if (!fuzz_on_r_thread()) {
295
0
        fprintf(stderr, "fuzz_init_r: must run on the R thread "
296
0
                        "(define fuzz_target_init, not LLVMFuzzerInitialize)\n");
297
0
        abort();
298
0
    }
299
300
2
    fuzz_set_r_home();
301
2
    fuzz_set_vsize_limit();
302
303
    /* GC consistency failures ("untraced old-to-new reference", a node
304
     * with a bad type) are memory corruption, not input errors.  R's
305
     * default is to report and carry on; this makes gc_error() fatal
306
     * (through R_Suicide, which instrumentation/0004 turns into abort)
307
     * so they surface as crashes at the collection that found them. */
308
2
    if (getenv("_R_GC_FAIL_ON_ERROR_") == NULL)
309
1
        setenv("_R_GC_FAIL_ON_ERROR_", "yes", 1);
310
311
    /* R's SIGSEGV/SIGILL/etc. handlers enter an interactive recovery
312
     * prompt instead of crashing, which would hang the fuzzer.  Telling
313
     * R not to install them (rather than resetting to SIG_DFL after
314
     * init) keeps the sanitizers' own handlers in place, so wild-pointer
315
     * faults still get full ASAN reports and clean deduplication. */
316
2
    R_SignalHandlers = 0;
317
318
    /* The two halves of Rf_initEmbeddedR, with the C stack check fixed
319
     * up in between.  On Linux Rf_initialize_R takes R_CStackStart from
320
     * __libc_stack_end, the main thread's stack, so from this thread
321
     * every R_CheckStack() while setup_Rmainloop loads base would see
322
     * terabytes of usage and R would abort ("unable to initialize the
323
     * JIT").  macOS never sets it when embedded, which hides this
324
     * locally.  Switch the check off for startup, then measure against
325
     * this thread with R's own 5% of headroom for handling the overflow
326
     * error: R_CheckStack() fires as an ordinary R error at
327
     * 0.95 * FUZZ_R_STACK_SIZE rather than the sanitizer catching a fault.
328
     * setup_Rmainloop itself would turn any limit above 100 MB into
329
     * "unlimited", hence setting it after. */
330
2
    char *r_argv[] = {"R", "--vanilla", "--no-echo", "--no-restore"};
331
2
    int r_argc = sizeof(r_argv) / sizeof(r_argv[0]);
332
2
    Rf_initialize_R(r_argc, r_argv);
333
2
    R_CStackStart = fuzz_r_thread.stack_top;
334
2
    R_CStackLimit = (uintptr_t)-1;
335
2
    R_Interactive = TRUE;   /* as Rf_initEmbeddedR */
336
2
    setup_Rmainloop();
337
2
    R_CStackLimit = (uintptr_t)(0.95 * FUZZ_R_STACK_SIZE);
338
339
2
    fuzz_suppress_warnings();
340
2
}
coerce.c:fuzz_init_r
Line
Count
Source
293
2
{
294
2
    if (!fuzz_on_r_thread()) {
295
0
        fprintf(stderr, "fuzz_init_r: must run on the R thread "
296
0
                        "(define fuzz_target_init, not LLVMFuzzerInitialize)\n");
297
0
        abort();
298
0
    }
299
300
2
    fuzz_set_r_home();
301
2
    fuzz_set_vsize_limit();
302
303
    /* GC consistency failures ("untraced old-to-new reference", a node
304
     * with a bad type) are memory corruption, not input errors.  R's
305
     * default is to report and carry on; this makes gc_error() fatal
306
     * (through R_Suicide, which instrumentation/0004 turns into abort)
307
     * so they surface as crashes at the collection that found them. */
308
2
    if (getenv("_R_GC_FAIL_ON_ERROR_") == NULL)
309
1
        setenv("_R_GC_FAIL_ON_ERROR_", "yes", 1);
310
311
    /* R's SIGSEGV/SIGILL/etc. handlers enter an interactive recovery
312
     * prompt instead of crashing, which would hang the fuzzer.  Telling
313
     * R not to install them (rather than resetting to SIG_DFL after
314
     * init) keeps the sanitizers' own handlers in place, so wild-pointer
315
     * faults still get full ASAN reports and clean deduplication. */
316
2
    R_SignalHandlers = 0;
317
318
    /* The two halves of Rf_initEmbeddedR, with the C stack check fixed
319
     * up in between.  On Linux Rf_initialize_R takes R_CStackStart from
320
     * __libc_stack_end, the main thread's stack, so from this thread
321
     * every R_CheckStack() while setup_Rmainloop loads base would see
322
     * terabytes of usage and R would abort ("unable to initialize the
323
     * JIT").  macOS never sets it when embedded, which hides this
324
     * locally.  Switch the check off for startup, then measure against
325
     * this thread with R's own 5% of headroom for handling the overflow
326
     * error: R_CheckStack() fires as an ordinary R error at
327
     * 0.95 * FUZZ_R_STACK_SIZE rather than the sanitizer catching a fault.
328
     * setup_Rmainloop itself would turn any limit above 100 MB into
329
     * "unlimited", hence setting it after. */
330
2
    char *r_argv[] = {"R", "--vanilla", "--no-echo", "--no-restore"};
331
2
    int r_argc = sizeof(r_argv) / sizeof(r_argv[0]);
332
2
    Rf_initialize_R(r_argc, r_argv);
333
2
    R_CStackStart = fuzz_r_thread.stack_top;
334
2
    R_CStackLimit = (uintptr_t)-1;
335
2
    R_Interactive = TRUE;   /* as Rf_initEmbeddedR */
336
2
    setup_Rmainloop();
337
2
    R_CStackLimit = (uintptr_t)(0.95 * FUZZ_R_STACK_SIZE);
338
339
2
    fuzz_suppress_warnings();
340
2
}
load.c:fuzz_init_r
Line
Count
Source
293
2
{
294
2
    if (!fuzz_on_r_thread()) {
295
0
        fprintf(stderr, "fuzz_init_r: must run on the R thread "
296
0
                        "(define fuzz_target_init, not LLVMFuzzerInitialize)\n");
297
0
        abort();
298
0
    }
299
300
2
    fuzz_set_r_home();
301
2
    fuzz_set_vsize_limit();
302
303
    /* GC consistency failures ("untraced old-to-new reference", a node
304
     * with a bad type) are memory corruption, not input errors.  R's
305
     * default is to report and carry on; this makes gc_error() fatal
306
     * (through R_Suicide, which instrumentation/0004 turns into abort)
307
     * so they surface as crashes at the collection that found them. */
308
2
    if (getenv("_R_GC_FAIL_ON_ERROR_") == NULL)
309
1
        setenv("_R_GC_FAIL_ON_ERROR_", "yes", 1);
310
311
    /* R's SIGSEGV/SIGILL/etc. handlers enter an interactive recovery
312
     * prompt instead of crashing, which would hang the fuzzer.  Telling
313
     * R not to install them (rather than resetting to SIG_DFL after
314
     * init) keeps the sanitizers' own handlers in place, so wild-pointer
315
     * faults still get full ASAN reports and clean deduplication. */
316
2
    R_SignalHandlers = 0;
317
318
    /* The two halves of Rf_initEmbeddedR, with the C stack check fixed
319
     * up in between.  On Linux Rf_initialize_R takes R_CStackStart from
320
     * __libc_stack_end, the main thread's stack, so from this thread
321
     * every R_CheckStack() while setup_Rmainloop loads base would see
322
     * terabytes of usage and R would abort ("unable to initialize the
323
     * JIT").  macOS never sets it when embedded, which hides this
324
     * locally.  Switch the check off for startup, then measure against
325
     * this thread with R's own 5% of headroom for handling the overflow
326
     * error: R_CheckStack() fires as an ordinary R error at
327
     * 0.95 * FUZZ_R_STACK_SIZE rather than the sanitizer catching a fault.
328
     * setup_Rmainloop itself would turn any limit above 100 MB into
329
     * "unlimited", hence setting it after. */
330
2
    char *r_argv[] = {"R", "--vanilla", "--no-echo", "--no-restore"};
331
2
    int r_argc = sizeof(r_argv) / sizeof(r_argv[0]);
332
2
    Rf_initialize_R(r_argc, r_argv);
333
2
    R_CStackStart = fuzz_r_thread.stack_top;
334
2
    R_CStackLimit = (uintptr_t)-1;
335
2
    R_Interactive = TRUE;   /* as Rf_initEmbeddedR */
336
2
    setup_Rmainloop();
337
2
    R_CStackLimit = (uintptr_t)(0.95 * FUZZ_R_STACK_SIZE);
338
339
2
    fuzz_suppress_warnings();
340
2
}
scan.c:fuzz_init_r
Line
Count
Source
293
2
{
294
2
    if (!fuzz_on_r_thread()) {
295
0
        fprintf(stderr, "fuzz_init_r: must run on the R thread "
296
0
                        "(define fuzz_target_init, not LLVMFuzzerInitialize)\n");
297
0
        abort();
298
0
    }
299
300
2
    fuzz_set_r_home();
301
2
    fuzz_set_vsize_limit();
302
303
    /* GC consistency failures ("untraced old-to-new reference", a node
304
     * with a bad type) are memory corruption, not input errors.  R's
305
     * default is to report and carry on; this makes gc_error() fatal
306
     * (through R_Suicide, which instrumentation/0004 turns into abort)
307
     * so they surface as crashes at the collection that found them. */
308
2
    if (getenv("_R_GC_FAIL_ON_ERROR_") == NULL)
309
1
        setenv("_R_GC_FAIL_ON_ERROR_", "yes", 1);
310
311
    /* R's SIGSEGV/SIGILL/etc. handlers enter an interactive recovery
312
     * prompt instead of crashing, which would hang the fuzzer.  Telling
313
     * R not to install them (rather than resetting to SIG_DFL after
314
     * init) keeps the sanitizers' own handlers in place, so wild-pointer
315
     * faults still get full ASAN reports and clean deduplication. */
316
2
    R_SignalHandlers = 0;
317
318
    /* The two halves of Rf_initEmbeddedR, with the C stack check fixed
319
     * up in between.  On Linux Rf_initialize_R takes R_CStackStart from
320
     * __libc_stack_end, the main thread's stack, so from this thread
321
     * every R_CheckStack() while setup_Rmainloop loads base would see
322
     * terabytes of usage and R would abort ("unable to initialize the
323
     * JIT").  macOS never sets it when embedded, which hides this
324
     * locally.  Switch the check off for startup, then measure against
325
     * this thread with R's own 5% of headroom for handling the overflow
326
     * error: R_CheckStack() fires as an ordinary R error at
327
     * 0.95 * FUZZ_R_STACK_SIZE rather than the sanitizer catching a fault.
328
     * setup_Rmainloop itself would turn any limit above 100 MB into
329
     * "unlimited", hence setting it after. */
330
2
    char *r_argv[] = {"R", "--vanilla", "--no-echo", "--no-restore"};
331
2
    int r_argc = sizeof(r_argv) / sizeof(r_argv[0]);
332
2
    Rf_initialize_R(r_argc, r_argv);
333
2
    R_CStackStart = fuzz_r_thread.stack_top;
334
2
    R_CStackLimit = (uintptr_t)-1;
335
2
    R_Interactive = TRUE;   /* as Rf_initEmbeddedR */
336
2
    setup_Rmainloop();
337
2
    R_CStackLimit = (uintptr_t)(0.95 * FUZZ_R_STACK_SIZE);
338
339
2
    fuzz_suppress_warnings();
340
2
}
colors.c:fuzz_init_r
Line
Count
Source
293
2
{
294
2
    if (!fuzz_on_r_thread()) {
295
0
        fprintf(stderr, "fuzz_init_r: must run on the R thread "
296
0
                        "(define fuzz_target_init, not LLVMFuzzerInitialize)\n");
297
0
        abort();
298
0
    }
299
300
2
    fuzz_set_r_home();
301
2
    fuzz_set_vsize_limit();
302
303
    /* GC consistency failures ("untraced old-to-new reference", a node
304
     * with a bad type) are memory corruption, not input errors.  R's
305
     * default is to report and carry on; this makes gc_error() fatal
306
     * (through R_Suicide, which instrumentation/0004 turns into abort)
307
     * so they surface as crashes at the collection that found them. */
308
2
    if (getenv("_R_GC_FAIL_ON_ERROR_") == NULL)
309
1
        setenv("_R_GC_FAIL_ON_ERROR_", "yes", 1);
310
311
    /* R's SIGSEGV/SIGILL/etc. handlers enter an interactive recovery
312
     * prompt instead of crashing, which would hang the fuzzer.  Telling
313
     * R not to install them (rather than resetting to SIG_DFL after
314
     * init) keeps the sanitizers' own handlers in place, so wild-pointer
315
     * faults still get full ASAN reports and clean deduplication. */
316
2
    R_SignalHandlers = 0;
317
318
    /* The two halves of Rf_initEmbeddedR, with the C stack check fixed
319
     * up in between.  On Linux Rf_initialize_R takes R_CStackStart from
320
     * __libc_stack_end, the main thread's stack, so from this thread
321
     * every R_CheckStack() while setup_Rmainloop loads base would see
322
     * terabytes of usage and R would abort ("unable to initialize the
323
     * JIT").  macOS never sets it when embedded, which hides this
324
     * locally.  Switch the check off for startup, then measure against
325
     * this thread with R's own 5% of headroom for handling the overflow
326
     * error: R_CheckStack() fires as an ordinary R error at
327
     * 0.95 * FUZZ_R_STACK_SIZE rather than the sanitizer catching a fault.
328
     * setup_Rmainloop itself would turn any limit above 100 MB into
329
     * "unlimited", hence setting it after. */
330
2
    char *r_argv[] = {"R", "--vanilla", "--no-echo", "--no-restore"};
331
2
    int r_argc = sizeof(r_argv) / sizeof(r_argv[0]);
332
2
    Rf_initialize_R(r_argc, r_argv);
333
2
    R_CStackStart = fuzz_r_thread.stack_top;
334
2
    R_CStackLimit = (uintptr_t)-1;
335
2
    R_Interactive = TRUE;   /* as Rf_initEmbeddedR */
336
2
    setup_Rmainloop();
337
2
    R_CStackLimit = (uintptr_t)(0.95 * FUZZ_R_STACK_SIZE);
338
339
2
    fuzz_suppress_warnings();
340
2
}
parse.c:fuzz_init_r
Line
Count
Source
293
2
{
294
2
    if (!fuzz_on_r_thread()) {
295
0
        fprintf(stderr, "fuzz_init_r: must run on the R thread "
296
0
                        "(define fuzz_target_init, not LLVMFuzzerInitialize)\n");
297
0
        abort();
298
0
    }
299
300
2
    fuzz_set_r_home();
301
2
    fuzz_set_vsize_limit();
302
303
    /* GC consistency failures ("untraced old-to-new reference", a node
304
     * with a bad type) are memory corruption, not input errors.  R's
305
     * default is to report and carry on; this makes gc_error() fatal
306
     * (through R_Suicide, which instrumentation/0004 turns into abort)
307
     * so they surface as crashes at the collection that found them. */
308
2
    if (getenv("_R_GC_FAIL_ON_ERROR_") == NULL)
309
1
        setenv("_R_GC_FAIL_ON_ERROR_", "yes", 1);
310
311
    /* R's SIGSEGV/SIGILL/etc. handlers enter an interactive recovery
312
     * prompt instead of crashing, which would hang the fuzzer.  Telling
313
     * R not to install them (rather than resetting to SIG_DFL after
314
     * init) keeps the sanitizers' own handlers in place, so wild-pointer
315
     * faults still get full ASAN reports and clean deduplication. */
316
2
    R_SignalHandlers = 0;
317
318
    /* The two halves of Rf_initEmbeddedR, with the C stack check fixed
319
     * up in between.  On Linux Rf_initialize_R takes R_CStackStart from
320
     * __libc_stack_end, the main thread's stack, so from this thread
321
     * every R_CheckStack() while setup_Rmainloop loads base would see
322
     * terabytes of usage and R would abort ("unable to initialize the
323
     * JIT").  macOS never sets it when embedded, which hides this
324
     * locally.  Switch the check off for startup, then measure against
325
     * this thread with R's own 5% of headroom for handling the overflow
326
     * error: R_CheckStack() fires as an ordinary R error at
327
     * 0.95 * FUZZ_R_STACK_SIZE rather than the sanitizer catching a fault.
328
     * setup_Rmainloop itself would turn any limit above 100 MB into
329
     * "unlimited", hence setting it after. */
330
2
    char *r_argv[] = {"R", "--vanilla", "--no-echo", "--no-restore"};
331
2
    int r_argc = sizeof(r_argv) / sizeof(r_argv[0]);
332
2
    Rf_initialize_R(r_argc, r_argv);
333
2
    R_CStackStart = fuzz_r_thread.stack_top;
334
2
    R_CStackLimit = (uintptr_t)-1;
335
2
    R_Interactive = TRUE;   /* as Rf_initEmbeddedR */
336
2
    setup_Rmainloop();
337
2
    R_CStackLimit = (uintptr_t)(0.95 * FUZZ_R_STACK_SIZE);
338
339
2
    fuzz_suppress_warnings();
340
2
}
sprintf.c:fuzz_init_r
Line
Count
Source
293
2
{
294
2
    if (!fuzz_on_r_thread()) {
295
0
        fprintf(stderr, "fuzz_init_r: must run on the R thread "
296
0
                        "(define fuzz_target_init, not LLVMFuzzerInitialize)\n");
297
0
        abort();
298
0
    }
299
300
2
    fuzz_set_r_home();
301
2
    fuzz_set_vsize_limit();
302
303
    /* GC consistency failures ("untraced old-to-new reference", a node
304
     * with a bad type) are memory corruption, not input errors.  R's
305
     * default is to report and carry on; this makes gc_error() fatal
306
     * (through R_Suicide, which instrumentation/0004 turns into abort)
307
     * so they surface as crashes at the collection that found them. */
308
2
    if (getenv("_R_GC_FAIL_ON_ERROR_") == NULL)
309
1
        setenv("_R_GC_FAIL_ON_ERROR_", "yes", 1);
310
311
    /* R's SIGSEGV/SIGILL/etc. handlers enter an interactive recovery
312
     * prompt instead of crashing, which would hang the fuzzer.  Telling
313
     * R not to install them (rather than resetting to SIG_DFL after
314
     * init) keeps the sanitizers' own handlers in place, so wild-pointer
315
     * faults still get full ASAN reports and clean deduplication. */
316
2
    R_SignalHandlers = 0;
317
318
    /* The two halves of Rf_initEmbeddedR, with the C stack check fixed
319
     * up in between.  On Linux Rf_initialize_R takes R_CStackStart from
320
     * __libc_stack_end, the main thread's stack, so from this thread
321
     * every R_CheckStack() while setup_Rmainloop loads base would see
322
     * terabytes of usage and R would abort ("unable to initialize the
323
     * JIT").  macOS never sets it when embedded, which hides this
324
     * locally.  Switch the check off for startup, then measure against
325
     * this thread with R's own 5% of headroom for handling the overflow
326
     * error: R_CheckStack() fires as an ordinary R error at
327
     * 0.95 * FUZZ_R_STACK_SIZE rather than the sanitizer catching a fault.
328
     * setup_Rmainloop itself would turn any limit above 100 MB into
329
     * "unlimited", hence setting it after. */
330
2
    char *r_argv[] = {"R", "--vanilla", "--no-echo", "--no-restore"};
331
2
    int r_argc = sizeof(r_argv) / sizeof(r_argv[0]);
332
2
    Rf_initialize_R(r_argc, r_argv);
333
2
    R_CStackStart = fuzz_r_thread.stack_top;
334
2
    R_CStackLimit = (uintptr_t)-1;
335
2
    R_Interactive = TRUE;   /* as Rf_initEmbeddedR */
336
2
    setup_Rmainloop();
337
2
    R_CStackLimit = (uintptr_t)(0.95 * FUZZ_R_STACK_SIZE);
338
339
2
    fuzz_suppress_warnings();
340
2
}
eval.c:fuzz_init_r
Line
Count
Source
293
2
{
294
2
    if (!fuzz_on_r_thread()) {
295
0
        fprintf(stderr, "fuzz_init_r: must run on the R thread "
296
0
                        "(define fuzz_target_init, not LLVMFuzzerInitialize)\n");
297
0
        abort();
298
0
    }
299
300
2
    fuzz_set_r_home();
301
2
    fuzz_set_vsize_limit();
302
303
    /* GC consistency failures ("untraced old-to-new reference", a node
304
     * with a bad type) are memory corruption, not input errors.  R's
305
     * default is to report and carry on; this makes gc_error() fatal
306
     * (through R_Suicide, which instrumentation/0004 turns into abort)
307
     * so they surface as crashes at the collection that found them. */
308
2
    if (getenv("_R_GC_FAIL_ON_ERROR_") == NULL)
309
1
        setenv("_R_GC_FAIL_ON_ERROR_", "yes", 1);
310
311
    /* R's SIGSEGV/SIGILL/etc. handlers enter an interactive recovery
312
     * prompt instead of crashing, which would hang the fuzzer.  Telling
313
     * R not to install them (rather than resetting to SIG_DFL after
314
     * init) keeps the sanitizers' own handlers in place, so wild-pointer
315
     * faults still get full ASAN reports and clean deduplication. */
316
2
    R_SignalHandlers = 0;
317
318
    /* The two halves of Rf_initEmbeddedR, with the C stack check fixed
319
     * up in between.  On Linux Rf_initialize_R takes R_CStackStart from
320
     * __libc_stack_end, the main thread's stack, so from this thread
321
     * every R_CheckStack() while setup_Rmainloop loads base would see
322
     * terabytes of usage and R would abort ("unable to initialize the
323
     * JIT").  macOS never sets it when embedded, which hides this
324
     * locally.  Switch the check off for startup, then measure against
325
     * this thread with R's own 5% of headroom for handling the overflow
326
     * error: R_CheckStack() fires as an ordinary R error at
327
     * 0.95 * FUZZ_R_STACK_SIZE rather than the sanitizer catching a fault.
328
     * setup_Rmainloop itself would turn any limit above 100 MB into
329
     * "unlimited", hence setting it after. */
330
2
    char *r_argv[] = {"R", "--vanilla", "--no-echo", "--no-restore"};
331
2
    int r_argc = sizeof(r_argv) / sizeof(r_argv[0]);
332
2
    Rf_initialize_R(r_argc, r_argv);
333
2
    R_CStackStart = fuzz_r_thread.stack_top;
334
2
    R_CStackLimit = (uintptr_t)-1;
335
2
    R_Interactive = TRUE;   /* as Rf_initEmbeddedR */
336
2
    setup_Rmainloop();
337
2
    R_CStackLimit = (uintptr_t)(0.95 * FUZZ_R_STACK_SIZE);
338
339
2
    fuzz_suppress_warnings();
340
2
}
zip.c:fuzz_init_r
Line
Count
Source
293
2
{
294
2
    if (!fuzz_on_r_thread()) {
295
0
        fprintf(stderr, "fuzz_init_r: must run on the R thread "
296
0
                        "(define fuzz_target_init, not LLVMFuzzerInitialize)\n");
297
0
        abort();
298
0
    }
299
300
2
    fuzz_set_r_home();
301
2
    fuzz_set_vsize_limit();
302
303
    /* GC consistency failures ("untraced old-to-new reference", a node
304
     * with a bad type) are memory corruption, not input errors.  R's
305
     * default is to report and carry on; this makes gc_error() fatal
306
     * (through R_Suicide, which instrumentation/0004 turns into abort)
307
     * so they surface as crashes at the collection that found them. */
308
2
    if (getenv("_R_GC_FAIL_ON_ERROR_") == NULL)
309
1
        setenv("_R_GC_FAIL_ON_ERROR_", "yes", 1);
310
311
    /* R's SIGSEGV/SIGILL/etc. handlers enter an interactive recovery
312
     * prompt instead of crashing, which would hang the fuzzer.  Telling
313
     * R not to install them (rather than resetting to SIG_DFL after
314
     * init) keeps the sanitizers' own handlers in place, so wild-pointer
315
     * faults still get full ASAN reports and clean deduplication. */
316
2
    R_SignalHandlers = 0;
317
318
    /* The two halves of Rf_initEmbeddedR, with the C stack check fixed
319
     * up in between.  On Linux Rf_initialize_R takes R_CStackStart from
320
     * __libc_stack_end, the main thread's stack, so from this thread
321
     * every R_CheckStack() while setup_Rmainloop loads base would see
322
     * terabytes of usage and R would abort ("unable to initialize the
323
     * JIT").  macOS never sets it when embedded, which hides this
324
     * locally.  Switch the check off for startup, then measure against
325
     * this thread with R's own 5% of headroom for handling the overflow
326
     * error: R_CheckStack() fires as an ordinary R error at
327
     * 0.95 * FUZZ_R_STACK_SIZE rather than the sanitizer catching a fault.
328
     * setup_Rmainloop itself would turn any limit above 100 MB into
329
     * "unlimited", hence setting it after. */
330
2
    char *r_argv[] = {"R", "--vanilla", "--no-echo", "--no-restore"};
331
2
    int r_argc = sizeof(r_argv) / sizeof(r_argv[0]);
332
2
    Rf_initialize_R(r_argc, r_argv);
333
2
    R_CStackStart = fuzz_r_thread.stack_top;
334
2
    R_CStackLimit = (uintptr_t)-1;
335
2
    R_Interactive = TRUE;   /* as Rf_initEmbeddedR */
336
2
    setup_Rmainloop();
337
2
    R_CStackLimit = (uintptr_t)(0.95 * FUZZ_R_STACK_SIZE);
338
339
2
    fuzz_suppress_warnings();
340
2
}
341
342
/*
343
 * Helper for protected evaluation via R_ToplevelExec.
344
 *
345
 * R API calls that touch R objects can longjmp on error.  Without a
346
 * top-level context, R's error handler crashes.  Wrapping calls in
347
 * R_ToplevelExec catches the longjmp cleanly.
348
 */
349
typedef struct {
350
    SEXP call;
351
    SEXP env;
352
} fuzz_eval_data_t;
353
354
static void fuzz_do_eval(void *data)
355
13.5k
{
356
13.5k
    fuzz_eval_data_t *ed = (fuzz_eval_data_t *)data;
357
13.5k
    Rf_eval(ed->call, ed->env);
358
13.5k
}
Unexecuted instantiation: io.c:fuzz_do_eval
Unexecuted instantiation: dcf.c:fuzz_do_eval
Unexecuted instantiation: character.c:fuzz_do_eval
Unexecuted instantiation: encoding.c:fuzz_do_eval
Unexecuted instantiation: sort.c:fuzz_do_eval
Unexecuted instantiation: connections.c:fuzz_do_eval
Unexecuted instantiation: unserialize.c:fuzz_do_eval
decompress.c:fuzz_do_eval
Line
Count
Source
355
1.61k
{
356
1.61k
    fuzz_eval_data_t *ed = (fuzz_eval_data_t *)data;
357
1.61k
    Rf_eval(ed->call, ed->env);
358
1.61k
}
Unexecuted instantiation: readtable.c:fuzz_do_eval
Unexecuted instantiation: format.c:fuzz_do_eval
datetime.c:fuzz_do_eval
Line
Count
Source
355
5.05k
{
356
5.05k
    fuzz_eval_data_t *ed = (fuzz_eval_data_t *)data;
357
5.05k
    Rf_eval(ed->call, ed->env);
358
5.05k
}
coerce.c:fuzz_do_eval
Line
Count
Source
355
6.87k
{
356
6.87k
    fuzz_eval_data_t *ed = (fuzz_eval_data_t *)data;
357
6.87k
    Rf_eval(ed->call, ed->env);
358
6.87k
}
Unexecuted instantiation: load.c:fuzz_do_eval
Unexecuted instantiation: scan.c:fuzz_do_eval
Unexecuted instantiation: colors.c:fuzz_do_eval
Unexecuted instantiation: parse.c:fuzz_do_eval
Unexecuted instantiation: sprintf.c:fuzz_do_eval
Unexecuted instantiation: eval.c:fuzz_do_eval
Unexecuted instantiation: zip.c:fuzz_do_eval
359
360
/* Evaluate malformed-input-heavy targets without printing each expected
361
 * R error. R_tryEvalSilent installs its own top-level error context. */
362
static void fuzz_eval_silent(SEXP call, SEXP env)
363
52.7k
{
364
52.7k
    int error = 0;
365
52.7k
    R_tryEvalSilent(call, env, &error);
366
52.7k
}
io.c:fuzz_eval_silent
Line
Count
Source
363
1.28k
{
364
1.28k
    int error = 0;
365
1.28k
    R_tryEvalSilent(call, env, &error);
366
1.28k
}
dcf.c:fuzz_eval_silent
Line
Count
Source
363
4.75k
{
364
4.75k
    int error = 0;
365
4.75k
    R_tryEvalSilent(call, env, &error);
366
4.75k
}
character.c:fuzz_eval_silent
Line
Count
Source
363
3.55k
{
364
3.55k
    int error = 0;
365
3.55k
    R_tryEvalSilent(call, env, &error);
366
3.55k
}
encoding.c:fuzz_eval_silent
Line
Count
Source
363
1.51k
{
364
1.51k
    int error = 0;
365
1.51k
    R_tryEvalSilent(call, env, &error);
366
1.51k
}
sort.c:fuzz_eval_silent
Line
Count
Source
363
6.31k
{
364
6.31k
    int error = 0;
365
6.31k
    R_tryEvalSilent(call, env, &error);
366
6.31k
}
connections.c:fuzz_eval_silent
Line
Count
Source
363
2.42k
{
364
2.42k
    int error = 0;
365
2.42k
    R_tryEvalSilent(call, env, &error);
366
2.42k
}
unserialize.c:fuzz_eval_silent
Line
Count
Source
363
4.93k
{
364
4.93k
    int error = 0;
365
4.93k
    R_tryEvalSilent(call, env, &error);
366
4.93k
}
Unexecuted instantiation: decompress.c:fuzz_eval_silent
readtable.c:fuzz_eval_silent
Line
Count
Source
363
370
{
364
370
    int error = 0;
365
370
    R_tryEvalSilent(call, env, &error);
366
370
}
format.c:fuzz_eval_silent
Line
Count
Source
363
5.14k
{
364
5.14k
    int error = 0;
365
5.14k
    R_tryEvalSilent(call, env, &error);
366
5.14k
}
datetime.c:fuzz_eval_silent
Line
Count
Source
363
2.41k
{
364
2.41k
    int error = 0;
365
2.41k
    R_tryEvalSilent(call, env, &error);
366
2.41k
}
Unexecuted instantiation: coerce.c:fuzz_eval_silent
load.c:fuzz_eval_silent
Line
Count
Source
363
5.32k
{
364
5.32k
    int error = 0;
365
5.32k
    R_tryEvalSilent(call, env, &error);
366
5.32k
}
scan.c:fuzz_eval_silent
Line
Count
Source
363
2.84k
{
364
2.84k
    int error = 0;
365
2.84k
    R_tryEvalSilent(call, env, &error);
366
2.84k
}
colors.c:fuzz_eval_silent
Line
Count
Source
363
1.90k
{
364
1.90k
    int error = 0;
365
1.90k
    R_tryEvalSilent(call, env, &error);
366
1.90k
}
parse.c:fuzz_eval_silent
Line
Count
Source
363
6.21k
{
364
6.21k
    int error = 0;
365
6.21k
    R_tryEvalSilent(call, env, &error);
366
6.21k
}
sprintf.c:fuzz_eval_silent
Line
Count
Source
363
1.95k
{
364
1.95k
    int error = 0;
365
1.95k
    R_tryEvalSilent(call, env, &error);
366
1.95k
}
Unexecuted instantiation: eval.c:fuzz_eval_silent
zip.c:fuzz_eval_silent
Line
Count
Source
363
1.80k
{
364
1.80k
    int error = 0;
365
1.80k
    R_tryEvalSilent(call, env, &error);
366
1.80k
}
367
368
/*
369
 * Stage per-iteration inputs under a toplevel context.
370
 *
371
 * Rf_mkChar and Rf_allocVector can themselves signal the vector-limit
372
 * error.  Outside a toplevel context that error longjmps into a stack
373
 * frame that returned during Rf_initEmbeddedR -- undefined behaviour --
374
 * so input staging must be wrapped just like evaluation.  Both helpers
375
 * return FALSE when the allocation failed; skip the iteration then.
376
 */
377
typedef struct {
378
    SEXP vec;
379
    const char *str;
380
} fuzz_string_data_t;
381
382
static void fuzz_do_set_string(void *data)
383
39.3k
{
384
39.3k
    fuzz_string_data_t *sd = (fuzz_string_data_t *)data;
385
39.3k
    SET_STRING_ELT(sd->vec, 0, Rf_mkChar(sd->str));
386
39.3k
}
Unexecuted instantiation: io.c:fuzz_do_set_string
dcf.c:fuzz_do_set_string
Line
Count
Source
383
4.75k
{
384
4.75k
    fuzz_string_data_t *sd = (fuzz_string_data_t *)data;
385
4.75k
    SET_STRING_ELT(sd->vec, 0, Rf_mkChar(sd->str));
386
4.75k
}
character.c:fuzz_do_set_string
Line
Count
Source
383
2.93k
{
384
2.93k
    fuzz_string_data_t *sd = (fuzz_string_data_t *)data;
385
2.93k
    SET_STRING_ELT(sd->vec, 0, Rf_mkChar(sd->str));
386
2.93k
}
encoding.c:fuzz_do_set_string
Line
Count
Source
383
673
{
384
673
    fuzz_string_data_t *sd = (fuzz_string_data_t *)data;
385
673
    SET_STRING_ELT(sd->vec, 0, Rf_mkChar(sd->str));
386
673
}
Unexecuted instantiation: sort.c:fuzz_do_set_string
Unexecuted instantiation: connections.c:fuzz_do_set_string
Unexecuted instantiation: unserialize.c:fuzz_do_set_string
Unexecuted instantiation: decompress.c:fuzz_do_set_string
readtable.c:fuzz_do_set_string
Line
Count
Source
383
330
{
384
330
    fuzz_string_data_t *sd = (fuzz_string_data_t *)data;
385
330
    SET_STRING_ELT(sd->vec, 0, Rf_mkChar(sd->str));
386
330
}
format.c:fuzz_do_set_string
Line
Count
Source
383
5.14k
{
384
5.14k
    fuzz_string_data_t *sd = (fuzz_string_data_t *)data;
385
5.14k
    SET_STRING_ELT(sd->vec, 0, Rf_mkChar(sd->str));
386
5.14k
}
datetime.c:fuzz_do_set_string
Line
Count
Source
383
10.1k
{
384
10.1k
    fuzz_string_data_t *sd = (fuzz_string_data_t *)data;
385
10.1k
    SET_STRING_ELT(sd->vec, 0, Rf_mkChar(sd->str));
386
10.1k
}
coerce.c:fuzz_do_set_string
Line
Count
Source
383
1.71k
{
384
1.71k
    fuzz_string_data_t *sd = (fuzz_string_data_t *)data;
385
1.71k
    SET_STRING_ELT(sd->vec, 0, Rf_mkChar(sd->str));
386
1.71k
}
Unexecuted instantiation: load.c:fuzz_do_set_string
scan.c:fuzz_do_set_string
Line
Count
Source
383
2.80k
{
384
2.80k
    fuzz_string_data_t *sd = (fuzz_string_data_t *)data;
385
2.80k
    SET_STRING_ELT(sd->vec, 0, Rf_mkChar(sd->str));
386
2.80k
}
colors.c:fuzz_do_set_string
Line
Count
Source
383
1.86k
{
384
1.86k
    fuzz_string_data_t *sd = (fuzz_string_data_t *)data;
385
1.86k
    SET_STRING_ELT(sd->vec, 0, Rf_mkChar(sd->str));
386
1.86k
}
parse.c:fuzz_do_set_string
Line
Count
Source
383
7.01k
{
384
7.01k
    fuzz_string_data_t *sd = (fuzz_string_data_t *)data;
385
7.01k
    SET_STRING_ELT(sd->vec, 0, Rf_mkChar(sd->str));
386
7.01k
}
sprintf.c:fuzz_do_set_string
Line
Count
Source
383
1.95k
{
384
1.95k
    fuzz_string_data_t *sd = (fuzz_string_data_t *)data;
385
1.95k
    SET_STRING_ELT(sd->vec, 0, Rf_mkChar(sd->str));
386
1.95k
}
Unexecuted instantiation: eval.c:fuzz_do_set_string
Unexecuted instantiation: zip.c:fuzz_do_set_string
387
388
static Rboolean fuzz_set_string(SEXP vec, const char *str)
389
39.3k
{
390
39.3k
    fuzz_string_data_t sd = { vec, str };
391
39.3k
    return R_ToplevelExec(fuzz_do_set_string, &sd);
392
39.3k
}
Unexecuted instantiation: io.c:fuzz_set_string
dcf.c:fuzz_set_string
Line
Count
Source
389
4.75k
{
390
4.75k
    fuzz_string_data_t sd = { vec, str };
391
4.75k
    return R_ToplevelExec(fuzz_do_set_string, &sd);
392
4.75k
}
character.c:fuzz_set_string
Line
Count
Source
389
2.93k
{
390
2.93k
    fuzz_string_data_t sd = { vec, str };
391
2.93k
    return R_ToplevelExec(fuzz_do_set_string, &sd);
392
2.93k
}
encoding.c:fuzz_set_string
Line
Count
Source
389
673
{
390
673
    fuzz_string_data_t sd = { vec, str };
391
673
    return R_ToplevelExec(fuzz_do_set_string, &sd);
392
673
}
Unexecuted instantiation: sort.c:fuzz_set_string
Unexecuted instantiation: connections.c:fuzz_set_string
Unexecuted instantiation: unserialize.c:fuzz_set_string
Unexecuted instantiation: decompress.c:fuzz_set_string
readtable.c:fuzz_set_string
Line
Count
Source
389
330
{
390
330
    fuzz_string_data_t sd = { vec, str };
391
330
    return R_ToplevelExec(fuzz_do_set_string, &sd);
392
330
}
format.c:fuzz_set_string
Line
Count
Source
389
5.14k
{
390
5.14k
    fuzz_string_data_t sd = { vec, str };
391
5.14k
    return R_ToplevelExec(fuzz_do_set_string, &sd);
392
5.14k
}
datetime.c:fuzz_set_string
Line
Count
Source
389
10.1k
{
390
10.1k
    fuzz_string_data_t sd = { vec, str };
391
10.1k
    return R_ToplevelExec(fuzz_do_set_string, &sd);
392
10.1k
}
coerce.c:fuzz_set_string
Line
Count
Source
389
1.71k
{
390
1.71k
    fuzz_string_data_t sd = { vec, str };
391
1.71k
    return R_ToplevelExec(fuzz_do_set_string, &sd);
392
1.71k
}
Unexecuted instantiation: load.c:fuzz_set_string
scan.c:fuzz_set_string
Line
Count
Source
389
2.80k
{
390
2.80k
    fuzz_string_data_t sd = { vec, str };
391
2.80k
    return R_ToplevelExec(fuzz_do_set_string, &sd);
392
2.80k
}
colors.c:fuzz_set_string
Line
Count
Source
389
1.86k
{
390
1.86k
    fuzz_string_data_t sd = { vec, str };
391
1.86k
    return R_ToplevelExec(fuzz_do_set_string, &sd);
392
1.86k
}
parse.c:fuzz_set_string
Line
Count
Source
389
7.01k
{
390
7.01k
    fuzz_string_data_t sd = { vec, str };
391
7.01k
    return R_ToplevelExec(fuzz_do_set_string, &sd);
392
7.01k
}
sprintf.c:fuzz_set_string
Line
Count
Source
389
1.95k
{
390
1.95k
    fuzz_string_data_t sd = { vec, str };
391
1.95k
    return R_ToplevelExec(fuzz_do_set_string, &sd);
392
1.95k
}
Unexecuted instantiation: eval.c:fuzz_set_string
Unexecuted instantiation: zip.c:fuzz_set_string
393
394
/*
395
 * Parse and evaluate one R function literal, once, at initialization.
396
 *
397
 * Harnesses whose calls need named arguments, on.exit(close(con)) or a
398
 * few R-level steps around the entry point express each slot as an R
399
 * closure and call it with Rf_lang*; that keeps the C side free of
400
 * argument plumbing.  The source is harness-authored (never fuzz
401
 * input), so a parse or evaluation failure is a harness bug: abort.
402
 */
403
static SEXP fuzz_make_wrapper(const char *source)
404
274
{
405
274
    ParseStatus status;
406
274
    SEXP text, parsed, wrapper;
407
274
    Rf_protect(text = Rf_mkString(source));
408
274
    Rf_protect(parsed = R_ParseVector(text, -1, &status, R_NilValue));
409
274
    if (status != PARSE_OK || XLENGTH(parsed) != 1)
410
0
        abort();
411
412
274
    wrapper = Rf_eval(VECTOR_ELT(parsed, 0), R_BaseEnv);
413
274
    Rf_unprotect(2);
414
274
    return wrapper;
415
274
}
io.c:fuzz_make_wrapper
Line
Count
Source
404
20
{
405
20
    ParseStatus status;
406
20
    SEXP text, parsed, wrapper;
407
20
    Rf_protect(text = Rf_mkString(source));
408
20
    Rf_protect(parsed = R_ParseVector(text, -1, &status, R_NilValue));
409
20
    if (status != PARSE_OK || XLENGTH(parsed) != 1)
410
0
        abort();
411
412
20
    wrapper = Rf_eval(VECTOR_ELT(parsed, 0), R_BaseEnv);
413
20
    Rf_unprotect(2);
414
20
    return wrapper;
415
20
}
Unexecuted instantiation: dcf.c:fuzz_make_wrapper
Unexecuted instantiation: character.c:fuzz_make_wrapper
Unexecuted instantiation: encoding.c:fuzz_make_wrapper
sort.c:fuzz_make_wrapper
Line
Count
Source
404
44
{
405
44
    ParseStatus status;
406
44
    SEXP text, parsed, wrapper;
407
44
    Rf_protect(text = Rf_mkString(source));
408
44
    Rf_protect(parsed = R_ParseVector(text, -1, &status, R_NilValue));
409
44
    if (status != PARSE_OK || XLENGTH(parsed) != 1)
410
0
        abort();
411
412
44
    wrapper = Rf_eval(VECTOR_ELT(parsed, 0), R_BaseEnv);
413
44
    Rf_unprotect(2);
414
44
    return wrapper;
415
44
}
connections.c:fuzz_make_wrapper
Line
Count
Source
404
20
{
405
20
    ParseStatus status;
406
20
    SEXP text, parsed, wrapper;
407
20
    Rf_protect(text = Rf_mkString(source));
408
20
    Rf_protect(parsed = R_ParseVector(text, -1, &status, R_NilValue));
409
20
    if (status != PARSE_OK || XLENGTH(parsed) != 1)
410
0
        abort();
411
412
20
    wrapper = Rf_eval(VECTOR_ELT(parsed, 0), R_BaseEnv);
413
20
    Rf_unprotect(2);
414
20
    return wrapper;
415
20
}
unserialize.c:fuzz_make_wrapper
Line
Count
Source
404
8
{
405
8
    ParseStatus status;
406
8
    SEXP text, parsed, wrapper;
407
8
    Rf_protect(text = Rf_mkString(source));
408
8
    Rf_protect(parsed = R_ParseVector(text, -1, &status, R_NilValue));
409
8
    if (status != PARSE_OK || XLENGTH(parsed) != 1)
410
0
        abort();
411
412
8
    wrapper = Rf_eval(VECTOR_ELT(parsed, 0), R_BaseEnv);
413
8
    Rf_unprotect(2);
414
8
    return wrapper;
415
8
}
Unexecuted instantiation: decompress.c:fuzz_make_wrapper
readtable.c:fuzz_make_wrapper
Line
Count
Source
404
40
{
405
40
    ParseStatus status;
406
40
    SEXP text, parsed, wrapper;
407
40
    Rf_protect(text = Rf_mkString(source));
408
40
    Rf_protect(parsed = R_ParseVector(text, -1, &status, R_NilValue));
409
40
    if (status != PARSE_OK || XLENGTH(parsed) != 1)
410
0
        abort();
411
412
40
    wrapper = Rf_eval(VECTOR_ELT(parsed, 0), R_BaseEnv);
413
40
    Rf_unprotect(2);
414
40
    return wrapper;
415
40
}
format.c:fuzz_make_wrapper
Line
Count
Source
404
48
{
405
48
    ParseStatus status;
406
48
    SEXP text, parsed, wrapper;
407
48
    Rf_protect(text = Rf_mkString(source));
408
48
    Rf_protect(parsed = R_ParseVector(text, -1, &status, R_NilValue));
409
48
    if (status != PARSE_OK || XLENGTH(parsed) != 1)
410
0
        abort();
411
412
48
    wrapper = Rf_eval(VECTOR_ELT(parsed, 0), R_BaseEnv);
413
48
    Rf_unprotect(2);
414
48
    return wrapper;
415
48
}
datetime.c:fuzz_make_wrapper
Line
Count
Source
404
2
{
405
2
    ParseStatus status;
406
2
    SEXP text, parsed, wrapper;
407
2
    Rf_protect(text = Rf_mkString(source));
408
2
    Rf_protect(parsed = R_ParseVector(text, -1, &status, R_NilValue));
409
2
    if (status != PARSE_OK || XLENGTH(parsed) != 1)
410
0
        abort();
411
412
2
    wrapper = Rf_eval(VECTOR_ELT(parsed, 0), R_BaseEnv);
413
2
    Rf_unprotect(2);
414
2
    return wrapper;
415
2
}
Unexecuted instantiation: coerce.c:fuzz_make_wrapper
load.c:fuzz_make_wrapper
Line
Count
Source
404
4
{
405
4
    ParseStatus status;
406
4
    SEXP text, parsed, wrapper;
407
4
    Rf_protect(text = Rf_mkString(source));
408
4
    Rf_protect(parsed = R_ParseVector(text, -1, &status, R_NilValue));
409
4
    if (status != PARSE_OK || XLENGTH(parsed) != 1)
410
0
        abort();
411
412
4
    wrapper = Rf_eval(VECTOR_ELT(parsed, 0), R_BaseEnv);
413
4
    Rf_unprotect(2);
414
4
    return wrapper;
415
4
}
scan.c:fuzz_make_wrapper
Line
Count
Source
404
36
{
405
36
    ParseStatus status;
406
36
    SEXP text, parsed, wrapper;
407
36
    Rf_protect(text = Rf_mkString(source));
408
36
    Rf_protect(parsed = R_ParseVector(text, -1, &status, R_NilValue));
409
36
    if (status != PARSE_OK || XLENGTH(parsed) != 1)
410
0
        abort();
411
412
36
    wrapper = Rf_eval(VECTOR_ELT(parsed, 0), R_BaseEnv);
413
36
    Rf_unprotect(2);
414
36
    return wrapper;
415
36
}
colors.c:fuzz_make_wrapper
Line
Count
Source
404
32
{
405
32
    ParseStatus status;
406
32
    SEXP text, parsed, wrapper;
407
32
    Rf_protect(text = Rf_mkString(source));
408
32
    Rf_protect(parsed = R_ParseVector(text, -1, &status, R_NilValue));
409
32
    if (status != PARSE_OK || XLENGTH(parsed) != 1)
410
0
        abort();
411
412
32
    wrapper = Rf_eval(VECTOR_ELT(parsed, 0), R_BaseEnv);
413
32
    Rf_unprotect(2);
414
32
    return wrapper;
415
32
}
parse.c:fuzz_make_wrapper
Line
Count
Source
404
12
{
405
12
    ParseStatus status;
406
12
    SEXP text, parsed, wrapper;
407
12
    Rf_protect(text = Rf_mkString(source));
408
12
    Rf_protect(parsed = R_ParseVector(text, -1, &status, R_NilValue));
409
12
    if (status != PARSE_OK || XLENGTH(parsed) != 1)
410
0
        abort();
411
412
12
    wrapper = Rf_eval(VECTOR_ELT(parsed, 0), R_BaseEnv);
413
12
    Rf_unprotect(2);
414
12
    return wrapper;
415
12
}
Unexecuted instantiation: sprintf.c:fuzz_make_wrapper
Unexecuted instantiation: eval.c:fuzz_make_wrapper
zip.c:fuzz_make_wrapper
Line
Count
Source
404
8
{
405
8
    ParseStatus status;
406
8
    SEXP text, parsed, wrapper;
407
8
    Rf_protect(text = Rf_mkString(source));
408
8
    Rf_protect(parsed = R_ParseVector(text, -1, &status, R_NilValue));
409
8
    if (status != PARSE_OK || XLENGTH(parsed) != 1)
410
0
        abort();
411
412
8
    wrapper = Rf_eval(VECTOR_ELT(parsed, 0), R_BaseEnv);
413
8
    Rf_unprotect(2);
414
8
    return wrapper;
415
8
}
416
417
/*
418
 * fuzz_set_string with an explicit encoding mark.
419
 *
420
 * R does not validate the mark (Encoding<- lets users set it on any
421
 * bytes), so handing the same payload over as UTF-8 or latin1 reaches
422
 * the multibyte branches and their handling of invalid sequences
423
 * without touching the process locale.
424
 */
425
typedef struct {
426
    SEXP vec;
427
    const char *str;
428
    cetype_t ce;
429
} fuzz_ce_string_data_t;
430
431
static void fuzz_do_set_string_ce(void *data)
432
2.02k
{
433
2.02k
    fuzz_ce_string_data_t *sd = (fuzz_ce_string_data_t *)data;
434
2.02k
    SET_STRING_ELT(sd->vec, 0, Rf_mkCharCE(sd->str, sd->ce));
435
2.02k
}
Unexecuted instantiation: io.c:fuzz_do_set_string_ce
Unexecuted instantiation: dcf.c:fuzz_do_set_string_ce
character.c:fuzz_do_set_string_ce
Line
Count
Source
432
1.83k
{
433
1.83k
    fuzz_ce_string_data_t *sd = (fuzz_ce_string_data_t *)data;
434
1.83k
    SET_STRING_ELT(sd->vec, 0, Rf_mkCharCE(sd->str, sd->ce));
435
1.83k
}
encoding.c:fuzz_do_set_string_ce
Line
Count
Source
432
192
{
433
192
    fuzz_ce_string_data_t *sd = (fuzz_ce_string_data_t *)data;
434
192
    SET_STRING_ELT(sd->vec, 0, Rf_mkCharCE(sd->str, sd->ce));
435
192
}
Unexecuted instantiation: sort.c:fuzz_do_set_string_ce
Unexecuted instantiation: connections.c:fuzz_do_set_string_ce
Unexecuted instantiation: unserialize.c:fuzz_do_set_string_ce
Unexecuted instantiation: decompress.c:fuzz_do_set_string_ce
Unexecuted instantiation: readtable.c:fuzz_do_set_string_ce
Unexecuted instantiation: format.c:fuzz_do_set_string_ce
Unexecuted instantiation: datetime.c:fuzz_do_set_string_ce
Unexecuted instantiation: coerce.c:fuzz_do_set_string_ce
Unexecuted instantiation: load.c:fuzz_do_set_string_ce
Unexecuted instantiation: scan.c:fuzz_do_set_string_ce
Unexecuted instantiation: colors.c:fuzz_do_set_string_ce
Unexecuted instantiation: parse.c:fuzz_do_set_string_ce
Unexecuted instantiation: sprintf.c:fuzz_do_set_string_ce
Unexecuted instantiation: eval.c:fuzz_do_set_string_ce
Unexecuted instantiation: zip.c:fuzz_do_set_string_ce
436
437
static Rboolean fuzz_set_string_ce(SEXP vec, const char *str, cetype_t ce)
438
2.02k
{
439
2.02k
    fuzz_ce_string_data_t sd = { vec, str, ce };
440
2.02k
    return R_ToplevelExec(fuzz_do_set_string_ce, &sd);
441
2.02k
}
Unexecuted instantiation: io.c:fuzz_set_string_ce
Unexecuted instantiation: dcf.c:fuzz_set_string_ce
character.c:fuzz_set_string_ce
Line
Count
Source
438
1.83k
{
439
1.83k
    fuzz_ce_string_data_t sd = { vec, str, ce };
440
1.83k
    return R_ToplevelExec(fuzz_do_set_string_ce, &sd);
441
1.83k
}
encoding.c:fuzz_set_string_ce
Line
Count
Source
438
192
{
439
192
    fuzz_ce_string_data_t sd = { vec, str, ce };
440
192
    return R_ToplevelExec(fuzz_do_set_string_ce, &sd);
441
192
}
Unexecuted instantiation: sort.c:fuzz_set_string_ce
Unexecuted instantiation: connections.c:fuzz_set_string_ce
Unexecuted instantiation: unserialize.c:fuzz_set_string_ce
Unexecuted instantiation: decompress.c:fuzz_set_string_ce
Unexecuted instantiation: readtable.c:fuzz_set_string_ce
Unexecuted instantiation: format.c:fuzz_set_string_ce
Unexecuted instantiation: datetime.c:fuzz_set_string_ce
Unexecuted instantiation: coerce.c:fuzz_set_string_ce
Unexecuted instantiation: load.c:fuzz_set_string_ce
Unexecuted instantiation: scan.c:fuzz_set_string_ce
Unexecuted instantiation: colors.c:fuzz_set_string_ce
Unexecuted instantiation: parse.c:fuzz_set_string_ce
Unexecuted instantiation: sprintf.c:fuzz_set_string_ce
Unexecuted instantiation: eval.c:fuzz_set_string_ce
Unexecuted instantiation: zip.c:fuzz_set_string_ce
442
443
typedef struct {
444
    SEXP call;
445
    const uint8_t *data;
446
    size_t size;
447
} fuzz_raw_data_t;
448
449
static void fuzz_do_set_raw(void *data)
450
10.2k
{
451
10.2k
    fuzz_raw_data_t *rd = (fuzz_raw_data_t *)data;
452
453
    /* The raw vector is reachable from the (protected) call as soon as
454
     * SETCADR runs, and nothing allocates before the memcpy completes,
455
     * so no extra protection is needed. */
456
10.2k
    SEXP raw = Rf_allocVector(RAWSXP, (R_xlen_t)rd->size);
457
10.2k
    SETCADR(rd->call, raw);
458
10.2k
    memcpy(RAW(raw), rd->data, rd->size);
459
10.2k
}
io.c:fuzz_do_set_raw
Line
Count
Source
450
1.28k
{
451
1.28k
    fuzz_raw_data_t *rd = (fuzz_raw_data_t *)data;
452
453
    /* The raw vector is reachable from the (protected) call as soon as
454
     * SETCADR runs, and nothing allocates before the memcpy completes,
455
     * so no extra protection is needed. */
456
1.28k
    SEXP raw = Rf_allocVector(RAWSXP, (R_xlen_t)rd->size);
457
1.28k
    SETCADR(rd->call, raw);
458
1.28k
    memcpy(RAW(raw), rd->data, rd->size);
459
1.28k
}
Unexecuted instantiation: dcf.c:fuzz_do_set_raw
Unexecuted instantiation: character.c:fuzz_do_set_raw
Unexecuted instantiation: encoding.c:fuzz_do_set_raw
Unexecuted instantiation: sort.c:fuzz_do_set_raw
connections.c:fuzz_do_set_raw
Line
Count
Source
450
2.42k
{
451
2.42k
    fuzz_raw_data_t *rd = (fuzz_raw_data_t *)data;
452
453
    /* The raw vector is reachable from the (protected) call as soon as
454
     * SETCADR runs, and nothing allocates before the memcpy completes,
455
     * so no extra protection is needed. */
456
2.42k
    SEXP raw = Rf_allocVector(RAWSXP, (R_xlen_t)rd->size);
457
2.42k
    SETCADR(rd->call, raw);
458
2.42k
    memcpy(RAW(raw), rd->data, rd->size);
459
2.42k
}
unserialize.c:fuzz_do_set_raw
Line
Count
Source
450
4.92k
{
451
4.92k
    fuzz_raw_data_t *rd = (fuzz_raw_data_t *)data;
452
453
    /* The raw vector is reachable from the (protected) call as soon as
454
     * SETCADR runs, and nothing allocates before the memcpy completes,
455
     * so no extra protection is needed. */
456
4.92k
    SEXP raw = Rf_allocVector(RAWSXP, (R_xlen_t)rd->size);
457
4.92k
    SETCADR(rd->call, raw);
458
4.92k
    memcpy(RAW(raw), rd->data, rd->size);
459
4.92k
}
decompress.c:fuzz_do_set_raw
Line
Count
Source
450
1.61k
{
451
1.61k
    fuzz_raw_data_t *rd = (fuzz_raw_data_t *)data;
452
453
    /* The raw vector is reachable from the (protected) call as soon as
454
     * SETCADR runs, and nothing allocates before the memcpy completes,
455
     * so no extra protection is needed. */
456
1.61k
    SEXP raw = Rf_allocVector(RAWSXP, (R_xlen_t)rd->size);
457
1.61k
    SETCADR(rd->call, raw);
458
1.61k
    memcpy(RAW(raw), rd->data, rd->size);
459
1.61k
}
Unexecuted instantiation: readtable.c:fuzz_do_set_raw
Unexecuted instantiation: format.c:fuzz_do_set_raw
Unexecuted instantiation: datetime.c:fuzz_do_set_raw
Unexecuted instantiation: coerce.c:fuzz_do_set_raw
Unexecuted instantiation: load.c:fuzz_do_set_raw
Unexecuted instantiation: scan.c:fuzz_do_set_raw
Unexecuted instantiation: colors.c:fuzz_do_set_raw
Unexecuted instantiation: parse.c:fuzz_do_set_raw
Unexecuted instantiation: sprintf.c:fuzz_do_set_raw
Unexecuted instantiation: eval.c:fuzz_do_set_raw
Unexecuted instantiation: zip.c:fuzz_do_set_raw
460
461
static Rboolean fuzz_set_raw_arg(SEXP call, const uint8_t *data, size_t size)
462
10.2k
{
463
10.2k
    fuzz_raw_data_t rd = { call, data, size };
464
10.2k
    return R_ToplevelExec(fuzz_do_set_raw, &rd);
465
10.2k
}
io.c:fuzz_set_raw_arg
Line
Count
Source
462
1.28k
{
463
1.28k
    fuzz_raw_data_t rd = { call, data, size };
464
1.28k
    return R_ToplevelExec(fuzz_do_set_raw, &rd);
465
1.28k
}
Unexecuted instantiation: dcf.c:fuzz_set_raw_arg
Unexecuted instantiation: character.c:fuzz_set_raw_arg
Unexecuted instantiation: encoding.c:fuzz_set_raw_arg
Unexecuted instantiation: sort.c:fuzz_set_raw_arg
connections.c:fuzz_set_raw_arg
Line
Count
Source
462
2.42k
{
463
2.42k
    fuzz_raw_data_t rd = { call, data, size };
464
2.42k
    return R_ToplevelExec(fuzz_do_set_raw, &rd);
465
2.42k
}
unserialize.c:fuzz_set_raw_arg
Line
Count
Source
462
4.92k
{
463
4.92k
    fuzz_raw_data_t rd = { call, data, size };
464
4.92k
    return R_ToplevelExec(fuzz_do_set_raw, &rd);
465
4.92k
}
decompress.c:fuzz_set_raw_arg
Line
Count
Source
462
1.61k
{
463
1.61k
    fuzz_raw_data_t rd = { call, data, size };
464
1.61k
    return R_ToplevelExec(fuzz_do_set_raw, &rd);
465
1.61k
}
Unexecuted instantiation: readtable.c:fuzz_set_raw_arg
Unexecuted instantiation: format.c:fuzz_set_raw_arg
Unexecuted instantiation: datetime.c:fuzz_set_raw_arg
Unexecuted instantiation: coerce.c:fuzz_set_raw_arg
Unexecuted instantiation: load.c:fuzz_set_raw_arg
Unexecuted instantiation: scan.c:fuzz_set_raw_arg
Unexecuted instantiation: colors.c:fuzz_set_raw_arg
Unexecuted instantiation: parse.c:fuzz_set_raw_arg
Unexecuted instantiation: sprintf.c:fuzz_set_raw_arg
Unexecuted instantiation: eval.c:fuzz_set_raw_arg
Unexecuted instantiation: zip.c:fuzz_set_raw_arg
466
467
/*
468
 * Stage the input in a scratch file.
469
 *
470
 * Some R entry points only take a path (load() of a pre-1.4 save file,
471
 * unzip(), file(encoding=)), so those targets rewrite one per-process
472
 * file each iteration instead of handing R a raw vector.  The file lives
473
 * in the system temp directory, which OSS-Fuzz runners allow writes to,
474
 * and is created once in fuzz_target_init so fuzzing never pays a
475
 * mkstemp per input.  Returns a malloc'd path, or NULL on failure.
476
 */
477
static char *fuzz_scratch_file(const char *name)
478
6
{
479
6
    const char *tmpdir = getenv("TMPDIR");
480
6
    if (tmpdir == NULL || *tmpdir == '\0')
481
6
        tmpdir = "/tmp";
482
483
6
    char *path = malloc(PATH_MAX);
484
6
    if (path == NULL)
485
0
        return NULL;
486
6
    snprintf(path, PATH_MAX, "%s/fuzz-%s-XXXXXX", tmpdir, name);
487
488
6
    int fd = mkstemp(path);
489
6
    if (fd < 0) {
490
0
        free(path);
491
0
        return NULL;
492
0
    }
493
6
    close(fd);
494
6
    return path;
495
6
}
Unexecuted instantiation: io.c:fuzz_scratch_file
Unexecuted instantiation: dcf.c:fuzz_scratch_file
Unexecuted instantiation: character.c:fuzz_scratch_file
Unexecuted instantiation: encoding.c:fuzz_scratch_file
Unexecuted instantiation: sort.c:fuzz_scratch_file
connections.c:fuzz_scratch_file
Line
Count
Source
478
2
{
479
2
    const char *tmpdir = getenv("TMPDIR");
480
2
    if (tmpdir == NULL || *tmpdir == '\0')
481
2
        tmpdir = "/tmp";
482
483
2
    char *path = malloc(PATH_MAX);
484
2
    if (path == NULL)
485
0
        return NULL;
486
2
    snprintf(path, PATH_MAX, "%s/fuzz-%s-XXXXXX", tmpdir, name);
487
488
2
    int fd = mkstemp(path);
489
2
    if (fd < 0) {
490
0
        free(path);
491
0
        return NULL;
492
0
    }
493
2
    close(fd);
494
2
    return path;
495
2
}
Unexecuted instantiation: unserialize.c:fuzz_scratch_file
Unexecuted instantiation: decompress.c:fuzz_scratch_file
Unexecuted instantiation: readtable.c:fuzz_scratch_file
Unexecuted instantiation: format.c:fuzz_scratch_file
Unexecuted instantiation: datetime.c:fuzz_scratch_file
Unexecuted instantiation: coerce.c:fuzz_scratch_file
load.c:fuzz_scratch_file
Line
Count
Source
478
2
{
479
2
    const char *tmpdir = getenv("TMPDIR");
480
2
    if (tmpdir == NULL || *tmpdir == '\0')
481
2
        tmpdir = "/tmp";
482
483
2
    char *path = malloc(PATH_MAX);
484
2
    if (path == NULL)
485
0
        return NULL;
486
2
    snprintf(path, PATH_MAX, "%s/fuzz-%s-XXXXXX", tmpdir, name);
487
488
2
    int fd = mkstemp(path);
489
2
    if (fd < 0) {
490
0
        free(path);
491
0
        return NULL;
492
0
    }
493
2
    close(fd);
494
2
    return path;
495
2
}
Unexecuted instantiation: scan.c:fuzz_scratch_file
Unexecuted instantiation: colors.c:fuzz_scratch_file
Unexecuted instantiation: parse.c:fuzz_scratch_file
Unexecuted instantiation: sprintf.c:fuzz_scratch_file
Unexecuted instantiation: eval.c:fuzz_scratch_file
zip.c:fuzz_scratch_file
Line
Count
Source
478
2
{
479
2
    const char *tmpdir = getenv("TMPDIR");
480
2
    if (tmpdir == NULL || *tmpdir == '\0')
481
2
        tmpdir = "/tmp";
482
483
2
    char *path = malloc(PATH_MAX);
484
2
    if (path == NULL)
485
0
        return NULL;
486
2
    snprintf(path, PATH_MAX, "%s/fuzz-%s-XXXXXX", tmpdir, name);
487
488
2
    int fd = mkstemp(path);
489
2
    if (fd < 0) {
490
0
        free(path);
491
0
        return NULL;
492
0
    }
493
2
    close(fd);
494
2
    return path;
495
2
}
496
497
/* Replace the scratch file's contents.  Returns FALSE on any I/O error so
498
 * the iteration can be skipped rather than fuzzing a stale file. */
499
static Rboolean fuzz_write_scratch(const char *path, const uint8_t *data,
500
                                   size_t size)
501
9.55k
{
502
9.55k
    FILE *fp = fopen(path, "wb");
503
9.55k
    if (fp == NULL)
504
0
        return FALSE;
505
506
9.55k
    size_t written = size > 0 ? fwrite(data, 1, size, fp) : 0;
507
9.55k
    int rc = fclose(fp);
508
9.55k
    return written == size && rc == 0;
509
9.55k
}
Unexecuted instantiation: io.c:fuzz_write_scratch
Unexecuted instantiation: dcf.c:fuzz_write_scratch
Unexecuted instantiation: character.c:fuzz_write_scratch
Unexecuted instantiation: encoding.c:fuzz_write_scratch
Unexecuted instantiation: sort.c:fuzz_write_scratch
connections.c:fuzz_write_scratch
Line
Count
Source
501
2.42k
{
502
2.42k
    FILE *fp = fopen(path, "wb");
503
2.42k
    if (fp == NULL)
504
0
        return FALSE;
505
506
2.42k
    size_t written = size > 0 ? fwrite(data, 1, size, fp) : 0;
507
2.42k
    int rc = fclose(fp);
508
2.42k
    return written == size && rc == 0;
509
2.42k
}
Unexecuted instantiation: unserialize.c:fuzz_write_scratch
Unexecuted instantiation: decompress.c:fuzz_write_scratch
Unexecuted instantiation: readtable.c:fuzz_write_scratch
Unexecuted instantiation: format.c:fuzz_write_scratch
Unexecuted instantiation: datetime.c:fuzz_write_scratch
Unexecuted instantiation: coerce.c:fuzz_write_scratch
load.c:fuzz_write_scratch
Line
Count
Source
501
5.32k
{
502
5.32k
    FILE *fp = fopen(path, "wb");
503
5.32k
    if (fp == NULL)
504
0
        return FALSE;
505
506
5.32k
    size_t written = size > 0 ? fwrite(data, 1, size, fp) : 0;
507
5.32k
    int rc = fclose(fp);
508
5.32k
    return written == size && rc == 0;
509
5.32k
}
Unexecuted instantiation: scan.c:fuzz_write_scratch
Unexecuted instantiation: colors.c:fuzz_write_scratch
Unexecuted instantiation: parse.c:fuzz_write_scratch
Unexecuted instantiation: sprintf.c:fuzz_write_scratch
Unexecuted instantiation: eval.c:fuzz_write_scratch
zip.c:fuzz_write_scratch
Line
Count
Source
501
1.80k
{
502
1.80k
    FILE *fp = fopen(path, "wb");
503
1.80k
    if (fp == NULL)
504
0
        return FALSE;
505
506
1.80k
    size_t written = size > 0 ? fwrite(data, 1, size, fp) : 0;
507
1.80k
    int rc = fclose(fp);
508
1.80k
    return written == size && rc == 0;
509
1.80k
}
510
511
/*
512
 * Guard against TRE's bounded-repeat blowup.
513
 *
514
 * TRE compiles bounded repeats by duplicating the pattern AST, so nested
515
 * counted repeats multiply: a 36-byte pattern like
516
 * (?:a{2,101,})(?:a{2,101,}){100}{100} expands to ~10^8 nodes and >8GB of
517
 * allocations at compile time.  Those allocations are malloc, not R's
518
 * vector heap, so R_MAX_VSIZE cannot bound them; reject the pattern
519
 * before it reaches R instead.
520
 *
521
 * The product of all repeat bounds is a deliberate over-estimate --
522
 * sequential (non-nested) repeats add rather than multiply -- trading a
523
 * little coverage of repeat-heavy patterns for a hard bound on compile
524
 * cost.
525
 */
526
364
#define FUZZ_MAX_REPEAT_PRODUCT 1000000.0
527
528
static int fuzz_repeat_product_excessive(const char *pattern)
529
265
{
530
265
    double product = 1.0;
531
532
36.6k
    for (const char *p = pattern; *p != '\0'; p++) {
533
36.3k
        if (*p != '{')
534
35.2k
            continue;
535
536
        /* The largest number inside the braces bounds this repeat. */
537
1.12k
        unsigned long bound = 0, cur = 0;
538
1.12k
        int counted = 0;
539
1.12k
        const char *q = p + 1;
540
5.17k
        for (; *q != '\0' && *q != '}'; q++) {
541
4.77k
            if (*q >= '0' && *q <= '9') {
542
3.10k
                cur = cur * 10 + (unsigned long)(*q - '0');
543
3.10k
                if (cur > 10000000)
544
460
                    cur = 10000000;  /* saturate; already over any budget */
545
3.10k
                counted = 1;
546
3.10k
            } else if (*q == ',') {
547
940
                if (cur > bound)
548
417
                    bound = cur;
549
940
                cur = 0;
550
940
            } else {
551
728
                counted = 0;  /* not a counted repeat, e.g. "{a}" */
552
728
                break;
553
728
            }
554
4.77k
        }
555
1.12k
        if (!counted || *q != '}')
556
761
            continue;
557
558
364
        if (cur > bound)
559
59
            bound = cur;
560
364
        if (bound > 1)
561
138
            product *= (double)bound;
562
364
        if (product > FUZZ_MAX_REPEAT_PRODUCT)
563
17
            return 1;
564
565
347
        p = q;
566
347
    }
567
568
248
    return 0;
569
265
}
Unexecuted instantiation: io.c:fuzz_repeat_product_excessive
Unexecuted instantiation: dcf.c:fuzz_repeat_product_excessive
character.c:fuzz_repeat_product_excessive
Line
Count
Source
529
265
{
530
265
    double product = 1.0;
531
532
36.6k
    for (const char *p = pattern; *p != '\0'; p++) {
533
36.3k
        if (*p != '{')
534
35.2k
            continue;
535
536
        /* The largest number inside the braces bounds this repeat. */
537
1.12k
        unsigned long bound = 0, cur = 0;
538
1.12k
        int counted = 0;
539
1.12k
        const char *q = p + 1;
540
5.17k
        for (; *q != '\0' && *q != '}'; q++) {
541
4.77k
            if (*q >= '0' && *q <= '9') {
542
3.10k
                cur = cur * 10 + (unsigned long)(*q - '0');
543
3.10k
                if (cur > 10000000)
544
460
                    cur = 10000000;  /* saturate; already over any budget */
545
3.10k
                counted = 1;
546
3.10k
            } else if (*q == ',') {
547
940
                if (cur > bound)
548
417
                    bound = cur;
549
940
                cur = 0;
550
940
            } else {
551
728
                counted = 0;  /* not a counted repeat, e.g. "{a}" */
552
728
                break;
553
728
            }
554
4.77k
        }
555
1.12k
        if (!counted || *q != '}')
556
761
            continue;
557
558
364
        if (cur > bound)
559
59
            bound = cur;
560
364
        if (bound > 1)
561
138
            product *= (double)bound;
562
364
        if (product > FUZZ_MAX_REPEAT_PRODUCT)
563
17
            return 1;
564
565
347
        p = q;
566
347
    }
567
568
248
    return 0;
569
265
}
Unexecuted instantiation: encoding.c:fuzz_repeat_product_excessive
Unexecuted instantiation: sort.c:fuzz_repeat_product_excessive
Unexecuted instantiation: connections.c:fuzz_repeat_product_excessive
Unexecuted instantiation: unserialize.c:fuzz_repeat_product_excessive
Unexecuted instantiation: decompress.c:fuzz_repeat_product_excessive
Unexecuted instantiation: readtable.c:fuzz_repeat_product_excessive
Unexecuted instantiation: format.c:fuzz_repeat_product_excessive
Unexecuted instantiation: datetime.c:fuzz_repeat_product_excessive
Unexecuted instantiation: coerce.c:fuzz_repeat_product_excessive
Unexecuted instantiation: load.c:fuzz_repeat_product_excessive
Unexecuted instantiation: scan.c:fuzz_repeat_product_excessive
Unexecuted instantiation: colors.c:fuzz_repeat_product_excessive
Unexecuted instantiation: parse.c:fuzz_repeat_product_excessive
Unexecuted instantiation: sprintf.c:fuzz_repeat_product_excessive
Unexecuted instantiation: eval.c:fuzz_repeat_product_excessive
Unexecuted instantiation: zip.c:fuzz_repeat_product_excessive
570
571
/*
572
 * libFuzzer entry points.
573
 *
574
 * A harness defines fuzz_target_init and fuzz_target_run with the
575
 * LLVMFuzzerInitialize / LLVMFuzzerTestOneInput signatures; these run
576
 * them on the R thread, one condition-variable handoff each way per input.
577
 */
578
int fuzz_target_init(int *argc, char ***argv);
579
int fuzz_target_run(const uint8_t *data, size_t size);
580
581
typedef struct {
582
    int *argc;
583
    char ***argv;
584
    int result;
585
} fuzz_init_job_t;
586
587
static void fuzz_do_target_init(void *data)
588
38
{
589
38
    fuzz_init_job_t *job = data;
590
38
    job->result = fuzz_target_init(job->argc, job->argv);
591
38
}
io.c:fuzz_do_target_init
Line
Count
Source
588
2
{
589
2
    fuzz_init_job_t *job = data;
590
2
    job->result = fuzz_target_init(job->argc, job->argv);
591
2
}
dcf.c:fuzz_do_target_init
Line
Count
Source
588
2
{
589
2
    fuzz_init_job_t *job = data;
590
2
    job->result = fuzz_target_init(job->argc, job->argv);
591
2
}
character.c:fuzz_do_target_init
Line
Count
Source
588
2
{
589
2
    fuzz_init_job_t *job = data;
590
2
    job->result = fuzz_target_init(job->argc, job->argv);
591
2
}
encoding.c:fuzz_do_target_init
Line
Count
Source
588
2
{
589
2
    fuzz_init_job_t *job = data;
590
2
    job->result = fuzz_target_init(job->argc, job->argv);
591
2
}
sort.c:fuzz_do_target_init
Line
Count
Source
588
2
{
589
2
    fuzz_init_job_t *job = data;
590
2
    job->result = fuzz_target_init(job->argc, job->argv);
591
2
}
connections.c:fuzz_do_target_init
Line
Count
Source
588
2
{
589
2
    fuzz_init_job_t *job = data;
590
2
    job->result = fuzz_target_init(job->argc, job->argv);
591
2
}
unserialize.c:fuzz_do_target_init
Line
Count
Source
588
2
{
589
2
    fuzz_init_job_t *job = data;
590
2
    job->result = fuzz_target_init(job->argc, job->argv);
591
2
}
decompress.c:fuzz_do_target_init
Line
Count
Source
588
2
{
589
2
    fuzz_init_job_t *job = data;
590
2
    job->result = fuzz_target_init(job->argc, job->argv);
591
2
}
readtable.c:fuzz_do_target_init
Line
Count
Source
588
2
{
589
2
    fuzz_init_job_t *job = data;
590
2
    job->result = fuzz_target_init(job->argc, job->argv);
591
2
}
format.c:fuzz_do_target_init
Line
Count
Source
588
2
{
589
2
    fuzz_init_job_t *job = data;
590
2
    job->result = fuzz_target_init(job->argc, job->argv);
591
2
}
datetime.c:fuzz_do_target_init
Line
Count
Source
588
2
{
589
2
    fuzz_init_job_t *job = data;
590
2
    job->result = fuzz_target_init(job->argc, job->argv);
591
2
}
coerce.c:fuzz_do_target_init
Line
Count
Source
588
2
{
589
2
    fuzz_init_job_t *job = data;
590
2
    job->result = fuzz_target_init(job->argc, job->argv);
591
2
}
load.c:fuzz_do_target_init
Line
Count
Source
588
2
{
589
2
    fuzz_init_job_t *job = data;
590
2
    job->result = fuzz_target_init(job->argc, job->argv);
591
2
}
scan.c:fuzz_do_target_init
Line
Count
Source
588
2
{
589
2
    fuzz_init_job_t *job = data;
590
2
    job->result = fuzz_target_init(job->argc, job->argv);
591
2
}
colors.c:fuzz_do_target_init
Line
Count
Source
588
2
{
589
2
    fuzz_init_job_t *job = data;
590
2
    job->result = fuzz_target_init(job->argc, job->argv);
591
2
}
parse.c:fuzz_do_target_init
Line
Count
Source
588
2
{
589
2
    fuzz_init_job_t *job = data;
590
2
    job->result = fuzz_target_init(job->argc, job->argv);
591
2
}
sprintf.c:fuzz_do_target_init
Line
Count
Source
588
2
{
589
2
    fuzz_init_job_t *job = data;
590
2
    job->result = fuzz_target_init(job->argc, job->argv);
591
2
}
eval.c:fuzz_do_target_init
Line
Count
Source
588
2
{
589
2
    fuzz_init_job_t *job = data;
590
2
    job->result = fuzz_target_init(job->argc, job->argv);
591
2
}
zip.c:fuzz_do_target_init
Line
Count
Source
588
2
{
589
2
    fuzz_init_job_t *job = data;
590
2
    job->result = fuzz_target_init(job->argc, job->argv);
591
2
}
592
593
typedef struct {
594
    const uint8_t *data;
595
    size_t size;
596
    int result;
597
} fuzz_run_job_t;
598
599
static void fuzz_do_target_run(void *data)
600
69.1k
{
601
69.1k
    fuzz_run_job_t *job = data;
602
69.1k
    job->result = fuzz_target_run(job->data, job->size);
603
69.1k
}
io.c:fuzz_do_target_run
Line
Count
Source
600
1.56k
{
601
1.56k
    fuzz_run_job_t *job = data;
602
1.56k
    job->result = fuzz_target_run(job->data, job->size);
603
1.56k
}
dcf.c:fuzz_do_target_run
Line
Count
Source
600
4.76k
{
601
4.76k
    fuzz_run_job_t *job = data;
602
4.76k
    job->result = fuzz_target_run(job->data, job->size);
603
4.76k
}
character.c:fuzz_do_target_run
Line
Count
Source
600
3.58k
{
601
3.58k
    fuzz_run_job_t *job = data;
602
3.58k
    job->result = fuzz_target_run(job->data, job->size);
603
3.58k
}
encoding.c:fuzz_do_target_run
Line
Count
Source
600
1.52k
{
601
1.52k
    fuzz_run_job_t *job = data;
602
1.52k
    job->result = fuzz_target_run(job->data, job->size);
603
1.52k
}
sort.c:fuzz_do_target_run
Line
Count
Source
600
6.33k
{
601
6.33k
    fuzz_run_job_t *job = data;
602
6.33k
    job->result = fuzz_target_run(job->data, job->size);
603
6.33k
}
connections.c:fuzz_do_target_run
Line
Count
Source
600
2.43k
{
601
2.43k
    fuzz_run_job_t *job = data;
602
2.43k
    job->result = fuzz_target_run(job->data, job->size);
603
2.43k
}
unserialize.c:fuzz_do_target_run
Line
Count
Source
600
4.93k
{
601
4.93k
    fuzz_run_job_t *job = data;
602
4.93k
    job->result = fuzz_target_run(job->data, job->size);
603
4.93k
}
decompress.c:fuzz_do_target_run
Line
Count
Source
600
1.62k
{
601
1.62k
    fuzz_run_job_t *job = data;
602
1.62k
    job->result = fuzz_target_run(job->data, job->size);
603
1.62k
}
readtable.c:fuzz_do_target_run
Line
Count
Source
600
347
{
601
347
    fuzz_run_job_t *job = data;
602
347
    job->result = fuzz_target_run(job->data, job->size);
603
347
}
format.c:fuzz_do_target_run
Line
Count
Source
600
5.15k
{
601
5.15k
    fuzz_run_job_t *job = data;
602
5.15k
    job->result = fuzz_target_run(job->data, job->size);
603
5.15k
}
datetime.c:fuzz_do_target_run
Line
Count
Source
600
5.06k
{
601
5.06k
    fuzz_run_job_t *job = data;
602
5.06k
    job->result = fuzz_target_run(job->data, job->size);
603
5.06k
}
coerce.c:fuzz_do_target_run
Line
Count
Source
600
1.72k
{
601
1.72k
    fuzz_run_job_t *job = data;
602
1.72k
    job->result = fuzz_target_run(job->data, job->size);
603
1.72k
}
load.c:fuzz_do_target_run
Line
Count
Source
600
5.33k
{
601
5.33k
    fuzz_run_job_t *job = data;
602
5.33k
    job->result = fuzz_target_run(job->data, job->size);
603
5.33k
}
scan.c:fuzz_do_target_run
Line
Count
Source
600
2.81k
{
601
2.81k
    fuzz_run_job_t *job = data;
602
2.81k
    job->result = fuzz_target_run(job->data, job->size);
603
2.81k
}
colors.c:fuzz_do_target_run
Line
Count
Source
600
1.88k
{
601
1.88k
    fuzz_run_job_t *job = data;
602
1.88k
    job->result = fuzz_target_run(job->data, job->size);
603
1.88k
}
parse.c:fuzz_do_target_run
Line
Count
Source
600
7.02k
{
601
7.02k
    fuzz_run_job_t *job = data;
602
7.02k
    job->result = fuzz_target_run(job->data, job->size);
603
7.02k
}
sprintf.c:fuzz_do_target_run
Line
Count
Source
600
1.97k
{
601
1.97k
    fuzz_run_job_t *job = data;
602
1.97k
    job->result = fuzz_target_run(job->data, job->size);
603
1.97k
}
eval.c:fuzz_do_target_run
Line
Count
Source
600
9.19k
{
601
9.19k
    fuzz_run_job_t *job = data;
602
9.19k
    job->result = fuzz_target_run(job->data, job->size);
603
9.19k
}
zip.c:fuzz_do_target_run
Line
Count
Source
600
1.81k
{
601
1.81k
    fuzz_run_job_t *job = data;
602
1.81k
    job->result = fuzz_target_run(job->data, job->size);
603
1.81k
}
604
605
int LLVMFuzzerInitialize(int *argc, char ***argv)
606
38
{
607
38
    fuzz_init_job_t job = { argc, argv, 0 };
608
38
    fuzz_run_on_r_thread(fuzz_do_target_init, &job);
609
38
    return job.result;
610
38
}
611
612
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
613
69.1k
{
614
69.1k
    fuzz_run_job_t job = { data, size, 0 };
615
69.1k
    fuzz_run_on_r_thread(fuzz_do_target_run, &job);
616
69.1k
    return job.result;
617
69.1k
}
618
619
#endif /* FUZZ_COMMON_H */