Coverage Report

Created: 2025-06-22 06:59

/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.83k
                      const void *const needle, const size_t needle_len) {
15
5.83k
  if (haystack_len == 0)
16
632
    return NULL;
17
5.20k
  if (needle_len == 0)
18
0
    return NULL;
19
20
44.6M
  for (const char *h = (const char *)haystack; haystack_len >= needle_len;
21
44.6M
       ++h, --haystack_len) {
22
44.6M
    if (!memcmp(h, needle, needle_len)) {
23
3.31k
      return (void *)h;
24
3.31k
    }
25
44.6M
  }
26
1.88k
  return NULL;
27
5.20k
}
28
29
static VSILFILE *SegmentFile(const char *filename, GByte **data_p,
30
5.83k
                             size_t *size_p) {
31
5.83k
  GByte *data = *data_p;
32
5.83k
  size_t size = *size_p;
33
34
5.83k
  GByte *separator = (GByte *)msMemmem(data, size, "deadbeef", 8);
35
5.83k
  if (separator != NULL) {
36
3.31k
    size = separator - data;
37
3.31k
    *data_p = separator + 8;
38
3.31k
    *size_p -= size + 8;
39
3.31k
  } else {
40
2.51k
    *size_p = 0;
41
2.51k
  }
42
43
5.83k
  return VSIFileFromMemBuffer(filename, data, size, false);
44
5.83k
}
45
46
6
int LLVMFuzzerInitialize(int *argc, char ***argv) {
47
6
  (void)argc;
48
6
  (void)argv;
49
6
  return 0;
50
6
}
51
52
1.94k
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.94k
  VSILFILE *shp = SegmentFile("/vsimem/foo.shp", &data, &size);
65
1.94k
  VSILFILE *shx = SegmentFile("/vsimem/foo.shx", &data, &size);
66
1.94k
  VSILFILE *dbf = SegmentFile("/vsimem/foo.dbf", &data, &size);
67
68
1.94k
  shapefileObj file;
69
1.94k
  errorObj *ms_error = msGetErrorObj();
70
1.94k
  if (msShapefileOpenVirtualFile(&file, "/vsimem/foo.shp", shp, shx, dbf,
71
1.94k
                                 false) == 0) {
72
1.39k
    if (file.numshapes > 100 * 1000) {
73
220
      VSIStatBufL sStat;
74
220
      if (VSIStatL("/vsimem/foo.shx", &sStat) == 0 && sStat.st_size >= 100 &&
75
220
          file.numshapes > (int)(sStat.st_size - 100) / 8) {
76
219
        file.numshapes = (int)(sStat.st_size - 100) / 8;
77
219
      }
78
220
    }
79
609k
    for (int i = 0; i < file.numshapes; ++i) {
80
609k
      shapeObj shape;
81
609k
      msInitShape(&shape);
82
609k
      msSHPReadShape(file.hSHP, i, &shape);
83
609k
      msFreeShape(&shape);
84
      // Give up as soon an error is triggered to avoid too long processing
85
      // time.
86
609k
      if (ms_error->code != MS_NOERR)
87
1.01k
        break;
88
609k
    }
89
90
1.39k
    msShapefileClose(&file);
91
1.39k
  }
92
93
1.94k
  msResetErrorList();
94
95
1.94k
  VSIUnlink("/vsimem/foo.shp");
96
1.94k
  VSIUnlink("/vsimem/foo.shx");
97
1.94k
  VSIUnlink("/vsimem/foo.dbf");
98
99
1.94k
  return EXIT_SUCCESS;
100
1.94k
}