1*6777b538SAndroid Build Coastguard Worker // Copyright 2019 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker
5*6777b538SAndroid Build Coastguard Worker #include <cstring>
6*6777b538SAndroid Build Coastguard Worker #include <iterator>
7*6777b538SAndroid Build Coastguard Worker #include <memory>
8*6777b538SAndroid Build Coastguard Worker #include <numeric>
9*6777b538SAndroid Build Coastguard Worker
10*6777b538SAndroid Build Coastguard Worker #include "base/profiler/stack_buffer.h"
11*6777b538SAndroid Build Coastguard Worker #include "base/profiler/stack_copier.h"
12*6777b538SAndroid Build Coastguard Worker #include "testing/gmock/include/gmock/gmock.h"
13*6777b538SAndroid Build Coastguard Worker #include "testing/gtest/include/gtest/gtest.h"
14*6777b538SAndroid Build Coastguard Worker
15*6777b538SAndroid Build Coastguard Worker namespace base {
16*6777b538SAndroid Build Coastguard Worker
17*6777b538SAndroid Build Coastguard Worker namespace {
18*6777b538SAndroid Build Coastguard Worker
19*6777b538SAndroid Build Coastguard Worker class CopyFunctions : public StackCopier {
20*6777b538SAndroid Build Coastguard Worker public:
21*6777b538SAndroid Build Coastguard Worker using StackCopier::CopyStackContentsAndRewritePointers;
22*6777b538SAndroid Build Coastguard Worker using StackCopier::RewritePointerIfInOriginalStack;
23*6777b538SAndroid Build Coastguard Worker };
24*6777b538SAndroid Build Coastguard Worker
25*6777b538SAndroid Build Coastguard Worker static constexpr size_t kTestStackBufferSize = sizeof(uintptr_t) * 4;
26*6777b538SAndroid Build Coastguard Worker
27*6777b538SAndroid Build Coastguard Worker union alignas(StackBuffer::kPlatformStackAlignment) TestStackBuffer {
28*6777b538SAndroid Build Coastguard Worker uintptr_t as_uintptr[kTestStackBufferSize / sizeof(uintptr_t)];
29*6777b538SAndroid Build Coastguard Worker uint16_t as_uint16[kTestStackBufferSize / sizeof(uint16_t)];
30*6777b538SAndroid Build Coastguard Worker uint8_t as_uint8[kTestStackBufferSize / sizeof(uint8_t)];
31*6777b538SAndroid Build Coastguard Worker };
32*6777b538SAndroid Build Coastguard Worker
33*6777b538SAndroid Build Coastguard Worker } // namespace
34*6777b538SAndroid Build Coastguard Worker
TEST(StackCopierTest,RewritePointerIfInOriginalStack_InStack)35*6777b538SAndroid Build Coastguard Worker TEST(StackCopierTest, RewritePointerIfInOriginalStack_InStack) {
36*6777b538SAndroid Build Coastguard Worker uintptr_t original_stack[4];
37*6777b538SAndroid Build Coastguard Worker uintptr_t stack_copy[4];
38*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(reinterpret_cast<uintptr_t>(&stack_copy[2]),
39*6777b538SAndroid Build Coastguard Worker CopyFunctions::RewritePointerIfInOriginalStack(
40*6777b538SAndroid Build Coastguard Worker reinterpret_cast<uint8_t*>(&original_stack[0]),
41*6777b538SAndroid Build Coastguard Worker &original_stack[0] + std::size(original_stack),
42*6777b538SAndroid Build Coastguard Worker reinterpret_cast<uint8_t*>(&stack_copy[0]),
43*6777b538SAndroid Build Coastguard Worker reinterpret_cast<uintptr_t>(&original_stack[2])));
44*6777b538SAndroid Build Coastguard Worker }
45*6777b538SAndroid Build Coastguard Worker
TEST(StackCopierTest,RewritePointerIfInOriginalStack_NotInStack)46*6777b538SAndroid Build Coastguard Worker TEST(StackCopierTest, RewritePointerIfInOriginalStack_NotInStack) {
47*6777b538SAndroid Build Coastguard Worker // We use this variable only for its address, which is outside of
48*6777b538SAndroid Build Coastguard Worker // original_stack.
49*6777b538SAndroid Build Coastguard Worker uintptr_t non_stack_location;
50*6777b538SAndroid Build Coastguard Worker uintptr_t original_stack[4];
51*6777b538SAndroid Build Coastguard Worker uintptr_t stack_copy[4];
52*6777b538SAndroid Build Coastguard Worker
53*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(reinterpret_cast<uintptr_t>(&non_stack_location),
54*6777b538SAndroid Build Coastguard Worker CopyFunctions::RewritePointerIfInOriginalStack(
55*6777b538SAndroid Build Coastguard Worker reinterpret_cast<uint8_t*>(&original_stack[0]),
56*6777b538SAndroid Build Coastguard Worker &original_stack[0] + std::size(original_stack),
57*6777b538SAndroid Build Coastguard Worker reinterpret_cast<uint8_t*>(&stack_copy[0]),
58*6777b538SAndroid Build Coastguard Worker reinterpret_cast<uintptr_t>(&non_stack_location)));
59*6777b538SAndroid Build Coastguard Worker }
60*6777b538SAndroid Build Coastguard Worker
TEST(StackCopierTest,StackCopy)61*6777b538SAndroid Build Coastguard Worker TEST(StackCopierTest, StackCopy) {
62*6777b538SAndroid Build Coastguard Worker TestStackBuffer original_stack;
63*6777b538SAndroid Build Coastguard Worker // Fill the stack buffer with increasing uintptr_t values.
64*6777b538SAndroid Build Coastguard Worker std::iota(
65*6777b538SAndroid Build Coastguard Worker &original_stack.as_uintptr[0],
66*6777b538SAndroid Build Coastguard Worker &original_stack.as_uintptr[0] + std::size(original_stack.as_uintptr),
67*6777b538SAndroid Build Coastguard Worker 100);
68*6777b538SAndroid Build Coastguard Worker // Replace the third value with an address within the buffer.
69*6777b538SAndroid Build Coastguard Worker original_stack.as_uintptr[2] =
70*6777b538SAndroid Build Coastguard Worker reinterpret_cast<uintptr_t>(&original_stack.as_uintptr[1]);
71*6777b538SAndroid Build Coastguard Worker TestStackBuffer stack_copy;
72*6777b538SAndroid Build Coastguard Worker
73*6777b538SAndroid Build Coastguard Worker CopyFunctions::CopyStackContentsAndRewritePointers(
74*6777b538SAndroid Build Coastguard Worker &original_stack.as_uint8[0],
75*6777b538SAndroid Build Coastguard Worker &original_stack.as_uintptr[0] + std::size(original_stack.as_uintptr),
76*6777b538SAndroid Build Coastguard Worker StackBuffer::kPlatformStackAlignment, &stack_copy.as_uintptr[0]);
77*6777b538SAndroid Build Coastguard Worker
78*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(original_stack.as_uintptr[0], stack_copy.as_uintptr[0]);
79*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(original_stack.as_uintptr[1], stack_copy.as_uintptr[1]);
80*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(reinterpret_cast<uintptr_t>(&stack_copy.as_uintptr[1]),
81*6777b538SAndroid Build Coastguard Worker stack_copy.as_uintptr[2]);
82*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(original_stack.as_uintptr[3], stack_copy.as_uintptr[3]);
83*6777b538SAndroid Build Coastguard Worker }
84*6777b538SAndroid Build Coastguard Worker
TEST(StackCopierTest,StackCopy_NonAlignedStackPointerCopy)85*6777b538SAndroid Build Coastguard Worker TEST(StackCopierTest, StackCopy_NonAlignedStackPointerCopy) {
86*6777b538SAndroid Build Coastguard Worker TestStackBuffer stack_buffer;
87*6777b538SAndroid Build Coastguard Worker
88*6777b538SAndroid Build Coastguard Worker // Fill the stack buffer with increasing uint16_t values.
89*6777b538SAndroid Build Coastguard Worker std::iota(&stack_buffer.as_uint16[0],
90*6777b538SAndroid Build Coastguard Worker &stack_buffer.as_uint16[0] + std::size(stack_buffer.as_uint16),
91*6777b538SAndroid Build Coastguard Worker 100);
92*6777b538SAndroid Build Coastguard Worker
93*6777b538SAndroid Build Coastguard Worker // Set the stack bottom to the unaligned location one uint16_t into the
94*6777b538SAndroid Build Coastguard Worker // buffer.
95*6777b538SAndroid Build Coastguard Worker uint8_t* unaligned_stack_bottom =
96*6777b538SAndroid Build Coastguard Worker reinterpret_cast<uint8_t*>(&stack_buffer.as_uint16[1]);
97*6777b538SAndroid Build Coastguard Worker
98*6777b538SAndroid Build Coastguard Worker // Leave extra space within the stack buffer beyond the end of the stack, but
99*6777b538SAndroid Build Coastguard Worker // preserve the platform alignment.
100*6777b538SAndroid Build Coastguard Worker const size_t extra_space = StackBuffer::kPlatformStackAlignment;
101*6777b538SAndroid Build Coastguard Worker uintptr_t* stack_top =
102*6777b538SAndroid Build Coastguard Worker &stack_buffer.as_uintptr[std::size(stack_buffer.as_uintptr) -
103*6777b538SAndroid Build Coastguard Worker extra_space / sizeof(uintptr_t)];
104*6777b538SAndroid Build Coastguard Worker
105*6777b538SAndroid Build Coastguard Worker // Initialize the copy to all zeros.
106*6777b538SAndroid Build Coastguard Worker TestStackBuffer stack_copy_buffer = {{0}};
107*6777b538SAndroid Build Coastguard Worker
108*6777b538SAndroid Build Coastguard Worker const uint8_t* stack_copy_bottom =
109*6777b538SAndroid Build Coastguard Worker CopyFunctions::CopyStackContentsAndRewritePointers(
110*6777b538SAndroid Build Coastguard Worker unaligned_stack_bottom, stack_top,
111*6777b538SAndroid Build Coastguard Worker StackBuffer::kPlatformStackAlignment,
112*6777b538SAndroid Build Coastguard Worker &stack_copy_buffer.as_uintptr[0]);
113*6777b538SAndroid Build Coastguard Worker
114*6777b538SAndroid Build Coastguard Worker // The stack copy bottom address is expected to be at the same offset into the
115*6777b538SAndroid Build Coastguard Worker // stack copy buffer as the unaligned stack bottom is from the stack buffer.
116*6777b538SAndroid Build Coastguard Worker // Since the buffers have the same platform stack alignment this also ensures
117*6777b538SAndroid Build Coastguard Worker // the alignment of the bottom addresses is the same.
118*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(unaligned_stack_bottom - &stack_buffer.as_uint8[0],
119*6777b538SAndroid Build Coastguard Worker stack_copy_bottom - &stack_copy_buffer.as_uint8[0]);
120*6777b538SAndroid Build Coastguard Worker
121*6777b538SAndroid Build Coastguard Worker // The first value in the copy should not be overwritten since the stack
122*6777b538SAndroid Build Coastguard Worker // starts at the second uint16_t.
123*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(0u, stack_copy_buffer.as_uint16[0]);
124*6777b538SAndroid Build Coastguard Worker
125*6777b538SAndroid Build Coastguard Worker // The next values up to the extra space should have been copied.
126*6777b538SAndroid Build Coastguard Worker const size_t max_index =
127*6777b538SAndroid Build Coastguard Worker std::size(stack_copy_buffer.as_uint16) - extra_space / sizeof(uint16_t);
128*6777b538SAndroid Build Coastguard Worker for (size_t i = 1; i < max_index; ++i)
129*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(i + 100, stack_copy_buffer.as_uint16[i]);
130*6777b538SAndroid Build Coastguard Worker
131*6777b538SAndroid Build Coastguard Worker // None of the values in the empty space should have been copied.
132*6777b538SAndroid Build Coastguard Worker for (size_t i = max_index; i < std::size(stack_copy_buffer.as_uint16); ++i)
133*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(0u, stack_copy_buffer.as_uint16[i]);
134*6777b538SAndroid Build Coastguard Worker }
135*6777b538SAndroid Build Coastguard Worker
136*6777b538SAndroid Build Coastguard Worker // Checks that an unaligned within-stack pointer value at the start of the stack
137*6777b538SAndroid Build Coastguard Worker // is not rewritten.
TEST(StackCopierTest,StackCopy_NonAlignedStackPointerUnalignedRewriteAtStart)138*6777b538SAndroid Build Coastguard Worker TEST(StackCopierTest, StackCopy_NonAlignedStackPointerUnalignedRewriteAtStart) {
139*6777b538SAndroid Build Coastguard Worker // Initially fill the buffer with 0s.
140*6777b538SAndroid Build Coastguard Worker TestStackBuffer stack_buffer = {{0}};
141*6777b538SAndroid Build Coastguard Worker
142*6777b538SAndroid Build Coastguard Worker // Set the stack bottom to the unaligned location one uint16_t into the
143*6777b538SAndroid Build Coastguard Worker // buffer.
144*6777b538SAndroid Build Coastguard Worker uint8_t* unaligned_stack_bottom =
145*6777b538SAndroid Build Coastguard Worker reinterpret_cast<uint8_t*>(&stack_buffer.as_uint16[1]);
146*6777b538SAndroid Build Coastguard Worker
147*6777b538SAndroid Build Coastguard Worker // Set the first unaligned pointer-sized value to an address within the stack.
148*6777b538SAndroid Build Coastguard Worker uintptr_t within_stack_pointer =
149*6777b538SAndroid Build Coastguard Worker reinterpret_cast<uintptr_t>(&stack_buffer.as_uintptr[2]);
150*6777b538SAndroid Build Coastguard Worker std::memcpy(unaligned_stack_bottom, &within_stack_pointer,
151*6777b538SAndroid Build Coastguard Worker sizeof(within_stack_pointer));
152*6777b538SAndroid Build Coastguard Worker
153*6777b538SAndroid Build Coastguard Worker TestStackBuffer stack_copy_buffer = {{0}};
154*6777b538SAndroid Build Coastguard Worker
155*6777b538SAndroid Build Coastguard Worker const uint8_t* stack_copy_bottom =
156*6777b538SAndroid Build Coastguard Worker CopyFunctions::CopyStackContentsAndRewritePointers(
157*6777b538SAndroid Build Coastguard Worker unaligned_stack_bottom,
158*6777b538SAndroid Build Coastguard Worker &stack_buffer.as_uintptr[0] + std::size(stack_buffer.as_uintptr),
159*6777b538SAndroid Build Coastguard Worker StackBuffer::kPlatformStackAlignment,
160*6777b538SAndroid Build Coastguard Worker &stack_copy_buffer.as_uintptr[0]);
161*6777b538SAndroid Build Coastguard Worker
162*6777b538SAndroid Build Coastguard Worker uintptr_t copied_within_stack_pointer;
163*6777b538SAndroid Build Coastguard Worker std::memcpy(&copied_within_stack_pointer, stack_copy_bottom,
164*6777b538SAndroid Build Coastguard Worker sizeof(copied_within_stack_pointer));
165*6777b538SAndroid Build Coastguard Worker
166*6777b538SAndroid Build Coastguard Worker // The rewriting should only operate on pointer-aligned values so the
167*6777b538SAndroid Build Coastguard Worker // unaligned value should be copied verbatim.
168*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(within_stack_pointer, copied_within_stack_pointer);
169*6777b538SAndroid Build Coastguard Worker }
170*6777b538SAndroid Build Coastguard Worker
171*6777b538SAndroid Build Coastguard Worker // Checks that an unaligned within-stack pointer after the start of the stack is
172*6777b538SAndroid Build Coastguard Worker // not rewritten.
TEST(StackCopierTest,StackCopy_NonAlignedStackPointerUnalignedRewriteAfterStart)173*6777b538SAndroid Build Coastguard Worker TEST(StackCopierTest,
174*6777b538SAndroid Build Coastguard Worker StackCopy_NonAlignedStackPointerUnalignedRewriteAfterStart) {
175*6777b538SAndroid Build Coastguard Worker // Initially fill the buffer with 0s.
176*6777b538SAndroid Build Coastguard Worker TestStackBuffer stack_buffer = {{0}};
177*6777b538SAndroid Build Coastguard Worker
178*6777b538SAndroid Build Coastguard Worker // Set the stack bottom to the unaligned location one uint16_t into the
179*6777b538SAndroid Build Coastguard Worker // buffer.
180*6777b538SAndroid Build Coastguard Worker uint8_t* unaligned_stack_bottom =
181*6777b538SAndroid Build Coastguard Worker reinterpret_cast<uint8_t*>(&stack_buffer.as_uint16[1]);
182*6777b538SAndroid Build Coastguard Worker
183*6777b538SAndroid Build Coastguard Worker // Set the second unaligned pointer-sized value to an address within the
184*6777b538SAndroid Build Coastguard Worker // stack.
185*6777b538SAndroid Build Coastguard Worker uintptr_t within_stack_pointer =
186*6777b538SAndroid Build Coastguard Worker reinterpret_cast<uintptr_t>(&stack_buffer.as_uintptr[2]);
187*6777b538SAndroid Build Coastguard Worker std::memcpy(unaligned_stack_bottom + sizeof(uintptr_t), &within_stack_pointer,
188*6777b538SAndroid Build Coastguard Worker sizeof(within_stack_pointer));
189*6777b538SAndroid Build Coastguard Worker
190*6777b538SAndroid Build Coastguard Worker TestStackBuffer stack_copy_buffer = {{0}};
191*6777b538SAndroid Build Coastguard Worker
192*6777b538SAndroid Build Coastguard Worker const uint8_t* stack_copy_bottom =
193*6777b538SAndroid Build Coastguard Worker CopyFunctions::CopyStackContentsAndRewritePointers(
194*6777b538SAndroid Build Coastguard Worker unaligned_stack_bottom,
195*6777b538SAndroid Build Coastguard Worker &stack_buffer.as_uintptr[0] + std::size(stack_buffer.as_uintptr),
196*6777b538SAndroid Build Coastguard Worker StackBuffer::kPlatformStackAlignment,
197*6777b538SAndroid Build Coastguard Worker &stack_copy_buffer.as_uintptr[0]);
198*6777b538SAndroid Build Coastguard Worker
199*6777b538SAndroid Build Coastguard Worker uintptr_t copied_within_stack_pointer;
200*6777b538SAndroid Build Coastguard Worker std::memcpy(&copied_within_stack_pointer,
201*6777b538SAndroid Build Coastguard Worker stack_copy_bottom + sizeof(uintptr_t),
202*6777b538SAndroid Build Coastguard Worker sizeof(copied_within_stack_pointer));
203*6777b538SAndroid Build Coastguard Worker
204*6777b538SAndroid Build Coastguard Worker // The rewriting should only operate on pointer-aligned values so the
205*6777b538SAndroid Build Coastguard Worker // unaligned value should be copied verbatim.
206*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(within_stack_pointer, copied_within_stack_pointer);
207*6777b538SAndroid Build Coastguard Worker }
208*6777b538SAndroid Build Coastguard Worker
TEST(StackCopierTest,StackCopy_NonAlignedStackPointerAlignedRewrite)209*6777b538SAndroid Build Coastguard Worker TEST(StackCopierTest, StackCopy_NonAlignedStackPointerAlignedRewrite) {
210*6777b538SAndroid Build Coastguard Worker // Initially fill the buffer with 0s.
211*6777b538SAndroid Build Coastguard Worker TestStackBuffer stack_buffer = {{0}};
212*6777b538SAndroid Build Coastguard Worker
213*6777b538SAndroid Build Coastguard Worker // Set the stack bottom to the unaligned location one uint16_t into the
214*6777b538SAndroid Build Coastguard Worker // buffer.
215*6777b538SAndroid Build Coastguard Worker uint8_t* unaligned_stack_bottom =
216*6777b538SAndroid Build Coastguard Worker reinterpret_cast<uint8_t*>(&stack_buffer.as_uint16[1]);
217*6777b538SAndroid Build Coastguard Worker
218*6777b538SAndroid Build Coastguard Worker // Set the second aligned pointer-sized value to an address within the stack.
219*6777b538SAndroid Build Coastguard Worker stack_buffer.as_uintptr[1] =
220*6777b538SAndroid Build Coastguard Worker reinterpret_cast<uintptr_t>(&stack_buffer.as_uintptr[2]);
221*6777b538SAndroid Build Coastguard Worker
222*6777b538SAndroid Build Coastguard Worker TestStackBuffer stack_copy_buffer = {{0}};
223*6777b538SAndroid Build Coastguard Worker
224*6777b538SAndroid Build Coastguard Worker CopyFunctions::CopyStackContentsAndRewritePointers(
225*6777b538SAndroid Build Coastguard Worker unaligned_stack_bottom,
226*6777b538SAndroid Build Coastguard Worker &stack_buffer.as_uintptr[0] + std::size(stack_buffer.as_uintptr),
227*6777b538SAndroid Build Coastguard Worker StackBuffer::kPlatformStackAlignment, &stack_copy_buffer.as_uintptr[0]);
228*6777b538SAndroid Build Coastguard Worker
229*6777b538SAndroid Build Coastguard Worker // The aligned pointer should have been rewritten to point within the stack
230*6777b538SAndroid Build Coastguard Worker // copy.
231*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(reinterpret_cast<uintptr_t>(&stack_copy_buffer.as_uintptr[2]),
232*6777b538SAndroid Build Coastguard Worker stack_copy_buffer.as_uintptr[1]);
233*6777b538SAndroid Build Coastguard Worker }
234*6777b538SAndroid Build Coastguard Worker
235*6777b538SAndroid Build Coastguard Worker } // namespace base
236