1 // Copyright 2022 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifdef UNSAFE_BUFFERS_BUILD
6 // TODO(crbug.com/40284755): Remove this and spanify to fix the errors.
7 #pragma allow_unsafe_buffers
8 #endif
9
10 #include "base/profiler/stack_buffer.h"
11
12 #include "base/memory/aligned_memory.h"
13 #include "build/build_config.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15
16 #if BUILDFLAG(IS_CHROMEOS)
17 #include "base/bits.h"
18 #include "base/memory/page_size.h"
19 #endif // #if BUILDFLAG(IS_CHROMEOS)
20
21 namespace base {
22
TEST(StackBufferTest,BufferAllocated)23 TEST(StackBufferTest, BufferAllocated) {
24 const unsigned int kBufferSize = 32 * 1024;
25 StackBuffer stack_buffer(kBufferSize);
26 EXPECT_EQ(stack_buffer.size(), kBufferSize);
27 // Without volatile, the compiler could simply optimize away the entire for
28 // loop below.
29 volatile uintptr_t* buffer = stack_buffer.buffer();
30 ASSERT_NE(nullptr, buffer);
31 EXPECT_TRUE(IsAligned(const_cast<uintptr_t*>(buffer),
32 StackBuffer::kPlatformStackAlignment));
33
34 // Memory pointed to by buffer should be writable.
35 for (unsigned int i = 0; i < (kBufferSize / sizeof(buffer[0])); i++) {
36 buffer[i] = i;
37 EXPECT_EQ(buffer[i], i);
38 }
39 }
40
41 #if BUILDFLAG(IS_CHROMEOS)
TEST(StackBufferTest,MarkBufferContentsAsUnneeded)42 TEST(StackBufferTest, MarkBufferContentsAsUnneeded) {
43 const unsigned int kBufferSize = 32 * GetPageSize();
44 StackBuffer stack_buffer(kBufferSize);
45 volatile uintptr_t* buffer = stack_buffer.buffer();
46 ASSERT_NE(nullptr, buffer);
47
48 // Force the kernel to allocate backing store for the buffer.
49 for (unsigned int i = 0; i < (kBufferSize / sizeof(uintptr_t)); i++) {
50 buffer[i] = i;
51 EXPECT_EQ(buffer[i], i);
52 }
53
54 // Tell kernel to discard (most of) the memory.
55 constexpr size_t kUndiscardedElements = 100;
56 stack_buffer.MarkUpperBufferContentsAsUnneeded(kUndiscardedElements *
57 sizeof(buffer[0]));
58
59 // The first 100 elements shouldn't have been discarded.
60 for (size_t i = 0; i < kUndiscardedElements; i++) {
61 EXPECT_EQ(buffer[i], i);
62 }
63
64 // Pages past the discard point should be zero-filled now.
65 const size_t kExpectedDiscardStartPoint =
66 bits::AlignUp(kUndiscardedElements * sizeof(buffer[0]), GetPageSize()) /
67 sizeof(buffer[0]);
68 for (size_t i = kExpectedDiscardStartPoint;
69 i < kBufferSize / sizeof(buffer[0]); i++) {
70 EXPECT_EQ(buffer[i], 0U);
71 }
72
73 // Writing to the memory (both discarded and undiscarded parts) shouldn't
74 // cause segmentation faults and should remember the value we write.
75 for (unsigned int i = 0; i < (kBufferSize / sizeof(buffer[0])); i++) {
76 buffer[i] = i + 7;
77 EXPECT_EQ(buffer[i], i + 7);
78 }
79 }
80 #endif // #if BUILDFLAG(IS_CHROMEOS)
81
82 } // namespace base
83