Skip to content

Commit 405713d

Browse files
author
MarcoFalke
committed
Merge #18529: Add fuzzer version of randomized prevector test
b1d24d1 Reorder the test instructions by number (Pieter Wuille) c2ccadc Merge and generalize case 3 and case 6 (Pieter Wuille) 402ad5a Only run sanity check once at the end (Pieter Wuille) eda8309 Assert immediately rather than caching failure (Pieter Wuille) 5560845 Make a fuzzer-based copy of the prevector randomized test (Pieter Wuille) Pull request description: The current prevector test effectively randomly generates a number of operations to perform on a prevector and a normal vector, and checks consistency between the two. By converting this into a fuzzer the operations can be targetted rather than random. ACKs for top commit: MarcoFalke: ACK b1d24d1 🍬 Tree-SHA512: 2b5c62abcd5fee94f42db03400531484d98c59e7f4308e0e683c61aabcd9ce42f85c5d058d2d5e7f8221124f71d2112b6a5f3c80e5d0fdae265a70647747e92f
2 parents 081dcbd + b1d24d1 commit 405713d

File tree

2 files changed

+270
-0
lines changed

2 files changed

+270
-0
lines changed

src/Makefile.test.include

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ FUZZ_TARGETS = \
6363
test/fuzz/parse_numbers \
6464
test/fuzz/parse_script \
6565
test/fuzz/parse_univalue \
66+
test/fuzz/prevector \
6667
test/fuzz/partial_merkle_tree_deserialize \
6768
test/fuzz/partially_signed_transaction_deserialize \
6869
test/fuzz/pow \
@@ -646,6 +647,12 @@ test_fuzz_parse_univalue_LDADD = $(FUZZ_SUITE_LD_COMMON)
646647
test_fuzz_parse_univalue_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
647648
test_fuzz_parse_univalue_SOURCES = test/fuzz/parse_univalue.cpp
648649

650+
test_fuzz_prevector_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
651+
test_fuzz_prevector_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
652+
test_fuzz_prevector_LDADD = $(FUZZ_SUITE_LD_COMMON)
653+
test_fuzz_prevector_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
654+
test_fuzz_prevector_SOURCES = test/fuzz/prevector.cpp
655+
649656
test_fuzz_partial_merkle_tree_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DPARTIAL_MERKLE_TREE_DESERIALIZE=1
650657
test_fuzz_partial_merkle_tree_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
651658
test_fuzz_partial_merkle_tree_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)

src/test/fuzz/prevector.cpp

Lines changed: 263 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,263 @@
1+
// Copyright (c) 2015-2020 The Bitcoin Core developers
2+
// Distributed under the MIT software license, see the accompanying
3+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4+
5+
#include <test/fuzz/fuzz.h>
6+
#include <test/fuzz/FuzzedDataProvider.h>
7+
8+
#include <vector>
9+
#include <prevector.h>
10+
11+
#include <reverse_iterator.h>
12+
#include <serialize.h>
13+
#include <streams.h>
14+
15+
namespace {
16+
17+
template<unsigned int N, typename T>
18+
class prevector_tester {
19+
typedef std::vector<T> realtype;
20+
realtype real_vector;
21+
realtype real_vector_alt;
22+
23+
typedef prevector<N, T> pretype;
24+
pretype pre_vector;
25+
pretype pre_vector_alt;
26+
27+
typedef typename pretype::size_type Size;
28+
29+
public:
30+
void test() const {
31+
const pretype& const_pre_vector = pre_vector;
32+
assert(real_vector.size() == pre_vector.size());
33+
assert(real_vector.empty() == pre_vector.empty());
34+
for (Size s = 0; s < real_vector.size(); s++) {
35+
assert(real_vector[s] == pre_vector[s]);
36+
assert(&(pre_vector[s]) == &(pre_vector.begin()[s]));
37+
assert(&(pre_vector[s]) == &*(pre_vector.begin() + s));
38+
assert(&(pre_vector[s]) == &*((pre_vector.end() + s) - real_vector.size()));
39+
}
40+
// assert(realtype(pre_vector) == real_vector);
41+
assert(pretype(real_vector.begin(), real_vector.end()) == pre_vector);
42+
assert(pretype(pre_vector.begin(), pre_vector.end()) == pre_vector);
43+
size_t pos = 0;
44+
for (const T& v : pre_vector) {
45+
assert(v == real_vector[pos]);
46+
++pos;
47+
}
48+
for (const T& v : reverse_iterate(pre_vector)) {
49+
--pos;
50+
assert(v == real_vector[pos]);
51+
}
52+
for (const T& v : const_pre_vector) {
53+
assert(v == real_vector[pos]);
54+
++pos;
55+
}
56+
for (const T& v : reverse_iterate(const_pre_vector)) {
57+
--pos;
58+
assert(v == real_vector[pos]);
59+
}
60+
CDataStream ss1(SER_DISK, 0);
61+
CDataStream ss2(SER_DISK, 0);
62+
ss1 << real_vector;
63+
ss2 << pre_vector;
64+
assert(ss1.size() == ss2.size());
65+
for (Size s = 0; s < ss1.size(); s++) {
66+
assert(ss1[s] == ss2[s]);
67+
}
68+
}
69+
70+
void resize(Size s) {
71+
real_vector.resize(s);
72+
assert(real_vector.size() == s);
73+
pre_vector.resize(s);
74+
assert(pre_vector.size() == s);
75+
}
76+
77+
void reserve(Size s) {
78+
real_vector.reserve(s);
79+
assert(real_vector.capacity() >= s);
80+
pre_vector.reserve(s);
81+
assert(pre_vector.capacity() >= s);
82+
}
83+
84+
void insert(Size position, const T& value) {
85+
real_vector.insert(real_vector.begin() + position, value);
86+
pre_vector.insert(pre_vector.begin() + position, value);
87+
}
88+
89+
void insert(Size position, Size count, const T& value) {
90+
real_vector.insert(real_vector.begin() + position, count, value);
91+
pre_vector.insert(pre_vector.begin() + position, count, value);
92+
}
93+
94+
template<typename I>
95+
void insert_range(Size position, I first, I last) {
96+
real_vector.insert(real_vector.begin() + position, first, last);
97+
pre_vector.insert(pre_vector.begin() + position, first, last);
98+
}
99+
100+
void erase(Size position) {
101+
real_vector.erase(real_vector.begin() + position);
102+
pre_vector.erase(pre_vector.begin() + position);
103+
}
104+
105+
void erase(Size first, Size last) {
106+
real_vector.erase(real_vector.begin() + first, real_vector.begin() + last);
107+
pre_vector.erase(pre_vector.begin() + first, pre_vector.begin() + last);
108+
}
109+
110+
void update(Size pos, const T& value) {
111+
real_vector[pos] = value;
112+
pre_vector[pos] = value;
113+
}
114+
115+
void push_back(const T& value) {
116+
real_vector.push_back(value);
117+
pre_vector.push_back(value);
118+
}
119+
120+
void pop_back() {
121+
real_vector.pop_back();
122+
pre_vector.pop_back();
123+
}
124+
125+
void clear() {
126+
real_vector.clear();
127+
pre_vector.clear();
128+
}
129+
130+
void assign(Size n, const T& value) {
131+
real_vector.assign(n, value);
132+
pre_vector.assign(n, value);
133+
}
134+
135+
Size size() const {
136+
return real_vector.size();
137+
}
138+
139+
Size capacity() const {
140+
return pre_vector.capacity();
141+
}
142+
143+
void shrink_to_fit() {
144+
pre_vector.shrink_to_fit();
145+
}
146+
147+
void swap() {
148+
real_vector.swap(real_vector_alt);
149+
pre_vector.swap(pre_vector_alt);
150+
}
151+
152+
void move() {
153+
real_vector = std::move(real_vector_alt);
154+
real_vector_alt.clear();
155+
pre_vector = std::move(pre_vector_alt);
156+
pre_vector_alt.clear();
157+
}
158+
159+
void copy() {
160+
real_vector = real_vector_alt;
161+
pre_vector = pre_vector_alt;
162+
}
163+
164+
void resize_uninitialized(realtype values) {
165+
size_t r = values.size();
166+
size_t s = real_vector.size() / 2;
167+
if (real_vector.capacity() < s + r) {
168+
real_vector.reserve(s + r);
169+
}
170+
real_vector.resize(s);
171+
pre_vector.resize_uninitialized(s);
172+
for (auto v : values) {
173+
real_vector.push_back(v);
174+
}
175+
auto p = pre_vector.size();
176+
pre_vector.resize_uninitialized(p + r);
177+
for (auto v : values) {
178+
pre_vector[p] = v;
179+
++p;
180+
}
181+
}
182+
};
183+
184+
}
185+
186+
void test_one_input(const std::vector<uint8_t>& buffer)
187+
{
188+
FuzzedDataProvider prov(buffer.data(), buffer.size());
189+
prevector_tester<8, int> test;
190+
191+
while (prov.remaining_bytes()) {
192+
switch (prov.ConsumeIntegralInRange<int>(0, 13 + 3 * (test.size() > 0))) {
193+
case 0:
194+
test.insert(prov.ConsumeIntegralInRange<size_t>(0, test.size()), prov.ConsumeIntegral<int>());
195+
break;
196+
case 1:
197+
test.resize(std::max(0, std::min(30, (int)test.size() + prov.ConsumeIntegralInRange<int>(0, 4) - 2)));
198+
break;
199+
case 2:
200+
test.insert(prov.ConsumeIntegralInRange<size_t>(0, test.size()), 1 + prov.ConsumeBool(), prov.ConsumeIntegral<int>());
201+
break;
202+
case 3: {
203+
int del = prov.ConsumeIntegralInRange<int>(0, test.size());
204+
int beg = prov.ConsumeIntegralInRange<int>(0, test.size() - del);
205+
test.erase(beg, beg + del);
206+
break;
207+
}
208+
case 4:
209+
test.push_back(prov.ConsumeIntegral<int>());
210+
break;
211+
case 5: {
212+
int values[4];
213+
int num = 1 + prov.ConsumeIntegralInRange<int>(0, 3);
214+
for (int k = 0; k < num; ++k) {
215+
values[k] = prov.ConsumeIntegral<int>();
216+
}
217+
test.insert_range(prov.ConsumeIntegralInRange<size_t>(0, test.size()), values, values + num);
218+
break;
219+
}
220+
case 6: {
221+
int num = 1 + prov.ConsumeIntegralInRange<int>(0, 15);
222+
std::vector<int> values(num);
223+
for (auto& v : values) {
224+
v = prov.ConsumeIntegral<int>();
225+
}
226+
test.resize_uninitialized(values);
227+
break;
228+
}
229+
case 7:
230+
test.reserve(prov.ConsumeIntegralInRange<size_t>(0, 32767));
231+
break;
232+
case 8:
233+
test.shrink_to_fit();
234+
break;
235+
case 9:
236+
test.clear();
237+
break;
238+
case 10:
239+
test.assign(prov.ConsumeIntegralInRange<size_t>(0, 32767), prov.ConsumeIntegral<int>());
240+
break;
241+
case 11:
242+
test.swap();
243+
break;
244+
case 12:
245+
test.copy();
246+
break;
247+
case 13:
248+
test.move();
249+
break;
250+
case 14:
251+
test.update(prov.ConsumeIntegralInRange<size_t>(0, test.size() - 1), prov.ConsumeIntegral<int>());
252+
break;
253+
case 15:
254+
test.erase(prov.ConsumeIntegralInRange<size_t>(0, test.size() - 1));
255+
break;
256+
case 16:
257+
test.pop_back();
258+
break;
259+
}
260+
}
261+
262+
test.test();
263+
}

0 commit comments

Comments
 (0)