Skip to content

Commit

Permalink
[sanitizer] Calculate Range sets intersection
Browse files Browse the repository at this point in the history
Will be used to handle Root Regions in LSAN D151781.

Reviewed By: MaskRay

Differential Revision: https://reviews.llvm.org/D151779
  • Loading branch information
vitalybuka committed Jun 2, 2023
1 parent a15eb89 commit 6b3ae49
Show file tree
Hide file tree
Showing 5 changed files with 167 additions and 0 deletions.
1 change: 1 addition & 0 deletions compiler-rt/lib/sanitizer_common/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

set(SANITIZER_SOURCES_NOTERMINATION
sanitizer_allocator.cpp
sanitizer_common_range.cpp
sanitizer_common.cpp
sanitizer_deadlock_detector1.cpp
sanitizer_deadlock_detector2.cpp
Expand Down
60 changes: 60 additions & 0 deletions compiler-rt/lib/sanitizer_common/sanitizer_common_range.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
//===-- sanitizer_common_range.cpp ----------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "sanitizer_common_range.h"

namespace __sanitizer {

void Intersect(ArrayRef<Range> a, ArrayRef<Range> b,
InternalMmapVectorNoCtor<Range> &output) {
output.clear();

struct Event {
uptr val;
s8 diff1;
s8 diff2;
};

InternalMmapVector<Event> events;
for (const Range &r : a) {
CHECK_LE(r.begin, r.end);
events.push_back({r.begin, 1, 0});
events.push_back({r.end, -1, 0});
}

for (const Range &r : b) {
CHECK_LE(r.begin, r.end);
events.push_back({r.begin, 0, 1});
events.push_back({r.end, 0, -1});
}

Sort(events.data(), events.size(),
[](const Event &lh, const Event &rh) { return lh.val < rh.val; });

uptr start = 0;
sptr state1 = 0;
sptr state2 = 0;
for (const auto &e : events) {
if (e.val != start) {
DCHECK_GE(state1, 0);
DCHECK_GE(state2, 0);
if (state1 && state2) {
if (!output.empty() && start == output.back().end)
output.back().end = e.val;
else
output.push_back({start, e.val});
}
start = e.val;
}

state1 += e.diff1;
state2 += e.diff2;
}
}

} // namespace __sanitizer
39 changes: 39 additions & 0 deletions compiler-rt/lib/sanitizer_common/sanitizer_common_range.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//===-- sanitizer_common_range.h --------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Contais Range and related utilities.
//
//===----------------------------------------------------------------------===//

#ifndef SANITIZER_COMMON_REGION_H
#define SANITIZER_COMMON_REGION_H

#include "sanitizer_common.h"

namespace __sanitizer {

struct Range {
uptr begin;
uptr end;
};

inline bool operator==(const Range &lhs, const Range &rhs) {
return lhs.begin == rhs.begin && lhs.end == rhs.end;
}

inline bool operator!=(const Range &lhs, const Range &rhs) {
return !(lhs == rhs);
}

// Calculates intersection of two sets of regions in O(N log N) time.
void Intersect(ArrayRef<Range> a, ArrayRef<Range> b,
InternalMmapVectorNoCtor<Range> &output);

} // namespace __sanitizer

#endif // SANITIZER_COMMON_REGION_H
1 change: 1 addition & 0 deletions compiler-rt/lib/sanitizer_common/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ set(SANITIZER_UNITTESTS
sanitizer_bitvector_test.cpp
sanitizer_bvgraph_test.cpp
sanitizer_chained_origin_depot_test.cpp
sanitizer_common_range_test.cpp
sanitizer_common_test.cpp
sanitizer_deadlock_detector_test.cpp
sanitizer_dense_map_test.cpp
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
//===-- sanitizer_common_region_test.cpp ----------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file is a part of ThreadSanitizer/AddressSanitizer runtime.
//
//===----------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_common_range.h"

#include <algorithm>

#include "gtest/gtest.h"
#include "sanitizer_common/sanitizer_common.h"

namespace __sanitizer {

class SanitizerCommon
: public testing::TestWithParam<std::tuple<
std::vector<Range>, std::vector<Range>, std::vector<Range>>> {};

TEST_P(SanitizerCommon, Intersect) {
{
InternalMmapVector<Range> output;
Intersect(std::get<0>(GetParam()), std::get<1>(GetParam()), output);
EXPECT_EQ(std::get<2>(GetParam()),
std::vector<Range>(output.begin(), output.end()));
}
{
InternalMmapVector<Range> output;
Intersect(std::get<1>(GetParam()), std::get<0>(GetParam()), output);
EXPECT_EQ(std::get<2>(GetParam()),
std::vector<Range>(output.begin(), output.end()));
}
}

static void PrintTo(const Range &r, std::ostream *os) {
*os << "[" << r.begin << ", " << r.end << ")";
}

static const std::tuple<std::vector<Range>, std::vector<Range>,
std::vector<Range>>
kTests[] = {
{{}, {}, {}},
{{{100, 1000}}, {{5000, 10000}}, {}},
{{{100, 1000}, {200, 2000}}, {{5000, 10000}, {6000, 11000}}, {}},
{{{100, 1000}}, {{100, 1000}}, {{100, 1000}}},
{{{100, 1000}}, {{50, 150}}, {{100, 150}}},
{{{100, 1000}}, {{150, 250}}, {{150, 250}}},
{{{100, 1000}, {100, 1000}}, {{100, 1000}}, {{100, 1000}}},
{{{100, 1000}}, {{500, 1500}}, {{500, 1000}}},
{{{100, 200}}, {{200, 300}, {1, 1000}}, {{100, 200}}},
{{{100, 200}, {200, 300}}, {{100, 300}}, {{100, 300}}},
{{{100, 200}, {200, 300}, {300, 400}}, {{150, 350}}, {{150, 350}}},
{{{100, 200}, {300, 400}, {500, 600}},
{{0, 1000}},
{{100, 200}, {300, 400}, {500, 600}}},
};

INSTANTIATE_TEST_SUITE_P(SanitizerCommonEmpty, SanitizerCommon,
testing::ValuesIn(kTests));

} // namespace __sanitizer

0 comments on commit 6b3ae49

Please sign in to comment.