aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/scheme/tests/fuzz_json/lib/fuzz_json.cpp
blob: f34571d9677a5f59a327ad670984510ebf5a3f0c (plain) (blame)
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();
    }
}