/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 | } 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 | } |
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 | } |
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 | } |
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 | } |
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 | } |
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 | } |
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 | } |
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 | } |
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 | } |
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 | } |
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 | } 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 | } |
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 | } |
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 | } 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 | } |
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 | } |
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 | } |
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 | } |
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 | } |
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 | } |
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 | } |
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 | } 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 | } |
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 | } |
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 | } |
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 | } |
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 | } |
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 | } |
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 | } |
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 | } |
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 | } |
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 | } |
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 | } |
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 | } |
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 | } |
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 | } |
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 | } |
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 | } |
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 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 | } |
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 | } Line | Count | Source | 363 | 1.28k | { | 364 | 1.28k | int error = 0; | 365 | 1.28k | R_tryEvalSilent(call, env, &error); | 366 | 1.28k | } |
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 | } |
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 Line | Count | Source | 363 | 5.32k | { | 364 | 5.32k | int error = 0; | 365 | 5.32k | R_tryEvalSilent(call, env, &error); | 366 | 5.32k | } |
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 | } |
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 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 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 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 | } |
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 | } |
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 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 | } |
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 | } |
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 | } 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 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 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 | } |
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 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 | } 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 | } 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 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 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 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 | } 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 | } 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 | } |
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 | } |
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 */ |