/src/MapServer/fuzzers/shapefuzzer.c
Line | Count | Source (jump to first uncovered line) |
1 | | #include "src/mapserver.h" |
2 | | #include "src/mapshape.h" |
3 | | |
4 | | #include "cpl_vsi.h" |
5 | | |
6 | | #include <stdlib.h> |
7 | | #include <string.h> |
8 | | #include <stdbool.h> |
9 | | |
10 | | extern int LLVMFuzzerTestOneInput(GByte *data, size_t size); |
11 | | extern int LLVMFuzzerInitialize(int *argc, char ***argv); |
12 | | |
13 | | static void *msMemmem(const void *haystack, size_t haystack_len, |
14 | 5.68k | const void *const needle, const size_t needle_len) { |
15 | 5.68k | if (haystack_len == 0) |
16 | 616 | return NULL; |
17 | 5.07k | if (needle_len == 0) |
18 | 0 | return NULL; |
19 | | |
20 | 46.4M | for (const char *h = (const char *)haystack; haystack_len >= needle_len; |
21 | 46.4M | ++h, --haystack_len) { |
22 | 46.4M | if (!memcmp(h, needle, needle_len)) { |
23 | 3.24k | return (void *)h; |
24 | 3.24k | } |
25 | 46.4M | } |
26 | 1.82k | return NULL; |
27 | 5.07k | } |
28 | | |
29 | | static VSILFILE *SegmentFile(const char *filename, GByte **data_p, |
30 | 5.68k | size_t *size_p) { |
31 | 5.68k | GByte *data = *data_p; |
32 | 5.68k | size_t size = *size_p; |
33 | | |
34 | 5.68k | GByte *separator = (GByte *)msMemmem(data, size, "deadbeef", 8); |
35 | 5.68k | if (separator != NULL) { |
36 | 3.24k | size = separator - data; |
37 | 3.24k | *data_p = separator + 8; |
38 | 3.24k | *size_p -= size + 8; |
39 | 3.24k | } else { |
40 | 2.44k | *size_p = 0; |
41 | 2.44k | } |
42 | | |
43 | 5.68k | return VSIFileFromMemBuffer(filename, data, size, false); |
44 | 5.68k | } |
45 | | |
46 | 2 | int LLVMFuzzerInitialize(int *argc, char ***argv) { |
47 | 2 | (void)argc; |
48 | 2 | (void)argv; |
49 | 2 | return 0; |
50 | 2 | } |
51 | | |
52 | 1.89k | int LLVMFuzzerTestOneInput(GByte *data, size_t size) { |
53 | | /* this fuzzer expects three files concatenated, separated by the |
54 | | string "deadbeef"; you can generate such a file by typing: |
55 | | |
56 | | { cat foo.shp; echo -n "deadbeef"; cat foo.shx; echo -n "deadbeef"; cat |
57 | | foo.dbf; } >/tmp/corpus/start |
58 | | |
59 | | then run the fuzzer: |
60 | | |
61 | | ./build/fuzzer/fuzzer /tmp/corpus |
62 | | */ |
63 | | |
64 | 1.89k | VSILFILE *shp = SegmentFile("/vsimem/foo.shp", &data, &size); |
65 | 1.89k | VSILFILE *shx = SegmentFile("/vsimem/foo.shx", &data, &size); |
66 | 1.89k | VSILFILE *dbf = SegmentFile("/vsimem/foo.dbf", &data, &size); |
67 | | |
68 | 1.89k | shapefileObj file; |
69 | 1.89k | errorObj *ms_error = msGetErrorObj(); |
70 | 1.89k | if (msShapefileOpenVirtualFile(&file, "/vsimem/foo.shp", shp, shx, dbf, |
71 | 1.89k | false) == 0) { |
72 | 1.35k | if (file.numshapes > 100 * 1000) { |
73 | 222 | VSIStatBufL sStat; |
74 | 222 | if (VSIStatL("/vsimem/foo.shx", &sStat) == 0 && sStat.st_size >= 100 && |
75 | 222 | file.numshapes > (int)(sStat.st_size - 100) / 8) { |
76 | 221 | file.numshapes = (int)(sStat.st_size - 100) / 8; |
77 | 221 | } |
78 | 222 | } |
79 | 663k | for (int i = 0; i < file.numshapes; ++i) { |
80 | 663k | shapeObj shape; |
81 | 663k | msInitShape(&shape); |
82 | 663k | msSHPReadShape(file.hSHP, i, &shape); |
83 | 663k | msFreeShape(&shape); |
84 | | // Give up as soon an error is triggered to avoid too long processing |
85 | | // time. |
86 | 663k | if (ms_error->code != MS_NOERR) |
87 | 985 | break; |
88 | 663k | } |
89 | | |
90 | 1.35k | msShapefileClose(&file); |
91 | 1.35k | } |
92 | | |
93 | 1.89k | msResetErrorList(); |
94 | | |
95 | 1.89k | VSIUnlink("/vsimem/foo.shp"); |
96 | 1.89k | VSIUnlink("/vsimem/foo.shx"); |
97 | 1.89k | VSIUnlink("/vsimem/foo.dbf"); |
98 | | |
99 | 1.89k | return EXIT_SUCCESS; |
100 | 1.89k | } |