Skip to content

Commit 6b3ae49

Browse files
committed
[sanitizer] Calculate Range sets intersection
Will be used to handle Root Regions in LSAN D151781. Reviewed By: MaskRay Differential Revision: https://reviews.llvm.org/D151779
1 parent a15eb89 commit 6b3ae49

File tree

5 files changed

+167
-0
lines changed

5 files changed

+167
-0
lines changed

compiler-rt/lib/sanitizer_common/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
set(SANITIZER_SOURCES_NOTERMINATION
55
sanitizer_allocator.cpp
6+
sanitizer_common_range.cpp
67
sanitizer_common.cpp
78
sanitizer_deadlock_detector1.cpp
89
sanitizer_deadlock_detector2.cpp
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
//===-- sanitizer_common_range.cpp ----------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "sanitizer_common_range.h"
10+
11+
namespace __sanitizer {
12+
13+
void Intersect(ArrayRef<Range> a, ArrayRef<Range> b,
14+
InternalMmapVectorNoCtor<Range> &output) {
15+
output.clear();
16+
17+
struct Event {
18+
uptr val;
19+
s8 diff1;
20+
s8 diff2;
21+
};
22+
23+
InternalMmapVector<Event> events;
24+
for (const Range &r : a) {
25+
CHECK_LE(r.begin, r.end);
26+
events.push_back({r.begin, 1, 0});
27+
events.push_back({r.end, -1, 0});
28+
}
29+
30+
for (const Range &r : b) {
31+
CHECK_LE(r.begin, r.end);
32+
events.push_back({r.begin, 0, 1});
33+
events.push_back({r.end, 0, -1});
34+
}
35+
36+
Sort(events.data(), events.size(),
37+
[](const Event &lh, const Event &rh) { return lh.val < rh.val; });
38+
39+
uptr start = 0;
40+
sptr state1 = 0;
41+
sptr state2 = 0;
42+
for (const auto &e : events) {
43+
if (e.val != start) {
44+
DCHECK_GE(state1, 0);
45+
DCHECK_GE(state2, 0);
46+
if (state1 && state2) {
47+
if (!output.empty() && start == output.back().end)
48+
output.back().end = e.val;
49+
else
50+
output.push_back({start, e.val});
51+
}
52+
start = e.val;
53+
}
54+
55+
state1 += e.diff1;
56+
state2 += e.diff2;
57+
}
58+
}
59+
60+
} // namespace __sanitizer
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
//===-- sanitizer_common_range.h --------------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// Contais Range and related utilities.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef SANITIZER_COMMON_REGION_H
14+
#define SANITIZER_COMMON_REGION_H
15+
16+
#include "sanitizer_common.h"
17+
18+
namespace __sanitizer {
19+
20+
struct Range {
21+
uptr begin;
22+
uptr end;
23+
};
24+
25+
inline bool operator==(const Range &lhs, const Range &rhs) {
26+
return lhs.begin == rhs.begin && lhs.end == rhs.end;
27+
}
28+
29+
inline bool operator!=(const Range &lhs, const Range &rhs) {
30+
return !(lhs == rhs);
31+
}
32+
33+
// Calculates intersection of two sets of regions in O(N log N) time.
34+
void Intersect(ArrayRef<Range> a, ArrayRef<Range> b,
35+
InternalMmapVectorNoCtor<Range> &output);
36+
37+
} // namespace __sanitizer
38+
39+
#endif // SANITIZER_COMMON_REGION_H

compiler-rt/lib/sanitizer_common/tests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ set(SANITIZER_UNITTESTS
1616
sanitizer_bitvector_test.cpp
1717
sanitizer_bvgraph_test.cpp
1818
sanitizer_chained_origin_depot_test.cpp
19+
sanitizer_common_range_test.cpp
1920
sanitizer_common_test.cpp
2021
sanitizer_deadlock_detector_test.cpp
2122
sanitizer_dense_map_test.cpp
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
//===-- sanitizer_common_region_test.cpp ----------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file is a part of ThreadSanitizer/AddressSanitizer runtime.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
#include "sanitizer_common/sanitizer_common_range.h"
13+
14+
#include <algorithm>
15+
16+
#include "gtest/gtest.h"
17+
#include "sanitizer_common/sanitizer_common.h"
18+
19+
namespace __sanitizer {
20+
21+
class SanitizerCommon
22+
: public testing::TestWithParam<std::tuple<
23+
std::vector<Range>, std::vector<Range>, std::vector<Range>>> {};
24+
25+
TEST_P(SanitizerCommon, Intersect) {
26+
{
27+
InternalMmapVector<Range> output;
28+
Intersect(std::get<0>(GetParam()), std::get<1>(GetParam()), output);
29+
EXPECT_EQ(std::get<2>(GetParam()),
30+
std::vector<Range>(output.begin(), output.end()));
31+
}
32+
{
33+
InternalMmapVector<Range> output;
34+
Intersect(std::get<1>(GetParam()), std::get<0>(GetParam()), output);
35+
EXPECT_EQ(std::get<2>(GetParam()),
36+
std::vector<Range>(output.begin(), output.end()));
37+
}
38+
}
39+
40+
static void PrintTo(const Range &r, std::ostream *os) {
41+
*os << "[" << r.begin << ", " << r.end << ")";
42+
}
43+
44+
static const std::tuple<std::vector<Range>, std::vector<Range>,
45+
std::vector<Range>>
46+
kTests[] = {
47+
{{}, {}, {}},
48+
{{{100, 1000}}, {{5000, 10000}}, {}},
49+
{{{100, 1000}, {200, 2000}}, {{5000, 10000}, {6000, 11000}}, {}},
50+
{{{100, 1000}}, {{100, 1000}}, {{100, 1000}}},
51+
{{{100, 1000}}, {{50, 150}}, {{100, 150}}},
52+
{{{100, 1000}}, {{150, 250}}, {{150, 250}}},
53+
{{{100, 1000}, {100, 1000}}, {{100, 1000}}, {{100, 1000}}},
54+
{{{100, 1000}}, {{500, 1500}}, {{500, 1000}}},
55+
{{{100, 200}}, {{200, 300}, {1, 1000}}, {{100, 200}}},
56+
{{{100, 200}, {200, 300}}, {{100, 300}}, {{100, 300}}},
57+
{{{100, 200}, {200, 300}, {300, 400}}, {{150, 350}}, {{150, 350}}},
58+
{{{100, 200}, {300, 400}, {500, 600}},
59+
{{0, 1000}},
60+
{{100, 200}, {300, 400}, {500, 600}}},
61+
};
62+
63+
INSTANTIATE_TEST_SUITE_P(SanitizerCommonEmpty, SanitizerCommon,
64+
testing::ValuesIn(kTests));
65+
66+
} // namespace __sanitizer

0 commit comments

Comments
 (0)