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