[XRay] Handle allocator exhaustion in segmented array

Summary:
This change allows us to handle allocator exhaustion properly in the
segmented array implementation. Before this change, we relied on the
caller of the `trim` function to provide a valid number of elements to
trim. This change allows us to do the right thing in case the elements
to trim is greater than the size of the container.

Reviewers: mboerger, eizan

Subscribers: llvm-commits

Differential Revision: https://reviews.llvm.org/D53484

llvm-svn: 344880
This commit is contained in:
Dean Michael Berris 2018-10-22 02:11:27 +00:00
parent dbabdfaca5
commit ebfbf89000
3 changed files with 48 additions and 5 deletions

View File

@ -1,9 +1,13 @@
#include "test_helpers.h"
#include "xray_segmented_array.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
namespace __xray {
namespace {
using ::testing::SizeIs;
struct TestData {
s64 First;
s64 Second;
@ -12,6 +16,10 @@ struct TestData {
TestData(s64 F, s64 S) : First(F), Second(S) {}
};
void PrintTo(const TestData &D, std::ostream *OS) {
*OS << "{ " << D.First << ", " << D.Second << " }";
}
TEST(SegmentedArrayTest, ConstructWithAllocators) {
using AllocatorType = typename Array<TestData>::AllocatorType;
AllocatorType A(1 << 4);
@ -161,6 +169,23 @@ TEST(SegmentedArrayTest, IteratorTrimBehaviour) {
EXPECT_EQ(Data.size(), SegmentX2);
}
TEST(SegmentedArrayTest, HandleExhaustedAllocator) {
using AllocatorType = typename Array<TestData>::AllocatorType;
constexpr auto Segment = Array<TestData>::SegmentSize;
constexpr auto MaxElements = Array<TestData>::ElementsPerSegment;
AllocatorType A(Segment);
Array<TestData> Data(A);
for (auto i = MaxElements; i > 0u; --i)
EXPECT_NE(Data.AppendEmplace(static_cast<s64>(i), static_cast<s64>(i)),
nullptr);
EXPECT_EQ(Data.AppendEmplace(0, 0), nullptr);
EXPECT_THAT(Data, SizeIs(MaxElements));
// Trimming more elements than there are in the container should be fine.
Data.trim(MaxElements + 1);
EXPECT_THAT(Data, SizeIs(0u));
}
struct ShadowStackEntry {
uint64_t EntryTSC = 0;
uint64_t *NodePtr = nullptr;

View File

@ -14,8 +14,9 @@
#define COMPILER_RT_LIB_XRAY_TESTS_TEST_HELPERS_H_
#include "xray_buffer_queue.h"
#include "llvm/XRay/XRayRecord.h"
#include "xray_segmented_array.h"
#include "llvm/XRay/Trace.h"
#include "llvm/XRay/XRayRecord.h"
#include "gmock/gmock.h"
// TODO: Move these to llvm/include/Testing/XRay/...
@ -54,6 +55,19 @@ namespace __xray {
std::string serialize(BufferQueue &Buffers, int32_t Version);
template <class T> void PrintTo(const Array<T> &A, std::ostream *OS) {
*OS << "[";
bool first = true;
for (const auto &E : A) {
if (!first) {
*OS << ", ";
}
PrintTo(E, OS);
first = false;
}
*OS << "]";
}
} // namespace __xray
#endif // COMPILER_RT_LIB_XRAY_TESTS_TEST_HELPERS_H_

View File

@ -78,6 +78,8 @@ public:
static SegmentBase SentinelSegment;
using size_type = size_t;
private:
AllocatorType *Alloc;
SegmentBase *Head = &SentinelSegment;
@ -334,9 +336,8 @@ public:
if (Elements == 0)
return;
DCHECK_LE(Elements, Size);
DCHECK_GT(Size, 0);
auto OldSize = Size;
Elements = Elements >= Size ? Size : Elements;
Size -= Elements;
DCHECK_NE(Head, &SentinelSegment);
@ -346,8 +347,11 @@ public:
nearest_boundary(Size, ElementsPerSegment)) /
ElementsPerSegment;
SegmentsToTrim > 0; --SegmentsToTrim) {
DCHECK_NE(Head, &SentinelSegment);
DCHECK_NE(Tail, &SentinelSegment);
// We want to short-circuit if the trace is already empty.
if (Head == &SentinelSegment && Head == Tail)
return;
// Put the tail into the Freelist.
auto *FreeSegment = Tail;
Tail = Tail->Prev;