src/apps/fuzzers/fuzzerPolygonToCells.c (70 lines of code) (raw):
/*
* Copyright 2022-2024 Uber Technologies, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/** @file
* @brief Fuzzer program for polygonToCells and related functions
*/
#include "aflHarness.h"
#include "h3api.h"
#include "polygon.h"
#include "utility.h"
typedef struct {
int res;
int numHoles;
// repeating: num verts, verts
// We add a large fixed buffer so our test case generator for AFL
// knows how large to make the file.
uint8_t buffer[1024];
} inputArgs;
const int MAX_RES = 15;
const int MAX_SZ = 4000000;
const int MAX_HOLES = 100;
int populateGeoLoop(GeoLoop *g, const uint8_t *data, size_t *offset,
size_t size) {
if (size < *offset + sizeof(int)) {
return 1;
}
int numVerts = *(const int *)(data + *offset);
*offset = *offset + sizeof(int);
g->numVerts = numVerts;
if (size < *offset + sizeof(LatLng) * numVerts) {
return 1;
}
g->verts = (LatLng *)(data + *offset);
*offset = *offset + sizeof(LatLng) * numVerts;
return 0;
}
void run(GeoPolygon *geoPolygon, uint32_t flags, int res) {
int64_t sz;
H3Error err = H3_EXPORT(maxPolygonToCellsSize)(geoPolygon, res, flags, &sz);
if (!err && sz < MAX_SZ) {
H3Index *out = calloc(sz, sizeof(H3Index));
H3_EXPORT(polygonToCells)(geoPolygon, res, flags, out);
free(out);
}
}
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
// TODO: It is difficult for the fuzzer to generate inputs that are
// considered valid by this fuzzer. fuzzerPolygonToCellsNoHoles.c
// is a workaround for that.
if (size < sizeof(inputArgs)) {
return 0;
}
const inputArgs *args = (const inputArgs *)data;
int res = args->res % (MAX_RES + 1);
GeoPolygon geoPolygon;
int originalNumHoles = args->numHoles % MAX_HOLES;
geoPolygon.numHoles = originalNumHoles;
if (geoPolygon.numHoles < 0) {
return 0;
}
geoPolygon.holes = calloc(geoPolygon.numHoles, sizeof(GeoLoop));
size_t offset = sizeof(inputArgs) - sizeof(args->buffer);
if (populateGeoLoop(&geoPolygon.geoloop, data, &offset, size)) {
free(geoPolygon.holes);
return 0;
}
for (int i = 0; i < geoPolygon.numHoles; i++) {
if (populateGeoLoop(&geoPolygon.holes[i], data, &offset, size)) {
free(geoPolygon.holes);
return 0;
}
}
for (uint32_t flags = 0; flags < CONTAINMENT_INVALID; flags++) {
geoPolygon.numHoles = originalNumHoles;
run(&geoPolygon, 0, res);
geoPolygon.numHoles = 0;
run(&geoPolygon, 0, res);
}
free(geoPolygon.holes);
return 0;
}
AFL_HARNESS_MAIN(sizeof(inputArgs));