diff --git a/test/tools/ossfuzz/protoToAbiV2.cpp b/test/tools/ossfuzz/protoToAbiV2.cpp index daea61c9a..5837d6f20 100644 --- a/test/tools/ossfuzz/protoToAbiV2.cpp +++ b/test/tools/ossfuzz/protoToAbiV2.cpp @@ -388,11 +388,14 @@ void ProtoConverter::visit(StructType const&) { } -std::string ProtoConverter::arrayDimInfoAsString(ArrayDimensionInfo const& _x) +std::string ProtoConverter::arrayDimInfoAsString( + ArrayDimensionInfo const& _x, + unsigned _numDimensions +) { return Whiskers(R"([])") ("isStatic", _x.is_static()) - ("length", std::to_string(getStaticArrayLengthFromFuzz(_x.length()))) + ("length", std::to_string(getStaticArrayLengthFromFuzz(_x.length(), _numDimensions))) .render(); } @@ -402,7 +405,7 @@ void ProtoConverter::arrayDimensionsAsStringVector( { solAssert(_x.info_size() > 0, "Proto ABIv2 Fuzzer: Array dimensions empty."); for (auto const& dim: _x.info()) - _vecOfStr.push_back(arrayDimInfoAsString(dim)); + _vecOfStr.push_back(arrayDimInfoAsString(dim, _x.info_size())); } ProtoConverter::VecOfBoolUnsigned ProtoConverter::arrayDimensionsAsPairVector( @@ -411,7 +414,7 @@ ProtoConverter::VecOfBoolUnsigned ProtoConverter::arrayDimensionsAsPairVector( { VecOfBoolUnsigned arrayDimsPairVector = {}; for (auto const& dim: _x.info()) - arrayDimsPairVector.push_back(arrayDimInfoAsPair(dim)); + arrayDimsPairVector.push_back(arrayDimInfoAsPair(dim, _x.info_size())); solAssert(!arrayDimsPairVector.empty(), "Proto ABIv2 Fuzzer: Array dimensions empty."); return arrayDimsPairVector; } @@ -467,7 +470,8 @@ unsigned ProtoConverter::resizeDimension( unsigned _arrayLen, std::string const& _var, std::string const& _param, - std::string const& _type + std::string const& _type, + unsigned _numDimensions ) { unsigned length; @@ -475,7 +479,7 @@ unsigned ProtoConverter::resizeDimension( length = _arrayLen; else { - length = getDynArrayLengthFromFuzz(_arrayLen, getNextCounter()); + length = getDynArrayLengthFromFuzz(_arrayLen, getNextCounter(), _numDimensions); // If local var, new T(l); // Else, l; @@ -501,7 +505,7 @@ unsigned ProtoConverter::resizeDimension( } // Add checks on array length pseudo randomly - if (addCheck(getNextCounter())) + if (addCheck(getNextCounter(), _numDimensions)) // if (c.length != l) checkResizeOp(_param, length); return length; @@ -512,7 +516,8 @@ void ProtoConverter::resizeHelper( std::vector _arrStrVec, VecOfBoolUnsigned _arrInfoVec, std::string const& _varName, - std::string const& _paramName + std::string const& _paramName, + unsigned _numDimensions ) { // Initialize value expressions if we have arrived at leaf node, @@ -523,7 +528,7 @@ void ProtoConverter::resizeHelper( // To ensure we do not create a very large test case // especially for multidimensional dynamic arrays, // we create a checked assignment pseudo randomly. - if (addCheck(getNextCounter())) + if (addCheck(getNextCounter(), _numDimensions)) { // expression name is _var // value is a value of base type @@ -542,7 +547,7 @@ void ProtoConverter::resizeHelper( _arrStrVec.end(), std::string("") ); - unsigned length = resizeDimension(dim.first, dim.second, _varName, _paramName, type); + unsigned length = resizeDimension(dim.first, dim.second, _varName, _paramName, type, _numDimensions); // Recurse one level dimension down. _arrStrVec.pop_back(); _arrInfoVec.pop_back(); @@ -552,7 +557,8 @@ void ProtoConverter::resizeHelper( _arrStrVec, _arrInfoVec, _varName + "[" + std::to_string(i) + "]", - _paramName + "[" + std::to_string(i) + "]" + _paramName + "[" + std::to_string(i) + "]", + _numDimensions ); } } @@ -569,7 +575,7 @@ void ProtoConverter::resizeInitArray( VecOfBoolUnsigned arrInfoVec = arrayDimensionsAsPairVector(_x); std::vector arrStrVec = {_baseType}; arrayDimensionsAsStringVector(_x, arrStrVec); - resizeHelper(_x, arrStrVec, arrInfoVec, _varName, _paramName); + resizeHelper(_x, arrStrVec, arrInfoVec, _varName, _paramName, arrInfoVec.size()); } // Returns array type from it's base type (e.g., int8) and array dimensions info contained in diff --git a/test/tools/ossfuzz/protoToAbiV2.h b/test/tools/ossfuzz/protoToAbiV2.h index 50ca4dc9c..b660e76a6 100644 --- a/test/tools/ossfuzz/protoToAbiV2.h +++ b/test/tools/ossfuzz/protoToAbiV2.h @@ -174,7 +174,8 @@ private: unsigned _arrayLen, std::string const& _var, std::string const& _param, - std::string const& _type + std::string const& _type, + unsigned _numDimensions ); void resizeHelper( @@ -182,7 +183,8 @@ private: std::vector _arrStrVec, VecOfBoolUnsigned _arrInfoVec, std::string const& _varName, - std::string const& _paramName + std::string const& _paramName, + unsigned _numDimensions ); // Utility functions @@ -293,7 +295,7 @@ private: bool _isHexLiteral ); static std::vector> arrayDimensionsAsPairVector(ArrayType const& _x); - static std::string arrayDimInfoAsString(ArrayDimensionInfo const& _x); + static std::string arrayDimInfoAsString(ArrayDimensionInfo const& _x, unsigned _numDimensions); static void arrayDimensionsAsStringVector( ArrayType const& _x, std::vector& @@ -371,25 +373,40 @@ private: /// Dynamically sized arrays can have a length of at least zero /// and at most s_maxArrayLength. - static unsigned getDynArrayLengthFromFuzz(unsigned _fuzz, unsigned _counter) + static unsigned getDynArrayLengthFromFuzz( + unsigned _fuzz, + unsigned _counter, + unsigned _numDimensions + ) { - // Increment modulo value by one in order to meet upper bound - return (_fuzz + _counter) % (s_maxArrayLength + 1); + // Zero length dimension is more likely when the total + // number of dimensions is high. + return ( + _fuzz % _numDimensions != 0 ? + 0 : + // Increment modulo value by one in order to meet upper bound + (_fuzz + _counter) % (s_maxArrayLength + 1) + ); } /// Statically sized arrays must have a length of at least one /// and at most s_maxArrayLength. - static unsigned getStaticArrayLengthFromFuzz(unsigned _fuzz) + static unsigned getStaticArrayLengthFromFuzz(unsigned _fuzz, unsigned _numDimensions) { - return _fuzz % s_maxArrayLength + 1; + // Unit length dimension is more likely when the total + // number of dimensions is high. + return (_fuzz % _numDimensions != 0 ? 1 : _fuzz % s_maxArrayLength + 1); } - static std::pair arrayDimInfoAsPair(ArrayDimensionInfo const& _x) + static std::pair arrayDimInfoAsPair( + ArrayDimensionInfo const& _x, + unsigned _numDimensions + ) { return ( _x.is_static() ? - std::make_pair(true, getStaticArrayLengthFromFuzz(_x.length())) : - std::make_pair(false, getDynArrayLengthFromFuzz(_x.length(), 0)) + std::make_pair(true, getStaticArrayLengthFromFuzz(_x.length(), _numDimensions)) : + std::make_pair(false, getDynArrayLengthFromFuzz(_x.length(), 0, _numDimensions)) ); } @@ -413,10 +430,12 @@ private: _counter, _isHexLiteral ); + } - static bool addCheck(unsigned _counter) + /// Checks are less likely for higher dimensional arrays + static bool addCheck(unsigned _counter, unsigned _numDimensions) { - return _counter % s_arrayCheckFrequency == 0; + return _counter % _numDimensions == 0; } /// Contains the test program @@ -438,9 +457,6 @@ private: static unsigned constexpr s_maxArrayLength = 4; static unsigned constexpr s_maxArrayDimensions = 4; static unsigned constexpr s_maxDynArrayLength = 256; - /// Add check only if counter returned by getNextCounter() - /// is divisible by s_arrayCheckFrequency - static unsigned constexpr s_arrayCheckFrequency = 11; /// Prefixes for declared and parameterized variable names static auto constexpr s_varNamePrefix = "x_"; static auto constexpr s_paramNamePrefix = "c_";