1*592efe25SPierre Pronchery /*
2*592efe25SPierre Pronchery * replay.c
3*592efe25SPierre Pronchery * Standalone driver that replays corpus files through a libFuzzer
4*592efe25SPierre Pronchery * LLVMFuzzerTestOneInput entry point, without libFuzzer.
5*592efe25SPierre Pronchery *
6*592efe25SPierre Pronchery * This lets the fuzz targets (and the allocator fault injection they drive via
7*592efe25SPierre Pronchery * alloc-inject) run deterministically over their seed corpus under an ordinary
8*592efe25SPierre Pronchery * compiler -- in particular a coverage build -- so their OOM-path coverage is
9*592efe25SPierre Pronchery * captured by codecov, which the libFuzzer/clang fuzz job does not provide.
10*592efe25SPierre Pronchery *
11*592efe25SPierre Pronchery * SPDX-License-Identifier: pkgconf
12*592efe25SPierre Pronchery *
13*592efe25SPierre Pronchery * Copyright (c) 2026 pkgconf authors (see AUTHORS).
14*592efe25SPierre Pronchery *
15*592efe25SPierre Pronchery * Permission to use, copy, modify, and/or distribute this software for any
16*592efe25SPierre Pronchery * purpose with or without fee is hereby granted, provided that the above
17*592efe25SPierre Pronchery * copyright notice and this permission notice appear in all copies.
18*592efe25SPierre Pronchery *
19*592efe25SPierre Pronchery * This software is provided 'as is' and without any warranty, express or
20*592efe25SPierre Pronchery * implied. In no event shall the authors be liable for any damages arising
21*592efe25SPierre Pronchery * from the use of this software.
22*592efe25SPierre Pronchery */
23*592efe25SPierre Pronchery
24*592efe25SPierre Pronchery #include <libpkgconf/stdinc.h>
25*592efe25SPierre Pronchery #include <sys/stat.h>
26*592efe25SPierre Pronchery #include <dirent.h>
27*592efe25SPierre Pronchery
28*592efe25SPierre Pronchery int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
29*592efe25SPierre Pronchery
30*592efe25SPierre Pronchery static void
replay_file(const char * path)31*592efe25SPierre Pronchery replay_file(const char *path)
32*592efe25SPierre Pronchery {
33*592efe25SPierre Pronchery FILE *f = fopen(path, "rb");
34*592efe25SPierre Pronchery if (f == NULL)
35*592efe25SPierre Pronchery return;
36*592efe25SPierre Pronchery
37*592efe25SPierre Pronchery if (fseek(f, 0, SEEK_END) != 0)
38*592efe25SPierre Pronchery {
39*592efe25SPierre Pronchery fclose(f);
40*592efe25SPierre Pronchery return;
41*592efe25SPierre Pronchery }
42*592efe25SPierre Pronchery
43*592efe25SPierre Pronchery long len = ftell(f);
44*592efe25SPierre Pronchery rewind(f);
45*592efe25SPierre Pronchery
46*592efe25SPierre Pronchery if (len < 0)
47*592efe25SPierre Pronchery {
48*592efe25SPierre Pronchery fclose(f);
49*592efe25SPierre Pronchery return;
50*592efe25SPierre Pronchery }
51*592efe25SPierre Pronchery
52*592efe25SPierre Pronchery uint8_t *buf = malloc((size_t) len + 1);
53*592efe25SPierre Pronchery if (buf == NULL)
54*592efe25SPierre Pronchery {
55*592efe25SPierre Pronchery fclose(f);
56*592efe25SPierre Pronchery return;
57*592efe25SPierre Pronchery }
58*592efe25SPierre Pronchery
59*592efe25SPierre Pronchery size_t got = fread(buf, 1, (size_t) len, f);
60*592efe25SPierre Pronchery fclose(f);
61*592efe25SPierre Pronchery
62*592efe25SPierre Pronchery LLVMFuzzerTestOneInput(buf, got);
63*592efe25SPierre Pronchery free(buf);
64*592efe25SPierre Pronchery }
65*592efe25SPierre Pronchery
66*592efe25SPierre Pronchery static void
replay_path(const char * path)67*592efe25SPierre Pronchery replay_path(const char *path)
68*592efe25SPierre Pronchery {
69*592efe25SPierre Pronchery struct stat st;
70*592efe25SPierre Pronchery if (stat(path, &st) != 0)
71*592efe25SPierre Pronchery return;
72*592efe25SPierre Pronchery
73*592efe25SPierre Pronchery if (!S_ISDIR(st.st_mode))
74*592efe25SPierre Pronchery {
75*592efe25SPierre Pronchery replay_file(path);
76*592efe25SPierre Pronchery return;
77*592efe25SPierre Pronchery }
78*592efe25SPierre Pronchery
79*592efe25SPierre Pronchery DIR *dir = opendir(path);
80*592efe25SPierre Pronchery if (dir == NULL)
81*592efe25SPierre Pronchery return;
82*592efe25SPierre Pronchery
83*592efe25SPierre Pronchery struct dirent *ent;
84*592efe25SPierre Pronchery while ((ent = readdir(dir)) != NULL)
85*592efe25SPierre Pronchery {
86*592efe25SPierre Pronchery if (ent->d_name[0] == '.')
87*592efe25SPierre Pronchery continue;
88*592efe25SPierre Pronchery
89*592efe25SPierre Pronchery char child[4096];
90*592efe25SPierre Pronchery snprintf(child, sizeof child, "%s/%s", path, ent->d_name);
91*592efe25SPierre Pronchery replay_path(child);
92*592efe25SPierre Pronchery }
93*592efe25SPierre Pronchery
94*592efe25SPierre Pronchery closedir(dir);
95*592efe25SPierre Pronchery }
96*592efe25SPierre Pronchery
97*592efe25SPierre Pronchery int
main(int argc,char * argv[])98*592efe25SPierre Pronchery main(int argc, char *argv[])
99*592efe25SPierre Pronchery {
100*592efe25SPierre Pronchery for (int i = 1; i < argc; i++)
101*592efe25SPierre Pronchery replay_path(argv[i]);
102*592efe25SPierre Pronchery
103*592efe25SPierre Pronchery return 0;
104*592efe25SPierre Pronchery }
105