Skip to content

Commit f3df47e

Browse files
committed
Separate geodesic fuzzer
1 parent c7a24cd commit f3df47e

5 files changed

Lines changed: 128 additions & 19 deletions

File tree

CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,7 @@ set(OTHER_SOURCE_FILES
313313
src/apps/fuzzers/fuzzerLocalIj.c
314314
src/apps/fuzzers/fuzzerPolygonToCells.c
315315
src/apps/fuzzers/fuzzerPolygonToCellsExperimental.c
316+
src/apps/fuzzers/fuzzerPolygonToCellsExperimentalGeodesic.c
316317
src/apps/fuzzers/fuzzerPolygonToCellsNoHoles.c
317318
src/apps/fuzzers/fuzzerPolygonToCellsExperimentalNoHoles.c
318319
src/apps/fuzzers/fuzzerCellToChildPos.c
@@ -641,6 +642,8 @@ if(BUILD_FUZZERS)
641642
add_h3_fuzzer(fuzzerPolygonToCells src/apps/fuzzers/fuzzerPolygonToCells.c)
642643
add_h3_fuzzer(fuzzerPolygonToCellsExperimental
643644
src/apps/fuzzers/fuzzerPolygonToCellsExperimental.c)
645+
add_h3_fuzzer(fuzzerPolygonToCellsExperimentalGeodesic
646+
src/apps/fuzzers/fuzzerPolygonToCellsExperimentalGeodesic.c)
644647
add_h3_fuzzer(fuzzerPolygonToCellsNoHoles
645648
src/apps/fuzzers/fuzzerPolygonToCellsNoHoles.c)
646649
add_h3_fuzzer(fuzzerPolygonToCellsExperimentalNoHoles

src/apps/fuzzers/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ The public API of H3 is covered in the following fuzzers:
6161
| localIjToCell | [fuzzerLocalIj](./fuzzerLocalIj.c)
6262
| originToDirectedEdges | [fuzzerDirectedEdge](./fuzzerDirectedEdge.c)
6363
| polygonToCells | [fuzzerPoylgonToCells](./fuzzerPolygonToCells.c)
64-
| polygonToCellsExperimental | [fuzzerPoylgonToCellsExperimental](./fuzzerPolygonToCellsExperimental.c) [fuzzerPoylgonToCellsExperimentalNoHoles](./fuzzerPolygonToCellsExperimentalNoHoles.c)
64+
| polygonToCellsExperimental | [fuzzerPoylgonToCellsExperimental](./fuzzerPolygonToCellsExperimental.c) [fuzzerPoylgonToCellsExperimentalGeodesic](./fuzzerPolygonToCellsExperimentalGeodesic.c) [fuzzerPoylgonToCellsExperimentalNoHoles](./fuzzerPolygonToCellsExperimentalNoHoles.c)
6565
| radsToDegs | Trivial
6666
| stringToH3 | [fuzzerIndexIO](./fuzzerIndexIO.c)
6767
| uncompactCells | [fuzzerCompact](./fuzzerCompact.c)

src/apps/fuzzers/fuzzerPolygonToCellsExperimental.c

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -93,21 +93,8 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
9393
}
9494

9595
for (uint32_t flags = 0; flags < CONTAINMENT_INVALID; flags++) {
96-
// Prepare geodesic flags:
97-
// 1. Run geodesic only for larger cells
98-
// 2. Don't run on very large polygons
99-
// 3. Don't run without holes (to avoid running long cases twice)
100-
bool canRunGeodesic = flags == CONTAINMENT_OVERLAPPING;
101-
canRunGeodesic &= res <= 6;
102-
canRunGeodesic &= geoPolygon.geoloop.numVerts <= 1024;
103-
uint32_t geodesicFlags = flags;
104-
FLAG_SET_GEODESIC(geodesicFlags);
105-
10696
geoPolygon.numHoles = originalNumHoles;
10797
run(&geoPolygon, flags, res);
108-
if (canRunGeodesic) {
109-
run(&geoPolygon, geodesicFlags, res);
110-
}
11198

11299
// Don't run polygon without holes twice
113100
if (originalNumHoles == 0) {
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
/*
2+
* Copyright 2023-2024 Uber Technologies, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
/** @file fuzzerPolygonToCellsExperimentalGeodesic.c
17+
* @brief Fuzzes the experimental polygon-to-cells implementation in geodesic
18+
* mode.
19+
*/
20+
21+
#include "aflHarness.h"
22+
#include "h3api.h"
23+
#include "polyfill.h"
24+
#include "polygon.h"
25+
#include "utility.h"
26+
27+
typedef struct {
28+
int res;
29+
int numHoles;
30+
// repeating: num verts, verts
31+
// We add a large fixed buffer so our test case generator for AFL
32+
// knows how large to make the file.
33+
uint8_t buffer[1024];
34+
} inputArgs;
35+
36+
const int MAX_GEODESIC_RES = 4;
37+
const int MAX_SZ = 100000;
38+
const int MAX_HOLES = 100;
39+
40+
static int populateGeoLoop(GeoLoop *g, const uint8_t *data, size_t *offset,
41+
size_t size) {
42+
if (size < *offset + sizeof(int)) {
43+
return 1;
44+
}
45+
int numVerts = *(const int *)(data + *offset);
46+
*offset = *offset + sizeof(int);
47+
g->numVerts = numVerts;
48+
if (size < *offset + sizeof(LatLng) * numVerts) {
49+
return 1;
50+
}
51+
g->verts = (LatLng *)(data + *offset);
52+
*offset = *offset + sizeof(LatLng) * numVerts;
53+
return 0;
54+
}
55+
56+
static void runGeodesic(GeoPolygon *geoPolygon, uint32_t flags, int res) {
57+
uint32_t geodesicFlags = flags;
58+
FLAG_SET_GEODESIC(geodesicFlags);
59+
60+
int64_t sz;
61+
H3Error err = H3_EXPORT(maxPolygonToCellsSizeExperimental)(
62+
geoPolygon, res, geodesicFlags, &sz);
63+
if (!err && sz < MAX_SZ) {
64+
H3Index *out = calloc(sz, sizeof(H3Index));
65+
H3_EXPORT(polygonToCellsExperimental)
66+
(geoPolygon, res, geodesicFlags, sz, out);
67+
free(out);
68+
}
69+
}
70+
71+
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
72+
if (size < sizeof(inputArgs)) {
73+
return 0;
74+
}
75+
const inputArgs *args = (const inputArgs *)data;
76+
int res = args->res % (MAX_GEODESIC_RES + 1);
77+
if (res == 0) {
78+
res = 1; // resolution 1 tests more code paths compared to 0
79+
}
80+
81+
GeoPolygon geoPolygon;
82+
int originalNumHoles = args->numHoles % MAX_HOLES;
83+
geoPolygon.numHoles = originalNumHoles;
84+
if (geoPolygon.numHoles < 0) {
85+
return 0;
86+
}
87+
geoPolygon.holes = calloc(geoPolygon.numHoles, sizeof(GeoLoop));
88+
size_t offset = sizeof(inputArgs) - sizeof(args->buffer);
89+
if (populateGeoLoop(&geoPolygon.geoloop, data, &offset, size)) {
90+
free(geoPolygon.holes);
91+
return 0;
92+
}
93+
for (int i = 0; i < geoPolygon.numHoles; i++) {
94+
if (populateGeoLoop(&geoPolygon.holes[i], data, &offset, size)) {
95+
free(geoPolygon.holes);
96+
return 0;
97+
}
98+
}
99+
100+
for (uint32_t flags = 0; flags < CONTAINMENT_INVALID; flags++) {
101+
bool canRunGeodesic =
102+
flags == CONTAINMENT_OVERLAPPING || flags == CONTAINMENT_FULL;
103+
canRunGeodesic &= geoPolygon.geoloop.numVerts <= 256;
104+
105+
if (!canRunGeodesic) {
106+
continue;
107+
}
108+
109+
geoPolygon.numHoles = originalNumHoles;
110+
runGeodesic(&geoPolygon, flags, res);
111+
112+
if (originalNumHoles == 0) {
113+
continue;
114+
}
115+
116+
geoPolygon.numHoles = 0;
117+
runGeodesic(&geoPolygon, flags, res);
118+
}
119+
free(geoPolygon.holes);
120+
121+
return 0;
122+
}
123+
124+
AFL_HARNESS_MAIN(sizeof(inputArgs));

src/apps/fuzzers/fuzzerPolygonToCellsExperimentalNoHoles.c

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,6 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
5555

5656
for (uint32_t flags = 0; flags < CONTAINMENT_INVALID; flags++) {
5757
run(&geoPolygon, flags, res);
58-
if (flags == CONTAINMENT_FULL || flags == CONTAINMENT_OVERLAPPING) {
59-
uint32_t geodesicFlags = flags;
60-
FLAG_SET_GEODESIC(geodesicFlags);
61-
run(&geoPolygon, geodesicFlags, res);
62-
}
6358
}
6459

6560
return 0;

0 commit comments

Comments
 (0)