diff --git a/fuzz-test-suite/CMakeLists.txt b/fuzz-test-suite/CMakeLists.txt index aaddcbfefd4..8542711f6fa 100644 --- a/fuzz-test-suite/CMakeLists.txt +++ b/fuzz-test-suite/CMakeLists.txt @@ -8,14 +8,16 @@ else() set(FUZZING_LINK_FLAGS "-fsanitize=fuzzer") endif() -# Define the fuzz target add_executable(DateParserFuzzer dateparserfuzzer.cpp) - -# Apply the determined flags set_target_properties(DateParserFuzzer PROPERTIES COMPILE_FLAGS "${FUZZING_COMPILE_FLAGS}" LINK_FLAGS "${FUZZING_LINK_FLAGS}" ) - -# Link QuantLib and any other necessary libraries target_link_libraries(DateParserFuzzer ql_library ${QL_THREAD_LIBRARIES}) + +add_executable(AmortizedBondsFuzzer amortizedbondsfuzzer.cpp) +set_target_properties(AmortizedBondsFuzzer PROPERTIES + COMPILE_FLAGS "${FUZZING_COMPILE_FLAGS}" + LINK_FLAGS "${FUZZING_LINK_FLAGS}" +) +target_link_libraries(AmortizedBondsFuzzer ql_library ${QL_THREAD_LIBRARIES}) diff --git a/fuzz-test-suite/amortizedbondsfuzzer.cpp b/fuzz-test-suite/amortizedbondsfuzzer.cpp new file mode 100644 index 00000000000..a04ea387665 --- /dev/null +++ b/fuzz-test-suite/amortizedbondsfuzzer.cpp @@ -0,0 +1,80 @@ +/* + Copyright (C) 2023 Nathaniel Brough + + This file is part of QuantLib, a free-software/open-source library + for financial quantitative analysts and developers - http://quantlib.org/ + + QuantLib is free software: you can redistribute it and/or modify it + under the terms of the QuantLib license. You should have received a + copy of the license along with this program; if not, please email + . The license is also available online at + . + + This program is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the license for more details. +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define _unused(x) ((void)(x)) + +using namespace QuantLib; + +std::vector fuzzedRates(FuzzedDataProvider& fdp, const size_t length) { + std::vector result; + for (size_t i = 0; i < length; i++) { + result.push_back(fdp.ConsumeProbability()); + } + return result; +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) { + FuzzedDataProvider fdp(Data, Size); + // Ensure settings are reset each iteration of the fuzzing loop. + // NOTE: this class manages the settings singleton using default + // (con/des)tructors. + SavedSettings saved_settings; + + constexpr size_t kMaxSize = 512; + auto length = fdp.ConsumeIntegralInRange(0, kMaxSize); + + Date refDate = Settings::instance().evaluationDate(); + + auto rates = fuzzedRates(fdp, length); + Frequency freq = Monthly; + + for (size_t i = 0; i < length; ++i) { + + auto schedule = sinkingSchedule(refDate, Period(30, Years), freq, NullCalendar()); + auto notionals = sinkingNotionals(Period(30, Years), freq, rates[i], 100.0); + + AmortizingFixedRateBond myBond(0, notionals, schedule, {rates[i]}, + ActualActual(ActualActual::ISMA)); + + Leg cashflows = myBond.cashflows(); + + Real lastTotalAmount = 0.0; + for (size_t k = 0; k < cashflows.size() / 2; ++k) { + Real coupon = cashflows[2 * k]->amount(); + Real principal = cashflows[2 * k + 1]->amount(); + Real totalAmount = coupon + principal; + // Assert invariants, these should always be true. + assert(coupon > 0.0); + assert(principal > 0.0); + assert(totalAmout > lastTotalAmount); + lastTotalAmount = totalAmount; + _unused(lastTotalAmount); + } + } + return 0; +}