Add simple fuzz-harness #1537

Closed
nathaniel-brough wants to merge 2 commits from add-fuzz-harness into main
5 changed files with 120 additions and 0 deletions

View File

@@ -31,6 +31,26 @@ jobs:
- name: Unit tests
run: ./unit_tests ${{ matrix.mode }}
build_fuzzers:
name: Build fuzzers [${{ matrix.toolchain }}][${{ matrix.mode }}]
runs-on: ubuntu-latest
strategy:
matrix:
mode: [Debug, Release]
toolchain: [Clang]
steps:
- uses: actions/checkout@v3
- name: Setup
uses: ./.github/actions/setup-cpp
with:
toolchain: ${{ matrix.toolchain }}
- name: Unit tests
run: ./build_fuzz_tests ${{ matrix.mode }}
benchmark:
name: Benchmark [${{ matrix.toolchain }}]
runs-on: ${{ (matrix.toolchain == 'MSVC') && 'windows-latest' || 'ubuntu-latest' }}

View File

@@ -12,6 +12,12 @@ include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/project-defaults.cmake)
add_subdirectory(yoga)
add_subdirectory(tests)
option(BUILD_FUZZ_TESTS "Build fuzz tests" OFF)
if ('${CMAKE_CXX_COMPILER_ID}' MATCHES 'Clang' AND BUILD_FUZZ_TESTS)
add_subdirectory(fuzz)
endif()
# cmake install config
include(GNUInstallDirs)
include(CMakePackageConfigHelpers)

28
build_fuzz_tests Executable file
View File

@@ -0,0 +1,28 @@
#!/usr/bin/env sh
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
if [ "$#" -eq 0 ]; then
build_type="Debug"
else
build_type="$1"
fi
export CC=clang
export CXX=clang++
# Make sure libc++ isn't used, as libfuzzer is linked against stdlibc++ which causes conflicts
unset CXXFLAGS
export LDFLAGS=-lstdc++
if which ninja; then
set -e
cmake -B build -S . -D BUILD_FUZZ_TESTS=ON -D CMAKE_BUILD_TYPE="$build_type" -G Ninja
else
set -e
cmake -B build -S . -D BUILD_FUZZ_TESTS=ON -D CMAKE_BUILD_TYPE="$build_type"
fi
cmake --build build --target fuzz_layout

16
fuzz/CMakeLists.txt Normal file
View File

@@ -0,0 +1,16 @@
# If google/oss-fuzz has set the fuzzing engine
if(DEFINED ENV{LIB_FUZZING_ENGINE})
set(FUZZING_ENGINE $ENV{LIB_FUZZING_ENGINE})
set(FUZZING_COMPILE_FLAGS "")
set(FUZZING_LINK_FLAGS "${FUZZING_ENGINE}")
else()
set(FUZZING_COMPILE_FLAGS "-fsanitize=fuzzer")
set(FUZZING_LINK_FLAGS "-fsanitize=fuzzer")
endif()
add_executable(fuzz_layout fuzz_layout.cpp)
set_target_properties(fuzz_layout PROPERTIES
COMPILE_FLAGS "${FUZZING_COMPILE_FLAGS}"
LINK_FLAGS "${FUZZING_LINK_FLAGS}"
)
target_link_libraries(fuzz_layout yogacore)

50
fuzz/fuzz_layout.cpp Normal file
View File

@@ -0,0 +1,50 @@
#include <fuzzer/FuzzedDataProvider.h>
#include <yoga/Yoga.h>
#include <cstdint>
YGFlexDirection fuzzed_flex_direction(FuzzedDataProvider& fdp) {
return fdp.PickValueInArray({
YGFlexDirectionColumn,
YGFlexDirectionColumnReverse,
YGFlexDirectionRow,
YGFlexDirectionRowReverse,
});
}
void FillFuzzedTree(
FuzzedDataProvider& fdp,
const YGConfigRef& config,
const YGNodeRef& root,
NickGerleman commented 2024-01-19 08:18:22 -08:00 (Migrated from github.com)
Review

I missed this the first time around, but YGConfigRef and YGNodeRef are themselves just pointers. That also makes const apply to the pointer value, instead of the underlying node/config.

Needed to fix a quick license header to make internal linter happy, but I'm going to make a quick ninja-edit to make that clearer.

I missed this the first time around, but `YGConfigRef` and `YGNodeRef` are themselves just pointers. That also makes `const` apply to the pointer value, instead of the underlying node/config. Needed to fix a quick license header to make internal linter happy, but I'm going to make a quick ninja-edit to make that clearer.
NickGerleman commented 2024-01-19 08:19:02 -08:00 (Migrated from github.com)
Review

Same for a couple other quick repo conventions around naming

Same for a couple other quick repo conventions around naming
nathaniel-brough commented 2024-01-19 09:00:48 -08:00 (Migrated from github.com)
Review

No worries. Let me know if there is anything you'd like me to do here :)

No worries. Let me know if there is anything you'd like me to do here :)
size_t depth = 0) {
constexpr size_t kMaxDepth = 20;
constexpr size_t kMaxChildren = 20;
if (depth > kMaxDepth) {
return;
}
size_t children = fdp.ConsumeIntegralInRange<size_t>(0, kMaxChildren);
for (size_t i = 0; i < children; i++) {
const YGNodeRef child = YGNodeNewWithConfig(config);
YGNodeStyleSetFlexDirection(root, fuzzed_flex_direction(fdp));
YGNodeStyleSetWidth(child, fdp.ConsumeFloatingPoint<float>());
YGNodeStyleSetGap(
child, YGGutterAll, fdp.ConsumeProbability<float>() * 100);
YGNodeStyleSetHeight(child, fdp.ConsumeFloatingPoint<float>());
YGNodeInsertChild(root, child, i);
FillFuzzedTree(fdp, config, child, depth + 1);
}
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
FuzzedDataProvider fdp(data, size);
const YGConfigRef config = YGConfigNew();
const YGNodeRef root = YGNodeNewWithConfig(config);
FillFuzzedTree(fdp, config, root);
YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
YGNodeFreeRecursive(root);
YGConfigFree(config);
return 0;
}