From 3e88f7f85ac0f53cb75a3c45ced41e64c281d016 Mon Sep 17 00:00:00 2001 From: Bhargava Shastry Date: Wed, 9 Feb 2022 12:00:15 +0100 Subject: [PATCH] Stick to constraint parsing convention and refactor fuzzer harness. --- test/tools/ossfuzz/LPSolverFuzzer.cpp | 115 +++++++++++------- .../ossfuzz/lpsolver/ConstraintGenerator.cpp | 2 +- .../ossfuzz/lpsolver/ConstraintGenerator.h | 2 +- .../lpsolver/FuzzerSolverInterface.cpp | 6 +- 4 files changed, 73 insertions(+), 52 deletions(-) diff --git a/test/tools/ossfuzz/LPSolverFuzzer.cpp b/test/tools/ossfuzz/LPSolverFuzzer.cpp index eb0e78fcd..43ebb463c 100644 --- a/test/tools/ossfuzz/LPSolverFuzzer.cpp +++ b/test/tools/ossfuzz/LPSolverFuzzer.cpp @@ -18,8 +18,10 @@ #include +#include #include #include +#include #include #include #include @@ -28,13 +30,16 @@ using namespace solidity::test::fuzzer::lpsolver; using namespace std; +using Constraint = pair>; +using Constraints = vector; + // Prototype as we can't use the FuzzerInterface.h header. extern "C" int LLVMFuzzerTestOneInput(uint8_t const* _data, size_t _size); namespace { #ifdef DEBUG -void printConstraints(vector>> _constraints) +void printConstraints(Constraints _constraints) { for (auto& i: _constraints) { @@ -46,65 +51,85 @@ void printConstraints(vector>> _constraints) } #endif -bool validConstraints(vector>> _constraints) +bool validInput(string const& _input) { + return all_of( + _input.begin(), + _input.end(), + [](unsigned char _c) { return isdigit(_c) || (_c == ',') || (_c == '-') || (_c == '\n'); } + ); +} + +optional parseConstraints(istringstream& _input) +{ + Constraints constraints; + for (string line; getline(_input, line); ) + { + istringstream lineStream; + lineStream.str(line); + Constraint constraint; + bool first = true; + for (string field; getline(lineStream, field, ','); ) + { + int val = 0; + try + { + val = stoi(field); + } + // Fuzzer can sometimes supply invalid input to stoi that needs to be + // rejected. + catch (invalid_argument const&) + { + return nullopt; + } + if (first) + { + constraint.first = static_cast(val); + first = false; + } + else + constraint.second.emplace_back(val); + } + constraints.emplace_back(constraint); + } // Zero input constraints is an invalid input - if (_constraints.size() < 1) - return false; + if (constraints.size() < 1) + return nullopt; // Incomplete constraints are invalid - for (auto c: _constraints) + for (auto c: constraints) if (c.second.empty()) - return false; - return true; + return nullopt; + return constraints; } } extern "C" int LLVMFuzzerTestOneInput(uint8_t const* _data, size_t _size) { - // Parse CSV input istringstream input; input.str(string(reinterpret_cast(_data), _size)); - - vector>> constraints; - for (string line; getline(input, line); ) + if (validInput(input.str())) { - istringstream lineStream; - lineStream.str(line); - pair> constraint; - bool first = true; - for (string field; getline(lineStream, field, ','); ) + // Parse CSV input + auto constraints = parseConstraints(input); + if (constraints.has_value()) { - if (first) + // TODO: Z3 on constraints provided by fuzzer interface and comparing its outcome + // with LP solver. + FuzzerSolverInterface solverWithoutModels(/*supportModels=*/false); + FuzzerSolverInterface solverWithModels(/*supportModels=*/true); + + solverWithoutModels.addConstraints(constraints.value()); + string resultWithoutModels = solverWithoutModels.checkResult(); + solverWithModels.addConstraints(constraints.value()); + string resultWithModels = solverWithModels.checkResult(); + + if (resultWithoutModels != resultWithModels) { - constraint.first = static_cast(stoi(field)); - first = false; + cout << resultWithoutModels << endl; + cout << resultWithModels << endl; + solAssert(false, "LP result without models did not match with result with models."); } - else - constraint.second.emplace_back(stoi(field)); } - constraints.emplace_back(constraint); - } - - if (!validConstraints(constraints)) - return 0; - else - { - // TODO: Z3 on constraints provided by fuzzer interface and comparing its outcome - // with LP solver. - FuzzerSolverInterface solverWithoutModels(/*supportModels=*/false); - FuzzerSolverInterface solverWithModels(/*supportModels=*/true); - - solverWithoutModels.addConstraints(constraints); - string resultWithoutModels = solverWithoutModels.checkResult(); - solverWithModels.addConstraints(constraints); - string resultWithModels = solverWithModels.checkResult(); - - if (resultWithoutModels != resultWithModels) - { - cout << resultWithoutModels << endl; - cout << resultWithModels << endl; - solAssert(false, "LP result without models did not match with result with models."); - } - return 0; } + return 0; } diff --git a/test/tools/ossfuzz/lpsolver/ConstraintGenerator.cpp b/test/tools/ossfuzz/lpsolver/ConstraintGenerator.cpp index ead67ed94..3d63c37d2 100644 --- a/test/tools/ossfuzz/lpsolver/ConstraintGenerator.cpp +++ b/test/tools/ossfuzz/lpsolver/ConstraintGenerator.cpp @@ -33,7 +33,7 @@ string ConstraintGenerator::generate() constraint += to_string(zeroOrOne()); for (int j = 0; j < numFactors(); j++) if (bernoulliDist(s_piecewiseConstantProb)) - constraint += "," + to_string(randomMinusOneToOne()); + constraint += ",0"; else constraint += "," + to_string(randomInteger()); constraint += "\n"; diff --git a/test/tools/ossfuzz/lpsolver/ConstraintGenerator.h b/test/tools/ossfuzz/lpsolver/ConstraintGenerator.h index 5f50c8394..3776af8d8 100644 --- a/test/tools/ossfuzz/lpsolver/ConstraintGenerator.h +++ b/test/tools/ossfuzz/lpsolver/ConstraintGenerator.h @@ -90,7 +90,7 @@ struct ConstraintGenerator /// Largest value of a factor in linear constraint static constexpr int s_maxFactor = 100; /// Probability that a factor in the range of [-1, 1] is chosen - static constexpr double s_piecewiseConstantProb = 0.25; + static constexpr double s_piecewiseConstantProb = 0.75; }; } diff --git a/test/tools/ossfuzz/lpsolver/FuzzerSolverInterface.cpp b/test/tools/ossfuzz/lpsolver/FuzzerSolverInterface.cpp index ee5534e13..365e42af8 100644 --- a/test/tools/ossfuzz/lpsolver/FuzzerSolverInterface.cpp +++ b/test/tools/ossfuzz/lpsolver/FuzzerSolverInterface.cpp @@ -32,11 +32,7 @@ LinearExpression FuzzerSolverInterface::linearExpression(vector _factors) LinearExpression lexp; lexp.resize(_factors.size()); for (auto&& [index, value]: _factors | ranges::views::enumerate) - // Move constant term to RHS. - if (index == 0) - lexp[index] = -rational{value}; - else - lexp[index] = rational{value}; + lexp[index] = rational{value}; return lexp; }