Coverage Report

Created: 2025-06-13 06:18

/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
}