Skip to content
This repository was archived by the owner on Nov 8, 2023. It is now read-only.

Commit 86b88c1

Browse files
cferris1000Gerrit Code Review
authored andcommitted
Merge "Add record_allocs_on_exit option." into main
2 parents a8873c5 + 9b88d0a commit 86b88c1

File tree

8 files changed

+104
-8
lines changed

8 files changed

+104
-8
lines changed

libc/malloc_debug/Config.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,10 @@ const std::unordered_map<std::string, Config::OptionInfo> Config::kOptions = {
187187
"record_allocs_file",
188188
{0, &Config::SetRecordAllocsFile},
189189
},
190+
{
191+
"record_allocs_on_exit",
192+
{0, &Config::SetRecordAllocsOnExit},
193+
},
190194

191195
{
192196
"verify_pointers",
@@ -401,6 +405,14 @@ bool Config::SetRecordAllocsFile(const std::string&, const std::string& value) {
401405
return true;
402406
}
403407

408+
bool Config::SetRecordAllocsOnExit(const std::string& option, const std::string& value) {
409+
if (Config::VerifyValueEmpty(option, value)) {
410+
record_allocs_on_exit_ = true;
411+
return true;
412+
}
413+
return false;
414+
}
415+
404416
bool Config::VerifyValueEmpty(const std::string& option, const std::string& value) {
405417
if (!value.empty()) {
406418
// This is not valid.

libc/malloc_debug/Config.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ class Config {
9898
int record_allocs_signal() const { return record_allocs_signal_; }
9999
size_t record_allocs_num_entries() const { return record_allocs_num_entries_; }
100100
const std::string& record_allocs_file() const { return record_allocs_file_; }
101+
bool record_allocs_on_exit() const { return record_allocs_on_exit_; }
101102

102103
int check_unreachable_signal() const { return check_unreachable_signal_; }
103104

@@ -139,6 +140,7 @@ class Config {
139140

140141
bool SetRecordAllocs(const std::string& option, const std::string& value);
141142
bool SetRecordAllocsFile(const std::string& option, const std::string& value);
143+
bool SetRecordAllocsOnExit(const std::string& option, const std::string& value);
142144

143145
bool VerifyValueEmpty(const std::string& option, const std::string& value);
144146

@@ -170,6 +172,7 @@ class Config {
170172
int record_allocs_signal_ = 0;
171173
size_t record_allocs_num_entries_ = 0;
172174
std::string record_allocs_file_;
175+
bool record_allocs_on_exit_ = false;
173176

174177
uint64_t options_ = 0;
175178
uint8_t fill_alloc_value_;

libc/malloc_debug/README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,19 @@ will be placed.
456456

457457
**NOTE**: This option is not available until the O release of Android.
458458

459+
### record\_allocs\_on\_exit
460+
This option only has meaning if record\_allocs is set. It indicates that
461+
when the process terminates, the record file should be created
462+
automatically.
463+
464+
The only caveat to this option is that when the process terminates,
465+
the file that will contain the records will be the normal file name
466+
with **.PID** appended. Where PID is the pid of the process that has
467+
terminated. This is to avoid cases where a number of processes exit
468+
at the same time and attempt to write to the same file.
469+
470+
**NOTE**: This option is not available until the V release of Android.
471+
459472
### verify\_pointers
460473
Track all live allocations to determine if a pointer is used that does not
461474
exist. This option is a lightweight way to verify that all

libc/malloc_debug/RecordData.cpp

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -131,17 +131,30 @@ void RecordData::WriteData(int, siginfo_t*, void*) {
131131
record_obj_->WriteEntries();
132132
}
133133

134+
void RecordData::WriteEntriesOnExit() {
135+
if (record_obj_ == nullptr) return;
136+
137+
// Append the current pid to the file name to avoid multiple processes
138+
// writing to the same file.
139+
std::string file(record_obj_->file());
140+
file += "." + std::to_string(getpid());
141+
record_obj_->WriteEntries(file);
142+
}
143+
134144
void RecordData::WriteEntries() {
145+
WriteEntries(file_);
146+
}
147+
148+
void RecordData::WriteEntries(const std::string& file) {
135149
std::lock_guard<std::mutex> entries_lock(entries_lock_);
136150
if (cur_index_ == 0) {
137151
info_log("No alloc entries to write.");
138152
return;
139153
}
140154

141-
int dump_fd =
142-
open(dump_file_.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW, 0755);
155+
int dump_fd = open(file.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW, 0755);
143156
if (dump_fd == -1) {
144-
error_log("Cannot create record alloc file %s: %s", dump_file_.c_str(), strerror(errno));
157+
error_log("Cannot create record alloc file %s: %s", file.c_str(), strerror(errno));
145158
return;
146159
}
147160

@@ -179,7 +192,7 @@ bool RecordData::Initialize(const Config& config) {
179192

180193
entries_.resize(config.record_allocs_num_entries());
181194
cur_index_ = 0U;
182-
dump_file_ = config.record_allocs_file();
195+
file_ = config.record_allocs_file();
183196

184197
return true;
185198
}

libc/malloc_debug/RecordData.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,19 +162,23 @@ class RecordData {
162162
void AddEntry(const RecordEntry* entry);
163163
void AddEntryOnly(const RecordEntry* entry);
164164

165+
const std::string& file() { return file_; }
165166
pthread_key_t key() { return key_; }
166167

168+
static void WriteEntriesOnExit();
169+
167170
private:
168171
static void WriteData(int, siginfo_t*, void*);
169172
static RecordData* record_obj_;
170173

171174
void WriteEntries();
175+
void WriteEntries(const std::string& file);
172176

173177
std::mutex entries_lock_;
174178
pthread_key_t key_;
175179
std::vector<std::unique_ptr<const RecordEntry>> entries_;
176180
size_t cur_index_;
177-
std::string dump_file_;
181+
std::string file_;
178182

179183
BIONIC_DISALLOW_COPY_AND_ASSIGN(RecordData);
180184
};

libc/malloc_debug/malloc_debug.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,10 @@ void debug_finalize() {
451451
PointerData::LogLeaks();
452452
}
453453

454+
if ((g_debug->config().options() & RECORD_ALLOCS) && g_debug->config().record_allocs_on_exit()) {
455+
RecordData::WriteEntriesOnExit();
456+
}
457+
454458
if ((g_debug->config().options() & BACKTRACE) && g_debug->config().backtrace_dump_on_exit()) {
455459
debug_dump_heap(android::base::StringPrintf("%s.%d.exit.txt",
456460
g_debug->config().backtrace_dump_prefix().c_str(),

libc/malloc_debug/tests/malloc_debug_config_tests.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -571,6 +571,25 @@ TEST_F(MallocDebugConfigTest, record_allocs_file) {
571571
ASSERT_STREQ("", getFakeLogPrint().c_str());
572572
}
573573

574+
TEST_F(MallocDebugConfigTest, record_allocs_on_exit) {
575+
ASSERT_TRUE(InitConfig("record_allocs_on_exit")) << getFakeLogPrint();
576+
ASSERT_EQ(0U, config->options());
577+
ASSERT_TRUE(config->record_allocs_on_exit());
578+
579+
ASSERT_STREQ("", getFakeLogBuf().c_str());
580+
ASSERT_STREQ("", getFakeLogPrint().c_str());
581+
}
582+
583+
TEST_F(MallocDebugConfigTest, record_allocs_on_exit_error) {
584+
ASSERT_FALSE(InitConfig("record_allocs_on_exit=something")) << getFakeLogPrint();
585+
586+
ASSERT_STREQ("", getFakeLogBuf().c_str());
587+
std::string log_msg(
588+
"6 malloc_debug malloc_testing: value set for option 'record_allocs_on_exit' "
589+
"which does not take a value\n");
590+
ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str());
591+
}
592+
574593
TEST_F(MallocDebugConfigTest, guard_min_error) {
575594
ASSERT_FALSE(InitConfig("guard=0"));
576595

libc/malloc_debug/tests/malloc_debug_unit_tests.cpp

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ std::string ShowDiffs(uint8_t* a, uint8_t* b, size_t size) {
185185
}
186186

187187
static void VerifyRecords(std::vector<std::string>& expected, std::string& actual) {
188+
ASSERT_TRUE(expected.size() != 0);
188189
size_t offset = 0;
189190
for (std::string& str : expected) {
190191
ASSERT_STREQ(str.c_str(), actual.substr(offset, str.size()).c_str());
@@ -1512,7 +1513,7 @@ TEST_F(MallocDebugTest, backtrace_dump_on_exit) {
15121513

15131514
// Call the exit function manually.
15141515
debug_finalize();
1515-
exit(0);
1516+
_exit(0);
15161517
}
15171518
ASSERT_NE(-1, pid);
15181519
ASSERT_EQ(pid, TEMP_FAILURE_RETRY(waitpid(pid, nullptr, 0)));
@@ -1561,7 +1562,7 @@ TEST_F(MallocDebugTest, backtrace_dump_on_exit_shared_backtrace) {
15611562

15621563
// Call the exit function manually.
15631564
debug_finalize();
1564-
exit(0);
1565+
_exit(0);
15651566
}
15661567
ASSERT_NE(-1, pid);
15671568
ASSERT_EQ(pid, TEMP_FAILURE_RETRY(waitpid(pid, nullptr, 0)));
@@ -1619,7 +1620,7 @@ TEST_F(MallocDebugTest, backtrace_full_dump_on_exit) {
16191620

16201621
// Call the exit function manually.
16211622
debug_finalize();
1622-
exit(0);
1623+
_exit(0);
16231624
}
16241625
ASSERT_NE(-1, pid);
16251626
ASSERT_EQ(pid, TEMP_FAILURE_RETRY(waitpid(pid, nullptr, 0)));
@@ -2429,6 +2430,33 @@ TEST_F(MallocDebugTest, record_allocs_write_entries_does_not_allocate) {
24292430
ASSERT_STREQ("", getFakeLogPrint().c_str());
24302431
}
24312432

2433+
TEST_F(MallocDebugTest, record_allocs_on_exit) {
2434+
InitRecordAllocs("record_allocs record_allocs_on_exit");
2435+
2436+
// The filename created on exit always appends the pid.
2437+
// Modify the variable so the file is deleted at the end of the test.
2438+
record_filename += '.' + std::to_string(getpid());
2439+
2440+
std::vector<std::string> expected;
2441+
void* ptr = debug_malloc(100);
2442+
expected.push_back(android::base::StringPrintf("%d: malloc %p 100", getpid(), ptr));
2443+
ptr = debug_malloc(200);
2444+
expected.push_back(android::base::StringPrintf("%d: malloc %p 200", getpid(), ptr));
2445+
ptr = debug_malloc(400);
2446+
expected.push_back(android::base::StringPrintf("%d: malloc %p 400", getpid(), ptr));
2447+
2448+
// Call the exit function manually.
2449+
debug_finalize();
2450+
2451+
// Read all of the contents.
2452+
std::string actual;
2453+
ASSERT_TRUE(android::base::ReadFileToString(record_filename, &actual));
2454+
VerifyRecords(expected, actual);
2455+
2456+
ASSERT_STREQ("", getFakeLogBuf().c_str());
2457+
ASSERT_STREQ("", getFakeLogPrint().c_str());
2458+
}
2459+
24322460
TEST_F(MallocDebugTest, verify_pointers) {
24332461
Init("verify_pointers");
24342462

0 commit comments

Comments
 (0)