Merge "Fix google-explicit-constructor warnings."
diff --git a/fastboot/engine.cpp b/fastboot/engine.cpp
index 47567c0..db5d0e0 100644
--- a/fastboot/engine.cpp
+++ b/fastboot/engine.cpp
@@ -351,21 +351,21 @@
}
if (a->op == OP_DOWNLOAD) {
status = fb_download_data(transport, a->data, a->size);
- status = a->func(a, status, status ? fb_get_error() : "");
+ status = a->func(a, status, status ? fb_get_error().c_str() : "");
if (status) break;
} else if (a->op == OP_COMMAND) {
status = fb_command(transport, a->cmd);
- status = a->func(a, status, status ? fb_get_error() : "");
+ status = a->func(a, status, status ? fb_get_error().c_str() : "");
if (status) break;
} else if (a->op == OP_QUERY) {
status = fb_command_response(transport, a->cmd, resp);
- status = a->func(a, status, status ? fb_get_error() : resp);
+ status = a->func(a, status, status ? fb_get_error().c_str() : resp);
if (status) break;
} else if (a->op == OP_NOTICE) {
fprintf(stderr,"%s\n",(char*)a->data);
} else if (a->op == OP_DOWNLOAD_SPARSE) {
status = fb_download_data_sparse(transport, reinterpret_cast<sparse_file*>(a->data));
- status = a->func(a, status, status ? fb_get_error() : "");
+ status = a->func(a, status, status ? fb_get_error().c_str() : "");
if (status) break;
} else if (a->op == OP_WAIT_FOR_DISCONNECT) {
transport->WaitForDisconnect();
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index fa8f19a..94efcc3 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -49,6 +49,7 @@
#include <android-base/parseint.h>
#include <android-base/parsenetaddress.h>
+#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <sparse/sparse.h>
#include <ziparchive/zip_archive.h>
@@ -108,12 +109,9 @@
{"vendor.img", "vendor.sig", "vendor", true},
};
-static char* find_item(const char* item, const char* product) {
- char *dir;
+static std::string find_item(const char* item, const char* product) {
const char *fn;
- char path[PATH_MAX + 128];
-
- if(!strcmp(item,"boot")) {
+ if (!strcmp(item,"boot")) {
fn = "boot.img";
} else if(!strcmp(item,"recovery")) {
fn = "recovery.img";
@@ -129,24 +127,22 @@
fn = "android-info.txt";
} else {
fprintf(stderr,"unknown partition '%s'\n", item);
- return 0;
+ return "";
}
- if(product) {
- get_my_path(path);
- sprintf(path + strlen(path),
- "../../../target/product/%s/%s", product, fn);
- return strdup(path);
+ if (product) {
+ std::string path = get_my_path();
+ path.erase(path.find_last_of('/'));
+ return android::base::StringPrintf("%s/../../../target/product/%s/%s",
+ path.c_str(), product, fn);
}
- dir = getenv("ANDROID_PRODUCT_OUT");
- if((dir == 0) || (dir[0] == 0)) {
+ char* dir = getenv("ANDROID_PRODUCT_OUT");
+ if (dir == nullptr || dir[0] == '\0') {
die("neither -p product specified nor ANDROID_PRODUCT_OUT set");
- return 0;
}
- sprintf(path, "%s/%s", dir, fn);
- return strdup(path);
+ return android::base::StringPrintf("%s/%s", dir, fn);
}
static int64_t get_file_size(int fd) {
@@ -179,8 +175,8 @@
return 0;
}
-static void* load_file(const char* fn, int64_t* sz) {
- int fd = open(fn, O_RDONLY | O_BINARY);
+static void* load_file(const std::string& path, int64_t* sz) {
+ int fd = open(path.c_str(), O_RDONLY | O_BINARY);
if (fd == -1) return nullptr;
return load_fd(fd, sz);
}
@@ -964,18 +960,19 @@
CloseArchive(zip);
}
-static void do_send_signature(char* fn) {
- char* xtn = strrchr(fn, '.');
- if (!xtn) return;
+static void do_send_signature(const char* filename) {
+ if (android::base::EndsWith(filename, ".img") == false) {
+ return;
+ }
- if (strcmp(xtn, ".img")) return;
-
- strcpy(xtn, ".sig");
+ std::string sig_path = filename;
+ sig_path.erase(sig_path.size() - 4);
+ sig_path += ".sig";
int64_t sz;
- void* data = load_file(fn, &sz);
- strcpy(xtn, ".img");
+ void* data = load_file(sig_path, &sz);
if (data == nullptr) return;
+
fb_queue_download("signature", data, sz);
fb_queue_command("signature", "installing signature");
}
@@ -985,8 +982,8 @@
fb_queue_query_save("product", cur_product, sizeof(cur_product));
- char* fname = find_item("info", product);
- if (fname == nullptr) die("cannot find android-info.txt");
+ std::string fname = find_item("info", product);
+ if (fname.empty()) die("cannot find android-info.txt");
int64_t sz;
void* data = load_file(fname, &sz);
@@ -997,14 +994,14 @@
for (size_t i = 0; i < ARRAY_SIZE(images); i++) {
fname = find_item(images[i].part_name, product);
fastboot_buffer buf;
- if (load_buf(transport, fname, &buf)) {
+ if (load_buf(transport, fname.c_str(), &buf)) {
if (images[i].is_optional)
continue;
die("could not load %s\n", images[i].img_name);
}
auto flashall = [&](const std::string &partition) {
- do_send_signature(fname);
+ do_send_signature(fname.c_str());
if (erase_first && needs_erase(transport, partition.c_str())) {
fb_queue_erase(partition.c_str());
}
@@ -1180,7 +1177,7 @@
fprintf(stderr, "Erase successful, but not automatically formatting.\n");
if (errMsg) fprintf(stderr, "%s", errMsg);
}
- fprintf(stderr,"FAILED (%s)\n", fb_get_error());
+ fprintf(stderr, "FAILED (%s)\n", fb_get_error().c_str());
}
int main(int argc, char **argv)
@@ -1441,8 +1438,8 @@
fb_queue_download("boot.img", data, sz);
fb_queue_command("boot", "booting");
} else if(!strcmp(*argv, "flash")) {
- char *pname = argv[1];
- char *fname = 0;
+ char* pname = argv[1];
+ std::string fname;
require(2);
if (argc > 2) {
fname = argv[2];
@@ -1451,13 +1448,13 @@
fname = find_item(pname, product);
skip(2);
}
- if (fname == 0) die("cannot determine image filename for '%s'", pname);
+ if (fname.empty()) die("cannot determine image filename for '%s'", pname);
auto flash = [&](const std::string &partition) {
if (erase_first && needs_erase(transport, partition.c_str())) {
fb_queue_erase(partition.c_str());
}
- do_flash(transport, partition.c_str(), fname);
+ do_flash(transport, partition.c_str(), fname.c_str());
};
do_for_partitions(transport, pname, slot_override.c_str(), flash, true);
} else if(!strcmp(*argv, "flash:raw")) {
diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h
index 1932bab..c2ea551 100644
--- a/fastboot/fastboot.h
+++ b/fastboot/fastboot.h
@@ -43,7 +43,7 @@
int fb_command_response(Transport* transport, const char* cmd, char* response);
int fb_download_data(Transport* transport, const void* data, uint32_t size);
int fb_download_data_sparse(Transport* transport, struct sparse_file* s);
-char *fb_get_error(void);
+const std::string fb_get_error();
#define FB_COMMAND_SZ 64
#define FB_RESPONSE_SZ 64
@@ -72,7 +72,7 @@
char *mkmsg(const char *fmt, ...);
__attribute__((__noreturn__)) void die(const char *fmt, ...);
-void get_my_path(char *path);
+std::string get_my_path();
/* Current product */
extern char cur_product[FB_RESPONSE_SZ + 1];
diff --git a/fastboot/protocol.cpp b/fastboot/protocol.cpp
index 1785b76..bfa83b0 100644
--- a/fastboot/protocol.cpp
+++ b/fastboot/protocol.cpp
@@ -36,16 +36,16 @@
#include <algorithm>
+#include <android-base/stringprintf.h>
#include <sparse/sparse.h>
#include "fastboot.h"
#include "transport.h"
-static char ERROR[128];
+static std::string g_error;
-char *fb_get_error(void)
-{
- return ERROR;
+const std::string fb_get_error() {
+ return g_error;
}
static int check_response(Transport* transport, uint32_t size, char* response) {
@@ -54,14 +54,14 @@
while (true) {
int r = transport->Read(status, 64);
if (r < 0) {
- snprintf(ERROR, sizeof(ERROR), "status read failed (%s)", strerror(errno));
+ g_error = android::base::StringPrintf("status read failed (%s)", strerror(errno));
transport->Close();
return -1;
}
status[r] = 0;
if (r < 4) {
- snprintf(ERROR, sizeof(ERROR), "status malformed (%d bytes)", r);
+ g_error = android::base::StringPrintf("status malformed (%d bytes)", r);
transport->Close();
return -1;
}
@@ -80,9 +80,9 @@
if (!memcmp(status, "FAIL", 4)) {
if (r > 4) {
- snprintf(ERROR, sizeof(ERROR), "remote: %s", status + 4);
+ g_error = android::base::StringPrintf("remote: %s", status + 4);
} else {
- strcpy(ERROR, "remote failure");
+ g_error = "remote failure";
}
return -1;
}
@@ -90,14 +90,14 @@
if (!memcmp(status, "DATA", 4) && size > 0){
uint32_t dsize = strtol(status + 4, 0, 16);
if (dsize > size) {
- strcpy(ERROR, "data size too large");
+ g_error = android::base::StringPrintf("data size too large (%d)", dsize);
transport->Close();
return -1;
}
return dsize;
}
- strcpy(ERROR,"unknown status code");
+ g_error = "unknown status code";
transport->Close();
break;
}
@@ -108,7 +108,7 @@
static int _command_start(Transport* transport, const char* cmd, uint32_t size, char* response) {
size_t cmdsize = strlen(cmd);
if (cmdsize > 64) {
- snprintf(ERROR, sizeof(ERROR), "command too large");
+ g_error = android::base::StringPrintf("command too large (%zu)", cmdsize);
return -1;
}
@@ -117,7 +117,7 @@
}
if (transport->Write(cmd, cmdsize) != static_cast<int>(cmdsize)) {
- snprintf(ERROR, sizeof(ERROR), "command write failed (%s)", strerror(errno));
+ g_error = android::base::StringPrintf("command write failed (%s)", strerror(errno));
transport->Close();
return -1;
}
@@ -128,12 +128,12 @@
static int _command_data(Transport* transport, const void* data, uint32_t size) {
int r = transport->Write(data, size);
if (r < 0) {
- snprintf(ERROR, sizeof(ERROR), "data transfer failure (%s)", strerror(errno));
+ g_error = android::base::StringPrintf("data transfer failure (%s)", strerror(errno));
transport->Close();
return -1;
}
if (r != ((int) size)) {
- snprintf(ERROR, sizeof(ERROR), "data transfer failure (short transfer)");
+ g_error = "data transfer failure (short transfer)";
transport->Close();
return -1;
}
@@ -216,7 +216,7 @@
if (len > TRANSPORT_BUF_SIZE) {
if (transport_buf_len > 0) {
- snprintf(ERROR, sizeof(ERROR), "internal error: transport_buf not empty\n");
+ g_error = "internal error: transport_buf not empty";
return -1;
}
to_write = round_down(len, TRANSPORT_BUF_SIZE);
@@ -230,7 +230,7 @@
if (len > 0) {
if (len > TRANSPORT_BUF_SIZE) {
- snprintf(ERROR, sizeof(ERROR), "internal error: too much left for transport_buf\n");
+ g_error = "internal error: too much left for transport_buf";
return -1;
}
memcpy(transport_buf, ptr, len);
diff --git a/fastboot/util_linux.cpp b/fastboot/util_linux.cpp
index b788199..2c6aedb 100644
--- a/fastboot/util_linux.cpp
+++ b/fastboot/util_linux.cpp
@@ -28,27 +28,16 @@
#include "fastboot.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <fcntl.h>
#include <unistd.h>
#include <limits.h>
-void get_my_path(char *path)
-{
- char proc[64];
- char *x;
+#include <android-base/stringprintf.h>
- sprintf(proc, "/proc/%d/exe", getpid());
- int err = readlink(proc, path, PATH_MAX - 1);
-
- if(err <= 0) {
- path[0] = 0;
- } else {
- path[err] = 0;
- x = strrchr(path,'/');
- if(x) x[1] = 0;
- }
+std::string get_my_path() {
+ std::string proc = android::base::StringPrintf("/proc/%d/exe", getpid());
+ char path[PATH_MAX + 1];
+ int rc = readlink(proc.c_str(), path, sizeof(path) - 1);
+ if (rc == -1) return "";
+ path[rc] = '\0';
+ return path;
}
diff --git a/fastboot/util_osx.cpp b/fastboot/util_osx.cpp
index ae0b024..4bae7c4 100644
--- a/fastboot/util_osx.cpp
+++ b/fastboot/util_osx.cpp
@@ -31,19 +31,15 @@
#import <Carbon/Carbon.h>
#include <unistd.h>
-void get_my_path(char s[PATH_MAX])
-{
+std::string get_my_path() {
CFBundleRef mainBundle = CFBundleGetMainBundle();
CFURLRef executableURL = CFBundleCopyExecutableURL(mainBundle);
CFStringRef executablePathString = CFURLCopyFileSystemPath(executableURL, kCFURLPOSIXPathStyle);
CFRelease(executableURL);
- CFStringGetFileSystemRepresentation(executablePathString, s, PATH_MAX-1);
+ char path[PATH_MAX + 1];
+ CFStringGetFileSystemRepresentation(executablePathString, path, sizeof(PATH_MAX)-1);
CFRelease(executablePathString);
- char *x;
- x = strrchr(s, '/');
- if(x) x[1] = 0;
+ return path;
}
-
-
diff --git a/fastboot/util_windows.cpp b/fastboot/util_windows.cpp
index ec52f39..3b22c55 100644
--- a/fastboot/util_windows.cpp
+++ b/fastboot/util_windows.cpp
@@ -38,14 +38,12 @@
#include <windows.h>
-void get_my_path(char exe[PATH_MAX])
-{
- char* r;
+std::string get_my_path() {
+ char path[PATH_MAX + 1];
- GetModuleFileName( NULL, exe, PATH_MAX-1 );
- exe[PATH_MAX-1] = 0;
- r = strrchr( exe, '\\' );
- if (r)
- *r = 0;
+ DWORD result = GetModuleFileName(NULL, path, sizeof(path) - 1);
+ if (result == 0 || result == sizeof(path) - 1) return "";
+ path[PATH_MAX - 1] = 0;
+
+ return path;
}
-
diff --git a/init/devices.cpp b/init/devices.cpp
index e74140b..d452dd3 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -244,7 +244,11 @@
mode = get_device_perm(path, links, &uid, &gid) | (block ? S_IFBLK : S_IFCHR);
- selabel_lookup_best_match(sehandle, &secontext, path, links, mode);
+ if (selabel_lookup_best_match(sehandle, &secontext, path, links, mode)) {
+ ERROR("Device '%s' not created; cannot find SELinux label (%s)\n",
+ path, strerror(errno));
+ return;
+ }
setfscreatecon(secontext);
dev = makedev(major, minor);
@@ -254,14 +258,19 @@
* racy. Fixing the gid race at least fixed the issue with system_server
* opening dynamic input devices under the AID_INPUT gid. */
setegid(gid);
- mknod(path, mode, dev);
+ /* If the node already exists update its SELinux label to handle cases when
+ * it was created with the wrong context during coldboot procedure. */
+ if (mknod(path, mode, dev) && (errno == EEXIST)) {
+ if (lsetfilecon(path, secontext)) {
+ ERROR("Cannot set '%s' SELinux label on '%s' device (%s)\n",
+ secontext, path, strerror(errno));
+ }
+ }
chown(path, uid, -1);
setegid(AID_ROOT);
- if (secontext) {
- freecon(secontext);
- setfscreatecon(NULL);
- }
+ freecon(secontext);
+ setfscreatecon(NULL);
}
static void add_platform_device(const char *path)
diff --git a/liblog/event_tag_map.c b/liblog/event_tag_map.c
index 64d872a..3cb04cf 100644
--- a/liblog/event_tag_map.c
+++ b/liblog/event_tag_map.c
@@ -73,7 +73,7 @@
if (newTagMap == NULL)
return NULL;
- fd = open(fileName, O_RDONLY);
+ fd = open(fileName, O_RDONLY | O_CLOEXEC);
if (fd < 0) {
fprintf(stderr, "%s: unable to open map '%s': %s\n",
OUT_TAG, fileName, strerror(errno));
diff --git a/liblog/logd_reader.c b/liblog/logd_reader.c
index d844104..b894349 100644
--- a/liblog/logd_reader.c
+++ b/liblog/logd_reader.c
@@ -85,7 +85,7 @@
.clear = logdClear,
.getSize = logdGetSize,
.setSize = logdSetSize,
- .getReadableSize = logdGetSize,
+ .getReadableSize = logdGetReadableSize,
.getPrune = logdGetPrune,
.setPrune = logdSetPrune,
.getStats = logdGetStats,
diff --git a/liblog/logprint.c b/liblog/logprint.c
index 88afc14..59bd479 100644
--- a/liblog/logprint.c
+++ b/liblog/logprint.c
@@ -1043,7 +1043,7 @@
* Anything in the Android Logger before the dmesg logging span will
* be highly suspect regarding the monotonic time calculations.
*/
- FILE *p = popen("/system/bin/dmesg", "r");
+ FILE *p = popen("/system/bin/dmesg", "re");
if (p) {
char *line = NULL;
size_t len = 0;
diff --git a/liblog/pmsg_reader.c b/liblog/pmsg_reader.c
index 5695e8a..f5e91c8 100644
--- a/liblog/pmsg_reader.c
+++ b/liblog/pmsg_reader.c
@@ -151,13 +151,13 @@
memset(log_msg, 0, sizeof(*log_msg));
if (transp->context.fd <= 0) {
- int fd = open("/sys/fs/pstore/pmsg-ramoops-0", O_RDONLY);
+ int fd = open("/sys/fs/pstore/pmsg-ramoops-0", O_RDONLY | O_CLOEXEC);
if (fd < 0) {
return -errno;
}
if (fd == 0) { /* Argggg */
- fd = open("/sys/fs/pstore/pmsg-ramoops-0", O_RDONLY);
+ fd = open("/sys/fs/pstore/pmsg-ramoops-0", O_RDONLY | O_CLOEXEC);
close(0);
if (fd < 0) {
return -errno;
diff --git a/liblog/pmsg_writer.c b/liblog/pmsg_writer.c
index 9cd3c48..2ba31fa 100644
--- a/liblog/pmsg_writer.c
+++ b/liblog/pmsg_writer.c
@@ -54,7 +54,7 @@
static int pmsgOpen()
{
if (pmsgLoggerWrite.context.fd < 0) {
- pmsgLoggerWrite.context.fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY));
+ pmsgLoggerWrite.context.fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY | O_CLOEXEC));
}
return pmsgLoggerWrite.context.fd;
diff --git a/libmemunreachable/HeapWalker.cpp b/libmemunreachable/HeapWalker.cpp
index 19393ec..62366f2 100644
--- a/libmemunreachable/HeapWalker.cpp
+++ b/libmemunreachable/HeapWalker.cpp
@@ -14,7 +14,10 @@
* limitations under the License.
*/
+#include <errno.h>
#include <inttypes.h>
+#include <sys/mman.h>
+#include <unistd.h>
#include <map>
#include <utility>
@@ -22,6 +25,7 @@
#include "Allocator.h"
#include "HeapWalker.h"
#include "LeakFolding.h"
+#include "ScopedSignalHandler.h"
#include "log.h"
bool HeapWalker::Allocation(uintptr_t begin, uintptr_t end) {
@@ -37,18 +41,26 @@
return true;
} else {
Range overlap = inserted.first->first;
- ALOGE("range %p-%p overlaps with existing range %p-%p",
- reinterpret_cast<void*>(begin),
- reinterpret_cast<void*>(end),
- reinterpret_cast<void*>(overlap.begin),
- reinterpret_cast<void*>(overlap.end));
+ if (overlap != range) {
+ ALOGE("range %p-%p overlaps with existing range %p-%p",
+ reinterpret_cast<void*>(begin),
+ reinterpret_cast<void*>(end),
+ reinterpret_cast<void*>(overlap.begin),
+ reinterpret_cast<void*>(overlap.end));
+ }
return false;
}
}
-bool HeapWalker::IsAllocationPtr(uintptr_t ptr, Range* range, AllocationInfo** info) {
- if (ptr >= valid_allocations_range_.begin && ptr < valid_allocations_range_.end) {
- AllocationMap::iterator it = allocations_.find(Range{ptr, ptr + 1});
+bool HeapWalker::WordContainsAllocationPtr(uintptr_t word_ptr, Range* range, AllocationInfo** info) {
+ walking_ptr_ = word_ptr;
+ // This access may segfault if the process under test has done something strange,
+ // for example mprotect(PROT_NONE) on a native heap page. If so, it will be
+ // caught and handled by mmaping a zero page over the faulting page.
+ uintptr_t value = *reinterpret_cast<uintptr_t*>(word_ptr);
+ walking_ptr_ = 0;
+ if (value >= valid_allocations_range_.begin && value < valid_allocations_range_.end) {
+ AllocationMap::iterator it = allocations_.find(Range{value, value + 1});
if (it != allocations_.end()) {
*range = it->first;
*info = &it->second;
@@ -135,3 +147,30 @@
return true;
}
+
+static bool MapOverPage(void* addr) {
+ const size_t page_size = sysconf(_SC_PAGE_SIZE);
+ void *page = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(addr) & ~(page_size-1));
+
+ void* ret = mmap(page, page_size, PROT_READ, MAP_ANONYMOUS|MAP_PRIVATE|MAP_FIXED, -1, 0);
+ if (ret == MAP_FAILED) {
+ ALOGE("failed to map page at %p: %s", page, strerror(errno));
+ return false;
+ }
+
+ return true;
+}
+
+void HeapWalker::HandleSegFault(ScopedSignalHandler& handler, int signal, siginfo_t* si, void* /*uctx*/) {
+ uintptr_t addr = reinterpret_cast<uintptr_t>(si->si_addr);
+ if (addr != walking_ptr_) {
+ handler.reset();
+ return;
+ }
+ ALOGW("failed to read page at %p, signal %d", si->si_addr, signal);
+ if (!MapOverPage(si->si_addr)) {
+ handler.reset();
+ }
+}
+
+ScopedSignalHandler::SignalFn ScopedSignalHandler::handler_;
diff --git a/libmemunreachable/HeapWalker.h b/libmemunreachable/HeapWalker.h
index 7b851c4..3c1b513 100644
--- a/libmemunreachable/HeapWalker.h
+++ b/libmemunreachable/HeapWalker.h
@@ -17,9 +17,12 @@
#ifndef LIBMEMUNREACHABLE_HEAP_WALKER_H_
#define LIBMEMUNREACHABLE_HEAP_WALKER_H_
+#include <signal.h>
+
#include "android-base/macros.h"
#include "Allocator.h"
+#include "ScopedSignalHandler.h"
#include "Tarjan.h"
// A range [begin, end)
@@ -28,6 +31,12 @@
uintptr_t end;
size_t size() const { return end - begin; };
+ bool operator==(const Range& other) const {
+ return this->begin == other.begin && this->end == other.end;
+ }
+ bool operator!=(const Range& other) const {
+ return !(*this == other);
+ }
};
// Comparator for Ranges that returns equivalence for overlapping ranges
@@ -41,10 +50,17 @@
public:
HeapWalker(Allocator<HeapWalker> allocator) : allocator_(allocator),
allocations_(allocator), allocation_bytes_(0),
- roots_(allocator), root_vals_(allocator) {
+ roots_(allocator), root_vals_(allocator),
+ segv_handler_(allocator), walking_ptr_(0) {
valid_allocations_range_.end = 0;
valid_allocations_range_.begin = ~valid_allocations_range_.end;
+
+ segv_handler_.install(SIGSEGV,
+ [=](ScopedSignalHandler& handler, int signal, siginfo_t* siginfo, void* uctx) {
+ this->HandleSegFault(handler, signal, siginfo, uctx);
+ });
}
+
~HeapWalker() {}
bool Allocation(uintptr_t begin, uintptr_t end);
void Root(uintptr_t begin, uintptr_t end);
@@ -70,7 +86,8 @@
private:
void RecurseRoot(const Range& root);
- bool IsAllocationPtr(uintptr_t ptr, Range* range, AllocationInfo** info);
+ bool WordContainsAllocationPtr(uintptr_t ptr, Range* range, AllocationInfo** info);
+ void HandleSegFault(ScopedSignalHandler&, int, siginfo_t*, void*);
DISALLOW_COPY_AND_ASSIGN(HeapWalker);
Allocator<HeapWalker> allocator_;
@@ -81,6 +98,9 @@
allocator::vector<Range> roots_;
allocator::vector<uintptr_t> root_vals_;
+
+ ScopedSignalHandler segv_handler_;
+ uintptr_t walking_ptr_;
};
template<class F>
@@ -92,7 +112,7 @@
for (uintptr_t i = begin; i < range.end; i += sizeof(uintptr_t)) {
Range ref_range;
AllocationInfo* ref_info;
- if (IsAllocationPtr(*reinterpret_cast<uintptr_t*>(i), &ref_range, &ref_info)) {
+ if (WordContainsAllocationPtr(i, &ref_range, &ref_info)) {
f(ref_range, ref_info);
}
}
diff --git a/libmemunreachable/ScopedSignalHandler.h b/libmemunreachable/ScopedSignalHandler.h
new file mode 100644
index 0000000..e006d43
--- /dev/null
+++ b/libmemunreachable/ScopedSignalHandler.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LIBMEMUNREACHABLE_SCOPED_SIGNAL_HANDLER_H_
+#define LIBMEMUNREACHABLE_SCOPED_SIGNAL_HANDLER_H_
+
+#include <errno.h>
+#include <signal.h>
+
+#include <functional>
+
+#include "android-base/macros.h"
+
+#include "log.h"
+
+class ScopedSignalHandler {
+ public:
+ using Fn = std::function<void(ScopedSignalHandler&, int, siginfo_t*, void*)>;
+
+ ScopedSignalHandler(Allocator<Fn> allocator) : allocator_(allocator), signal_(-1) {}
+ ~ScopedSignalHandler() {
+ reset();
+ }
+
+ template <class F>
+ void install(int signal, F&& f) {
+ LOG_ALWAYS_FATAL_IF(signal_ != -1, "ScopedSignalHandler already installed");
+
+ handler_ = SignalFn(std::allocator_arg, allocator_,
+ [=](int signal, siginfo_t* si, void* uctx) {
+ f(*this, signal, si, uctx);
+ });
+
+ struct sigaction act{};
+ act.sa_sigaction = [](int signal, siginfo_t* si, void* uctx) {
+ handler_(signal, si, uctx);
+ };
+ act.sa_flags = SA_SIGINFO;
+
+ int ret = sigaction(signal, &act, &old_act_);
+ if (ret < 0) {
+ LOG_ALWAYS_FATAL("failed to install segfault handler: %s", strerror(errno));
+ }
+
+ signal_ = signal;
+ }
+
+ void reset() {
+ if (signal_ != -1) {
+ int ret = sigaction(signal_, &old_act_, NULL);
+ if (ret < 0) {
+ ALOGE("failed to uninstall segfault handler");
+ }
+ handler_ = SignalFn{};
+ signal_ = -1;
+ }
+ }
+
+
+ private:
+ using SignalFn = std::function<void(int, siginfo_t*, void*)>;
+ DISALLOW_COPY_AND_ASSIGN(ScopedSignalHandler);
+ Allocator<Fn> allocator_;
+ int signal_;
+ struct sigaction old_act_;
+ // TODO(ccross): to support multiple ScopedSignalHandlers handler_ would need
+ // to be a static map of signals to handlers, but allocated with Allocator.
+ static SignalFn handler_;
+};
+
+#endif // LIBMEMUNREACHABLE_SCOPED_SIGNAL_HANDLER_H_
diff --git a/libmemunreachable/tests/HeapWalker_test.cpp b/libmemunreachable/tests/HeapWalker_test.cpp
index c3e1c4d..98e4aa1 100644
--- a/libmemunreachable/tests/HeapWalker_test.cpp
+++ b/libmemunreachable/tests/HeapWalker_test.cpp
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+#include <sys/mman.h>
+#include <unistd.h>
+
#include "HeapWalker.h"
#include <gtest/gtest.h>
@@ -172,3 +175,27 @@
EXPECT_EQ(2*sizeof(uintptr_t), leaked_bytes);
ASSERT_EQ(2U, leaked.size());
}
+
+TEST_F(HeapWalkerTest, segv) {
+ const size_t page_size = sysconf(_SC_PAGE_SIZE);
+ void* buffer1 = mmap(NULL, page_size, PROT_NONE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+ ASSERT_NE(buffer1, nullptr);
+ void* buffer2;
+
+ buffer2 = &buffer1;
+
+ HeapWalker heap_walker(heap_);
+ heap_walker.Allocation(buffer_begin(buffer1), buffer_begin(buffer1)+page_size);
+ heap_walker.Root(buffer_begin(buffer2), buffer_end(buffer2));
+
+ ASSERT_EQ(true, heap_walker.DetectLeaks());
+
+ allocator::vector<Range> leaked(heap_);
+ size_t num_leaks = 0;
+ size_t leaked_bytes = 0;
+ ASSERT_EQ(true, heap_walker.Leaked(leaked, 100, &num_leaks, &leaked_bytes));
+
+ EXPECT_EQ(0U, num_leaks);
+ EXPECT_EQ(0U, leaked_bytes);
+ ASSERT_EQ(0U, leaked.size());
+}
diff --git a/logcat/tests/logcat_test.cpp b/logcat/tests/logcat_test.cpp
index 997e682..920d504 100644
--- a/logcat/tests/logcat_test.cpp
+++ b/logcat/tests/logcat_test.cpp
@@ -810,12 +810,14 @@
ASSERT_TRUE(NULL != (fp = popen(
"( trap exit HUP QUIT INT PIPE KILL ; sleep 6; echo DONE )&"
" logcat -b events -c 2>&1 ;"
+ " logcat -b events -g 2>&1 ;"
" logcat -v brief -b events 2>&1",
"r")));
char buffer[BIG_BUFFER];
int count = 0;
+ int minus_g = 0;
int signals = 0;
@@ -833,6 +835,50 @@
break;
}
+ int size, consumed, max, payload;
+ char size_mult[3], consumed_mult[3];
+ size = consumed = max = payload = 0;
+ if (6 == sscanf(buffer, "events: ring buffer is %d%2s (%d%2s consumed),"
+ " max entry is %db, max payload is %db",
+ &size, size_mult, &consumed, consumed_mult,
+ &max, &payload)) {
+ long full_size = size, full_consumed = consumed;
+
+ switch(size_mult[0]) {
+ case 'G':
+ full_size *= 1024;
+ /* FALLTHRU */
+ case 'M':
+ full_size *= 1024;
+ /* FALLTHRU */
+ case 'K':
+ full_size *= 1024;
+ /* FALLTHRU */
+ case 'b':
+ break;
+ }
+ switch(consumed_mult[0]) {
+ case 'G':
+ full_consumed *= 1024;
+ /* FALLTHRU */
+ case 'M':
+ full_consumed *= 1024;
+ /* FALLTHRU */
+ case 'K':
+ full_consumed *= 1024;
+ /* FALLTHRU */
+ case 'b':
+ break;
+ }
+ EXPECT_GT(full_size, full_consumed);
+ EXPECT_GT(full_size, max);
+ EXPECT_GT(max, payload);
+ EXPECT_GT(max, full_consumed);
+
+ ++minus_g;
+ continue;
+ }
+
++count;
int p;
@@ -861,6 +907,7 @@
pclose(fp);
EXPECT_LE(1, count);
+ EXPECT_EQ(1, minus_g);
EXPECT_EQ(1, signals);
}
diff --git a/toolbox/upstream-netbsd/include/util.h b/toolbox/upstream-netbsd/include/util.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/toolbox/upstream-netbsd/include/util.h