15c22cdee0
Change a test to use a signal that does not trigger a tombstone. Also changed the gwp_asan_integration.DISABLED_assert_gwp_asan_enabled test to inherit from the SilentDeathTest to prevent tombstones being generated. Test: Ran tests and no tombstones generated. Change-Id: I0f104704829dde692aa515a63dea1c6971278c29
270 lines
10 KiB
C++
270 lines
10 KiB
C++
/*
|
|
* Copyright (C) 2021 The Android Open Source Project
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* * Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* * Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in
|
|
* the documentation and/or other materials provided with the
|
|
* distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
|
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <gtest/gtest.h>
|
|
#include <stdio.h>
|
|
#include <sys/file.h>
|
|
#include <string>
|
|
|
|
#if defined(__BIONIC__)
|
|
|
|
#include "android-base/file.h"
|
|
#include "android-base/silent_death_test.h"
|
|
#include "android-base/test_utils.h"
|
|
#include "gwp_asan/options.h"
|
|
#include "platform/bionic/malloc.h"
|
|
#include "sys/system_properties.h"
|
|
#include "utils.h"
|
|
|
|
using gwp_asan_integration_DeathTest = SilentDeathTest;
|
|
|
|
// basename is a mess, use gnu basename explicitly to avoid the need for string
|
|
// mutation.
|
|
extern "C" const char* __gnu_basename(const char* path);
|
|
|
|
// GWP-ASan tests can run much slower, especially when combined with HWASan.
|
|
// Triple the deadline to avoid flakes (b/238585984).
|
|
extern "C" bool GetInitialArgs(const char*** args, size_t* num_args) {
|
|
static const char* initial_args[] = {"--deadline_threshold_ms=270000"};
|
|
*args = initial_args;
|
|
*num_args = 1;
|
|
return true;
|
|
}
|
|
|
|
// This file implements "torture testing" under GWP-ASan, where we sample every
|
|
// single allocation. The upper limit for the number of GWP-ASan allocations in
|
|
// the torture mode is is generally 40,000, so that svelte devices don't
|
|
// explode, as this uses ~163MiB RAM (4KiB per live allocation).
|
|
TEST(gwp_asan_integration, malloc_tests_under_torture) {
|
|
// Do not override HWASan with GWP ASan.
|
|
SKIP_WITH_HWASAN;
|
|
|
|
RunGwpAsanTest("malloc.*:-malloc.mallinfo*");
|
|
}
|
|
|
|
class SyspropRestorer {
|
|
private:
|
|
std::vector<std::pair<std::string, std::string>> props_to_restore_;
|
|
// System properties are global for a device, so the tests that mutate the
|
|
// GWP-ASan system properties must be run mutually exclusive. Because
|
|
// bionic-unit-tests is run in an isolated gtest fashion (each test is run in
|
|
// its own process), we have to use flocks to synchronise between tests.
|
|
int flock_fd_;
|
|
|
|
public:
|
|
SyspropRestorer() {
|
|
std::string path = testing::internal::GetArgvs()[0];
|
|
flock_fd_ = open(path.c_str(), O_RDONLY);
|
|
EXPECT_NE(flock_fd_, -1) << "failed to open self for a flock";
|
|
EXPECT_NE(flock(flock_fd_, LOCK_EX), -1) << "failed to flock myself";
|
|
|
|
const char* basename = __gnu_basename(path.c_str());
|
|
std::vector<std::string> props = {
|
|
std::string("libc.debug.gwp_asan.sample_rate.") + basename,
|
|
std::string("libc.debug.gwp_asan.process_sampling.") + basename,
|
|
std::string("libc.debug.gwp_asan.max_allocs.") + basename,
|
|
"libc.debug.gwp_asan.sample_rate.system_default",
|
|
"libc.debug.gwp_asan.sample_rate.app_default",
|
|
"libc.debug.gwp_asan.process_sampling.system_default",
|
|
"libc.debug.gwp_asan.process_sampling.app_default",
|
|
"libc.debug.gwp_asan.max_allocs.system_default",
|
|
"libc.debug.gwp_asan.max_allocs.app_default",
|
|
};
|
|
|
|
size_t base_props_size = props.size();
|
|
for (size_t i = 0; i < base_props_size; ++i) {
|
|
props.push_back("persist." + props[i]);
|
|
}
|
|
|
|
std::string reset_log;
|
|
|
|
for (const std::string& prop : props) {
|
|
std::string value = GetSysprop(prop);
|
|
props_to_restore_.emplace_back(prop, value);
|
|
if (!value.empty()) {
|
|
__system_property_set(prop.c_str(), "");
|
|
}
|
|
}
|
|
}
|
|
|
|
~SyspropRestorer() {
|
|
for (const auto& kv : props_to_restore_) {
|
|
if (kv.second != GetSysprop(kv.first)) {
|
|
__system_property_set(kv.first.c_str(), kv.second.c_str());
|
|
}
|
|
}
|
|
close(flock_fd_);
|
|
}
|
|
|
|
static std::string GetSysprop(const std::string& name) {
|
|
std::string value;
|
|
const prop_info* pi = __system_property_find(name.c_str());
|
|
if (pi == nullptr) return value;
|
|
__system_property_read_callback(
|
|
pi,
|
|
[](void* cookie, const char* /* name */, const char* value, uint32_t /* serial */) {
|
|
std::string* v = static_cast<std::string*>(cookie);
|
|
*v = value;
|
|
},
|
|
&value);
|
|
return value;
|
|
}
|
|
};
|
|
|
|
TEST_F(gwp_asan_integration_DeathTest, DISABLED_assert_gwp_asan_enabled) {
|
|
std::string maps;
|
|
EXPECT_TRUE(android::base::ReadFileToString("/proc/self/maps", &maps));
|
|
EXPECT_TRUE(maps.find("GWP-ASan") != std::string::npos) << maps;
|
|
|
|
volatile int* x = new int;
|
|
delete x;
|
|
EXPECT_DEATH({ *x = 7; }, "");
|
|
}
|
|
|
|
// A weaker version of the above tests, only checking that GWP-ASan is enabled
|
|
// for any pointer, not *our* pointer. This allows us to test the system_default
|
|
// sysprops without potentially OOM-ing other random processes:
|
|
// b/273904016#comment5
|
|
TEST(gwp_asan_integration, DISABLED_assert_gwp_asan_enabled_weaker) {
|
|
std::string maps;
|
|
EXPECT_TRUE(android::base::ReadFileToString("/proc/self/maps", &maps));
|
|
EXPECT_TRUE(maps.find("GWP-ASan") != std::string::npos) << maps;
|
|
}
|
|
|
|
TEST(gwp_asan_integration, DISABLED_assert_gwp_asan_disabled) {
|
|
std::string maps;
|
|
EXPECT_TRUE(android::base::ReadFileToString("/proc/self/maps", &maps));
|
|
EXPECT_TRUE(maps.find("GWP-ASan") == std::string::npos);
|
|
}
|
|
|
|
TEST(gwp_asan_integration, sysprops_program_specific) {
|
|
// Do not override HWASan with GWP ASan.
|
|
SKIP_WITH_HWASAN;
|
|
|
|
SyspropRestorer restorer;
|
|
|
|
std::string path = testing::internal::GetArgvs()[0];
|
|
const char* basename = __gnu_basename(path.c_str());
|
|
__system_property_set((std::string("libc.debug.gwp_asan.sample_rate.") + basename).c_str(), "1");
|
|
__system_property_set((std::string("libc.debug.gwp_asan.process_sampling.") + basename).c_str(),
|
|
"1");
|
|
__system_property_set((std::string("libc.debug.gwp_asan.max_allocs.") + basename).c_str(),
|
|
"40000");
|
|
|
|
RunSubtestNoEnv("gwp_asan_integration_DeathTest.DISABLED_assert_gwp_asan_enabled");
|
|
}
|
|
|
|
TEST(gwp_asan_integration, sysprops_persist_program_specific) {
|
|
// Do not override HWASan with GWP ASan.
|
|
SKIP_WITH_HWASAN;
|
|
|
|
SyspropRestorer restorer;
|
|
|
|
std::string path = testing::internal::GetArgvs()[0];
|
|
const char* basename = __gnu_basename(path.c_str());
|
|
__system_property_set(
|
|
(std::string("persist.libc.debug.gwp_asan.sample_rate.") + basename).c_str(), "1");
|
|
__system_property_set(
|
|
(std::string("persist.libc.debug.gwp_asan.process_sampling.") + basename).c_str(), "1");
|
|
__system_property_set((std::string("persist.libc.debug.gwp_asan.max_allocs.") + basename).c_str(),
|
|
"40000");
|
|
|
|
RunSubtestNoEnv("gwp_asan_integration_DeathTest.DISABLED_assert_gwp_asan_enabled");
|
|
}
|
|
|
|
TEST(gwp_asan_integration, sysprops_non_persist_overrides_persist) {
|
|
// Do not override HWASan with GWP ASan.
|
|
SKIP_WITH_HWASAN;
|
|
|
|
SyspropRestorer restorer;
|
|
|
|
__system_property_set("libc.debug.gwp_asan.sample_rate.system_default", "1");
|
|
__system_property_set("libc.debug.gwp_asan.process_sampling.system_default", "1");
|
|
// Note, any processes launched elsewhere on the system right now will have
|
|
// GWP-ASan enabled. Make sure that we only use a single slot, otherwise we
|
|
// could end up causing said badly-timed processes to use up to 163MiB extra
|
|
// penalty that 40,000 allocs would cause. See b/273904016#comment5 for more
|
|
// context.
|
|
__system_property_set("libc.debug.gwp_asan.max_allocs.system_default", "1");
|
|
|
|
__system_property_set("persist.libc.debug.gwp_asan.sample_rate.system_default", "0");
|
|
__system_property_set("persist.libc.debug.gwp_asan.process_sampling.system_default", "0");
|
|
__system_property_set("persist.libc.debug.gwp_asan.max_allocs.system_default", "0");
|
|
|
|
RunSubtestNoEnv("gwp_asan_integration.DISABLED_assert_gwp_asan_enabled_weaker");
|
|
}
|
|
|
|
TEST(gwp_asan_integration, sysprops_program_specific_overrides_default) {
|
|
// Do not override HWASan with GWP ASan.
|
|
SKIP_WITH_HWASAN;
|
|
|
|
SyspropRestorer restorer;
|
|
|
|
std::string path = testing::internal::GetArgvs()[0];
|
|
const char* basename = __gnu_basename(path.c_str());
|
|
__system_property_set(
|
|
(std::string("persist.libc.debug.gwp_asan.sample_rate.") + basename).c_str(), "1");
|
|
__system_property_set(
|
|
(std::string("persist.libc.debug.gwp_asan.process_sampling.") + basename).c_str(), "1");
|
|
__system_property_set((std::string("persist.libc.debug.gwp_asan.max_allocs.") + basename).c_str(),
|
|
"40000");
|
|
|
|
__system_property_set("libc.debug.gwp_asan.sample_rate.system_default", "0");
|
|
__system_property_set("libc.debug.gwp_asan.process_sampling.system_default", "0");
|
|
__system_property_set("libc.debug.gwp_asan.max_allocs.system_default", "0");
|
|
|
|
RunSubtestNoEnv("gwp_asan_integration_DeathTest.DISABLED_assert_gwp_asan_enabled");
|
|
}
|
|
|
|
TEST(gwp_asan_integration, sysprops_can_disable) {
|
|
// Do not override HWASan with GWP ASan.
|
|
SKIP_WITH_HWASAN;
|
|
|
|
SyspropRestorer restorer;
|
|
|
|
__system_property_set("libc.debug.gwp_asan.sample_rate.system_default", "0");
|
|
__system_property_set("libc.debug.gwp_asan.process_sampling.system_default", "0");
|
|
__system_property_set("libc.debug.gwp_asan.max_allocs.system_default", "0");
|
|
|
|
RunSubtestNoEnv("gwp_asan_integration.DISABLED_assert_gwp_asan_disabled");
|
|
}
|
|
|
|
TEST(gwp_asan_integration, env_overrides_sysprop) {
|
|
// Do not override HWASan with GWP ASan.
|
|
SKIP_WITH_HWASAN;
|
|
|
|
SyspropRestorer restorer;
|
|
|
|
__system_property_set("libc.debug.gwp_asan.sample_rate.system_default", "0");
|
|
__system_property_set("libc.debug.gwp_asan.process_sampling.system_default", "0");
|
|
__system_property_set("libc.debug.gwp_asan.max_allocs.system_default", "0");
|
|
|
|
RunGwpAsanTest("gwp_asan_integration_DeathTest.DISABLED_assert_gwp_asan_enabled");
|
|
}
|
|
|
|
#endif // defined(__BIONIC__)
|