diff --git a/CMakeLists.txt b/CMakeLists.txt index 088bb31..3dc0c4a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -84,4 +84,11 @@ add_executable(soak tests/soak.c lib/common.c lib/tdigest.c lib/roaring.c) target_link_libraries(soak PRIVATE sparsemap) target_include_directories(soak PRIVATE ${HEADER_DIR} lib) target_link_libraries(soak PUBLIC m) -add_custom_target(run_soak COMMAND soak WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) \ No newline at end of file +add_custom_target(run_soak COMMAND soak WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) + +# Add fuzzer program +add_executable(fuzzer tests/fuzzer.c) +target_link_libraries(fuzzer PRIVATE sparsemap) +target_include_directories(fuzzer PRIVATE ${HEADER_DIR} lib) +target_link_libraries(fuzzer PUBLIC m) +add_custom_target(run_fuzzer COMMAND fuzzer WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) diff --git a/Makefile b/Makefile index 2c00376..67b2443 100644 --- a/Makefile +++ b/Makefile @@ -6,19 +6,19 @@ SHARED_LIB = libsparsemap.so LIBS = -lm #CFLAGS = -Wall -Wextra -Wpedantic -Of -std=c11 -Iinclude/ -fPIC #CFLAGS = -Wall -Wextra -Wpedantic -Og -g -std=c11 -Iinclude/ -fPIC -#CFLAGS = -DSPARSEMAP_DIAGNOSTIC -DDEBUG -Wall -Wextra -Wpedantic -O0 -g -std=c11 -Iinclude/ -fPIC -CFLAGS = -DSPARSEMAP_DIAGNOSTIC -DDEBUG -Wall -Wextra -Ofast -g -std=c11 -Iinclude/ -fPIC +CFLAGS = -DSPARSEMAP_DIAGNOSTIC -DDEBUG -Wall -Wextra -Wpedantic -O0 -g -std=c11 -Iinclude/ -fPIC +#CFLAGS = -DSPARSEMAP_DIAGNOSTIC -DDEBUG -Wall -Wextra -Ofast -g -std=c11 -Iinclude/ -fPIC #CFLAGS = -Wall -Wextra -Wpedantic -Og -g -std=c11 -Iinclude/ -fPIC #CFLAGS = -Wall -Wextra -Wpedantic -Ofast -g -std=c11 -Iinclude/ -fPIC #CFLAGS = -DSPARSEMAP_DIAGNOSTIC -DDEBUG -Wall -Wextra -Wpedantic -Og -g -fsanitize=address,leak,object-size,pointer-compare,pointer-subtract,null,return,bounds,pointer-overflow,undefined -fsanitize-address-use-after-scope -std=c11 -Iinclude/ -fPIC #CFLAGS = -Wall -Wextra -Wpedantic -Og -g -fsanitize=all -fhardened -std=c11 -Iinclude/ -fPIC -#TEST_FLAGS = -DDEBUG -Wall -Wextra -Wpedantic -O0 -g -std=c11 -Iinclude/ -Itests/ -fPIC -TEST_FLAGS = -Wall -Wextra -Wpedantic -Ofast -g -std=c11 -Iinclude/ -Itests/ -fPIC +TEST_FLAGS = -DDEBUG -Wall -Wextra -Wpedantic -O0 -g -std=c11 -Iinclude/ -Itests/ -fPIC +#TEST_FLAGS = -Wall -Wextra -Wpedantic -Ofast -g -std=c11 -Iinclude/ -Itests/ -fPIC #TEST_FLAGS = -Wall -Wextra -Wpedantic -Og -g -std=c11 -Iinclude/ -Itests/ -fPIC #TEST_FLAGS = -DDEBUG -Wall -Wextra -Wpedantic -Og -g -fsanitize=address,leak,object-size,pointer-compare,pointer-subtract,null,return,bounds,pointer-overflow,undefined -fsanitize-address-use-after-scope -std=c11 -Iinclude/ -fPIC -TESTS = tests/test tests/soak +TESTS = tests/test tests/soak tests/fuzzer TEST_OBJS = tests/test.o lib/munit.o lib/tdigest.o lib/common.o LIB_OBJS = lib/munit.o lib/tdigest.o lib/common.o lib/roaring.o EXAMPLES = examples/ex_1 examples/ex_2 examples/ex_3 examples/ex_4 @@ -49,6 +49,9 @@ test: tests soak: tests env ASAN_OPTIONS=detect_leaks=1 LSAN_OPTIONS=verbosity=1:log_threads=1 ./tests/soak +fuzzer: tests + env ASAN_OPTIONS=detect_leaks=1 LSAN_OPTIONS=verbosity=1:log_threads=1 ./tests/fuzzer ./crash.case + tests/test: $(TEST_OBJS) $(LIB_OBJS) $(STATIC_LIB) $(CC) $^ $(LIBS) -o $@ $(TEST_FLAGS) @@ -60,7 +63,7 @@ clean: rm -f $(EXAMPLES) examples/*.o format: - clang-format -i src/sparsemap.c include/sparsemap.h examples/ex_*.c tests/soak.c tests/test.c tests/midl.c lib/common.c include/common.h + clang-format -i src/sparsemap.c include/sparsemap.h examples/ex_*.c tests/soak.c tests/fuzzer.c tests/test.c tests/midl.c lib/common.c include/common.h # clang-format -i include/*.h src/*.c tests/*.c tests/*.h examples/*.c %.o: src/%.c @@ -90,6 +93,9 @@ examples/ex_4: $(LIB_OBJS) examples/ex_4.o $(STATIC_LIB) tests/soak: $(LIB_OBJS) tests/soak.o $(STATIC_LIB) $(CC) $^ $(LIBS) -o $@ $(TEST_FLAGS) +tests/fuzzer: $(LIB_OBJS) tests/fuzzer.o $(STATIC_LIB) + $(CC) $^ $(LIBS) -o $@ $(TEST_FLAGS) -DFUZZ_DEBUG + todo: rg -i 'todo|gsb|abort' diff --git a/crash.case b/crash.case new file mode 100644 index 0000000..5436af4 Binary files /dev/null and b/crash.case differ diff --git a/src/sparsemap.c b/src/sparsemap.c index da9ad78..4b1d479 100644 --- a/src/sparsemap.c +++ b/src/sparsemap.c @@ -1705,6 +1705,10 @@ sparsemap_select(sparsemap_t *map, sparsemap_idx_t n, bool value) sm_idx_t start; size_t count = __sm_get_chunk_count(map); + if (count == 0 && value == false) { + return n; + } + uint8_t *p = __sm_get_chunk_data(map, 0); for (size_t i = 0; i < count; i++) { @@ -1847,6 +1851,9 @@ sparsemap_span(sparsemap_t *map, sparsemap_idx_t idx, size_t len, bool value) many selects we can avoid by taking the rank of the range and starting at that bit. */ nth = (idx == 0) ? 0 : sparsemap_rank(map, 0, idx - 1, value); + if (SPARSEMAP_NOT_FOUND(nth)) { + return nth; + } /* Find the first bit that matches value, then... */ offset = sparsemap_select(map, nth, value); do {