summaryrefslogtreecommitdiff
path: root/oss-fuzz/fuzzing/datasource/datasource.hpp
blob: e0699d3e6d7d7e0e9d89688f17d584fbdb5a47c6 (plain)
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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
#pragma once

#include <fuzzing/exception.hpp>
#include <fuzzing/types.hpp>
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <string>
#include <vector>

namespace fuzzing {
namespace datasource  {

class Base
{
    protected:
        virtual std::vector<uint8_t> get(const size_t min, const size_t max, const uint64_t id = 0) = 0;
    public:
        Base(void) = default;
        virtual ~Base(void) = default;

        template<class T> T Get(const uint64_t id = 0);
        uint16_t GetChoice(const uint64_t id = 0);
        std::vector<uint8_t> GetData(const uint64_t id, const size_t min = 0, const size_t max = 0);
        template <class T> std::vector<T> GetVector(const uint64_t id = 0);

        class OutOfData : public fuzzing::exception::FlowException {
            public:
                OutOfData() = default;
        };

        class DeserializationFailure : public fuzzing::exception::FlowException {
            public:
                DeserializationFailure() = default;
        };
};

#ifndef FUZZING_HEADERS_NO_IMPL
template<class T> T Base::Get(const uint64_t id)
{
    T ret;
    const auto v = get(sizeof(ret), sizeof(ret), id);
    memcpy(&ret, v.data(), sizeof(ret));
    return ret;
}

template <> bool Base::Get<bool>(const uint64_t id)
{
    uint8_t ret;
    const auto v = get(sizeof(ret), sizeof(ret), id);
    memcpy(&ret, v.data(), sizeof(ret));
    return (ret % 2) ? true : false;
}

template <> std::string Base::Get<std::string>(const uint64_t id)
{
    auto data = GetData(id);
    return std::string(data.data(), data.data() + data.size());
}

template <> std::vector<std::string> Base::Get<std::vector<std::string>>(const uint64_t id)
{
    std::vector<std::string> ret;
    while ( true ) {
        auto data = GetData(id);
        ret.push_back( std::string(data.data(), data.data() + data.size()) );
        if ( Get<bool>(id) == false ) {
            break;
        }
    }
    return ret;
}

uint16_t Base::GetChoice(const uint64_t id)
{
    return Get<uint16_t>(id);
}

std::vector<uint8_t> Base::GetData(const uint64_t id, const size_t min, const size_t max)
{
    return get(min, max, id);
}


template <> types::String<> Base::Get<types::String<>>(const uint64_t id) {
    const auto data = GetData(id);
    types::String<> ret(data.data(), data.size());
    return ret;
}

template <> types::Data<> Base::Get<types::Data<>>(const uint64_t id) {
    const auto data = GetData(id);
    types::Data<> ret(data.data(), data.size());
    return ret;
}

template <class T>
std::vector<T> Base::GetVector(const uint64_t id) {
    std::vector<T> ret;

    while ( Get<bool>(id) == true ) {
        ret.push_back( Get<T>(id) );
    }

    return ret;
}
#endif

class Datasource : public Base
{
    private:
        const uint8_t* data;
        const size_t size;
        size_t idx;
        size_t left;
        std::vector<uint8_t> get(const size_t min, const size_t max, const uint64_t id = 0) override;

		// Make copy constructor and assignment opertator private.
        Datasource(const Datasource &) : data(0), size(0), idx(0), left(0) {}
        Datasource& operator=(const Datasource &) { return *this; }
    public:
        Datasource(const uint8_t* _data, const size_t _size);
};

#ifndef FUZZING_HEADERS_NO_IMPL
Datasource::Datasource(const uint8_t* _data, const size_t _size) :
    Base(), data(_data), size(_size), idx(0), left(size)
{
}

std::vector<uint8_t> Datasource::get(const size_t min, const size_t max, const uint64_t id) {
    (void)id;

    uint32_t getSize;
    if ( left < sizeof(getSize) ) {
        throw OutOfData();
    }
    memcpy(&getSize, data + idx, sizeof(getSize));
    idx += sizeof(getSize);
    left -= sizeof(getSize);

    if ( getSize < min ) {
        getSize = min;
    }
    if ( max && getSize > max ) {
        getSize = max;
    }

    if ( left < getSize ) {
        throw OutOfData();
    }

    std::vector<uint8_t> ret(getSize);

    if ( getSize > 0 ) {
        memcpy(ret.data(), data + idx, getSize);
    }
    idx += getSize;
    left -= getSize;

    return ret;
}
#endif

} /* namespace datasource */
} /* namespace fuzzing */