fuzzHelper.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  1. /*
  2. This file is part of cpp-ethereum.
  3. cpp-ethereum is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation, either version 3 of the License, or
  6. (at your option) any later version.
  7. cpp-ethereum is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
  13. */
  14. /** @file fuzzHelper.cpp
  15. * @author Dimitry Khokhlov <winsvega@mail.ru>
  16. * @date 2015
  17. */
  18. #include "fuzzHelper.h"
  19. #include <chrono>
  20. #include <boost/random.hpp>
  21. #include <boost/filesystem/path.hpp>
  22. #include <libevmcore/Instruction.h>
  23. namespace dev
  24. {
  25. namespace test
  26. {
  27. boost::random::mt19937 RandomCode::gen;
  28. boostIntDistrib RandomCode::opCodeDist = boostIntDistrib (0, 255);
  29. boostIntDistrib RandomCode::opLengDist = boostIntDistrib (1, 32);
  30. boostIntDistrib RandomCode::uniIntDist = boostIntDistrib (0, 0x7fffffff);
  31. boostUint64Distrib RandomCode::uInt64Dist = boostUint64Distrib (0, std::numeric_limits<uint64_t>::max());
  32. boostIntGenerator RandomCode::randOpCodeGen = boostIntGenerator(gen, opCodeDist);
  33. boostIntGenerator RandomCode::randOpLengGen = boostIntGenerator(gen, opLengDist);
  34. boostIntGenerator RandomCode::randUniIntGen = boostIntGenerator(gen, uniIntDist);
  35. boostUInt64Generator RandomCode::randUInt64Gen = boostUInt64Generator(gen, uInt64Dist);
  36. int RandomCode::recursiveRLP(std::string& _result, int _depth, std::string& _debug)
  37. {
  38. bool genValidRlp = true;
  39. int bugProbability = randUniIntGen() % 100;
  40. if (bugProbability < 80)
  41. genValidRlp = false;
  42. if (_depth > 1)
  43. {
  44. //create rlp blocks
  45. int size = 1 + randUniIntGen() % 4;
  46. for (auto i = 0; i < size; i++)
  47. {
  48. std::string blockstr;
  49. std::string blockDebug;
  50. recursiveRLP(blockstr, _depth - 1, blockDebug);
  51. _result += blockstr;
  52. _debug += blockDebug;
  53. }
  54. //make rlp header
  55. int length = _result.size() / 2;
  56. std::string header;
  57. int rtype = 0;
  58. int rnd = randUniIntGen() % 100;
  59. if (rnd < 10)
  60. {
  61. //make header as array
  62. if (length <= 55)
  63. {
  64. header = toCompactHex(128 + length);
  65. rtype = 1;
  66. }
  67. else
  68. {
  69. std::string hexlength = toCompactHex(length);
  70. header = toCompactHex(183 + hexlength.size() / 2) + hexlength;
  71. rtype = 2;
  72. }
  73. }
  74. else
  75. {
  76. //make header as list
  77. if (length <= 55)
  78. {
  79. header = toCompactHex(192 + length);
  80. rtype = 3;
  81. }
  82. else
  83. {
  84. std::string hexlength = toCompactHex(length, HexPrefix::DontAdd, 1);
  85. header = toCompactHex(247 + hexlength.size() / 2) + hexlength;
  86. rtype = 4;
  87. }
  88. }
  89. _result = header + _result;
  90. _debug = "[" + header + "(" + toString(length) + "){" + toString(rtype) + "}]" + _debug;
  91. return _result.size() / 2;
  92. }
  93. if (_depth == 1)
  94. {
  95. bool genbug = false;
  96. bool genbug2 = false;
  97. int bugProbability = randUniIntGen() % 100;
  98. if (bugProbability < 50 && !genValidRlp)
  99. genbug = true;
  100. bugProbability = randUniIntGen() % 100; //more randomness
  101. if (bugProbability < 50 && !genValidRlp)
  102. genbug2 = true;
  103. std::string emptyZeros = genValidRlp ? "" : genbug ? "00" : "";
  104. std::string emptyZeros2 = genValidRlp ? "" : genbug2 ? "00" : "";
  105. int rnd = randUniIntGen() % 5;
  106. switch (rnd)
  107. {
  108. case 0:
  109. {
  110. //single byte [0x00, 0x7f]
  111. std::string rlp = emptyZeros + toCompactHex(genbug ? randUniIntGen() % 255 : randUniIntGen() % 128, HexPrefix::DontAdd, 1);
  112. _result.insert(0, rlp);
  113. _debug.insert(0, "[" + rlp + "]");
  114. return 1;
  115. }
  116. case 1:
  117. {
  118. //string 0-55 [0x80, 0xb7] + string
  119. int len = genbug ? randUniIntGen() % 255 : randUniIntGen() % 55;
  120. std::string hex = rndByteSequence(len);
  121. if (len == 1)
  122. if (genValidRlp && fromHex(hex)[0] < 128)
  123. hex = toCompactHex((u64)128);
  124. _result.insert(0, toCompactHex(128 + len) + emptyZeros + hex);
  125. _debug.insert(0, "[" + toCompactHex(128 + len) + "(" + toString(len) + ")]" + emptyZeros + hex);
  126. return len + 1;
  127. }
  128. case 2:
  129. {
  130. //string more 55 [0xb8, 0xbf] + length + string
  131. int len = randUniIntGen() % 100;
  132. if (len < 56 && genValidRlp)
  133. len = 56;
  134. std::string hex = rndByteSequence(len);
  135. std::string hexlen = emptyZeros2 + toCompactHex(len, HexPrefix::DontAdd, 1);
  136. std::string rlpblock = toCompactHex(183 + hexlen.size() / 2) + hexlen + emptyZeros + hex;
  137. _debug.insert(0, "[" + toCompactHex(183 + hexlen.size() / 2) + hexlen + "(" + toString(len) + "){2}]" + emptyZeros + hex);
  138. _result.insert(0, rlpblock);
  139. return rlpblock.size() / 2;
  140. }
  141. case 3:
  142. {
  143. //list 0-55 [0xc0, 0xf7] + data
  144. int len = genbug ? randUniIntGen() % 255 : randUniIntGen() % 55;
  145. std::string hex = emptyZeros + rndByteSequence(len);
  146. _result.insert(0, toCompactHex(192 + len) + hex);
  147. _debug.insert(0, "[" + toCompactHex(192 + len) + "(" + toString(len) + "){3}]" + hex);
  148. return len + 1;
  149. }
  150. case 4:
  151. {
  152. //list more 55 [0xf8, 0xff] + length + data
  153. int len = randUniIntGen() % 100;
  154. if (len < 56 && genValidRlp)
  155. len = 56;
  156. std::string hexlen = emptyZeros2 + toCompactHex(len, HexPrefix::DontAdd, 1);
  157. std::string rlpblock = toCompactHex(247 + hexlen.size() / 2) + hexlen + emptyZeros + rndByteSequence(len);
  158. _debug.insert(0, "[" + toCompactHex(247 + hexlen.size() / 2) + hexlen + "(" + toString(len) + "){4}]" + emptyZeros + rndByteSequence(len));
  159. _result.insert(0, rlpblock);
  160. return rlpblock.size() / 2;
  161. }
  162. }
  163. }
  164. return 0;
  165. }
  166. std::string RandomCode::rndRLPSequence(int _depth, std::string& _debug)
  167. {
  168. refreshSeed();
  169. std::string hash;
  170. _depth = std::min(std::max(1, _depth), 7); //limit depth to avoid overkill
  171. recursiveRLP(hash, _depth, _debug);
  172. return hash;
  173. }
  174. std::string RandomCode::rndByteSequence(int _length, SizeStrictness _sizeType)
  175. {
  176. refreshSeed();
  177. std::string hash = "";
  178. _length = (_sizeType == SizeStrictness::Strict) ? std::max(0, _length) : (int)randomUniInt() % _length;
  179. for (auto i = 0; i < _length; i++)
  180. {
  181. uint8_t byte = randOpCodeGen();
  182. hash += toCompactHex(byte, HexPrefix::DontAdd, 1);
  183. }
  184. return hash;
  185. }
  186. //generate smart random code
  187. std::string RandomCode::generate(int _maxOpNumber, RandomCodeOptions _options)
  188. {
  189. refreshSeed();
  190. std::string code;
  191. //random opCode amount
  192. boostIntDistrib sizeDist (0, _maxOpNumber);
  193. boostIntGenerator rndSizeGen(gen, sizeDist);
  194. int size = (int)rndSizeGen();
  195. boostWeightGenerator randOpCodeWeight (gen, _options.opCodeProbability);
  196. bool weightsDefined = _options.opCodeProbability.probabilities().size() == 255;
  197. for (auto i = 0; i < size; i++)
  198. {
  199. uint8_t opcode = weightsDefined ? randOpCodeWeight() : randOpCodeGen();
  200. dev::eth::InstructionInfo info = dev::eth::instructionInfo((dev::eth::Instruction) opcode);
  201. if (info.name.find("INVALID_INSTRUCTION") != std::string::npos)
  202. {
  203. //Byte code is yet not implemented
  204. if (_options.useUndefinedOpCodes == false)
  205. {
  206. i--;
  207. continue;
  208. }
  209. }
  210. else
  211. {
  212. if (info.name.find("PUSH") != std::string::npos)
  213. code += toCompactHex(opcode);
  214. code += fillArguments((dev::eth::Instruction) opcode, _options);
  215. }
  216. if (info.name.find("PUSH") == std::string::npos)
  217. {
  218. std::string byte = toCompactHex(opcode);
  219. code += (byte == "") ? "00" : byte;
  220. }
  221. }
  222. return code;
  223. }
  224. std::string RandomCode::randomUniIntHex(u256 _maxVal)
  225. {
  226. if (_maxVal == 0)
  227. _maxVal = std::numeric_limits<uint64_t>::max();
  228. refreshSeed();
  229. int rand = randUniIntGen() % 100;
  230. if (rand < 50)
  231. return "0x" + toCompactHex((u256)randUniIntGen() % _maxVal);
  232. return "0x" + toCompactHex((u256)randUInt64Gen() % _maxVal);
  233. }
  234. u256 RandomCode::randomUniInt(u256 _maxVal)
  235. {
  236. if (_maxVal == 0)
  237. _maxVal = std::numeric_limits<uint64_t>::max();
  238. refreshSeed();
  239. return (u256)randUInt64Gen() % _maxVal;
  240. }
  241. void RandomCode::refreshSeed()
  242. {
  243. auto now = std::chrono::steady_clock::now().time_since_epoch();
  244. auto timeSinceEpoch = std::chrono::duration_cast<std::chrono::nanoseconds>(now).count();
  245. gen.seed(static_cast<unsigned int>(timeSinceEpoch));
  246. }
  247. std::string RandomCode::getPushCode(std::string const& _hex)
  248. {
  249. int length = _hex.length() / 2;
  250. int pushCode = 96 + length - 1;
  251. return toCompactHex(pushCode) + _hex;
  252. }
  253. std::string RandomCode::getPushCode(int _value)
  254. {
  255. std::string hexString = toCompactHex(_value);
  256. return getPushCode(hexString);
  257. }
  258. std::string RandomCode::fillArguments(dev::eth::Instruction _opcode, RandomCodeOptions const& _options)
  259. {
  260. dev::eth::InstructionInfo info = dev::eth::instructionInfo(_opcode);
  261. std::string code;
  262. bool smart = false;
  263. unsigned num = info.args;
  264. int rand = randUniIntGen() % 100;
  265. if (rand < _options.smartCodeProbability)
  266. smart = true;
  267. if (smart)
  268. {
  269. //PUSH1 ... PUSH32
  270. if (dev::eth::Instruction::PUSH1 <= _opcode && _opcode <= dev::eth::Instruction::PUSH32)
  271. {
  272. code += rndByteSequence(int(_opcode) - int(dev::eth::Instruction::PUSH1) + 1);
  273. return code;
  274. }
  275. //SWAP1 ... SWAP16 || DUP1 ... DUP16
  276. bool isSWAP = (dev::eth::Instruction::SWAP1 <= _opcode && _opcode <= dev::eth::Instruction::SWAP16);
  277. bool isDUP = (dev::eth::Instruction::DUP1 <= _opcode && _opcode <= dev::eth::Instruction::DUP16);
  278. if (isSWAP || isDUP)
  279. {
  280. int times = 0;
  281. if (isSWAP)
  282. times = int(_opcode) - int(dev::eth::Instruction::SWAP1) + 2;
  283. else
  284. if (isDUP)
  285. times = int(_opcode) - int(dev::eth::Instruction::DUP1) + 1;
  286. for (int i = 0; i < times; i ++)
  287. code += getPushCode(randUniIntGen() % 32);
  288. return code;
  289. }
  290. switch (_opcode)
  291. {
  292. case dev::eth::Instruction::CREATE:
  293. //(CREATE value mem1 mem2)
  294. code += getPushCode(randUniIntGen() % 128); //memlen1
  295. code += getPushCode(randUniIntGen() % 32); //memlen1
  296. code += getPushCode(randUniIntGen()); //value
  297. break;
  298. case dev::eth::Instruction::CALL:
  299. case dev::eth::Instruction::CALLCODE:
  300. //(CALL gaslimit address value memstart1 memlen1 memstart2 memlen2)
  301. //(CALLCODE gaslimit address value memstart1 memlen1 memstart2 memlen2)
  302. code += getPushCode(randUniIntGen() % 128); //memlen2
  303. code += getPushCode(randUniIntGen() % 32); //memstart2
  304. code += getPushCode(randUniIntGen() % 128); //memlen1
  305. code += getPushCode(randUniIntGen() % 32); //memlen1
  306. code += getPushCode(randUniIntGen()); //value
  307. code += getPushCode(toString(_options.getRandomAddress()));//address
  308. code += getPushCode(randUniIntGen()); //gaslimit
  309. break;
  310. case dev::eth::Instruction::SUICIDE: //(SUICIDE address)
  311. code += getPushCode(toString(_options.getRandomAddress()));
  312. break;
  313. case dev::eth::Instruction::RETURN: //(RETURN memlen1 memlen2)
  314. code += getPushCode(randUniIntGen() % 128); //memlen1
  315. code += getPushCode(randUniIntGen() % 32); //memlen1
  316. break;
  317. default:
  318. smart = false;
  319. }
  320. }
  321. if (smart == false)
  322. for (unsigned i = 0; i < num; i++)
  323. {
  324. //generate random parameters
  325. int length = randOpLengGen();
  326. code += getPushCode(rndByteSequence(length));
  327. }
  328. return code;
  329. }
  330. //Ramdom Code Options
  331. RandomCodeOptions::RandomCodeOptions() : useUndefinedOpCodes(false), smartCodeProbability(50)
  332. {
  333. //each op code with same weight-probability
  334. for (auto i = 0; i < 255; i++)
  335. mapWeights.insert(std::pair<int, int>(i, 50));
  336. setWeights();
  337. }
  338. void RandomCodeOptions::setWeight(dev::eth::Instruction _opCode, int _weight)
  339. {
  340. mapWeights.at((int)_opCode) = _weight;
  341. setWeights();
  342. }
  343. void RandomCodeOptions::addAddress(dev::Address const& _address)
  344. {
  345. addressList.push_back(_address);
  346. }
  347. dev::Address RandomCodeOptions::getRandomAddress() const
  348. {
  349. if (addressList.size() > 0)
  350. {
  351. int index = (int)RandomCode::randomUniInt() % addressList.size();
  352. return addressList[index];
  353. }
  354. return Address(RandomCode::rndByteSequence(20));
  355. }
  356. void RandomCodeOptions::setWeights()
  357. {
  358. std::vector<int> weights;
  359. for (auto const& element: mapWeights)
  360. weights.push_back(element.second);
  361. opCodeProbability = boostDescreteDistrib(weights);
  362. }
  363. BOOST_FIXTURE_TEST_SUITE(RandomCodeTests, TestOutputHelper)
  364. BOOST_AUTO_TEST_CASE(rndCode)
  365. {
  366. std::string code;
  367. cnote << "Testing Random Code: ";
  368. try
  369. {
  370. code = dev::test::RandomCode::generate(10);
  371. }
  372. catch(...)
  373. {
  374. BOOST_ERROR("Exception thrown when generating random code!");
  375. }
  376. cnote << code;
  377. }
  378. BOOST_AUTO_TEST_SUITE_END()
  379. }
  380. }