Add simple fuzz-harness (#1537)
Summary: > This PR is based on the proposal in https://github.com/facebook/yoga/issues/1538 inlined below, to integrate yoga with `oss-fuzz` Hey yoga team, I've recently become interested in yoga. I'd like to suggest and champion an effort to set up some basic fuzz-testing and combine it with google/oss-fuzz for continuous fuzzing. I'm fully aware that you are very busy people and I don't want to overload your review/maintenance capacity. Is this a bad time to discuss potential security/reliability improvements? If you're not familiar with fuzzing or oss-fuzz I've included a few brief notes below. #### **Benefits of Fuzz-Testing** - **Dynamic Code Testing**: Fuzz-testing challenges systems with unexpected data, aiming to identify vulnerabilities or bugs. It’s akin to an exhaustive stress-test for the code. - **Detecting Hidden Vulnerabilities**: It can uncover potential weaknesses that may not be evident in routine tests. - **Continuous and Automated Testing**: With tools like Google’s OSS-Fuzz, fuzz-testing can be automated, running continuously on distributed systems, ensuring daily resilience checks. #### **Google/oss-fuzz for Continuous Fuzzing** - **Automated Fuzzing**: OSS-Fuzz undertakes comprehensive fuzz-testing daily on a distributed cluster. - **Detailed Reporting**: OSS-Fuzz offers exhaustive reports in case of detected anomalies, enabling effective action. I’d be more than happy to lead the effort in integrating fuzz testing with the yoga and assist in any way required. #### Prior integrations There have been a number of previous integrations completed with facebook repositories and google/oss-fuzz including; - facebook/time - facebook/zstd - facebookexperimental/starlark-rust (this was me) - facebook/proxygen - facebook/hermes - facebook/rocksdb As a proof of concept I created a couple of super simple fuzz harnesses in https://github.com/facebook/yoga/issues/1537. NOTE: Adding fuzz-testing and integrating with google/oss-fuzz was previously suggested here https://github.com/facebook/yoga/pull/1055 and was rejected. I think I've addressed the concerns raised in the first PR. While the original PR contained what was probably a higher performance fuzzer, the new fuzzer should be easier to integrate and doesn't introduce multiple sources of truth. Pull Request resolved: https://github.com/facebook/yoga/pull/1537 Reviewed By: yungsters Differential Revision: D52800366 Pulled By: NickGerleman fbshipit-source-id: 4957282456f3263e600d13ae6f3e983681bebda6
This commit is contained in:
committed by
Facebook GitHub Bot
parent
1541f9d528
commit
1a8b80a3d5
20
.github/workflows/validate-cpp.yml
vendored
20
.github/workflows/validate-cpp.yml
vendored
@@ -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' }}
|
||||
|
@@ -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
28
build_fuzz_tests
Executable 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
|
21
fuzz/CMakeLists.txt
Normal file
21
fuzz/CMakeLists.txt
Normal file
@@ -0,0 +1,21 @@
|
||||
# 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 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 FuzzLayout.cpp)
|
||||
set_target_properties(fuzz_layout PROPERTIES
|
||||
COMPILE_FLAGS "${FUZZING_COMPILE_FLAGS}"
|
||||
LINK_FLAGS "${FUZZING_LINK_FLAGS}"
|
||||
)
|
||||
target_link_libraries(fuzz_layout yogacore)
|
57
fuzz/FuzzLayout.cpp
Normal file
57
fuzz/FuzzLayout.cpp
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <fuzzer/FuzzedDataProvider.h>
|
||||
#include <yoga/Yoga.h>
|
||||
#include <cstdint>
|
||||
|
||||
YGFlexDirection fuzzedFlexDirection(FuzzedDataProvider& fdp) {
|
||||
return fdp.PickValueInArray({
|
||||
YGFlexDirectionColumn,
|
||||
YGFlexDirectionColumnReverse,
|
||||
YGFlexDirectionRow,
|
||||
YGFlexDirectionRowReverse,
|
||||
});
|
||||
}
|
||||
|
||||
void fillFuzzedTree(
|
||||
FuzzedDataProvider& fdp,
|
||||
YGConfigConstRef config,
|
||||
YGNodeRef root,
|
||||
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++) {
|
||||
YGNodeRef child = YGNodeNewWithConfig(config);
|
||||
YGNodeStyleSetFlexDirection(root, fuzzedFlexDirection(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);
|
||||
YGConfigRef config = YGConfigNew();
|
||||
YGNodeRef root = YGNodeNewWithConfig(config);
|
||||
fillFuzzedTree(fdp, config, root);
|
||||
|
||||
YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
|
||||
|
||||
YGNodeFreeRecursive(root);
|
||||
YGConfigFree(config);
|
||||
return 0;
|
||||
}
|
Reference in New Issue
Block a user