fuzz_json.cpp 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. #include "fuzz_json.h"
  2. #include "util/generic/fwd.h"
  3. #include <library/cpp/scheme/scheme.h>
  4. #include <util/stream/null.h>
  5. namespace {
  6. static constexpr size_t MAX_DEPTH = 4;
  7. static constexpr size_t MAX_PATH_LEN = 256;
  8. static constexpr size_t MAX_ITERATIONS = 4;
  9. void SplitOnDepth(const TStringBuf src, const size_t depth, const size_t maxPathLen,
  10. TStringBuf& left, TStringBuf& right)
  11. {
  12. size_t pos = 0;
  13. size_t prevPos = 0;
  14. for(size_t i = 0; i < depth; ++i) {
  15. if (pos > maxPathLen) {
  16. break;
  17. }
  18. prevPos = pos;
  19. pos = src.find_first_of(TStringBuf("/]"), pos + 1);
  20. if (pos == TStringBuf::npos) {
  21. break;
  22. }
  23. }
  24. if (pos == TStringBuf::npos && prevPos > 0) {
  25. pos = prevPos;
  26. }
  27. if (src.length() > maxPathLen) {
  28. if (pos == TStringBuf::npos || pos > maxPathLen) {
  29. pos = maxPathLen;
  30. }
  31. }
  32. if (pos == TStringBuf::npos || pos == 0) {
  33. left = src;
  34. right = TStringBuf();
  35. } else {
  36. src.SplitAt(pos + 1, left, right);
  37. }
  38. }
  39. TString tmp;
  40. //Limit max array size in the path to 256
  41. TStringBuf ProcessPath(TStringBuf path) {
  42. size_t pos = 0;
  43. while(pos != TStringBuf::npos) {
  44. pos = path.find(']', pos + 1);
  45. if (pos == TStringBuf::npos) {
  46. continue;
  47. }
  48. size_t open = path.rfind('[', pos);
  49. if (open == TStringBuf::npos) {
  50. continue;
  51. }
  52. bool allDigit = true;
  53. for(size_t i = open + 1; i < pos; ++i) {
  54. if (path[i] < '0' || path[i] > '9') {
  55. allDigit = false;
  56. break;
  57. }
  58. }
  59. if (!allDigit) {
  60. continue;
  61. }
  62. if (pos - open > 4) {
  63. TString str = TString::Join(path.Head(open + 1), "256", path.Tail(pos));
  64. tmp = std::move(str);
  65. path = tmp;
  66. pos = (open + 1) + 3;
  67. continue;
  68. }
  69. }
  70. return path;
  71. }
  72. }
  73. namespace NSc::NUt {
  74. void FuzzJson(TStringBuf wire) {
  75. if (wire.size() < 2) {
  76. return;
  77. }
  78. ProcessPath("[123][1234][12][2134][12312312][1][12]");
  79. ui8 len1 = wire[0];
  80. ui8 len2 = wire[1];
  81. wire.Skip(2);
  82. auto json1 = wire.NextTokAt(len1);
  83. auto json2 = wire.NextTokAt(len2);
  84. NSc::TValue val1 = NSc::TValue::FromJson(json1);
  85. NSc::TValue val2 = NSc::TValue::FromJson(json2);
  86. NSc::TValue val3;
  87. val3.MergeUpdate(val1);
  88. size_t i = 0;
  89. while (!wire.empty()) {
  90. TStringBuf path;
  91. SplitOnDepth(wire, MAX_DEPTH, MAX_PATH_LEN, path, wire);
  92. path = ProcessPath(path);
  93. if (auto* target = val3.TrySelectOrAdd(path)) {
  94. target->MergeUpdate(val2);
  95. }
  96. ++i;
  97. // Release memory since there are up to MAX_DICT_SIZE * MAX_DEPTH elements
  98. if (i > MAX_ITERATIONS) {
  99. Cnull << val3.ToJson();
  100. val3 = NSc::TValue();
  101. }
  102. }
  103. Cnull << val3.ToJson();
  104. }
  105. }