xref: /openbsd-src/gnu/llvm/compiler-rt/lib/sanitizer_common/tests/sanitizer_bvgraph_test.cpp (revision 3cab2bb3f667058bece8e38b12449a63a9d73c4b)
1*3cab2bb3Spatrick //===-- sanitizer_bvgraph_test.cpp ----------------------------------------===//
2*3cab2bb3Spatrick //
3*3cab2bb3Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*3cab2bb3Spatrick // See https://llvm.org/LICENSE.txt for license information.
5*3cab2bb3Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*3cab2bb3Spatrick //
7*3cab2bb3Spatrick //===----------------------------------------------------------------------===//
8*3cab2bb3Spatrick //
9*3cab2bb3Spatrick // This file is a part of Sanitizer runtime.
10*3cab2bb3Spatrick // Tests for sanitizer_bvgraph.h.
11*3cab2bb3Spatrick //
12*3cab2bb3Spatrick //===----------------------------------------------------------------------===//
13*3cab2bb3Spatrick #include "sanitizer_common/sanitizer_bvgraph.h"
14*3cab2bb3Spatrick 
15*3cab2bb3Spatrick #include "sanitizer_test_utils.h"
16*3cab2bb3Spatrick 
17*3cab2bb3Spatrick #include "gtest/gtest.h"
18*3cab2bb3Spatrick 
19*3cab2bb3Spatrick #include <algorithm>
20*3cab2bb3Spatrick #include <vector>
21*3cab2bb3Spatrick #include <set>
22*3cab2bb3Spatrick 
23*3cab2bb3Spatrick using namespace __sanitizer;
24*3cab2bb3Spatrick using namespace std;
25*3cab2bb3Spatrick 
26*3cab2bb3Spatrick typedef BasicBitVector<u8> BV1;
27*3cab2bb3Spatrick typedef BasicBitVector<> BV2;
28*3cab2bb3Spatrick typedef TwoLevelBitVector<> BV3;
29*3cab2bb3Spatrick typedef TwoLevelBitVector<3, BasicBitVector<u8> > BV4;
30*3cab2bb3Spatrick 
31*3cab2bb3Spatrick template<class G>
PrintGraph(const G & g)32*3cab2bb3Spatrick void PrintGraph(const G &g) {
33*3cab2bb3Spatrick   for (uptr i = 0; i < g.size(); i++) {
34*3cab2bb3Spatrick     for (uptr j = 0; j < g.size(); j++) {
35*3cab2bb3Spatrick       fprintf(stderr, "%d", g.hasEdge(i, j));
36*3cab2bb3Spatrick     }
37*3cab2bb3Spatrick     fprintf(stderr, "\n");
38*3cab2bb3Spatrick   }
39*3cab2bb3Spatrick }
40*3cab2bb3Spatrick 
41*3cab2bb3Spatrick 
42*3cab2bb3Spatrick class SimpleGraph {
43*3cab2bb3Spatrick  public:
clear()44*3cab2bb3Spatrick   void clear() { s_.clear(); }
addEdge(uptr from,uptr to)45*3cab2bb3Spatrick   bool addEdge(uptr from, uptr to) {
46*3cab2bb3Spatrick     return s_.insert(idx(from, to)).second;
47*3cab2bb3Spatrick   }
removeEdge(uptr from,uptr to)48*3cab2bb3Spatrick   bool removeEdge(uptr from, uptr to) {
49*3cab2bb3Spatrick     return s_.erase(idx(from, to));
50*3cab2bb3Spatrick   }
51*3cab2bb3Spatrick   template <class G>
checkSameAs(G * g)52*3cab2bb3Spatrick   void checkSameAs(G *g) {
53*3cab2bb3Spatrick     for (set<uptr>::iterator it = s_.begin(); it != s_.end(); ++it) {
54*3cab2bb3Spatrick       uptr from = *it >> 16;
55*3cab2bb3Spatrick       uptr to = *it & ((1 << 16) - 1);
56*3cab2bb3Spatrick       EXPECT_TRUE(g->removeEdge(from, to));
57*3cab2bb3Spatrick     }
58*3cab2bb3Spatrick     EXPECT_TRUE(g->empty());
59*3cab2bb3Spatrick   }
60*3cab2bb3Spatrick  private:
idx(uptr from,uptr to)61*3cab2bb3Spatrick   uptr idx(uptr from, uptr to) {
62*3cab2bb3Spatrick     CHECK_LE(from|to, 1 << 16);
63*3cab2bb3Spatrick     return (from << 16) + to;
64*3cab2bb3Spatrick   }
65*3cab2bb3Spatrick   set<uptr> s_;
66*3cab2bb3Spatrick };
67*3cab2bb3Spatrick 
68*3cab2bb3Spatrick template <class BV>
BasicTest()69*3cab2bb3Spatrick void BasicTest() {
70*3cab2bb3Spatrick   BVGraph<BV> g;
71*3cab2bb3Spatrick   g.clear();
72*3cab2bb3Spatrick   BV target;
73*3cab2bb3Spatrick   SimpleGraph s_g;
74*3cab2bb3Spatrick   set<uptr> s;
75*3cab2bb3Spatrick   set<uptr> s_target;
76*3cab2bb3Spatrick   int num_reachable = 0;
77*3cab2bb3Spatrick   for (int it = 0; it < 1000; it++) {
78*3cab2bb3Spatrick     target.clear();
79*3cab2bb3Spatrick     s_target.clear();
80*3cab2bb3Spatrick     for (int t = 0; t < 4; t++) {
81*3cab2bb3Spatrick       uptr idx = (uptr)my_rand() % g.size();
82*3cab2bb3Spatrick       EXPECT_EQ(target.setBit(idx), s_target.insert(idx).second);
83*3cab2bb3Spatrick     }
84*3cab2bb3Spatrick     uptr from = my_rand() % g.size();
85*3cab2bb3Spatrick     uptr to = my_rand() % g.size();
86*3cab2bb3Spatrick     EXPECT_EQ(g.addEdge(from, to), s_g.addEdge(from, to));
87*3cab2bb3Spatrick     EXPECT_TRUE(g.hasEdge(from, to));
88*3cab2bb3Spatrick     for (int i = 0; i < 10; i++) {
89*3cab2bb3Spatrick       from = my_rand() % g.size();
90*3cab2bb3Spatrick       bool is_reachable = g.isReachable(from, target);
91*3cab2bb3Spatrick       if (is_reachable) {
92*3cab2bb3Spatrick         uptr path[BV::kSize];
93*3cab2bb3Spatrick         uptr len;
94*3cab2bb3Spatrick         for (len = 1; len < BV::kSize; len++) {
95*3cab2bb3Spatrick           if (g.findPath(from, target, path, len) == len)
96*3cab2bb3Spatrick             break;
97*3cab2bb3Spatrick         }
98*3cab2bb3Spatrick         EXPECT_LT(len, BV::kSize);
99*3cab2bb3Spatrick         EXPECT_TRUE(target.getBit(path[len - 1]));
100*3cab2bb3Spatrick         // fprintf(stderr, "reachable: %zd; path %zd {%zd %zd %zd}\n",
101*3cab2bb3Spatrick         //        from, len, path[0], path[1], path[2]);
102*3cab2bb3Spatrick         num_reachable++;
103*3cab2bb3Spatrick       }
104*3cab2bb3Spatrick     }
105*3cab2bb3Spatrick   }
106*3cab2bb3Spatrick   EXPECT_GT(num_reachable, 0);
107*3cab2bb3Spatrick }
108*3cab2bb3Spatrick 
TEST(BVGraph,BasicTest)109*3cab2bb3Spatrick TEST(BVGraph, BasicTest) {
110*3cab2bb3Spatrick   BasicTest<BV1>();
111*3cab2bb3Spatrick   BasicTest<BV2>();
112*3cab2bb3Spatrick   BasicTest<BV3>();
113*3cab2bb3Spatrick   BasicTest<BV4>();
114*3cab2bb3Spatrick }
115*3cab2bb3Spatrick 
116*3cab2bb3Spatrick template <class BV>
RemoveEdges()117*3cab2bb3Spatrick void RemoveEdges() {
118*3cab2bb3Spatrick   SimpleGraph s_g;
119*3cab2bb3Spatrick   BVGraph<BV> g;
120*3cab2bb3Spatrick   g.clear();
121*3cab2bb3Spatrick   BV bv;
122*3cab2bb3Spatrick   set<uptr> s;
123*3cab2bb3Spatrick   for (int it = 0; it < 100; it++) {
124*3cab2bb3Spatrick     s.clear();
125*3cab2bb3Spatrick     bv.clear();
126*3cab2bb3Spatrick     s_g.clear();
127*3cab2bb3Spatrick     g.clear();
128*3cab2bb3Spatrick     for (uptr j = 0; j < g.size() * 2; j++) {
129*3cab2bb3Spatrick       uptr from = my_rand() % g.size();
130*3cab2bb3Spatrick       uptr to = my_rand() % g.size();
131*3cab2bb3Spatrick       EXPECT_EQ(g.addEdge(from, to), s_g.addEdge(from, to));
132*3cab2bb3Spatrick     }
133*3cab2bb3Spatrick     for (uptr j = 0; j < 5; j++) {
134*3cab2bb3Spatrick       uptr idx = my_rand() % g.size();
135*3cab2bb3Spatrick       s.insert(idx);
136*3cab2bb3Spatrick       bv.setBit(idx);
137*3cab2bb3Spatrick     }
138*3cab2bb3Spatrick 
139*3cab2bb3Spatrick     if (it % 2) {
140*3cab2bb3Spatrick       g.removeEdgesFrom(bv);
141*3cab2bb3Spatrick       for (set<uptr>::iterator from = s.begin(); from != s.end(); ++from) {
142*3cab2bb3Spatrick         for (uptr to = 0; to < g.size(); to++)
143*3cab2bb3Spatrick           s_g.removeEdge(*from, to);
144*3cab2bb3Spatrick       }
145*3cab2bb3Spatrick     } else {
146*3cab2bb3Spatrick       g.removeEdgesTo(bv);
147*3cab2bb3Spatrick       for (set<uptr>::iterator to = s.begin(); to != s.end(); ++to) {
148*3cab2bb3Spatrick         for (uptr from = 0; from < g.size(); from++)
149*3cab2bb3Spatrick           s_g.removeEdge(from, *to);
150*3cab2bb3Spatrick       }
151*3cab2bb3Spatrick     }
152*3cab2bb3Spatrick     s_g.checkSameAs(&g);
153*3cab2bb3Spatrick   }
154*3cab2bb3Spatrick }
155*3cab2bb3Spatrick 
TEST(BVGraph,RemoveEdges)156*3cab2bb3Spatrick TEST(BVGraph, RemoveEdges) {
157*3cab2bb3Spatrick   RemoveEdges<BV1>();
158*3cab2bb3Spatrick   RemoveEdges<BV2>();
159*3cab2bb3Spatrick   RemoveEdges<BV3>();
160*3cab2bb3Spatrick   RemoveEdges<BV4>();
161*3cab2bb3Spatrick }
162*3cab2bb3Spatrick 
163*3cab2bb3Spatrick template <class BV>
Test_isReachable()164*3cab2bb3Spatrick void Test_isReachable() {
165*3cab2bb3Spatrick   uptr path[5];
166*3cab2bb3Spatrick   BVGraph<BV> g;
167*3cab2bb3Spatrick   g.clear();
168*3cab2bb3Spatrick   BV target;
169*3cab2bb3Spatrick   target.clear();
170*3cab2bb3Spatrick   uptr t0 = 0;
171*3cab2bb3Spatrick   uptr t1 = g.size() - 1;
172*3cab2bb3Spatrick   target.setBit(t0);
173*3cab2bb3Spatrick   target.setBit(t1);
174*3cab2bb3Spatrick 
175*3cab2bb3Spatrick   uptr f0 = 1;
176*3cab2bb3Spatrick   uptr f1 = 2;
177*3cab2bb3Spatrick   uptr f2 = g.size() / 2;
178*3cab2bb3Spatrick   uptr f3 = g.size() - 2;
179*3cab2bb3Spatrick 
180*3cab2bb3Spatrick   EXPECT_FALSE(g.isReachable(f0, target));
181*3cab2bb3Spatrick   EXPECT_FALSE(g.isReachable(f1, target));
182*3cab2bb3Spatrick   EXPECT_FALSE(g.isReachable(f2, target));
183*3cab2bb3Spatrick   EXPECT_FALSE(g.isReachable(f3, target));
184*3cab2bb3Spatrick 
185*3cab2bb3Spatrick   g.addEdge(f0, f1);
186*3cab2bb3Spatrick   g.addEdge(f1, f2);
187*3cab2bb3Spatrick   g.addEdge(f2, f3);
188*3cab2bb3Spatrick   EXPECT_FALSE(g.isReachable(f0, target));
189*3cab2bb3Spatrick   EXPECT_FALSE(g.isReachable(f1, target));
190*3cab2bb3Spatrick   EXPECT_FALSE(g.isReachable(f2, target));
191*3cab2bb3Spatrick   EXPECT_FALSE(g.isReachable(f3, target));
192*3cab2bb3Spatrick 
193*3cab2bb3Spatrick   g.addEdge(f1, t0);
194*3cab2bb3Spatrick   EXPECT_TRUE(g.isReachable(f0, target));
195*3cab2bb3Spatrick   EXPECT_TRUE(g.isReachable(f1, target));
196*3cab2bb3Spatrick   EXPECT_FALSE(g.isReachable(f2, target));
197*3cab2bb3Spatrick   EXPECT_FALSE(g.isReachable(f3, target));
198*3cab2bb3Spatrick   EXPECT_EQ(g.findPath(f0, target, path, ARRAY_SIZE(path)), 3U);
199*3cab2bb3Spatrick   EXPECT_EQ(path[0], f0);
200*3cab2bb3Spatrick   EXPECT_EQ(path[1], f1);
201*3cab2bb3Spatrick   EXPECT_EQ(path[2], t0);
202*3cab2bb3Spatrick   EXPECT_EQ(g.findPath(f1, target, path, ARRAY_SIZE(path)), 2U);
203*3cab2bb3Spatrick   EXPECT_EQ(path[0], f1);
204*3cab2bb3Spatrick   EXPECT_EQ(path[1], t0);
205*3cab2bb3Spatrick 
206*3cab2bb3Spatrick   g.addEdge(f3, t1);
207*3cab2bb3Spatrick   EXPECT_TRUE(g.isReachable(f0, target));
208*3cab2bb3Spatrick   EXPECT_TRUE(g.isReachable(f1, target));
209*3cab2bb3Spatrick   EXPECT_TRUE(g.isReachable(f2, target));
210*3cab2bb3Spatrick   EXPECT_TRUE(g.isReachable(f3, target));
211*3cab2bb3Spatrick }
212*3cab2bb3Spatrick 
TEST(BVGraph,isReachable)213*3cab2bb3Spatrick TEST(BVGraph, isReachable) {
214*3cab2bb3Spatrick   Test_isReachable<BV1>();
215*3cab2bb3Spatrick   Test_isReachable<BV2>();
216*3cab2bb3Spatrick   Test_isReachable<BV3>();
217*3cab2bb3Spatrick   Test_isReachable<BV4>();
218*3cab2bb3Spatrick }
219*3cab2bb3Spatrick 
220*3cab2bb3Spatrick template <class BV>
LongCycle()221*3cab2bb3Spatrick void LongCycle() {
222*3cab2bb3Spatrick   BVGraph<BV> g;
223*3cab2bb3Spatrick   g.clear();
224*3cab2bb3Spatrick   vector<uptr> path_vec(g.size());
225*3cab2bb3Spatrick   uptr *path = path_vec.data();
226*3cab2bb3Spatrick   uptr start = 5;
227*3cab2bb3Spatrick   for (uptr i = start; i < g.size() - 1; i++) {
228*3cab2bb3Spatrick     g.addEdge(i, i + 1);
229*3cab2bb3Spatrick     for (uptr j = 0; j < start; j++)
230*3cab2bb3Spatrick       g.addEdge(i, j);
231*3cab2bb3Spatrick   }
232*3cab2bb3Spatrick   //  Bad graph that looks like this:
233*3cab2bb3Spatrick   // 00000000000000
234*3cab2bb3Spatrick   // 00000000000000
235*3cab2bb3Spatrick   // 00000000000000
236*3cab2bb3Spatrick   // 00000000000000
237*3cab2bb3Spatrick   // 00000000000000
238*3cab2bb3Spatrick   // 11111010000000
239*3cab2bb3Spatrick   // 11111001000000
240*3cab2bb3Spatrick   // 11111000100000
241*3cab2bb3Spatrick   // 11111000010000
242*3cab2bb3Spatrick   // 11111000001000
243*3cab2bb3Spatrick   // 11111000000100
244*3cab2bb3Spatrick   // 11111000000010
245*3cab2bb3Spatrick   // 11111000000001
246*3cab2bb3Spatrick   // if (g.size() <= 64) PrintGraph(g);
247*3cab2bb3Spatrick   BV target;
248*3cab2bb3Spatrick   for (uptr i = start + 1; i < g.size(); i += 11) {
249*3cab2bb3Spatrick     // if ((i & (i - 1)) == 0) fprintf(stderr, "Path: : %zd\n", i);
250*3cab2bb3Spatrick     target.clear();
251*3cab2bb3Spatrick     target.setBit(i);
252*3cab2bb3Spatrick     EXPECT_TRUE(g.isReachable(start, target));
253*3cab2bb3Spatrick     EXPECT_EQ(g.findPath(start, target, path, g.size()), i - start + 1);
254*3cab2bb3Spatrick   }
255*3cab2bb3Spatrick }
256*3cab2bb3Spatrick 
TEST(BVGraph,LongCycle)257*3cab2bb3Spatrick TEST(BVGraph, LongCycle) {
258*3cab2bb3Spatrick   LongCycle<BV1>();
259*3cab2bb3Spatrick   LongCycle<BV2>();
260*3cab2bb3Spatrick   LongCycle<BV3>();
261*3cab2bb3Spatrick   LongCycle<BV4>();
262*3cab2bb3Spatrick }
263*3cab2bb3Spatrick 
264*3cab2bb3Spatrick template <class BV>
ShortestPath()265*3cab2bb3Spatrick void ShortestPath() {
266*3cab2bb3Spatrick   uptr path[8];
267*3cab2bb3Spatrick   BVGraph<BV> g;
268*3cab2bb3Spatrick   g.clear();
269*3cab2bb3Spatrick   BV t7;
270*3cab2bb3Spatrick   t7.clear();
271*3cab2bb3Spatrick   t7.setBit(7);
272*3cab2bb3Spatrick   // 1=>2=>3=>4=>5=>6=>7
273*3cab2bb3Spatrick   // 1=>7
274*3cab2bb3Spatrick   g.addEdge(1, 2);
275*3cab2bb3Spatrick   g.addEdge(2, 3);
276*3cab2bb3Spatrick   g.addEdge(3, 4);
277*3cab2bb3Spatrick   g.addEdge(4, 5);
278*3cab2bb3Spatrick   g.addEdge(5, 6);
279*3cab2bb3Spatrick   g.addEdge(6, 7);
280*3cab2bb3Spatrick   g.addEdge(1, 7);
281*3cab2bb3Spatrick   EXPECT_TRUE(g.isReachable(1, t7));
282*3cab2bb3Spatrick   // No path of length 1.
283*3cab2bb3Spatrick   EXPECT_EQ(0U, g.findPath(1, t7, path, 1));
284*3cab2bb3Spatrick   // Trying to find a path of len 2..6 gives path of len 2.
285*3cab2bb3Spatrick   EXPECT_EQ(2U, g.findPath(1, t7, path, 2));
286*3cab2bb3Spatrick   EXPECT_EQ(2U, g.findPath(1, t7, path, 3));
287*3cab2bb3Spatrick   EXPECT_EQ(2U, g.findPath(1, t7, path, 4));
288*3cab2bb3Spatrick   EXPECT_EQ(2U, g.findPath(1, t7, path, 5));
289*3cab2bb3Spatrick   EXPECT_EQ(2U, g.findPath(1, t7, path, 6));
290*3cab2bb3Spatrick   // Trying to find a path of len 7 gives path of len 7, because this is DFS.
291*3cab2bb3Spatrick   EXPECT_EQ(7U, g.findPath(1, t7, path, 7));
292*3cab2bb3Spatrick   // But findShortestPath will find the shortest path.
293*3cab2bb3Spatrick   EXPECT_EQ(2U, g.findShortestPath(1, t7, path, 2));
294*3cab2bb3Spatrick   EXPECT_EQ(2U, g.findShortestPath(1, t7, path, 7));
295*3cab2bb3Spatrick }
296*3cab2bb3Spatrick 
TEST(BVGraph,ShortestPath)297*3cab2bb3Spatrick TEST(BVGraph, ShortestPath) {
298*3cab2bb3Spatrick   ShortestPath<BV1>();
299*3cab2bb3Spatrick   ShortestPath<BV2>();
300*3cab2bb3Spatrick   ShortestPath<BV3>();
301*3cab2bb3Spatrick   ShortestPath<BV4>();
302*3cab2bb3Spatrick }
303*3cab2bb3Spatrick 
304*3cab2bb3Spatrick template <class BV>
RunAddEdgesTest()305*3cab2bb3Spatrick void RunAddEdgesTest() {
306*3cab2bb3Spatrick   BVGraph<BV> g;
307*3cab2bb3Spatrick   BV from;
308*3cab2bb3Spatrick   const int kMaxEdges = 10;
309*3cab2bb3Spatrick   uptr added_edges[kMaxEdges];
310*3cab2bb3Spatrick   g.clear();
311*3cab2bb3Spatrick   from.clear();
312*3cab2bb3Spatrick   EXPECT_EQ(0U, g.addEdges(from, 0, added_edges, kMaxEdges));
313*3cab2bb3Spatrick   EXPECT_EQ(0U, g.addEdges(from, 1, added_edges, kMaxEdges));
314*3cab2bb3Spatrick   from.setBit(0);
315*3cab2bb3Spatrick   EXPECT_EQ(1U, g.addEdges(from, 1, added_edges, kMaxEdges));
316*3cab2bb3Spatrick   EXPECT_EQ(0U, added_edges[0]);
317*3cab2bb3Spatrick   EXPECT_EQ(0U, g.addEdges(from, 1, added_edges, kMaxEdges));
318*3cab2bb3Spatrick 
319*3cab2bb3Spatrick   from.clear();
320*3cab2bb3Spatrick   from.setBit(1);
321*3cab2bb3Spatrick   EXPECT_EQ(1U, g.addEdges(from, 4, added_edges, kMaxEdges));
322*3cab2bb3Spatrick   EXPECT_TRUE(g.hasEdge(1, 4));
323*3cab2bb3Spatrick   EXPECT_FALSE(g.hasEdge(1, 5));
324*3cab2bb3Spatrick   EXPECT_EQ(1U, added_edges[0]);
325*3cab2bb3Spatrick   from.setBit(2);
326*3cab2bb3Spatrick   from.setBit(3);
327*3cab2bb3Spatrick   EXPECT_EQ(2U, g.addEdges(from, 4, added_edges, kMaxEdges));
328*3cab2bb3Spatrick   EXPECT_TRUE(g.hasEdge(2, 4));
329*3cab2bb3Spatrick   EXPECT_FALSE(g.hasEdge(2, 5));
330*3cab2bb3Spatrick   EXPECT_TRUE(g.hasEdge(3, 4));
331*3cab2bb3Spatrick   EXPECT_FALSE(g.hasEdge(3, 5));
332*3cab2bb3Spatrick   EXPECT_EQ(2U, added_edges[0]);
333*3cab2bb3Spatrick   EXPECT_EQ(3U, added_edges[1]);
334*3cab2bb3Spatrick }
335*3cab2bb3Spatrick 
TEST(BVGraph,AddEdgesTest)336*3cab2bb3Spatrick TEST(BVGraph, AddEdgesTest) {
337*3cab2bb3Spatrick   RunAddEdgesTest<BV2>();
338*3cab2bb3Spatrick }
339