Browse Source

Merge pull request #2436 from winsvega/fuzz

Fuzz: random RLP generation
cl-refactor
Gav Wood 10 years ago
parent
commit
940b4fcbff
  1. 2
      test/fuzzTesting/CMakeLists.txt
  2. 37
      test/fuzzTesting/createRandomTest.cpp
  3. 150
      test/fuzzTesting/fuzzHelper.cpp
  4. 17
      test/fuzzTesting/fuzzHelper.h
  5. 34
      test/libdevcore/rlp.cpp

2
test/fuzzTesting/CMakeLists.txt

@ -8,7 +8,7 @@ include_directories(${Boost_INCLUDE_DIRS})
include_directories(${CRYPTOPP_INCLUDE_DIRS})
include_directories(${JSON_RPC_CPP_INCLUDE_DIRS})
add_executable(createRandomTest "./createRandomTest.cpp" "../TestHelper.cpp" "../Stats.cpp" "fuzzHelper.cpp" "../libethereum/transaction.cpp" "../libethereum/state.cpp" "../libevm/vm.cpp" "../libethereum/blockchain.cpp")
add_executable(createRandomTest "./createRandomTest.cpp" "../TestHelper.cpp" "../Stats.cpp" "fuzzHelper.cpp" "../libethereum/transaction.cpp" "../libethereum/state.cpp" "../libevm/vm.cpp" "../libethereum/blockchain.cpp" "../libdevcore/rlp.cpp")
add_executable(createRandomVMTest "./createRandomVMTest.cpp" "../libevm/vm.cpp" "../TestHelper.cpp" "../Stats.cpp")
add_executable(createRandomStateTest "./createRandomStateTest.cpp" "../TestHelper.cpp" "../Stats.cpp" "fuzzHelper.cpp")

37
test/fuzzTesting/createRandomTest.cpp

@ -34,6 +34,7 @@ extern std::string const c_testExampleStateTest;
extern std::string const c_testExampleTransactionTest;
extern std::string const c_testExampleVMTest;
extern std::string const c_testExampleBlockchainTest;
extern std::string const c_testExampleRLPTest;
//Main Test functinos
void fillRandomTest(std::function<void(json_spirit::mValue&, bool)> _doTests, std::string const& _testString, bool _debug = false);
@ -62,7 +63,8 @@ int main(int argc, char *argv[])
if (arg == "-t" && i + 1 < argc)
{
testSuite = argv[i + 1];
if (testSuite != "BlockChainTests" && testSuite != "TransactionTests" && testSuite != "StateTests" && testSuite != "VMTests")
if (testSuite != "BlockChainTests" && testSuite != "TransactionTests" && testSuite != "StateTests"
&& testSuite != "VMTests" && testSuite != "RLPTests")
testSuite = "";
}
else
@ -139,6 +141,14 @@ int main(int argc, char *argv[])
else
fillRandomTest(dev::test::doVMTests, (filltest) ? testFillString : c_testExampleVMTest, filldebug);
}
else
if (testSuite == "RLPTests")
{
if (checktest)
return checkRandomTest(dev::test::doRlpTests, testmValue, debug);
else
fillRandomTest(dev::test::doRlpTests, (filltest) ? testFillString : c_testExampleRLPTest, filldebug);
}
}
return 0;
@ -239,12 +249,23 @@ void parseTestWithTypes(std::string& _test)
std::size_t pos = _test.find(types.at(i));
while (pos != std::string::npos)
{
if (types.at(i) == "[RLP]")
{
std::string debug;
int randomDepth = 1 + dev::test::RandomCode::randomUniInt() % 10;
_test.replace(pos, 5, dev::test::RandomCode::rndRLPSequence(randomDepth, debug));
cnote << debug;
}
else
if (types.at(i) == "[CODE]")
_test.replace(pos, 6, "0x"+dev::test::RandomCode::generate(10, options));
else
if (types.at(i) == "[HEX]")
_test.replace(pos, 5, dev::test::RandomCode::randomUniIntHex());
else
if (types.at(i) == "[HEX32]")
_test.replace(pos, 7, dev::test::RandomCode::randomUniIntHex(std::numeric_limits<uint32_t>::max()));
else
if (types.at(i) == "[GASLIMIT]")
_test.replace(pos, 10, dev::test::RandomCode::randomUniIntHex(dev::u256("3000000000")));
else
@ -276,7 +297,7 @@ void parseTestWithTypes(std::string& _test)
std::vector<std::string> getTypes()
{
return {"[CODE]", "[HEX]", "[HASH20]", "[HASH32]", "[0xHASH32]", "[V]", "[GASLIMIT]"};
return {"[RLP]", "[CODE]", "[HEX]", "[HEX32]", "[HASH20]", "[HASH32]", "[0xHASH32]", "[V]", "[GASLIMIT]"};
}
std::string const c_testExampleTransactionTest = R"(
@ -305,7 +326,7 @@ std::string const c_testExampleStateTest = R"(
"currentCoinbase" : "[HASH20]",
"currentDifficulty" : "[HEX]",
"currentGasLimit" : "[GASLIMIT]",
"currentNumber" : "[HEX]",
"currentNumber" : "[HEX32]",
"currentTimestamp" : "[HEX]",
"previousHash" : "[HASH32]"
},
@ -335,7 +356,7 @@ std::string const c_testExampleStateTest = R"(
"transaction" : {
"data" : "[CODE]",
"gasLimit" : "[HEX]",
"gasPrice" : "[V]",
"gasPrice" : "[HEX32]",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
@ -377,6 +398,14 @@ std::string const c_testExampleVMTest = R"(
}
)";
std::string const c_testExampleRLPTest = R"(
{
"randomRLPTest" : {
"out" : "[RLP]"
}
}
)";
std::string const c_testExampleBlockchainTest = R"(
{
"randomBlockTest" : {

150
test/fuzzTesting/fuzzHelper.cpp

@ -42,11 +42,157 @@ boostIntGenerator RandomCode::randOpLengGen = boostIntGenerator(gen, opLengDist)
boostIntGenerator RandomCode::randUniIntGen = boostIntGenerator(gen, uniIntDist);
boostUInt64Generator RandomCode::randUInt64Gen = boostUInt64Generator(gen, uInt64Dist);
std::string RandomCode::rndByteSequence(int _length, SizeStrictness _sizeType)
int RandomCode::recursiveRLP(std::string& _result, int _depth, std::string& _debug)
{
bool genValidRlp = true;
int bugProbability = randUniIntGen() % 100;
if (bugProbability < 80)
genValidRlp = false;
if (_depth > 1)
{
//create rlp blocks
int size = 1 + randUniIntGen() % 4;
for (auto i = 0; i < size; i++)
{
std::string blockstr;
std::string blockDebug;
recursiveRLP(blockstr, _depth - 1, blockDebug);
_result += blockstr;
_debug += blockDebug;
}
//make rlp header
int length = _result.size() / 2;
std::string header;
int rtype = 0;
int rnd = randUniIntGen() % 100;
if (rnd < 10)
{
//make header as array
if (length <= 55)
{
header = toCompactHex(128 + length);
rtype = 1;
}
else
{
std::string hexlength = toCompactHex(length);
header = toCompactHex(183 + hexlength.size() / 2) + hexlength;
rtype = 2;
}
}
else
{
//make header as list
if (length <= 55)
{
header = toCompactHex(192 + length);
rtype = 3;
}
else
{
std::string hexlength = toCompactHex(length, HexPrefix::DontAdd, 1);
header = toCompactHex(247 + hexlength.size() / 2) + hexlength;
rtype = 4;
}
}
_result = header + _result;
_debug = "[" + header + "(" + toString(length) + "){" + toString(rtype) + "}]" + _debug;
return _result.size() / 2;
}
if (_depth == 1)
{
bool genbug = false;
bool genbug2 = false;
int bugProbability = randUniIntGen() % 100;
if (bugProbability < 50 && !genValidRlp)
genbug = true;
bugProbability = randUniIntGen() % 100; //more randomness
if (bugProbability < 50 && !genValidRlp)
genbug2 = true;
std::string emptyZeros = genValidRlp ? "" : genbug ? "00" : "";
std::string emptyZeros2 = genValidRlp ? "" : genbug2 ? "00" : "";
int rnd = randUniIntGen() % 5;
switch (rnd)
{
case 0:
{
//single byte [0x00, 0x7f]
std::string rlp = emptyZeros + toCompactHex(genbug ? randUniIntGen() % 255 : randUniIntGen() % 128, HexPrefix::DontAdd, 1);
_result.insert(0, rlp);
_debug.insert(0, "[" + rlp + "]");
return 1;
}
case 1:
{
//string 0-55 [0x80, 0xb7] + string
int len = genbug ? randUniIntGen() % 255 : randUniIntGen() % 55;
std::string hex = rndByteSequence(len);
if (len == 1)
if (genValidRlp && fromHex(hex)[0] < 128)
hex = toCompactHex((u64)128);
_result.insert(0, toCompactHex(128 + len) + emptyZeros + hex);
_debug.insert(0, "[" + toCompactHex(128 + len) + "(" + toString(len) + ")]" + emptyZeros + hex);
return len + 1;
}
case 2:
{
//string more 55 [0xb8, 0xbf] + length + string
int len = randUniIntGen() % 100;
if (len < 56 && genValidRlp)
len = 56;
std::string hex = rndByteSequence(len);
std::string hexlen = emptyZeros2 + toCompactHex(len, HexPrefix::DontAdd, 1);
std::string rlpblock = toCompactHex(183 + hexlen.size() / 2) + hexlen + emptyZeros + hex;
_debug.insert(0, "[" + toCompactHex(183 + hexlen.size() / 2) + hexlen + "(" + toString(len) + "){2}]" + emptyZeros + hex);
_result.insert(0, rlpblock);
return rlpblock.size() / 2;
}
case 3:
{
//list 0-55 [0xc0, 0xf7] + data
int len = genbug ? randUniIntGen() % 255 : randUniIntGen() % 55;
std::string hex = emptyZeros + rndByteSequence(len);
_result.insert(0, toCompactHex(192 + len) + hex);
_debug.insert(0, "[" + toCompactHex(192 + len) + "(" + toString(len) + "){3}]" + hex);
return len + 1;
}
case 4:
{
//list more 55 [0xf8, 0xff] + length + data
int len = randUniIntGen() % 100;
if (len < 56 && genValidRlp)
len = 56;
std::string hexlen = emptyZeros2 + toCompactHex(len, HexPrefix::DontAdd, 1);
std::string rlpblock = toCompactHex(247 + hexlen.size() / 2) + hexlen + emptyZeros + rndByteSequence(len);
_debug.insert(0, "[" + toCompactHex(247 + hexlen.size() / 2) + hexlen + "(" + toString(len) + "){4}]" + emptyZeros + rndByteSequence(len));
_result.insert(0, rlpblock);
return rlpblock.size() / 2;
}
}
}
return 0;
}
std::string RandomCode::rndRLPSequence(int _depth, std::string& _debug)
{
refreshSeed();
std::string hash;
_length = (_sizeType == SizeStrictness::Strict) ? std::max(1, _length) : randomUniInt() % _length;
_depth = std::min(std::max(1, _depth), 7); //limit depth to avoid overkill
recursiveRLP(hash, _depth, _debug);
return hash;
}
std::string RandomCode::rndByteSequence(int _length, SizeStrictness _sizeType)
{
refreshSeed();
std::string hash = "";
_length = (_sizeType == SizeStrictness::Strict) ? std::max(0, _length) : randomUniInt() % _length;
for (auto i = 0; i < _length; i++)
{
uint8_t byte = randOpCodeGen();

17
test/fuzzTesting/fuzzHelper.h

@ -66,6 +66,12 @@ enum class SizeStrictness
Random
};
struct RlpDebug
{
std::string rlp;
int insertions;
};
class RandomCode
{
public:
@ -75,6 +81,16 @@ public:
/// Generate random byte string of a given length
static std::string rndByteSequence(int _length = 1, SizeStrictness _sizeType = SizeStrictness::Strict);
/// Generate random rlp byte sequence of a given depth (e.g [[[]],[]]). max depth level = 20.
/// The _debug string contains returned rlp string with analysed sections
/// [] - length section/ or single byte rlp encoding
/// () - decimal representation of length
/// {1} - Array
/// {2} - Array more than 55
/// {3} - List
/// {4} - List more than 55
static std::string rndRLPSequence(int _depth, std::string& _debug);
/// Generate random int64
static std::string randomUniIntHex(u256 _maxVal = 0);
static int randomUniInt();
@ -83,6 +99,7 @@ private:
static std::string fillArguments(dev::eth::Instruction _opcode, RandomCodeOptions const& _options);
static std::string getPushCode(int _value);
static std::string getPushCode(std::string const& _hex);
static int recursiveRLP(std::string& _result, int _depth, std::string& _debug);
static void refreshSeed();
static boost::random::mt19937 gen; ///< Random generator

34
test/libdevcore/rlp.cpp

@ -30,8 +30,8 @@
#include <libdevcore/Common.h>
#include <libdevcore/CommonIO.h>
#include <algorithm>
#include "../JsonSpiritHeaders.h"
#include "../TestHelper.h"
#include "test/JsonSpiritHeaders.h"
#include "test/TestHelper.h"
using namespace std;
using namespace dev;
@ -72,8 +72,6 @@ namespace dev
bytes payloadToDecode = fromHex(o["out"].get_str());
RLP payload(payloadToDecode);
ostringstream() << payload;
if (payload.isEmpty())
BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("Decoded Empty RLP!"));
o["in"] = "VALID";
}
catch (Exception const& _e)
@ -129,6 +127,8 @@ namespace dev
{
bytes payloadToDecode = fromHex(o["out"].get_str());
RLP payload(payloadToDecode);
//attempt to read all the contents of RLP
ostringstream() << payload;
if (rlpType == RlpType::Test)
@ -144,6 +144,10 @@ namespace dev
cnote << "rlp exception: " << _e.what();
was_exception = true;
}
catch (...)
{
was_exception = true;
}
//Expect exception as input is INVALID
if (rlpType == RlpType::Invalid && was_exception)
@ -238,6 +242,28 @@ namespace dev
BOOST_AUTO_TEST_SUITE(RlpTests)
BOOST_AUTO_TEST_CASE(EmptyArrayList)
{
try
{
bytes payloadToDecode = fromHex("80");
RLP payload(payloadToDecode);
ostringstream() << payload;
payloadToDecode = fromHex("с0");
RLP payload2(payloadToDecode);
ostringstream() << payload2;
}
catch (Exception const& _e)
{
TBOOST_ERROR("Failed test with Exception: " << _e.what());
}
catch (exception const& _e)
{
TBOOST_ERROR("Failed test with Exception: " << _e.what());
}
}
BOOST_AUTO_TEST_CASE(invalidRLPtest)
{
dev::test::executeTests("invalidRLPTest", "/RLPTests", dev::test::getFolder(__FILE__) + "/RLPTestsFiller", dev::test::doRlpTests);

Loading…
Cancel
Save