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