Coverage Report

Created: 2025-11-16 06:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/MapServer/fuzzers/shapefuzzer.c
Line
Count
Source
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.22k
                      const void *const needle, const size_t needle_len) {
15
5.22k
  if (haystack_len == 0)
16
573
    return NULL;
17
4.64k
  if (needle_len == 0)
18
0
    return NULL;
19
20
35.0M
  for (const char *h = (const char *)haystack; haystack_len >= needle_len;
21
35.0M
       ++h, --haystack_len) {
22
35.0M
    if (!memcmp(h, needle, needle_len)) {
23
2.95k
      return (void *)h;
24
2.95k
    }
25
35.0M
  }
26
1.69k
  return NULL;
27
4.64k
}
28
29
static VSILFILE *SegmentFile(const char *filename, GByte **data_p,
30
5.22k
                             size_t *size_p) {
31
5.22k
  GByte *data = *data_p;
32
5.22k
  size_t size = *size_p;
33
34
5.22k
  GByte *separator = (GByte *)msMemmem(data, size, "deadbeef", 8);
35
5.22k
  if (separator != NULL) {
36
2.95k
    size = separator - data;
37
2.95k
    *data_p = separator + 8;
38
2.95k
    *size_p -= size + 8;
39
2.95k
  } else {
40
2.26k
    *size_p = 0;
41
2.26k
  }
42
43
5.22k
  return VSIFileFromMemBuffer(filename, data, size, false);
44
5.22k
}
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.74k
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.74k
  VSILFILE *shp = SegmentFile("/vsimem/foo.shp", &data, &size);
65
1.74k
  VSILFILE *shx = SegmentFile("/vsimem/foo.shx", &data, &size);
66
1.74k
  VSILFILE *dbf = SegmentFile("/vsimem/foo.dbf", &data, &size);
67
68
1.74k
  shapefileObj file;
69
1.74k
  errorObj *ms_error = msGetErrorObj();
70
1.74k
  if (msShapefileOpenVirtualFile(&file, "/vsimem/foo.shp", shp, shx, dbf,
71
1.74k
                                 false) == 0) {
72
1.25k
    if (file.numshapes > 100 * 1000) {
73
181
      VSIStatBufL sStat;
74
181
      if (VSIStatL("/vsimem/foo.shx", &sStat) == 0 && sStat.st_size >= 100 &&
75
181
          file.numshapes > (int)(sStat.st_size - 100) / 8) {
76
179
        file.numshapes = (int)(sStat.st_size - 100) / 8;
77
179
      }
78
181
    }
79
587k
    for (int i = 0; i < file.numshapes; ++i) {
80
586k
      shapeObj shape;
81
586k
      msInitShape(&shape);
82
586k
      msSHPReadShape(file.hSHP, i, &shape);
83
586k
      msFreeShape(&shape);
84
      // Give up as soon an error is triggered to avoid too long processing
85
      // time.
86
586k
      if (ms_error->code != MS_NOERR)
87
956
        break;
88
586k
    }
89
90
1.25k
    msShapefileClose(&file);
91
1.25k
  }
92
93
1.74k
  msResetErrorList();
94
95
1.74k
  VSIUnlink("/vsimem/foo.shp");
96
1.74k
  VSIUnlink("/vsimem/foo.shx");
97
1.74k
  VSIUnlink("/vsimem/foo.dbf");
98
99
  return EXIT_SUCCESS;
100
1.74k
}