#ifdef UNSAFE_BUFFERS_BUILD
#pragma allow_unsafe_buffers
#endif
#include "base/memory/protected_memory.h"
#include <stddef.h>
#include <stdint.h>
#include <climits>
#include <type_traits>
#include "base/memory/protected_memory_buildflags.h"
#include "base/synchronization/lock.h"
#include "base/test/gtest_util.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
namespace {
struct Data { … };
struct DataWithNonTrivialConstructor { … };
static_assert …;
#if BUILDFLAG(PROTECTED_MEMORY_ENABLED)
void VerifyByteSequenceIsNotWriteable(unsigned char* const byte_pattern,
const size_t number_of_bits,
const size_t bit_increment) {
const auto check_bit_not_writeable = [=](const size_t bit_index) {
const size_t byte_index = bit_index / CHAR_BIT;
const size_t local_bit_index = bit_index % CHAR_BIT;
EXPECT_CHECK_DEATH_WITH(
byte_pattern[byte_index] ^= (0x1 << local_bit_index), "")
<< " at bit " << bit_index << " of " << number_of_bits;
};
if (number_of_bits >= 1) {
check_bit_not_writeable(0);
}
if (number_of_bits >= 2) {
check_bit_not_writeable(number_of_bits - 1);
}
for (size_t bit_index = bit_increment; bit_index < (number_of_bits - 1);
bit_index += bit_increment) {
check_bit_not_writeable(bit_index);
}
}
template <typename T>
void VerifyInstanceIsNotWriteable(T& instance, const size_t bit_increment = 3) {
VerifyByteSequenceIsNotWriteable(
reinterpret_cast<unsigned char*>(std::addressof(instance)),
sizeof(T) * CHAR_BIT, bit_increment);
}
#endif
DEFINE_PROTECTED_DATA ProtectedMemory<int> g_explicit_initialization;
TEST(ProtectedMemoryTest, ExplicitInitializationWithExplicitValue) { … }
DEFINE_PROTECTED_DATA ProtectedMemory<int>
g_explicit_initialization_with_default_value;
TEST(ProtectedMemoryTest, VerifyExplicitInitializationWithDefaultValue) { … }
DEFINE_PROTECTED_DATA
ProtectedMemory<DataWithNonTrivialConstructor>
g_lazily_initialized_with_explicit_initialization;
TEST(ProtectedMemoryTest, ExplicitLazyInitializationWithExplicitValue) { … }
DEFINE_PROTECTED_DATA
ProtectedMemory<DataWithNonTrivialConstructor> g_uninitialized;
TEST(ProtectedMemoryDeathTest, AccessWithoutInitialization) { … }
#if BUILDFLAG(PROTECTED_MEMORY_ENABLED)
DEFINE_PROTECTED_DATA ProtectedMemory<Data> g_initialized;
TEST(ProtectedMemoryTest, VerifySetValue) {
static ProtectedMemoryInitializer initializer_explicit_value(g_initialized);
ASSERT_NE(g_initialized->foo, 5);
EXPECT_EQ(g_initialized->bar, -1);
{
base::AutoWritableMemory writer(g_initialized);
writer.GetProtectedDataPtr()->foo = 5;
}
EXPECT_EQ(g_initialized->foo, 5);
EXPECT_EQ(g_initialized->bar, -1);
}
DEFINE_PROTECTED_DATA ProtectedMemory<Data> g_not_writable;
TEST(ProtectedMemoryDeathTest, AccessWithoutWriteAccessCrashes) {
static ProtectedMemoryInitializer initializer_explicit_value(g_not_writable);
VerifyInstanceIsNotWriteable(g_not_writable);
}
TEST(ProtectedMemoryDeathTest, FailsIfDefinedOutsideOfProtectMemoryRegion) {
ProtectedMemory<Data> data;
EXPECT_CHECK_DEATH({ AutoWritableMemory writer(data); });
}
#endif
}
}