Merge "Fix bugs with verify_trace." into main
diff --git a/memory_replay/VerifyTrace.cpp b/memory_replay/VerifyTrace.cpp
index daac05d..0094940 100644
--- a/memory_replay/VerifyTrace.cpp
+++ b/memory_replay/VerifyTrace.cpp
@@ -18,6 +18,7 @@
#include <getopt.h>
#include <inttypes.h>
#include <stdio.h>
+#include <unistd.h>
#include <string>
#include <unordered_map>
@@ -30,36 +31,37 @@
#include "File.h"
static void Usage() {
- fprintf(stderr, "Usage: %s [--attempt_recovery] TRACE_FILE1 TRACE_FILE2 ...\n",
+ fprintf(stderr, "Usage: %s [--attempt_repair] TRACE_FILE1 TRACE_FILE2 ...\n",
android::base::Basename(android::base::GetExecutablePath()).c_str());
- fprintf(stderr, " --attempt_recovery\n");
- fprintf(stderr, " If a trace file has some errors, try to fix it. The new\n");
+ fprintf(stderr, " --attempt_repair\n");
+ fprintf(stderr, " If a trace file has some errors, try to fix them. The new\n");
fprintf(stderr, " file will be named TRACE_FILE.repair\n");
fprintf(stderr, " TRACE_FILE1 TRACE_FILE2 ...\n");
fprintf(stderr, " The trace files to verify\n");
- fprintf(stderr, "\n Print a trace to stdout.\n");
+ fprintf(stderr, "\n Verify trace are valid.\n");
exit(1);
}
-static bool WriteRepairEntries(const char* trace_file, memory_trace::Entry* entries,
+static bool WriteRepairEntries(const std::string& repair_file, memory_trace::Entry* entries,
size_t num_entries) {
- printf("Attempting to reapir trace_file %s\n", trace_file);
- std::string repair_file(std::string(trace_file) + ".repair");
- int fd = open(repair_file.c_str(), O_WRONLY | O_CREAT | O_CLOEXEC, 0644);
+ int fd = open(repair_file.c_str(), O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, 0644);
if (fd == -1) {
- printf("Failed to create repair file %s: %s\n", repair_file.c_str(), strerror(errno));
+ printf(" Failed to create repair file %s: %s\n", repair_file.c_str(), strerror(errno));
return false;
}
+ bool valid = true;
for (size_t i = 0; i < num_entries; i++) {
if (!memory_trace::WriteEntryToFd(fd, entries[i])) {
- printf("Failed to write entry to file:\n");
- close(fd);
- return false;
+ printf(" Failed to write entry to file:\n");
+ valid = false;
+ break;
}
}
close(fd);
- printf("Attempt to repair trace has succeeded, new trace %s\n", repair_file.c_str());
- return true;
+ if (!valid) {
+ unlink(repair_file.c_str());
+ }
+ return valid;
}
static void VerifyTrace(const char* trace_file, bool attempt_repair) {
@@ -69,9 +71,10 @@
size_t num_entries;
GetUnwindInfo(trace_file, &entries, &num_entries);
- bool found_error = false;
- bool error_repaired = false;
+ size_t errors_found = 0;
+ size_t errors_repaired = 0;
std::unordered_map<uint64_t, std::pair<memory_trace::Entry*, size_t>> live_ptrs;
+ std::pair<memory_trace::Entry*, size_t> erased(nullptr, 0);
for (size_t i = 0; i < num_entries; i++) {
memory_trace::Entry* entry = &entries[i];
@@ -90,32 +93,38 @@
}
if (entry->u.old_ptr != 0) {
// Verify old pointer
- auto old_entry = live_ptrs.find(entry->u.old_ptr);
- if (old_entry == live_ptrs.end()) {
- printf(" Line %zu: freeing of unknown ptr 0x%" PRIx64 "\n", i + 1, entry->u.old_ptr);
- printf(" %s\n", memory_trace::CreateStringFromEntry(*entry).c_str());
- found_error = true;
- if (attempt_repair) {
- printf(" Unable to repair this failure.\n");
+ auto entry_iter = live_ptrs.find(entry->u.old_ptr);
+ if (entry_iter == live_ptrs.end()) {
+ // Verify the pointer didn't get realloc'd to itself.
+ if (entry->u.old_ptr != entry->ptr) {
+ printf(" Line %zu: freeing of unknown ptr 0x%" PRIx64 "\n", i + 1, entry->u.old_ptr);
+ printf(" %s\n", memory_trace::CreateStringFromEntry(*entry).c_str());
+ errors_found++;
+ if (attempt_repair) {
+ printf(" Unable to repair this failure.\n");
+ }
}
} else {
- live_ptrs.erase(old_entry);
+ if (attempt_repair) {
+ erased = entry_iter->second;
+ }
+ live_ptrs.erase(entry_iter);
}
}
break;
case memory_trace::FREE:
if (entry->ptr != 0) {
// Verify pointer is present.
- auto old_entry = live_ptrs.find(entry->ptr);
- if (old_entry == live_ptrs.end()) {
+ auto entry_iter = live_ptrs.find(entry->ptr);
+ if (entry_iter == live_ptrs.end()) {
printf(" Line %zu: freeing of unknown ptr 0x%" PRIx64 "\n", i + 1, entry->ptr);
printf(" %s\n", memory_trace::CreateStringFromEntry(*entry).c_str());
- found_error = true;
+ errors_found++;
if (attempt_repair) {
printf(" Unable to repair this failure.\n");
}
} else {
- live_ptrs.erase(old_entry);
+ live_ptrs.erase(entry_iter);
}
}
break;
@@ -126,30 +135,44 @@
if (ptr != 0) {
auto old_entry = live_ptrs.find(ptr);
if (old_entry != live_ptrs.end()) {
- printf(" Line %zu: duplicate ptr 0x%" PRIx64 " previously found at line %" PRId64 "\n",
- i + 1, ptr, old_entry->second.second);
- printf(" Original entry:\n");
- printf(" %s\n", memory_trace::CreateStringFromEntry(*entry).c_str());
- printf(" Duplicate pointer entry:\n");
+ printf(" Line %zu: duplicate ptr 0x%" PRIx64 "\n", i + 1, ptr);
+ printf(" Original entry at line %zu:\n", old_entry->second.second);
printf(" %s\n", memory_trace::CreateStringFromEntry(*old_entry->second.first).c_str());
- found_error = true;
+ printf(" Duplicate entry at line %zu:\n", i + 1);
+ printf(" %s\n", memory_trace::CreateStringFromEntry(*entry).c_str());
+ errors_found++;
if (attempt_repair) {
// There is a small chance of a race where the same pointer is returned
// in two different threads before the free is recorded. If this occurs,
// the way to repair is to search forward for the free of the pointer and
// swap the two entries.
- error_repaired = false;
+ bool fixed = false;
for (size_t j = i + 1; j < num_entries; j++) {
- if (entries[j].type == memory_trace::FREE && entries[j].ptr == ptr) {
- memory_trace::Entry alloc_entry = *entry;
+ if ((entries[j].type == memory_trace::FREE && entries[j].ptr == ptr) ||
+ (entries[j].type == memory_trace::REALLOC && entries[j].u.old_ptr == ptr)) {
+ memory_trace::Entry tmp_entry = *entry;
*entry = entries[j];
- entries[j] = alloc_entry;
- error_repaired = true;
+ entries[j] = tmp_entry;
+ errors_repaired++;
live_ptrs.erase(old_entry);
+ if (entry->type == memory_trace::REALLOC) {
+ if (entry->ptr != 0) {
+ // Need to add the newly allocated pointer.
+ live_ptrs[entry->ptr] = std::make_pair(entry, i + 1);
+ }
+ if (erased.first != nullptr) {
+ // Need to put the erased old ptr back.
+ live_ptrs[tmp_entry.u.old_ptr] = erased;
+ }
+ }
+ fixed = true;
break;
}
}
+ if (!fixed) {
+ printf(" Unable to fix error.\n");
+ }
}
} else {
live_ptrs[ptr] = std::make_pair(entry, i + 1);
@@ -157,18 +180,22 @@
}
}
- if (found_error) {
+ if (errors_found != 0) {
printf("Trace %s is not valid.\n", trace_file);
if (attempt_repair) {
- if (error_repaired) {
- // Save the repaired data out to a file.
- if (!WriteRepairEntries(trace_file, entries, num_entries)) {
- printf("Failed to write repaired entries to a file.\n");
- }
+ // Save the repaired data out to a file.
+ std::string repair_file(std::string(trace_file) + ".repair");
+ printf("Creating repaired trace file %s...\n", repair_file.c_str());
+ if (!WriteRepairEntries(repair_file, entries, num_entries)) {
+ printf("Failed trying to write repaired entries to file.\n");
+ } else if (errors_repaired == errors_found) {
+ printf("Repaired file is complete, no more errors.\n");
} else {
- printf("Attempt to repair trace has failed.\n");
+ printf("Repaired file is still not valid.\n");
}
}
+ } else if (attempt_repair) {
+ printf("Trace %s is valid, no repair needed.\n", trace_file);
} else {
printf("Trace %s is valid.\n", trace_file);
}
@@ -183,17 +210,22 @@
};
int option_index = 0;
int opt = getopt_long(argc, argv, "", options, &option_index);
+ if (argc == 1 || (argc == 2 && opt != -1)) {
+ fprintf(stderr, "Requires at least one TRACE_FILE\n");
+ Usage();
+ }
+
bool attempt_repair = false;
if (opt == 'a') {
attempt_repair = true;
} else if (opt != -1) {
Usage();
- } else if (optind == argc) {
- fprintf(stderr, "Requires at least one TRACE_FILE\n");
- Usage();
}
- for (int i = optind; i < argc; i++) {
+ for (int i = 1; i < argc; i++) {
+ if (i + 1 == optind) {
+ continue;
+ }
VerifyTrace(argv[i], attempt_repair);
}