blob: 53bbeee0e410b04666841180006b0186d28377a5 [file]
/*
* Copyright 2010-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
#include "ShadowStack.hpp"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "Memory.h"
#include "Types.h"
#include "Utils.hpp"
#include "std_support/Memory.hpp"
#include "std_support/Vector.hpp"
using namespace kotlin;
namespace {
template <size_t ParametersCount, size_t LocalsCount>
class StackEntry : private Pinned {
public:
static_assert(ParametersCount + LocalsCount > 0, "Must have at least 1 object on stack");
explicit StackEntry(mm::ShadowStack& shadowStack) : shadowStack_(shadowStack), value_(std_support::make_unique<ObjHeader>()) {
// Fill `locals_` with some values.
for (size_t i = 0; i < LocalsCount; ++i) {
(*this)[i] = value_.get() + i;
}
shadowStack_.EnterFrame(data_.data(), ParametersCount, kTotalCount);
}
~StackEntry() { shadowStack_.LeaveFrame(data_.data(), ParametersCount, kTotalCount); }
ObjHeader*& operator[](size_t index) { return data_[kFrameOverlayCount + ParametersCount + index]; }
private:
mm::ShadowStack& shadowStack_;
std_support::unique_ptr<ObjHeader> value_;
// The following is what the compiler creates on the stack.
static inline constexpr int kFrameOverlayCount = sizeof(FrameOverlay) / sizeof(ObjHeader**);
static inline constexpr int kTotalCount = kFrameOverlayCount + ParametersCount + LocalsCount;
std::array<ObjHeader*, kTotalCount> data_;
};
std_support::vector<ObjHeader*> Collect(mm::ShadowStack& shadowStack) {
std_support::vector<ObjHeader*> result;
for (ObjHeader* local : shadowStack) {
result.push_back(local);
}
return result;
}
} // namespace
TEST(ShadowStackTest, Empty) {
mm::ShadowStack shadowStack;
auto actual = Collect(shadowStack);
EXPECT_THAT(actual, testing::IsEmpty());
}
TEST(ShadowStackTest, OneLocal) {
mm::ShadowStack shadowStack;
StackEntry<0, 1> frame1(shadowStack);
auto actual = Collect(shadowStack);
EXPECT_THAT(actual, testing::ElementsAre(frame1[0]));
}
TEST(ShadowStackTest, ThreeLocals) {
mm::ShadowStack shadowStack;
StackEntry<0, 3> frame1(shadowStack);
auto actual = Collect(shadowStack);
EXPECT_THAT(actual, testing::ElementsAre(frame1[0], frame1[1], frame1[2]));
}
TEST(ShadowStackTest, OneParameter) {
mm::ShadowStack shadowStack;
StackEntry<1, 0> frame1(shadowStack);
auto actual = Collect(shadowStack);
EXPECT_THAT(actual, testing::IsEmpty());
}
TEST(ShadowStackTest, ThreeLocalsAndOneParameter) {
mm::ShadowStack shadowStack;
StackEntry<1, 3> frame1(shadowStack);
auto actual = Collect(shadowStack);
EXPECT_THAT(actual, testing::ElementsAre(frame1[0], frame1[1], frame1[2]));
}
TEST(ShadowStackTest, TwoStackFrames) {
mm::ShadowStack shadowStack;
StackEntry<1, 3> frame1(shadowStack);
StackEntry<1, 3> frame2(shadowStack);
auto actual = Collect(shadowStack);
EXPECT_THAT(actual, testing::ElementsAre(frame2[0], frame2[1], frame2[2], frame1[0], frame1[1], frame1[2]));
}
TEST(ShadowStackTest, ManyStackFrames) {
mm::ShadowStack shadowStack;
StackEntry<0, 3> frame1(shadowStack);
StackEntry<1, 0> frame2(shadowStack);
StackEntry<3, 1> frame3(shadowStack);
StackEntry<3, 3> frame4(shadowStack);
auto actual = Collect(shadowStack);
EXPECT_THAT(actual, testing::ElementsAre(frame4[0], frame4[1], frame4[2], frame3[0], frame1[0], frame1[1], frame1[2]));
}