xref: /freebsd/contrib/pkgconf/fuzzer/replay.c (revision 592efe252472a3385acf36b1f49ecf710a7f3d9c)
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