Merge "Break libdl.so and ld-android.so's dependency on libc.so."
diff --git a/libc/SECCOMP_BLACKLIST_APP.TXT b/libc/SECCOMP_BLACKLIST_APP.TXT
index 25542d6..66e24cb 100644
--- a/libc/SECCOMP_BLACKLIST_APP.TXT
+++ b/libc/SECCOMP_BLACKLIST_APP.TXT
@@ -28,6 +28,9 @@
#
# This file is processed by a python script named genseccomp.py.
+# Note: Some privileged syscalls are still needed in app process after fork before uid change,
+# including capset and setresuid.
+
# syscalls to modify IDs
int setgid:setgid32(gid_t) arm,x86
int setgid:setgid(gid_t) arm64,mips,mips64,x86_64
@@ -35,8 +38,6 @@
int setuid:setuid(uid_t) arm64,mips,mips64,x86_64
int setreuid:setreuid32(uid_t, uid_t) arm,x86
int setreuid:setreuid(uid_t, uid_t) arm64,mips,mips64,x86_64
-int setresuid:setresuid32(uid_t, uid_t, uid_t) arm,x86
-int setresuid:setresuid(uid_t, uid_t, uid_t) arm64,mips,mips64,x86_64
int setresgid:setresgid32(gid_t, gid_t, gid_t) arm,x86
int setresgid:setresgid(gid_t, gid_t, gid_t) arm64,mips,mips64,x86_64
int setfsgid(gid_t) all
@@ -52,8 +53,6 @@
int acct(const char* filepath) all
int klogctl:syslog(int, char*, int) all
-
-int capset(cap_user_header_t header, const cap_user_data_t data) all
int chroot(const char*) all
# syscalls to change machine various configurations
diff --git a/libc/dns/include/resolv_params.h b/libc/dns/include/resolv_params.h
index 1b9d433..3c07d8a 100644
--- a/libc/dns/include/resolv_params.h
+++ b/libc/dns/include/resolv_params.h
@@ -34,6 +34,10 @@
* servers.
*/
+/* If EDNS0_PADDING is defined, queries will be padded to a multiple of this length
+when EDNS0 is active. */
+#define EDNS0_PADDING 128
+
/* per-netid configuration parameters passed from netd to the resolver */
struct __res_params {
uint16_t sample_validity; // sample lifetime in s
diff --git a/libc/dns/resolv/res_mkquery.c b/libc/dns/resolv/res_mkquery.c
index c73d588..1b4c4af 100644
--- a/libc/dns/resolv/res_mkquery.c
+++ b/libc/dns/resolv/res_mkquery.c
@@ -269,8 +269,28 @@
}
ns_put16(flags, cp);
cp += INT16SZ;
+#ifdef EDNS0_PADDING
+ {
+ u_int16_t minlen = (cp - buf) + 3 * INT16SZ;
+ u_int16_t extra = minlen % EDNS0_PADDING;
+ u_int16_t padlen = (EDNS0_PADDING - extra) % EDNS0_PADDING;
+ if (minlen > buflen) {
+ return (-1);
+ }
+ padlen = MIN(padlen, buflen - minlen);
+ ns_put16(padlen + 2 * INT16SZ, cp); /* RDLEN */
+ cp += INT16SZ;
+ ns_put16(NS_OPT_PADDING, cp); /* OPTION-CODE */
+ cp += INT16SZ;
+ ns_put16(padlen, cp); /* OPTION-LENGTH */
+ cp += INT16SZ;
+ memset(cp, 0, padlen);
+ cp += padlen;
+ }
+#else
ns_put16(0, cp); /* RDLEN */
cp += INT16SZ;
+#endif
hp->arcount = htons(ntohs(hp->arcount) + 1);
return (cp - buf);
diff --git a/libc/include/arpa/nameser.h b/libc/include/arpa/nameser.h
index ffb5250..e0b5c45 100644
--- a/libc/include/arpa/nameser.h
+++ b/libc/include/arpa/nameser.h
@@ -474,6 +474,7 @@
*/
#define NS_OPT_DNSSEC_OK 0x8000U
#define NS_OPT_NSID 3
+#define NS_OPT_PADDING 12
/*
* Inline versions of get/put short/long. Pointer is advanced.
diff --git a/libc/kernel/uapi/linux/ion.h b/libc/kernel/uapi/linux/ion.h
index 7b5b031..7c9e6d7 100644
--- a/libc/kernel/uapi/linux/ion.h
+++ b/libc/kernel/uapi/linux/ion.h
@@ -20,7 +20,6 @@
#define _UAPI_LINUX_ION_H
#include <linux/ioctl.h>
#include <linux/types.h>
-typedef int ion_user_handle_t;
enum ion_heap_type {
ION_HEAP_TYPE_SYSTEM,
ION_HEAP_TYPE_SYSTEM_CONTIG,
@@ -31,24 +30,12 @@
};
#define ION_NUM_HEAP_IDS (sizeof(unsigned int) * 8)
#define ION_FLAG_CACHED 1
-#define ION_FLAG_CACHED_NEEDS_SYNC 2
struct ion_allocation_data {
- size_t len;
- size_t align;
- unsigned int heap_id_mask;
- unsigned int flags;
- ion_user_handle_t handle;
-};
-struct ion_fd_data {
- ion_user_handle_t handle;
- int fd;
-};
-struct ion_handle_data {
- ion_user_handle_t handle;
-};
-struct ion_custom_data {
- unsigned int cmd;
- unsigned long arg;
+ __u64 len;
+ __u32 heap_id_mask;
+ __u32 flags;
+ __u32 fd;
+ __u32 unused;
};
#define MAX_HEAP_NAME 32
struct ion_heap_data {
@@ -68,11 +55,5 @@
};
#define ION_IOC_MAGIC 'I'
#define ION_IOC_ALLOC _IOWR(ION_IOC_MAGIC, 0, struct ion_allocation_data)
-#define ION_IOC_FREE _IOWR(ION_IOC_MAGIC, 1, struct ion_handle_data)
-#define ION_IOC_MAP _IOWR(ION_IOC_MAGIC, 2, struct ion_fd_data)
-#define ION_IOC_SHARE _IOWR(ION_IOC_MAGIC, 4, struct ion_fd_data)
-#define ION_IOC_IMPORT _IOWR(ION_IOC_MAGIC, 5, struct ion_fd_data)
-#define ION_IOC_SYNC _IOWR(ION_IOC_MAGIC, 7, struct ion_fd_data)
-#define ION_IOC_CUSTOM _IOWR(ION_IOC_MAGIC, 6, struct ion_custom_data)
#define ION_IOC_HEAP_QUERY _IOWR(ION_IOC_MAGIC, 8, struct ion_heap_query)
#endif
diff --git a/libc/malloc_debug/Android.bp b/libc/malloc_debug/Android.bp
index ede2431..899987c 100644
--- a/libc/malloc_debug/Android.bp
+++ b/libc/malloc_debug/Android.bp
@@ -42,15 +42,13 @@
name: "libc_malloc_debug",
srcs: [
- "BacktraceData.cpp",
"Config.cpp",
"DebugData.cpp",
"debug_disable.cpp",
- "FreeTrackData.cpp",
"GuardData.cpp",
"malloc_debug.cpp",
+ "PointerData.cpp",
"RecordData.cpp",
- "TrackData.cpp",
],
stl: "libc++_static",
@@ -91,6 +89,7 @@
"-Werror",
"-fno-stack-protector",
"-Wno-error=format-zero-length",
+ "-Wthread-safety",
],
}
@@ -98,16 +97,7 @@
// Unit Tests
// ==============================================================
cc_test {
-
name: "malloc_debug_unit_tests",
- multilib: {
- lib32: {
- suffix: "32",
- },
- lib64: {
- suffix: "64",
- },
- },
srcs: [
"tests/backtrace_fake.cpp",
diff --git a/libc/malloc_debug/BacktraceData.cpp b/libc/malloc_debug/BacktraceData.cpp
deleted file mode 100644
index 57d8f2a..0000000
--- a/libc/malloc_debug/BacktraceData.cpp
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2015 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 <errno.h>
-#include <signal.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <private/bionic_macros.h>
-
-#include "BacktraceData.h"
-#include "Config.h"
-#include "DebugData.h"
-#include "debug_log.h"
-#include "malloc_debug.h"
-
-static void ToggleBacktraceEnable(int, siginfo_t*, void*) {
- g_debug->backtrace->ToggleBacktraceEnabled();
-}
-
-static void EnableDump(int, siginfo_t*, void*) {
- g_debug->backtrace->EnableDumping();
-}
-
-BacktraceData::BacktraceData(DebugData* debug_data, const Config& config, size_t* offset)
- : OptionData(debug_data) {
- size_t hdr_len = sizeof(BacktraceHeader) + sizeof(uintptr_t) * config.backtrace_frames();
- alloc_offset_ = *offset;
- *offset += __BIONIC_ALIGN(hdr_len, MINIMUM_ALIGNMENT_BYTES);
-}
-
-bool BacktraceData::Initialize(const Config& config) {
- enabled_ = config.backtrace_enabled();
- if (config.backtrace_enable_on_signal()) {
- struct sigaction64 enable_act = {};
- enable_act.sa_sigaction = ToggleBacktraceEnable;
- enable_act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
- if (sigaction64(config.backtrace_signal(), &enable_act, nullptr) != 0) {
- error_log("Unable to set up backtrace signal enable function: %s", strerror(errno));
- return false;
- }
- info_log("%s: Run: 'kill -%d %d' to enable backtracing.", getprogname(),
- config.backtrace_signal(), getpid());
- }
-
- struct sigaction64 act = {};
- act.sa_sigaction = EnableDump;
- act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
- if (sigaction64(config.backtrace_dump_signal(), &act, nullptr) != 0) {
- error_log("Unable to set up backtrace dump signal function: %s", strerror(errno));
- return false;
- }
- info_log("%s: Run: 'kill -%d %d' to dump the backtrace.", getprogname(),
- config.backtrace_dump_signal(), getpid());
-
- dump_ = false;
- return true;
-}
diff --git a/libc/malloc_debug/BacktraceData.h b/libc/malloc_debug/BacktraceData.h
deleted file mode 100644
index 3c15348..0000000
--- a/libc/malloc_debug/BacktraceData.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2015 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.
- */
-
-#pragma once
-
-#include <stdint.h>
-
-#include <atomic>
-
-#include <private/bionic_macros.h>
-
-#include "OptionData.h"
-
-// Forward declarations.
-class Config;
-
-class BacktraceData : public OptionData {
- public:
- BacktraceData(DebugData* debug_data, const Config& config, size_t* offset);
- virtual ~BacktraceData() = default;
-
- bool Initialize(const Config& config);
-
- inline size_t alloc_offset() { return alloc_offset_; }
-
- bool ShouldBacktrace() { return enabled_ == 1; }
- void ToggleBacktraceEnabled() { enabled_.fetch_xor(1); }
-
- void EnableDumping() { dump_ = true; }
- bool ShouldDumpAndReset() {
- bool expected = true;
- return dump_.compare_exchange_strong(expected, false);
- }
-
- private:
- size_t alloc_offset_ = 0;
-
- std::atomic_uint8_t enabled_;
-
- std::atomic_bool dump_;
-
- DISALLOW_COPY_AND_ASSIGN(BacktraceData);
-};
diff --git a/libc/malloc_debug/Config.cpp b/libc/malloc_debug/Config.cpp
index 3cecf9b..2c94fe8 100644
--- a/libc/malloc_debug/Config.cpp
+++ b/libc/malloc_debug/Config.cpp
@@ -69,65 +69,70 @@
static constexpr const char DEFAULT_RECORD_ALLOCS_FILE[] = "/data/local/tmp/record_allocs.txt";
const std::unordered_map<std::string, Config::OptionInfo> Config::kOptions = {
- {"guard",
- {FRONT_GUARD | REAR_GUARD, &Config::SetGuard},
+ {
+ "guard", {FRONT_GUARD | REAR_GUARD | TRACK_ALLOCS, &Config::SetGuard},
},
- {"front_guard",
- {FRONT_GUARD, &Config::SetFrontGuard},
+ {
+ "front_guard", {FRONT_GUARD | TRACK_ALLOCS, &Config::SetFrontGuard},
},
- {"rear_guard",
- {REAR_GUARD, &Config::SetRearGuard},
+ {
+ "rear_guard", {REAR_GUARD | TRACK_ALLOCS, &Config::SetRearGuard},
},
- {"backtrace",
- {BACKTRACE | TRACK_ALLOCS, &Config::SetBacktrace},
+ {
+ "backtrace", {BACKTRACE | TRACK_ALLOCS, &Config::SetBacktrace},
},
- {"backtrace_enable_on_signal",
- {BACKTRACE | TRACK_ALLOCS, &Config::SetBacktraceEnableOnSignal},
+ {
+ "backtrace_enable_on_signal",
+ {BACKTRACE | TRACK_ALLOCS, &Config::SetBacktraceEnableOnSignal},
},
- {"backtrace_dump_on_exit",
- {0, &Config::SetBacktraceDumpOnExit},
+ {
+ "backtrace_dump_on_exit", {0, &Config::SetBacktraceDumpOnExit},
},
- {"backtrace_dump_prefix",
- {0, &Config::SetBacktraceDumpPrefix},
+ {
+ "backtrace_dump_prefix", {0, &Config::SetBacktraceDumpPrefix},
},
- {"fill",
- {FILL_ON_ALLOC | FILL_ON_FREE, &Config::SetFill},
+ {
+ "fill", {FILL_ON_ALLOC | FILL_ON_FREE, &Config::SetFill},
},
- {"fill_on_alloc",
- {FILL_ON_ALLOC, &Config::SetFillOnAlloc},
+ {
+ "fill_on_alloc", {FILL_ON_ALLOC, &Config::SetFillOnAlloc},
},
- {"fill_on_free",
- {FILL_ON_FREE, &Config::SetFillOnFree},
+ {
+ "fill_on_free", {FILL_ON_FREE, &Config::SetFillOnFree},
},
- {"expand_alloc",
- {EXPAND_ALLOC, &Config::SetExpandAlloc},
+ {
+ "expand_alloc", {EXPAND_ALLOC, &Config::SetExpandAlloc},
},
- {"free_track",
- {FREE_TRACK | FILL_ON_FREE, &Config::SetFreeTrack},
+ {
+ "free_track", {FREE_TRACK | FILL_ON_FREE | TRACK_ALLOCS, &Config::SetFreeTrack},
},
- {"free_track_backtrace_num_frames",
- {0, &Config::SetFreeTrackBacktraceNumFrames},
+ {
+ "free_track_backtrace_num_frames", {0, &Config::SetFreeTrackBacktraceNumFrames},
},
- {"leak_track",
- {LEAK_TRACK | TRACK_ALLOCS, &Config::VerifyValueEmpty},
+ {
+ "leak_track", {LEAK_TRACK | TRACK_ALLOCS, &Config::VerifyValueEmpty},
},
- {"record_allocs",
- {RECORD_ALLOCS, &Config::SetRecordAllocs},
+ {
+ "record_allocs", {RECORD_ALLOCS, &Config::SetRecordAllocs},
},
- {"record_allocs_file",
- {0, &Config::SetRecordAllocsFile},
+ {
+ "record_allocs_file", {0, &Config::SetRecordAllocsFile},
+ },
+
+ {
+ "verify_pointers", {TRACK_ALLOCS, &Config::VerifyValueEmpty},
},
};
-bool Config::ParseValue(const std::string& option, const std::string& value,
- size_t min_value, size_t max_value, size_t* parsed_value) const {
+bool Config::ParseValue(const std::string& option, const std::string& value, size_t min_value,
+ size_t max_value, size_t* parsed_value) const {
assert(!value.empty());
// Parse the value into a size_t value.
@@ -135,8 +140,7 @@
char* end;
long long_value = strtol(value.c_str(), &end, 10);
if (errno != 0) {
- error_log("%s: bad value for option '%s': %s", getprogname(), option.c_str(),
- strerror(errno));
+ error_log("%s: bad value for option '%s': %s", getprogname(), option.c_str(), strerror(errno));
return false;
}
if (end == value.c_str()) {
@@ -144,24 +148,24 @@
return false;
}
if (static_cast<size_t>(end - value.c_str()) != value.size()) {
- error_log("%s: bad value for option '%s', non space found after option: %s",
- getprogname(), option.c_str(), end);
+ error_log("%s: bad value for option '%s', non space found after option: %s", getprogname(),
+ option.c_str(), end);
return false;
}
if (long_value < 0) {
- error_log("%s: bad value for option '%s', value cannot be negative: %ld",
- getprogname(), option.c_str(), long_value);
+ error_log("%s: bad value for option '%s', value cannot be negative: %ld", getprogname(),
+ option.c_str(), long_value);
return false;
}
if (static_cast<size_t>(long_value) < min_value) {
- error_log("%s: bad value for option '%s', value must be >= %zu: %ld",
- getprogname(), option.c_str(), min_value, long_value);
+ error_log("%s: bad value for option '%s', value must be >= %zu: %ld", getprogname(),
+ option.c_str(), min_value, long_value);
return false;
}
if (static_cast<size_t>(long_value) > max_value) {
- error_log("%s: bad value for option '%s', value must be <= %zu: %ld",
- getprogname(), option.c_str(), max_value, long_value);
+ error_log("%s: bad value for option '%s', value must be <= %zu: %ld", getprogname(),
+ option.c_str(), max_value, long_value);
return false;
}
*parsed_value = static_cast<size_t>(long_value);
@@ -261,7 +265,6 @@
return true;
}
-
bool Config::SetExpandAlloc(const std::string& option, const std::string& value) {
return ParseValue(option, value, DEFAULT_EXPAND_BYTES, 1, MAX_EXPAND_BYTES, &expand_alloc_bytes_);
}
@@ -305,14 +308,13 @@
bool Config::VerifyValueEmpty(const std::string& option, const std::string& value) {
if (!value.empty()) {
// This is not valid.
- error_log("%s: value set for option '%s' which does not take a value",
- getprogname(), option.c_str());
+ error_log("%s: value set for option '%s' which does not take a value", getprogname(),
+ option.c_str());
return false;
}
return true;
}
-
void Config::LogUsage() const {
error_log("malloc debug options usage:");
error_log("");
@@ -329,8 +331,8 @@
error_log(" guard[=XX]");
error_log(" Enables both a front guard and a rear guard on all allocations.");
error_log(" If XX is set it sets the number of bytes in both guards.");
- error_log(" The default is %zu bytes, the max bytes is %zu.",
- DEFAULT_GUARD_BYTES, MAX_GUARD_BYTES);
+ error_log(" The default is %zu bytes, the max bytes is %zu.", DEFAULT_GUARD_BYTES,
+ MAX_GUARD_BYTES);
error_log("");
error_log(" backtrace[=XX]");
error_log(" Enable capturing the backtrace at the point of allocation.");
@@ -419,13 +421,16 @@
error_log(" This option only has meaning if the record_allocs options has been specified.");
error_log(" This is the name of the file to which recording information will be dumped.");
error_log(" The default is %s.", DEFAULT_RECORD_ALLOCS_FILE);
+ error_log("");
+ error_log(" verify_pointers");
+ error_log(" A lightweight way to verify that free/malloc_usable_size/realloc");
+ error_log(" are passed valid pointers.");
}
bool Config::GetOption(const char** options_str, std::string* option, std::string* value) {
const char* cur = *options_str;
// Process each property name we can find.
- while (isspace(*cur))
- ++cur;
+ while (isspace(*cur)) ++cur;
if (*cur == '\0') {
*options_str = cur;
@@ -433,25 +438,21 @@
}
const char* start = cur;
- while (!isspace(*cur) && *cur != '=' && *cur != '\0')
- ++cur;
+ while (!isspace(*cur) && *cur != '=' && *cur != '\0') ++cur;
*option = std::string(start, cur - start);
// Skip any spaces after the name.
- while (isspace(*cur))
- ++cur;
+ while (isspace(*cur)) ++cur;
value->clear();
if (*cur == '=') {
++cur;
// Skip the space after the equal.
- while (isspace(*cur))
- ++cur;
+ while (isspace(*cur)) ++cur;
start = cur;
- while (!isspace(*cur) && *cur != '\0')
- ++cur;
+ while (!isspace(*cur) && *cur != '\0') ++cur;
if (cur != start) {
*value = std::string(start, cur - start);
diff --git a/libc/malloc_debug/Config.h b/libc/malloc_debug/Config.h
index a310e09..3bcef0b 100644
--- a/libc/malloc_debug/Config.h
+++ b/libc/malloc_debug/Config.h
@@ -53,7 +53,7 @@
#endif
// If one or more of these options is set, then a special header is needed.
-constexpr uint64_t HEADER_OPTIONS = FRONT_GUARD | REAR_GUARD | BACKTRACE | FREE_TRACK | LEAK_TRACK;
+constexpr uint64_t HEADER_OPTIONS = FRONT_GUARD | REAR_GUARD;
class Config {
public:
diff --git a/libc/malloc_debug/DebugData.cpp b/libc/malloc_debug/DebugData.cpp
index 76f8fbb..44c4a10 100644
--- a/libc/malloc_debug/DebugData.cpp
+++ b/libc/malloc_debug/DebugData.cpp
@@ -28,14 +28,12 @@
#include <stdint.h>
-#include "BacktraceData.h"
#include "Config.h"
#include "DebugData.h"
-#include "debug_disable.h"
-#include "FreeTrackData.h"
#include "GuardData.h"
+#include "PointerData.h"
+#include "debug_disable.h"
#include "malloc_debug.h"
-#include "TrackData.h"
bool DebugData::Initialize(const char* options) {
if (!config_.Init(options)) {
@@ -44,18 +42,9 @@
// Check to see if the options that require a header are enabled.
if (config_.options() & HEADER_OPTIONS) {
- need_header_ = true;
-
// Initialize all of the static header offsets.
pointer_offset_ = __BIONIC_ALIGN(sizeof(Header), MINIMUM_ALIGNMENT_BYTES);
- if (config_.options() & BACKTRACE) {
- backtrace.reset(new BacktraceData(this, config_, &pointer_offset_));
- if (!backtrace->Initialize(config_)) {
- return false;
- }
- }
-
if (config_.options() & FRONT_GUARD) {
front_guard.reset(new FrontGuardData(this, config_, &pointer_offset_));
}
@@ -67,13 +56,12 @@
rear_guard.reset(new RearGuardData(this, config_));
extra_bytes_ += config_.rear_guard_bytes();
}
+ }
- if (config_.options() & FREE_TRACK) {
- free_track.reset(new FreeTrackData(this, config_));
- }
-
- if (config_.options() & TRACK_ALLOCS) {
- track.reset(new TrackData(this));
+ if (TrackPointers()) {
+ pointer.reset(new PointerData(this));
+ if (!pointer->Initialize(config_)) {
+ return false;
}
}
@@ -91,28 +79,19 @@
}
void DebugData::PrepareFork() {
- if (track != nullptr) {
- track->PrepareFork();
- }
- if (free_track != nullptr) {
- free_track->PrepareFork();
+ if (pointer != nullptr) {
+ pointer->PrepareFork();
}
}
void DebugData::PostForkParent() {
- if (track != nullptr) {
- track->PostForkParent();
- }
- if (free_track != nullptr) {
- free_track->PostForkParent();
+ if (pointer != nullptr) {
+ pointer->PostForkParent();
}
}
void DebugData::PostForkChild() {
- if (track != nullptr) {
- track->PostForkChild();
- }
- if (free_track != nullptr) {
- free_track->PostForkChild();
+ if (pointer != nullptr) {
+ pointer->PostForkChild();
}
}
diff --git a/libc/malloc_debug/DebugData.h b/libc/malloc_debug/DebugData.h
index 9aece0b..f7cf8ab 100644
--- a/libc/malloc_debug/DebugData.h
+++ b/libc/malloc_debug/DebugData.h
@@ -35,13 +35,11 @@
#include <private/bionic_macros.h>
-#include "BacktraceData.h"
#include "Config.h"
-#include "FreeTrackData.h"
#include "GuardData.h"
-#include "malloc_debug.h"
+#include "PointerData.h"
#include "RecordData.h"
-#include "TrackData.h"
+#include "malloc_debug.h"
class DebugData {
public:
@@ -62,11 +60,6 @@
return reinterpret_cast<Header*>(value - pointer_offset_);
}
- BacktraceHeader* GetAllocBacktrace(const Header* header) {
- uintptr_t value = reinterpret_cast<uintptr_t>(header);
- return reinterpret_cast<BacktraceHeader*>(value + backtrace->alloc_offset());
- }
-
uint8_t* GetFrontGuard(const Header* header) {
uintptr_t value = reinterpret_cast<uintptr_t>(header);
return reinterpret_cast<uint8_t*>(value + front_guard->offset());
@@ -74,30 +67,30 @@
uint8_t* GetRearGuard(const Header* header) {
uintptr_t value = reinterpret_cast<uintptr_t>(GetPointer(header));
- return reinterpret_cast<uint8_t*>(value + header->real_size());
+ return reinterpret_cast<uint8_t*>(value + header->size);
}
const Config& config() { return config_; }
size_t pointer_offset() { return pointer_offset_; }
- bool need_header() { return need_header_; }
size_t extra_bytes() { return extra_bytes_; }
+ bool TrackPointers() { return config_.options() & TRACK_ALLOCS; }
+
+ bool HeaderEnabled() { return config_.options() & HEADER_OPTIONS; }
+
void PrepareFork();
void PostForkParent();
void PostForkChild();
- std::unique_ptr<BacktraceData> backtrace;
- std::unique_ptr<TrackData> track;
std::unique_ptr<FrontGuardData> front_guard;
+ std::unique_ptr<PointerData> pointer;
std::unique_ptr<RearGuardData> rear_guard;
- std::unique_ptr<FreeTrackData> free_track;
std::unique_ptr<RecordData> record;
private:
size_t extra_bytes_ = 0;
size_t pointer_offset_ = 0;
- bool need_header_ = false;
Config config_;
diff --git a/libc/malloc_debug/FreeTrackData.cpp b/libc/malloc_debug/FreeTrackData.cpp
deleted file mode 100644
index e8e7a67..0000000
--- a/libc/malloc_debug/FreeTrackData.cpp
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (C) 2015 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 <stdint.h>
-
-#include "backtrace.h"
-#include "Config.h"
-#include "DebugData.h"
-#include "debug_disable.h"
-#include "debug_log.h"
-#include "FreeTrackData.h"
-#include "malloc_debug.h"
-
-FreeTrackData::FreeTrackData(DebugData* debug, const Config& config)
- : OptionData(debug), backtrace_num_frames_(config.free_track_backtrace_num_frames()) {
- cmp_mem_.resize(4096);
- memset(cmp_mem_.data(), config.fill_free_value(), cmp_mem_.size());
-}
-
-void FreeTrackData::LogFreeError(const Header* header, const uint8_t* pointer) {
- error_log(LOG_DIVIDER);
- error_log("+++ ALLOCATION %p USED AFTER FREE", pointer);
- uint8_t fill_free_value = debug_->config().fill_free_value();
- for (size_t i = 0; i < header->usable_size; i++) {
- if (pointer[i] != fill_free_value) {
- error_log(" allocation[%zu] = 0x%02x (expected 0x%02x)", i, pointer[i], fill_free_value);
- }
- }
- auto back_iter = backtraces_.find(header);
- if (back_iter != backtraces_.end()) {
- const BacktraceHeader* back_header = back_iter->second;
- error_log("Backtrace at time of free:");
- backtrace_log(&back_header->frames[0], back_header->num_frames);
- }
- error_log(LOG_DIVIDER);
-}
-
-void FreeTrackData::VerifyAndFree(const Header* header) {
- const void* pointer = debug_->GetPointer(header);
- if (header->tag != DEBUG_FREE_TAG) {
- error_log(LOG_DIVIDER);
- error_log("+++ ALLOCATION %p HAS CORRUPTED HEADER TAG 0x%x AFTER FREE", pointer, header->tag);
- error_log(LOG_DIVIDER);
- } else {
- const uint8_t* memory = reinterpret_cast<const uint8_t*>(pointer);
- size_t bytes = header->usable_size;
- bytes = (bytes < debug_->config().fill_on_free_bytes()) ? bytes
- : debug_->config().fill_on_free_bytes();
- while (bytes > 0) {
- size_t bytes_to_cmp = (bytes < cmp_mem_.size()) ? bytes : cmp_mem_.size();
- if (memcmp(memory, cmp_mem_.data(), bytes_to_cmp) != 0) {
- LogFreeError(header, reinterpret_cast<const uint8_t*>(pointer));
- break;
- }
- bytes -= bytes_to_cmp;
- memory = &memory[bytes_to_cmp];
- }
- }
-
- auto back_iter = backtraces_.find(header);
- if (back_iter != backtraces_.end()) {
- g_dispatch->free(reinterpret_cast<void*>(back_iter->second));
- backtraces_.erase(header);
- }
- g_dispatch->free(header->orig_pointer);
-}
-
-void FreeTrackData::Add(const Header* header) {
- pthread_mutex_lock(&mutex_);
- if (list_.size() == debug_->config().free_track_allocations()) {
- const Header* old_header = list_.back();
- VerifyAndFree(old_header);
- list_.pop_back();
- }
-
- if (backtrace_num_frames_ > 0) {
- BacktraceHeader* back_header = reinterpret_cast<BacktraceHeader*>(
- g_dispatch->malloc(sizeof(BacktraceHeader) + backtrace_num_frames_ * sizeof(uintptr_t)));
- if (back_header) {
- back_header->num_frames = backtrace_get(&back_header->frames[0], backtrace_num_frames_);
- backtraces_[header] = back_header;
- }
- }
- list_.push_front(header);
-
- pthread_mutex_unlock(&mutex_);
-}
-
-void FreeTrackData::VerifyAll() {
- for (const auto& header : list_) {
- VerifyAndFree(header);
- }
- list_.clear();
-}
-
-void FreeTrackData::LogBacktrace(const Header* header) {
- auto back_iter = backtraces_.find(header);
- if (back_iter == backtraces_.end()) {
- return;
- }
-
- error_log("Backtrace of original free:");
- backtrace_log(&back_iter->second->frames[0], back_iter->second->num_frames);
-}
diff --git a/libc/malloc_debug/FreeTrackData.h b/libc/malloc_debug/FreeTrackData.h
deleted file mode 100644
index bd3497d..0000000
--- a/libc/malloc_debug/FreeTrackData.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2015 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.
- */
-
-#pragma once
-
-#include <stdint.h>
-#include <pthread.h>
-
-#include <deque>
-#include <unordered_map>
-#include <vector>
-
-#include <private/bionic_macros.h>
-
-#include "OptionData.h"
-
-// Forward declarations.
-struct BacktraceHeader;
-class Config;
-class DebugData;
-struct Header;
-
-class FreeTrackData : public OptionData {
- public:
- FreeTrackData(DebugData* debug_data, const Config& config);
- virtual ~FreeTrackData() = default;
-
- void Add(const Header* header);
-
- void VerifyAll();
-
- void LogBacktrace(const Header* header);
-
- void PrepareFork() { pthread_mutex_lock(&mutex_); }
-
- void PostForkParent() { pthread_mutex_unlock(&mutex_); }
-
- void PostForkChild() { pthread_mutex_init(&mutex_, NULL); }
-
- private:
- void LogFreeError(const Header* header, const uint8_t* pointer);
- void VerifyAndFree(const Header* header);
-
- pthread_mutex_t mutex_ = PTHREAD_MUTEX_INITIALIZER;
- std::deque<const Header*> list_;
- std::vector<uint8_t> cmp_mem_;
- std::unordered_map<const Header*, BacktraceHeader*> backtraces_;
- size_t backtrace_num_frames_;
-
- DISALLOW_COPY_AND_ASSIGN(FreeTrackData);
-};
diff --git a/libc/malloc_debug/GuardData.cpp b/libc/malloc_debug/GuardData.cpp
index d6cef85..f9a2dca 100644
--- a/libc/malloc_debug/GuardData.cpp
+++ b/libc/malloc_debug/GuardData.cpp
@@ -31,13 +31,13 @@
#include <vector>
-#include "backtrace.h"
#include "Config.h"
+#include "DebugData.h"
+#include "GuardData.h"
+#include "backtrace.h"
#include "debug_disable.h"
#include "debug_log.h"
-#include "DebugData.h"
#include "malloc_debug.h"
-#include "GuardData.h"
GuardData::GuardData(DebugData* debug_data, int init_value, size_t num_bytes)
: OptionData(debug_data) {
@@ -48,8 +48,8 @@
void GuardData::LogFailure(const Header* header, const void* pointer, const void* data) {
error_log(LOG_DIVIDER);
- error_log("+++ ALLOCATION %p SIZE %zu HAS A CORRUPTED %s GUARD", pointer,
- header->real_size(), GetTypeName());
+ error_log("+++ ALLOCATION %p SIZE %zu HAS A CORRUPTED %s GUARD", pointer, header->size,
+ GetTypeName());
// Log all of the failing bytes.
const uint8_t* expected = cmp_mem_.data();
@@ -70,7 +70,7 @@
}
FrontGuardData::FrontGuardData(DebugData* debug_data, const Config& config, size_t* offset)
- : GuardData(debug_data, config.front_guard_value(), config.front_guard_bytes()) {
+ : GuardData(debug_data, config.front_guard_value(), config.front_guard_bytes()) {
// Create a buffer for fast comparisons of the front guard.
cmp_mem_.resize(config.front_guard_bytes());
memset(cmp_mem_.data(), config.front_guard_value(), cmp_mem_.size());
@@ -88,8 +88,7 @@
}
RearGuardData::RearGuardData(DebugData* debug_data, const Config& config)
- : GuardData(debug_data, config.rear_guard_value(), config.rear_guard_bytes()) {
-}
+ : GuardData(debug_data, config.rear_guard_value(), config.rear_guard_bytes()) {}
bool RearGuardData::Valid(const Header* header) {
return GuardData::Valid(debug_->GetRearGuard(header));
diff --git a/libc/malloc_debug/MapData.cpp b/libc/malloc_debug/MapData.cpp
index d57017e..060425e 100644
--- a/libc/malloc_debug/MapData.cpp
+++ b/libc/malloc_debug/MapData.cpp
@@ -31,8 +31,8 @@
#include <inttypes.h>
#include <link.h>
#include <stdio.h>
-#include <string.h>
#include <stdlib.h>
+#include <string.h>
#include <vector>
@@ -46,8 +46,8 @@
uintptr_t offset;
char permissions[5];
int name_pos;
- if (sscanf(line, "%" PRIxPTR "-%" PRIxPTR " %4s %" PRIxPTR " %*x:%*x %*d %n", &start,
- &end, permissions, &offset, &name_pos) < 2) {
+ if (sscanf(line, "%" PRIxPTR "-%" PRIxPTR " %4s %" PRIxPTR " %*x:%*x %*d %n", &start, &end,
+ permissions, &offset, &name_pos) < 2) {
return nullptr;
}
@@ -66,13 +66,13 @@
return entry;
}
-template<typename T>
+template <typename T>
static inline bool get_val(MapEntry* entry, uintptr_t addr, T* store) {
if (addr < entry->start || addr + sizeof(T) > entry->end) {
return false;
}
// Make sure the address is aligned properly.
- if (addr & (sizeof(T)-1)) {
+ if (addr & (sizeof(T) - 1)) {
return false;
}
*store = *reinterpret_cast<T*>(addr);
@@ -157,7 +157,7 @@
return nullptr;
}
- MapEntry *entry = *it;
+ MapEntry* entry = *it;
if (!entry->load_base_read) {
read_loadbase(entry);
}
diff --git a/libc/malloc_debug/MapData.h b/libc/malloc_debug/MapData.h
index a71f96d..d8398bd 100644
--- a/libc/malloc_debug/MapData.h
+++ b/libc/malloc_debug/MapData.h
@@ -31,8 +31,8 @@
#include <sys/cdefs.h>
#include <mutex>
-#include <string>
#include <set>
+#include <string>
#include <private/bionic_macros.h>
@@ -50,12 +50,9 @@
std::string name;
};
-
// Ordering comparator that returns equivalence for overlapping entries
struct compare_entries {
- bool operator()(const MapEntry* a, const MapEntry* b) const {
- return a->end <= b->start;
- }
+ bool operator()(const MapEntry* a, const MapEntry* b) const { return a->end <= b->start; }
};
class MapData {
diff --git a/libc/malloc_debug/PointerData.cpp b/libc/malloc_debug/PointerData.cpp
new file mode 100644
index 0000000..f811a5e
--- /dev/null
+++ b/libc/malloc_debug/PointerData.cpp
@@ -0,0 +1,553 @@
+/*
+ * Copyright (C) 2015 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 <errno.h>
+#include <inttypes.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <mutex>
+#include <string>
+#include <unordered_map>
+#include <utility>
+#include <vector>
+
+#include <android-base/stringprintf.h>
+#include <android-base/thread_annotations.h>
+#include <private/bionic_macros.h>
+
+#include "Config.h"
+#include "DebugData.h"
+#include "PointerData.h"
+#include "backtrace.h"
+#include "debug_log.h"
+#include "malloc_debug.h"
+
+std::atomic_uint8_t PointerData::backtrace_enabled_;
+std::atomic_bool PointerData::backtrace_dump_;
+
+std::mutex PointerData::pointer_mutex_;
+std::unordered_map<uintptr_t, PointerInfoType> PointerData::pointers_ GUARDED_BY(
+ PointerData::pointer_mutex_);
+
+std::mutex PointerData::frame_mutex_;
+std::unordered_map<FrameKeyType, size_t> PointerData::key_to_index_ GUARDED_BY(
+ PointerData::frame_mutex_);
+std::unordered_map<size_t, FrameInfoType> PointerData::frames_ GUARDED_BY(PointerData::frame_mutex_);
+constexpr size_t kBacktraceEmptyIndex = 1;
+size_t PointerData::cur_hash_index_ GUARDED_BY(PointerData::frame_mutex_);
+
+std::mutex PointerData::free_pointer_mutex_;
+std::deque<FreePointerInfoType> PointerData::free_pointers_ GUARDED_BY(
+ PointerData::free_pointer_mutex_);
+
+// Buffer to use for comparison.
+static constexpr size_t kCompareBufferSize = 512 * 1024;
+static std::vector<uint8_t> g_cmp_mem(0);
+
+static void ToggleBacktraceEnable(int, siginfo_t*, void*) {
+ g_debug->pointer->ToggleBacktraceEnabled();
+}
+
+static void EnableDump(int, siginfo_t*, void*) {
+ g_debug->pointer->EnableDumping();
+}
+
+PointerData::PointerData(DebugData* debug_data) : OptionData(debug_data) {}
+
+bool PointerData::Initialize(const Config& config) NO_THREAD_SAFETY_ANALYSIS {
+ pointers_.clear();
+ key_to_index_.clear();
+ frames_.clear();
+ free_pointers_.clear();
+ // A hash index of kBacktraceEmptyIndex indicates that we tried to get
+ // a backtrace, but there was nothing recorded.
+ cur_hash_index_ = kBacktraceEmptyIndex + 1;
+
+ backtrace_enabled_ = config.backtrace_enabled();
+ if (config.backtrace_enable_on_signal()) {
+ struct sigaction64 enable_act = {};
+ enable_act.sa_sigaction = ToggleBacktraceEnable;
+ enable_act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
+ if (sigaction64(config.backtrace_signal(), &enable_act, nullptr) != 0) {
+ error_log("Unable to set up backtrace signal enable function: %s", strerror(errno));
+ return false;
+ }
+ info_log("%s: Run: 'kill -%d %d' to enable backtracing.", getprogname(),
+ config.backtrace_signal(), getpid());
+ }
+
+ if (config.options() & BACKTRACE) {
+ struct sigaction64 act = {};
+ act.sa_sigaction = EnableDump;
+ act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
+ if (sigaction64(config.backtrace_dump_signal(), &act, nullptr) != 0) {
+ error_log("Unable to set up backtrace dump signal function: %s", strerror(errno));
+ return false;
+ }
+ info_log("%s: Run: 'kill -%d %d' to dump the backtrace.", getprogname(),
+ config.backtrace_dump_signal(), getpid());
+ }
+
+ backtrace_dump_ = false;
+
+ if (config.options() & FREE_TRACK) {
+ g_cmp_mem.resize(kCompareBufferSize, config.fill_free_value());
+ }
+ return true;
+}
+
+size_t PointerData::AddBacktrace(size_t num_frames) {
+ std::vector<uintptr_t> frames(num_frames);
+ num_frames = backtrace_get(frames.data(), frames.size());
+ if (num_frames == 0) {
+ return kBacktraceEmptyIndex;
+ }
+
+ FrameKeyType key{.num_frames = num_frames, .frames = frames.data()};
+ size_t hash_index;
+ std::lock_guard<std::mutex> frame_guard(frame_mutex_);
+ auto entry = key_to_index_.find(key);
+ if (entry == key_to_index_.end()) {
+ frames.resize(num_frames);
+ hash_index = cur_hash_index_++;
+ key.frames = frames.data();
+ key_to_index_.emplace(key, hash_index);
+
+ frames_.emplace(hash_index, FrameInfoType{.references = 1, .frames = std::move(frames)});
+ } else {
+ hash_index = entry->second;
+ FrameInfoType* frame_info = &frames_[hash_index];
+ frame_info->references++;
+ }
+ return hash_index;
+}
+
+void PointerData::RemoveBacktrace(size_t hash_index) {
+ if (hash_index <= kBacktraceEmptyIndex) {
+ return;
+ }
+
+ std::lock_guard<std::mutex> frame_guard(frame_mutex_);
+ auto frame_entry = frames_.find(hash_index);
+ if (frame_entry == frames_.end()) {
+ error_log("hash_index %zu does not have matching frame data.", hash_index);
+ return;
+ }
+ FrameInfoType* frame_info = &frame_entry->second;
+ if (--frame_info->references == 0) {
+ FrameKeyType key{.num_frames = frame_info->frames.size(), .frames = frame_info->frames.data()};
+ key_to_index_.erase(key);
+ frames_.erase(hash_index);
+ }
+}
+
+void PointerData::Add(const void* ptr, size_t pointer_size) {
+ uintptr_t pointer = reinterpret_cast<uintptr_t>(ptr);
+ size_t hash_index = 0;
+ if (backtrace_enabled_) {
+ hash_index = AddBacktrace(g_debug->config().backtrace_frames());
+ }
+
+ std::lock_guard<std::mutex> pointer_guard(pointer_mutex_);
+ pointers_[pointer] = PointerInfoType{PointerInfoType::GetEncodedSize(pointer_size), hash_index};
+}
+
+void PointerData::Remove(const void* ptr) {
+ uintptr_t pointer = reinterpret_cast<uintptr_t>(ptr);
+ size_t hash_index;
+ {
+ std::lock_guard<std::mutex> pointer_guard(pointer_mutex_);
+ auto entry = pointers_.find(pointer);
+ if (entry == pointers_.end()) {
+ // Error.
+ error_log("No tracked pointer found for 0x%" PRIxPTR, pointer);
+ return;
+ }
+ hash_index = entry->second.hash_index;
+ pointers_.erase(pointer);
+ }
+
+ RemoveBacktrace(hash_index);
+}
+
+size_t PointerData::GetFrames(const void* ptr, uintptr_t* frames, size_t max_frames) {
+ uintptr_t pointer = reinterpret_cast<uintptr_t>(ptr);
+ size_t hash_index;
+ {
+ std::lock_guard<std::mutex> pointer_guard(pointer_mutex_);
+ auto entry = pointers_.find(pointer);
+ if (entry == pointers_.end()) {
+ return 0;
+ }
+ hash_index = entry->second.hash_index;
+ }
+
+ if (hash_index <= kBacktraceEmptyIndex) {
+ return 0;
+ }
+
+ std::lock_guard<std::mutex> frame_guard(frame_mutex_);
+ auto frame_entry = frames_.find(hash_index);
+ if (frame_entry == frames_.end()) {
+ return 0;
+ }
+ FrameInfoType* frame_info = &frame_entry->second;
+ if (max_frames > frame_info->frames.size()) {
+ max_frames = frame_info->frames.size();
+ }
+ memcpy(frames, &frame_info->frames[0], max_frames * sizeof(uintptr_t));
+
+ return max_frames;
+}
+
+void PointerData::LogFreeError(const FreePointerInfoType& info, size_t usable_size) {
+ error_log(LOG_DIVIDER);
+ uint8_t* memory = reinterpret_cast<uint8_t*>(info.pointer);
+ error_log("+++ ALLOCATION %p USED AFTER FREE", memory);
+ uint8_t fill_free_value = g_debug->config().fill_free_value();
+ for (size_t i = 0; i < usable_size; i++) {
+ if (memory[i] != fill_free_value) {
+ error_log(" allocation[%zu] = 0x%02x (expected 0x%02x)", i, memory[i], fill_free_value);
+ }
+ }
+
+ if (info.hash_index > kBacktraceEmptyIndex) {
+ std::lock_guard<std::mutex> frame_guard(frame_mutex_);
+ auto frame_entry = frames_.find(info.hash_index);
+ if (frame_entry != frames_.end()) {
+ FrameInfoType* frame_info = &frame_entry->second;
+ error_log("Backtrace at time of free:");
+ backtrace_log(frame_info->frames.data(), frame_info->frames.size());
+ }
+ }
+
+ error_log(LOG_DIVIDER);
+}
+
+void PointerData::VerifyFreedPointer(const FreePointerInfoType& info) {
+ size_t usable_size;
+ if (g_debug->HeaderEnabled()) {
+ // Check to see if the tag data has been damaged.
+ Header* header = g_debug->GetHeader(reinterpret_cast<const void*>(info.pointer));
+ if (header->tag != DEBUG_FREE_TAG) {
+ error_log(LOG_DIVIDER);
+ error_log("+++ ALLOCATION 0x%" PRIxPTR " HAS CORRUPTED HEADER TAG 0x%x AFTER FREE",
+ info.pointer, header->tag);
+ error_log(LOG_DIVIDER);
+
+ // Stop processing here, it is impossible to tell how the header
+ // may have been damaged.
+ return;
+ }
+ usable_size = header->usable_size;
+ } else {
+ usable_size = g_dispatch->malloc_usable_size(reinterpret_cast<const void*>(info.pointer));
+ }
+
+ size_t bytes = (usable_size < g_debug->config().fill_on_free_bytes())
+ ? usable_size
+ : g_debug->config().fill_on_free_bytes();
+ const uint8_t* memory = reinterpret_cast<const uint8_t*>(info.pointer);
+ while (bytes > 0) {
+ size_t bytes_to_cmp = (bytes < g_cmp_mem.size()) ? bytes : g_cmp_mem.size();
+ if (memcmp(memory, g_cmp_mem.data(), bytes_to_cmp) != 0) {
+ LogFreeError(info, usable_size);
+ }
+ bytes -= bytes_to_cmp;
+ memory = &memory[bytes_to_cmp];
+ }
+}
+
+void* PointerData::AddFreed(const void* ptr) {
+ uintptr_t pointer = reinterpret_cast<uintptr_t>(ptr);
+
+ size_t hash_index = 0;
+ size_t num_frames = g_debug->config().free_track_backtrace_num_frames();
+ if (num_frames) {
+ hash_index = AddBacktrace(num_frames);
+ }
+
+ void* last = nullptr;
+ std::lock_guard<std::mutex> freed_guard(free_pointer_mutex_);
+ if (free_pointers_.size() == g_debug->config().free_track_allocations()) {
+ FreePointerInfoType info(free_pointers_.front());
+ free_pointers_.pop_front();
+ VerifyFreedPointer(info);
+ RemoveBacktrace(info.hash_index);
+ last = reinterpret_cast<void*>(info.pointer);
+ }
+
+ free_pointers_.emplace_back(FreePointerInfoType{pointer, hash_index});
+ return last;
+}
+
+void PointerData::LogFreeBacktrace(const void* ptr) {
+ size_t hash_index = 0;
+ {
+ uintptr_t pointer = reinterpret_cast<uintptr_t>(ptr);
+ std::lock_guard<std::mutex> freed_guard(free_pointer_mutex_);
+ for (const auto& info : free_pointers_) {
+ if (info.pointer == pointer) {
+ hash_index = info.hash_index;
+ break;
+ }
+ }
+ }
+
+ if (hash_index <= kBacktraceEmptyIndex) {
+ return;
+ }
+
+ std::lock_guard<std::mutex> frame_guard(frame_mutex_);
+ auto frame_entry = frames_.find(hash_index);
+ if (frame_entry == frames_.end()) {
+ error_log("Freed pointer hash_index %zu does not have matching frame data.", hash_index);
+ return;
+ }
+ FrameInfoType* frame_info = &frame_entry->second;
+ error_log("Backtrace of original free:");
+ backtrace_log(frame_info->frames.data(), frame_info->frames.size());
+}
+
+void PointerData::VerifyAllFreed() {
+ std::lock_guard<std::mutex> freed_guard(free_pointer_mutex_);
+ for (auto& free_info : free_pointers_) {
+ VerifyFreedPointer(free_info);
+ }
+}
+
+void PointerData::GetList(std::vector<ListInfoType>* list, bool only_with_backtrace)
+ REQUIRES(pointer_mutex_, frame_mutex_) {
+ for (const auto& entry : pointers_) {
+ FrameInfoType* frame_info = nullptr;
+ size_t hash_index = entry.second.hash_index;
+ if (hash_index > kBacktraceEmptyIndex) {
+ frame_info = &frames_[hash_index];
+ if (frame_info->references == 0) {
+ // Somehow wound up with a pointer with a valid hash_index, but
+ // no frame data. This should not be possible since adding a pointer
+ // occurs after the hash_index and frame data have been added.
+ // When removing a pointer, the pointer is deleted before the frame
+ // data.
+ frames_.erase(hash_index);
+ error_log("Pointer 0x%" PRIxPTR " hash_index %zu does not exist.", entry.first, hash_index);
+ frame_info = nullptr;
+ }
+ }
+ if (hash_index == 0 && only_with_backtrace) {
+ continue;
+ }
+
+ list->emplace_back(ListInfoType{entry.first, 1, entry.second.RealSize(),
+ entry.second.ZygoteChildAlloc(), frame_info});
+ }
+
+ // Sort by the size of the allocation.
+ std::sort(list->begin(), list->end(), [](const ListInfoType& a, const ListInfoType& b) {
+ // Put zygote child allocations first.
+ bool a_zygote_child_alloc = a.zygote_child_alloc;
+ bool b_zygote_child_alloc = b.zygote_child_alloc;
+ if (a_zygote_child_alloc && !b_zygote_child_alloc) {
+ return false;
+ }
+ if (!a_zygote_child_alloc && b_zygote_child_alloc) {
+ return true;
+ }
+
+ // Sort by size, descending order.
+ if (a.size != b.size) return a.size > b.size;
+
+ // Put pointers with no backtrace last.
+ FrameInfoType* a_frame = a.frame_info;
+ FrameInfoType* b_frame = b.frame_info;
+ if (a_frame == nullptr && b_frame != nullptr) {
+ return false;
+ }
+ if (a_frame != nullptr && b_frame == nullptr) {
+ return true;
+ }
+ // Put the pointers with longest backtrace first.
+ if (a_frame->frames.size() != b_frame->frames.size()) {
+ return a_frame->frames.size() > b_frame->frames.size();
+ }
+
+ // Last sort by pointer.
+ return a.pointer < b.pointer;
+ });
+}
+
+void PointerData::GetUniqueList(std::vector<ListInfoType>* list, bool only_with_backtrace)
+ REQUIRES(pointer_mutex_, frame_mutex_) {
+ GetList(list, only_with_backtrace);
+
+ // Remove duplicates of size/backtraces.
+ for (auto iter = list->begin(); iter != list->end();) {
+ auto dup_iter = iter + 1;
+ bool zygote_child_alloc = iter->zygote_child_alloc;
+ size_t size = iter->size;
+ FrameInfoType* frame_info = iter->frame_info;
+ for (; dup_iter != list->end(); ++dup_iter) {
+ if (zygote_child_alloc != dup_iter->zygote_child_alloc || size != dup_iter->size ||
+ frame_info != dup_iter->frame_info) {
+ break;
+ }
+ iter->num_allocations++;
+ }
+ iter = list->erase(iter + 1, dup_iter);
+ }
+}
+
+void PointerData::LogLeaks() {
+ std::vector<ListInfoType> list;
+
+ std::lock_guard<std::mutex> pointer_guard(pointer_mutex_);
+ std::lock_guard<std::mutex> frame_guard(frame_mutex_);
+ GetList(&list, false);
+
+ size_t track_count = 0;
+ for (const auto& list_info : list) {
+ error_log("+++ %s leaked block of size %zu at 0x%" PRIxPTR " (leak %zu of %zu)", getprogname(),
+ list_info.size, list_info.pointer, ++track_count, list.size());
+ if (list_info.frame_info != nullptr) {
+ error_log("Backtrace at time of allocation:");
+ backtrace_log(list_info.frame_info->frames.data(), list_info.frame_info->frames.size());
+ }
+ // Do not bother to free the pointers, we are about to exit any way.
+ }
+}
+
+void PointerData::GetInfo(uint8_t** info, size_t* overall_size, size_t* info_size,
+ size_t* total_memory, size_t* backtrace_size) {
+ std::lock_guard<std::mutex> pointer_guard(pointer_mutex_);
+ std::lock_guard<std::mutex> frame_guard(frame_mutex_);
+
+ if (pointers_.empty()) {
+ return;
+ }
+
+ std::vector<ListInfoType> list;
+ GetUniqueList(&list, true);
+ if (list.empty()) {
+ return;
+ }
+
+ *backtrace_size = g_debug->config().backtrace_frames();
+ *info_size = sizeof(size_t) * 2 + sizeof(uintptr_t) * *backtrace_size;
+ *overall_size = *info_size * list.size();
+ *info = reinterpret_cast<uint8_t*>(g_dispatch->calloc(*info_size, list.size()));
+ if (*info == nullptr) {
+ return;
+ }
+
+ uint8_t* data = *info;
+ *total_memory = 0;
+ for (const auto& list_info : list) {
+ FrameInfoType* frame_info = list_info.frame_info;
+ *total_memory += list_info.size * list_info.num_allocations;
+ size_t allocation_size =
+ PointerInfoType::GetEncodedSize(list_info.zygote_child_alloc, list_info.size);
+ memcpy(data, &allocation_size, sizeof(size_t));
+ memcpy(&data[sizeof(size_t)], &list_info.num_allocations, sizeof(size_t));
+ if (frame_info != nullptr) {
+ memcpy(&data[2 * sizeof(size_t)], frame_info->frames.data(),
+ frame_info->frames.size() * sizeof(uintptr_t));
+ }
+ data += *info_size;
+ }
+}
+
+bool PointerData::Exists(const void* ptr) {
+ uintptr_t pointer = reinterpret_cast<uintptr_t>(ptr);
+ std::lock_guard<std::mutex> pointer_guard(pointer_mutex_);
+ return pointers_.count(pointer) != 0;
+}
+
+void PointerData::DumpLiveToFile(FILE* fp) {
+ std::vector<ListInfoType> list;
+
+ std::lock_guard<std::mutex> pointer_guard(pointer_mutex_);
+ std::lock_guard<std::mutex> frame_guard(frame_mutex_);
+ GetUniqueList(&list, false);
+
+ size_t total_memory = 0;
+ for (const auto& info : list) {
+ total_memory += info.size * info.num_allocations;
+ }
+
+ fprintf(fp, "Total memory: %zu\n", total_memory);
+ fprintf(fp, "Allocation records: %zd\n", list.size());
+ fprintf(fp, "Backtrace size: %zu\n", g_debug->config().backtrace_frames());
+ fprintf(fp, "\n");
+
+ for (const auto& info : list) {
+ fprintf(fp, "z %d sz %8zu num %zu bt", (info.zygote_child_alloc) ? 1 : 0, info.size,
+ info.num_allocations);
+ FrameInfoType* frame_info = info.frame_info;
+ if (frame_info != nullptr) {
+ for (size_t i = 0; i < frame_info->frames.size(); i++) {
+ if (frame_info->frames[i] == 0) {
+ break;
+ }
+#if defined(__LP64__)
+ fprintf(fp, " %016" PRIxPTR, frame_info->frames[i]);
+#else
+ fprintf(fp, " %08" PRIxPTR, frame_info->frames[i]);
+#endif
+ }
+ }
+ fprintf(fp, "\n");
+ }
+}
+
+void PointerData::PrepareFork() NO_THREAD_SAFETY_ANALYSIS {
+ pointer_mutex_.lock();
+ frame_mutex_.lock();
+ free_pointer_mutex_.lock();
+}
+
+void PointerData::PostForkParent() NO_THREAD_SAFETY_ANALYSIS {
+ frame_mutex_.unlock();
+ pointer_mutex_.unlock();
+ free_pointer_mutex_.unlock();
+}
+
+void PointerData::PostForkChild() __attribute__((no_thread_safety_analysis)) {
+ // Make sure that any potential mutexes have been released and are back
+ // to an initial state.
+ frame_mutex_.try_lock();
+ frame_mutex_.unlock();
+ pointer_mutex_.try_lock();
+ pointer_mutex_.unlock();
+ free_pointer_mutex_.try_lock();
+ free_pointer_mutex_.unlock();
+}
diff --git a/libc/malloc_debug/PointerData.h b/libc/malloc_debug/PointerData.h
new file mode 100644
index 0000000..7a0b3b8
--- /dev/null
+++ b/libc/malloc_debug/PointerData.h
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include <atomic>
+#include <deque>
+#include <mutex>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include <private/bionic_macros.h>
+
+#include "OptionData.h"
+
+extern int* g_malloc_zygote_child;
+
+// Forward declarations.
+class Config;
+
+struct FrameKeyType {
+ size_t num_frames;
+ uintptr_t* frames;
+
+ bool operator==(const FrameKeyType& comp) const {
+ if (num_frames != comp.num_frames) return false;
+ for (size_t i = 0; i < num_frames; i++) {
+ if (frames[i] != comp.frames[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+};
+
+namespace std {
+template <>
+struct hash<FrameKeyType> {
+ std::size_t operator()(const FrameKeyType& key) const {
+ std::size_t cur_hash = key.frames[0];
+ // Limit the number of frames to speed up hashing.
+ size_t max_frames = (key.num_frames > 5) ? 5 : key.num_frames;
+ for (size_t i = 1; i < max_frames; i++) {
+ cur_hash ^= key.frames[i];
+ }
+ return cur_hash;
+ }
+};
+}; // namespace std
+
+struct FrameInfoType {
+ size_t references = 0;
+ std::vector<uintptr_t> frames;
+};
+
+struct PointerInfoType {
+ size_t size;
+ size_t hash_index;
+ size_t RealSize() const { return size & ~(1U << 31); }
+ bool ZygoteChildAlloc() const { return size & (1U << 31); }
+ static size_t GetEncodedSize(size_t size) { return GetEncodedSize(*g_malloc_zygote_child, size); }
+ static size_t GetEncodedSize(bool child_alloc, size_t size) {
+ return size | ((child_alloc) ? (1U << 31) : 0);
+ }
+ static size_t MaxSize() { return (1U << 31) - 1; }
+};
+
+struct FreePointerInfoType {
+ uintptr_t pointer;
+ size_t hash_index;
+};
+
+struct ListInfoType {
+ uintptr_t pointer;
+ size_t num_allocations;
+ size_t size;
+ bool zygote_child_alloc;
+ FrameInfoType* frame_info;
+};
+
+class PointerData : public OptionData {
+ public:
+ PointerData(DebugData* debug_data);
+ virtual ~PointerData() = default;
+
+ bool Initialize(const Config& config);
+
+ inline size_t alloc_offset() { return alloc_offset_; }
+
+ bool ShouldBacktrace() { return backtrace_enabled_ == 1; }
+ void ToggleBacktraceEnabled() { backtrace_enabled_.fetch_xor(1); }
+
+ void EnableDumping() { backtrace_dump_ = true; }
+ bool ShouldDumpAndReset() {
+ bool expected = true;
+ return backtrace_dump_.compare_exchange_strong(expected, false);
+ }
+
+ void PrepareFork();
+ void PostForkParent();
+ void PostForkChild();
+
+ static void GetList(std::vector<ListInfoType>* list, bool only_with_backtrace);
+ static void GetUniqueList(std::vector<ListInfoType>* list, bool only_with_backtrace);
+
+ static size_t AddBacktrace(size_t num_frames);
+ static void RemoveBacktrace(size_t hash_index);
+
+ static void Add(const void* pointer, size_t size);
+ static void Remove(const void* pointer);
+
+ typedef std::unordered_map<uintptr_t, PointerInfoType>::iterator iterator;
+ static iterator begin() { return pointers_.begin(); }
+ static iterator end() { return pointers_.end(); }
+
+ static void* AddFreed(const void* pointer);
+ static void LogFreeError(const FreePointerInfoType& info, size_t usable_size);
+ static void LogFreeBacktrace(const void* ptr);
+ static void VerifyFreedPointer(const FreePointerInfoType& info);
+ static void VerifyAllFreed();
+
+ static void LogLeaks();
+ static void DumpLiveToFile(FILE* fp);
+
+ static void GetInfo(uint8_t** info, size_t* overall_size, size_t* info_size, size_t* total_memory,
+ size_t* backtrace_size);
+
+ static size_t GetFrames(const void* pointer, uintptr_t* frames, size_t max_frames);
+
+ static bool Exists(const void* pointer);
+
+ private:
+ static std::string GetHashString(uintptr_t* frames, size_t num_frames);
+
+ size_t alloc_offset_ = 0;
+ std::vector<uint8_t> cmp_mem_;
+
+ static std::atomic_uint8_t backtrace_enabled_;
+
+ static std::atomic_bool backtrace_dump_;
+
+ static std::mutex pointer_mutex_;
+ static std::unordered_map<uintptr_t, PointerInfoType> pointers_;
+
+ static std::mutex frame_mutex_;
+ static std::unordered_map<FrameKeyType, size_t> key_to_index_;
+ static std::unordered_map<size_t, FrameInfoType> frames_;
+ static size_t cur_hash_index_;
+
+ static std::mutex free_pointer_mutex_;
+ static std::deque<FreePointerInfoType> free_pointers_;
+
+ DISALLOW_COPY_AND_ASSIGN(PointerData);
+};
diff --git a/libc/malloc_debug/README.md b/libc/malloc_debug/README.md
index 69d0648..59ab6ad 100644
--- a/libc/malloc_debug/README.md
+++ b/libc/malloc_debug/README.md
@@ -33,6 +33,13 @@
Any errors detected by the library are reported in the log.
+NOTE: There is a small behavioral change beginning in P for realloc.
+Before, a realloc from one size to a smaller size would not update the
+backtrace related to the allocation. Starting in P, every single realloc
+call changes the backtrace for the pointer no matter whether the pointer
+returned has changed or not.
+
+
Controlling Malloc Debug Behavior
---------------------------------
Malloc debug is controlled by individual options. Each option can be enabled
@@ -106,8 +113,9 @@
capture in a backtrace. The default is 16 frames, the maximumum value
this can be set to is 256.
-This option adds a special header to all allocations that contains the
-backtrace and information about the original allocation.
+Before P, this option adds a special header to all allocations that contains
+the backtrace and information about the original allocation. After that, this
+option will not add a special header.
As of P, this option will also enable dumping backtrace heap data to a
file when the process receives the signal SIGRTMAX - 17 ( which is 47 on most
@@ -132,8 +140,9 @@
capture in a backtrace. The default is 16 frames, the maximumum value
this can be set to is 256.
-This option adds a special header to all allocations that contains the
-backtrace and information about the original allocation.
+Before P, this option adds a special header to all allocations that contains
+the backtrace and information about the original allocation. After that, this
+option will not add a special header.
### backtrace\_dump\_on\_exit
As of P, when the backtrace option has been enabled, this causes the backtrace
@@ -201,8 +210,9 @@
in the list. The default is to record 100 freed allocations, the max
allocations to record is 16384.
-This option adds a special header to all allocations that contains
-information about the original allocation.
+Before P, this option adds a special header to all allocations that contains
+the backtrace and information about the original allocation. After that, this
+option will not add a special header.
Example error:
@@ -238,8 +248,9 @@
option is not useful when enabled globally because a lot of programs do not
free everything before the program terminates.
-This option adds a special header to all allocations that contains
-information about the original allocation.
+Before P, this option adds a special header to all allocations that contains
+the backtrace and information about the original allocation. After that, this
+option will not add a special header.
Example leak error found in the log:
@@ -362,6 +373,26 @@
**NOTE**: This option is not available until the O release of Android.
+### verify\_pointers
+Track all live allocations to determine if a pointer is used that does not
+exist. This option is a lightweight way to verify that all
+free/malloc\_usable\_size/realloc calls are passed valid pointers.
+
+Example error:
+
+ 04-15 12:00:31.304 7412 7412 E malloc_debug: +++ ALLOCATION 0x12345678 UNKNOWN POINTER (free)
+ 04-15 12:00:31.305 7412 7412 E malloc_debug: Backtrace at time of failure:
+ 04-15 12:00:31.305 7412 7412 E malloc_debug: #00 pc 00029310 /system/lib/libc.so
+ 04-15 12:00:31.305 7412 7412 E malloc_debug: #01 pc 00021438 /system/lib/libc.so (newlocale+160)
+ 04-15 12:00:31.305 7412 7412 E malloc_debug: #02 pc 000a9e38 /system/lib/libc++.so
+ 04-15 12:00:31.305 7412 7412 E malloc_debug: #03 pc 000a28a8 /system/lib/libc++.so
+
+Where the name of the function varies depending on the function that called
+with a bad pointer. Only three functions do this checking: free,
+malloc\_usable\_size, realloc.
+
+**NOTE**: This option is not available until the P release of Android.
+
Additional Errors
-----------------
There are a few other error messages that might appear in the log.
diff --git a/libc/malloc_debug/RecordData.cpp b/libc/malloc_debug/RecordData.cpp
index 8e9c671..aea2513 100644
--- a/libc/malloc_debug/RecordData.cpp
+++ b/libc/malloc_debug/RecordData.cpp
@@ -40,10 +40,10 @@
#include <android-base/stringprintf.h>
#include "Config.h"
-#include "debug_disable.h"
-#include "debug_log.h"
#include "DebugData.h"
#include "RecordData.h"
+#include "debug_disable.h"
+#include "debug_log.h"
RecordEntry::RecordEntry() : tid_(gettid()) {
}
@@ -52,52 +52,45 @@
return android::base::StringPrintf("%d: thread_done 0x0\n", tid_);
}
-AllocEntry::AllocEntry(void* pointer) : pointer_(pointer) {
-}
+AllocEntry::AllocEntry(void* pointer) : pointer_(pointer) {}
-MallocEntry::MallocEntry(void* pointer, size_t size) : AllocEntry(pointer), size_(size) {
-}
+MallocEntry::MallocEntry(void* pointer, size_t size) : AllocEntry(pointer), size_(size) {}
std::string MallocEntry::GetString() const {
return android::base::StringPrintf("%d: malloc %p %zu\n", tid_, pointer_, size_);
}
-FreeEntry::FreeEntry(void* pointer) : AllocEntry(pointer) {
-}
+FreeEntry::FreeEntry(void* pointer) : AllocEntry(pointer) {}
std::string FreeEntry::GetString() const {
return android::base::StringPrintf("%d: free %p\n", tid_, pointer_);
}
CallocEntry::CallocEntry(void* pointer, size_t nmemb, size_t size)
- : MallocEntry(pointer, size), nmemb_(nmemb) {
-}
+ : MallocEntry(pointer, size), nmemb_(nmemb) {}
std::string CallocEntry::GetString() const {
return android::base::StringPrintf("%d: calloc %p %zu %zu\n", tid_, pointer_, nmemb_, size_);
}
ReallocEntry::ReallocEntry(void* pointer, size_t size, void* old_pointer)
- : MallocEntry(pointer, size), old_pointer_(old_pointer) {
-}
+ : MallocEntry(pointer, size), old_pointer_(old_pointer) {}
std::string ReallocEntry::GetString() const {
- return android::base::StringPrintf("%d: realloc %p %p %zu\n", tid_, pointer_,
- old_pointer_, size_);
+ return android::base::StringPrintf("%d: realloc %p %p %zu\n", tid_, pointer_, old_pointer_, size_);
}
// aligned_alloc, posix_memalign, memalign, pvalloc, valloc all recorded with this class.
MemalignEntry::MemalignEntry(void* pointer, size_t size, size_t alignment)
- : MallocEntry(pointer, size), alignment_(alignment) {
-}
+ : MallocEntry(pointer, size), alignment_(alignment) {}
std::string MemalignEntry::GetString() const {
- return android::base::StringPrintf("%d: memalign %p %zu %zu\n", tid_, pointer_,
- alignment_, size_);
+ return android::base::StringPrintf("%d: memalign %p %zu %zu\n", tid_, pointer_, alignment_, size_);
}
struct ThreadData {
- ThreadData(RecordData* record_data, ThreadCompleteEntry* entry) : record_data(record_data), entry(entry) {}
+ ThreadData(RecordData* record_data, ThreadCompleteEntry* entry)
+ : record_data(record_data), entry(entry) {}
RecordData* record_data;
ThreadCompleteEntry* entry;
size_t count = 0;
@@ -141,8 +134,8 @@
last_entry_index = num_entries_;
}
- int dump_fd = open(dump_file_.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
- 0755);
+ int dump_fd =
+ open(dump_file_.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW, 0755);
if (dump_fd != -1) {
for (size_t i = 0; i < last_entry_index; i++) {
std::string line = entries_[i]->GetString();
@@ -201,7 +194,7 @@
}
RecordData::~RecordData() {
- delete [] entries_;
+ delete[] entries_;
pthread_key_delete(key_);
}
diff --git a/libc/malloc_debug/RecordData.h b/libc/malloc_debug/RecordData.h
index 021a299..3e5ca02 100644
--- a/libc/malloc_debug/RecordData.h
+++ b/libc/malloc_debug/RecordData.h
@@ -28,8 +28,8 @@
#pragma once
-#include <stdint.h>
#include <pthread.h>
+#include <stdint.h>
#include <unistd.h>
#include <atomic>
diff --git a/libc/malloc_debug/TrackData.cpp b/libc/malloc_debug/TrackData.cpp
deleted file mode 100644
index 4266aa2..0000000
--- a/libc/malloc_debug/TrackData.cpp
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Copyright (C) 2015 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 <pthread.h>
-#include <stdint.h>
-#include <stdlib.h>
-
-#include <algorithm>
-#include <vector>
-
-#include <private/ScopedPthreadMutexLocker.h>
-
-#include "backtrace.h"
-#include "BacktraceData.h"
-#include "Config.h"
-#include "DebugData.h"
-#include "debug_disable.h"
-#include "debug_log.h"
-#include "malloc_debug.h"
-#include "TrackData.h"
-
-TrackData::TrackData(DebugData* debug_data) : OptionData(debug_data) {
-}
-
-void TrackData::GetList(std::vector<const Header*>* list) {
- for (const auto& header : headers_) {
- list->push_back(header);
- }
-
- // Sort by the size of the allocation.
- std::sort(list->begin(), list->end(), [](const Header* a, const Header* b) {
- if (a->size == b->size) return a < b;
- return a->size > b->size;
- });
-}
-
-void TrackData::GetListBySizeThenBacktrace(std::vector<const Header*>* list, size_t* total_memory) {
- if (!(debug_->config().options() & BACKTRACE)) {
- return;
- }
-
- *total_memory = 0;
- for (const auto& header : headers_) {
- list->push_back(header);
- *total_memory += header->real_size();
- }
-
- // Put all zygote allocations first by size and backtrace.
- // Then all zygote child allocation by size and backtrace.
- std::sort(list->begin(), list->end(), [&](const Header* a, const Header* b) {
- if (a->zygote_child_alloc() && !b->zygote_child_alloc()) {
- return false;
- } else if (!a->zygote_child_alloc() && b->zygote_child_alloc()) {
- return true;
- }
- if (a->real_size() != b->real_size()) return a->real_size() < b->real_size();
- // If the size is the same, compare backtrace elements.
- BacktraceHeader* a_back = debug_->GetAllocBacktrace(a);
- BacktraceHeader* b_back = debug_->GetAllocBacktrace(b);
- for (size_t i = 0; i < a_back->num_frames; i++) {
- if (i > b_back->num_frames) {
- // All frames equal up to this point, but a has more frames available.
- return false;
- }
- if (a_back->frames[i] < b_back->frames[i]) {
- return false;
- } else if (a_back->frames[i] > b_back->frames[i]) {
- return true;
- }
- }
- if (a_back->num_frames < b_back->num_frames) {
- // All frames equal up to this point, but b has more frames available.
- return true;
- }
- return false;
- });
-
-}
-
-void TrackData::Add(const Header* header, bool backtrace_found) {
- pthread_mutex_lock(&mutex_);
- if (backtrace_found) {
- total_backtrace_allocs_++;
- }
- headers_.insert(header);
- pthread_mutex_unlock(&mutex_);
-}
-
-void TrackData::Remove(const Header* header, bool backtrace_found) {
- pthread_mutex_lock(&mutex_);
- headers_.erase(header);
- if (backtrace_found) {
- total_backtrace_allocs_--;
- }
- pthread_mutex_unlock(&mutex_);
-}
-
-bool TrackData::Contains(const Header* header) {
- pthread_mutex_lock(&mutex_);
- bool found = headers_.count(header);
- pthread_mutex_unlock(&mutex_);
- return found;
-}
-
-void TrackData::DisplayLeaks() {
- std::vector<const Header*> list;
- GetList(&list);
-
- size_t track_count = 0;
- for (const auto& header : list) {
- error_log("+++ %s leaked block of size %zu at %p (leak %zu of %zu)", getprogname(),
- header->real_size(), debug_->GetPointer(header), ++track_count, list.size());
- if (debug_->config().options() & BACKTRACE) {
- BacktraceHeader* back_header = debug_->GetAllocBacktrace(header);
- if (back_header->num_frames > 0) {
- error_log("Backtrace at time of allocation:");
- backtrace_log(&back_header->frames[0], back_header->num_frames);
- }
- }
- g_dispatch->free(header->orig_pointer);
- }
-}
-
-void TrackData::GetInfo(uint8_t** info, size_t* overall_size, size_t* info_size,
- size_t* total_memory, size_t* backtrace_size) {
- ScopedPthreadMutexLocker scoped(&mutex_);
-
- if (headers_.size() == 0 || total_backtrace_allocs_ == 0) {
- return;
- }
-
- *backtrace_size = debug_->config().backtrace_frames();
- *info_size = sizeof(size_t) * 2 + sizeof(uintptr_t) * *backtrace_size;
- *info = reinterpret_cast<uint8_t*>(g_dispatch->calloc(*info_size, total_backtrace_allocs_));
- if (*info == nullptr) {
- return;
- }
- *overall_size = *info_size * total_backtrace_allocs_;
-
- std::vector<const Header*> list;
- GetList(&list);
-
- uint8_t* data = *info;
- size_t num_allocations = 1;
- for (const auto& header : list) {
- BacktraceHeader* back_header = debug_->GetAllocBacktrace(header);
- if (back_header->num_frames > 0) {
- memcpy(data, &header->size, sizeof(size_t));
- memcpy(&data[sizeof(size_t)], &num_allocations, sizeof(size_t));
- memcpy(&data[2 * sizeof(size_t)], &back_header->frames[0],
- back_header->num_frames * sizeof(uintptr_t));
-
- *total_memory += header->real_size();
-
- data += *info_size;
- }
- }
-}
diff --git a/libc/malloc_debug/TrackData.h b/libc/malloc_debug/TrackData.h
deleted file mode 100644
index 7201c49..0000000
--- a/libc/malloc_debug/TrackData.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2015 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.
- */
-
-#pragma once
-
-#include <stdint.h>
-#include <pthread.h>
-
-#include <vector>
-#include <unordered_set>
-
-#include <private/bionic_macros.h>
-
-#include "OptionData.h"
-
-// Forward declarations.
-struct Header;
-class Config;
-class DebugData;
-
-class TrackData : public OptionData {
- public:
- explicit TrackData(DebugData* debug_data);
- virtual ~TrackData() = default;
-
- void GetList(std::vector<const Header*>* list);
-
- void GetListBySizeThenBacktrace(std::vector<const Header*>* list, size_t* total_memory);
-
- void Add(const Header* header, bool backtrace_found);
-
- void Remove(const Header* header, bool backtrace_found);
-
- bool Contains(const Header *header);
-
- void GetInfo(uint8_t** info, size_t* overall_size, size_t* info_size,
- size_t* total_memory, size_t* backtrace_size);
-
- void DisplayLeaks();
-
- void PrepareFork() { pthread_mutex_lock(&mutex_); }
- void PostForkParent() { pthread_mutex_unlock(&mutex_); }
- void PostForkChild() { pthread_mutex_init(&mutex_, NULL); }
-
- private:
- pthread_mutex_t mutex_ = PTHREAD_MUTEX_INITIALIZER;
- std::unordered_set<const Header*> headers_;
- size_t total_backtrace_allocs_ = 0;
-
- DISALLOW_COPY_AND_ASSIGN(TrackData);
-};
diff --git a/libc/malloc_debug/backtrace.cpp b/libc/malloc_debug/backtrace.cpp
index 2443ba1..cd8c334 100644
--- a/libc/malloc_debug/backtrace.cpp
+++ b/libc/malloc_debug/backtrace.cpp
@@ -38,9 +38,9 @@
#include <demangle.h>
+#include "MapData.h"
#include "backtrace.h"
#include "debug_log.h"
-#include "MapData.h"
#if defined(__LP64__)
#define PAD_PTR "016" PRIxPTR
@@ -69,8 +69,7 @@
_Unwind_Backtrace(find_current_map, nullptr);
}
-void backtrace_shutdown() {
-}
+void backtrace_shutdown() {}
struct stack_crawl_state_t {
uintptr_t* frames;
@@ -165,13 +164,13 @@
char buf[1024];
if (symbol != nullptr) {
- async_safe_format_buffer(
- buf, sizeof(buf), " #%02zd pc %" PAD_PTR " %s%s (%s+%" PRIuPTR ")\n", frame_num,
- rel_pc, soname, offset_buf, demangle(symbol).c_str(), frames[frame_num] - offset);
+ async_safe_format_buffer(buf, sizeof(buf),
+ " #%02zd pc %" PAD_PTR " %s%s (%s+%" PRIuPTR ")\n",
+ frame_num, rel_pc, soname, offset_buf, demangle(symbol).c_str(),
+ frames[frame_num] - offset);
} else {
- async_safe_format_buffer(
- buf, sizeof(buf), " #%02zd pc %" PAD_PTR " %s%s\n", frame_num, rel_pc, soname,
- offset_buf);
+ async_safe_format_buffer(buf, sizeof(buf), " #%02zd pc %" PAD_PTR " %s%s\n",
+ frame_num, rel_pc, soname, offset_buf);
}
str += buf;
}
diff --git a/libc/malloc_debug/debug_log.h b/libc/malloc_debug/debug_log.h
index 54dd221..d2257df 100644
--- a/libc/malloc_debug/debug_log.h
+++ b/libc/malloc_debug/debug_log.h
@@ -33,11 +33,10 @@
// =============================================================================
// log functions
// =============================================================================
-#define debug_log(format, ...) \
- async_safe_format_log(ANDROID_LOG_DEBUG, "malloc_debug", (format), ##__VA_ARGS__ )
-#define error_log(format, ...) \
- async_safe_format_log(ANDROID_LOG_ERROR, "malloc_debug", (format), ##__VA_ARGS__ )
-#define error_log_string(str) \
- async_safe_write_log(ANDROID_LOG_ERROR, "malloc_debug", (str))
-#define info_log(format, ...) \
- async_safe_format_log(ANDROID_LOG_INFO, "malloc_debug", (format), ##__VA_ARGS__ )
+#define debug_log(format, ...) \
+ async_safe_format_log(ANDROID_LOG_DEBUG, "malloc_debug", (format), ##__VA_ARGS__)
+#define error_log(format, ...) \
+ async_safe_format_log(ANDROID_LOG_ERROR, "malloc_debug", (format), ##__VA_ARGS__)
+#define error_log_string(str) async_safe_write_log(ANDROID_LOG_ERROR, "malloc_debug", (str))
+#define info_log(format, ...) \
+ async_safe_format_log(ANDROID_LOG_INFO, "malloc_debug", (format), ##__VA_ARGS__)
diff --git a/libc/malloc_debug/malloc_debug.cpp b/libc/malloc_debug/malloc_debug.cpp
index ecfbd71..6f841ca 100644
--- a/libc/malloc_debug/malloc_debug.cpp
+++ b/libc/malloc_debug/malloc_debug.cpp
@@ -41,9 +41,9 @@
#include <android-base/stringprintf.h>
#include <private/bionic_malloc_dispatch.h>
-#include "backtrace.h"
#include "Config.h"
#include "DebugData.h"
+#include "backtrace.h"
#include "debug_disable.h"
#include "debug_log.h"
#include "malloc_debug.h"
@@ -66,12 +66,11 @@
__BEGIN_DECLS
bool debug_initialize(const MallocDispatch* malloc_dispatch, int* malloc_zygote_child,
- const char* options);
+ const char* options);
void debug_finalize();
bool debug_dump_heap(const char* file_name);
-void debug_get_malloc_leak_info(
- uint8_t** info, size_t* overall_size, size_t* info_size, size_t* total_memory,
- size_t* backtrace_size);
+void debug_get_malloc_leak_info(uint8_t** info, size_t* overall_size, size_t* info_size,
+ size_t* total_memory, size_t* backtrace_size);
ssize_t debug_malloc_backtrace(void* pointer, uintptr_t* frames, size_t frame_count);
void debug_free_malloc_leak_info(uint8_t* info);
size_t debug_malloc_usable_size(void* pointer);
@@ -85,7 +84,7 @@
int debug_mallopt(int param, int value);
int debug_posix_memalign(void** memptr, size_t alignment, size_t size);
int debug_iterate(uintptr_t base, size_t size,
- void (*callback)(uintptr_t base, size_t size, void* arg), void* arg);
+ void (*callback)(uintptr_t base, size_t size, void* arg), void* arg);
void debug_malloc_disable();
void debug_malloc_enable();
@@ -99,59 +98,92 @@
static void InitAtfork() {
static pthread_once_t atfork_init = PTHREAD_ONCE_INIT;
- pthread_once(&atfork_init, [](){
+ pthread_once(&atfork_init, []() {
pthread_atfork(
- [](){
+ []() {
if (g_debug != nullptr) {
g_debug->PrepareFork();
}
},
- [](){
+ []() {
if (g_debug != nullptr) {
g_debug->PostForkParent();
}
},
- [](){
+ []() {
if (g_debug != nullptr) {
g_debug->PostForkChild();
}
- }
- );
+ });
});
}
-static void LogTagError(const Header* header, const void* pointer, const char* name) {
+static void LogError(const void* pointer, const char* error_str) {
error_log(LOG_DIVIDER);
- if (header->tag == DEBUG_FREE_TAG) {
- error_log("+++ ALLOCATION %p USED AFTER FREE (%s)", pointer, name);
- if (g_debug->config().options() & FREE_TRACK) {
- g_debug->free_track->LogBacktrace(header);
- }
- } else {
- error_log("+++ ALLOCATION %p HAS INVALID TAG %" PRIx32 " (%s)", pointer, header->tag, name);
+ error_log("+++ ALLOCATION %p %s", pointer, error_str);
+
+ // If we are tracking already freed pointers, check to see if this is
+ // one so we can print extra information.
+ if (g_debug->config().options() & FREE_TRACK) {
+ PointerData::LogFreeBacktrace(pointer);
}
- error_log("Backtrace at time of failure:");
- std::vector<uintptr_t> frames(64);
- size_t frame_num = backtrace_get(frames.data(), frames.size());
- frames.resize(frame_num);
- backtrace_log(frames.data(), frames.size());
+
+ std::vector<uintptr_t> frames(128);
+ size_t num_frames = backtrace_get(frames.data(), frames.size());
+ if (num_frames == 0) {
+ error_log("Backtrace failed to get any frames.");
+ } else {
+ error_log("Backtrace at time of failure:");
+ backtrace_log(frames.data(), num_frames);
+ }
error_log(LOG_DIVIDER);
}
+static bool VerifyPointer(const void* pointer, const char* function_name) {
+ if (g_debug->HeaderEnabled()) {
+ Header* header = g_debug->GetHeader(pointer);
+ if (header->tag != DEBUG_TAG) {
+ std::string error_str;
+ if (header->tag == DEBUG_FREE_TAG) {
+ error_str = std::string("USED AFTER FREE (") + function_name + ")";
+ } else {
+ error_str = android::base::StringPrintf("HAS INVALID TAG %" PRIx32 " (%s)", header->tag,
+ function_name);
+ }
+ LogError(pointer, error_str.c_str());
+ return false;
+ }
+ }
+
+ if (g_debug->TrackPointers()) {
+ if (!PointerData::Exists(pointer)) {
+ std::string error_str(std::string("UNKNOWN POINTER (") + function_name + ")");
+ LogError(pointer, error_str.c_str());
+ return false;
+ }
+ }
+ return true;
+}
+
+static size_t InternalMallocUsableSize(void* pointer) {
+ if (g_debug->HeaderEnabled()) {
+ return g_debug->GetHeader(pointer)->usable_size;
+ } else {
+ return g_dispatch->malloc_usable_size(pointer);
+ }
+}
+
static void* InitHeader(Header* header, void* orig_pointer, size_t size) {
header->tag = DEBUG_TAG;
header->orig_pointer = orig_pointer;
header->size = size;
- if (*g_malloc_zygote_child) {
- header->set_zygote_child_alloc();
- }
header->usable_size = g_dispatch->malloc_usable_size(orig_pointer);
if (header->usable_size == 0) {
g_dispatch->free(orig_pointer);
return nullptr;
}
- header->usable_size -= g_debug->pointer_offset() +
- reinterpret_cast<uintptr_t>(header) - reinterpret_cast<uintptr_t>(orig_pointer);
+ header->usable_size -= g_debug->pointer_offset() + reinterpret_cast<uintptr_t>(header) -
+ reinterpret_cast<uintptr_t>(orig_pointer);
if (g_debug->config().options() & FRONT_GUARD) {
uint8_t* guard = g_debug->GetFrontGuard(header);
@@ -163,30 +195,14 @@
memset(guard, g_debug->config().rear_guard_value(), g_debug->config().rear_guard_bytes());
// If the rear guard is enabled, set the usable size to the exact size
// of the allocation.
- header->usable_size = header->real_size();
- }
-
- bool backtrace_found = false;
- if (g_debug->config().options() & BACKTRACE) {
- BacktraceHeader* back_header = g_debug->GetAllocBacktrace(header);
- if (g_debug->backtrace->ShouldBacktrace()) {
- back_header->num_frames = backtrace_get(
- &back_header->frames[0], g_debug->config().backtrace_frames());
- backtrace_found = back_header->num_frames > 0;
- } else {
- back_header->num_frames = 0;
- }
- }
-
- if (g_debug->config().options() & TRACK_ALLOCS) {
- g_debug->track->Add(header, backtrace_found);
+ header->usable_size = header->size;
}
return g_debug->GetPointer(header);
}
bool debug_initialize(const MallocDispatch* malloc_dispatch, int* malloc_zygote_child,
- const char* options) {
+ const char* options) {
if (malloc_zygote_child == nullptr || options == nullptr) {
return false;
}
@@ -222,18 +238,19 @@
}
if (g_debug->config().options() & FREE_TRACK) {
- g_debug->free_track->VerifyAll();
+ PointerData::VerifyAllFreed();
}
if (g_debug->config().options() & LEAK_TRACK) {
- g_debug->track->DisplayLeaks();
+ PointerData::LogLeaks();
}
if ((g_debug->config().options() & BACKTRACE) && g_debug->config().backtrace_dump_on_exit()) {
ScopedDisableDebugCalls disable;
- debug_dump_heap(
- android::base::StringPrintf("%s.%d.exit.txt",
- g_debug->config().backtrace_dump_prefix().c_str(), getpid()).c_str());
+ debug_dump_heap(android::base::StringPrintf("%s.%d.exit.txt",
+ g_debug->config().backtrace_dump_prefix().c_str(),
+ getpid())
+ .c_str());
}
DebugDisableSet(true);
@@ -246,13 +263,13 @@
DebugDisableFinalize();
}
-void debug_get_malloc_leak_info(uint8_t** info, size_t* overall_size,
- size_t* info_size, size_t* total_memory, size_t* backtrace_size) {
+void debug_get_malloc_leak_info(uint8_t** info, size_t* overall_size, size_t* info_size,
+ size_t* total_memory, size_t* backtrace_size) {
ScopedDisableDebugCalls disable;
// Verify the arguments.
- if (info == nullptr || overall_size == nullptr || info_size == NULL ||
- total_memory == nullptr || backtrace_size == nullptr) {
+ if (info == nullptr || overall_size == nullptr || info_size == NULL || total_memory == nullptr ||
+ backtrace_size == nullptr) {
error_log("get_malloc_leak_info: At least one invalid parameter.");
return;
}
@@ -264,47 +281,37 @@
*backtrace_size = 0;
if (!(g_debug->config().options() & BACKTRACE)) {
- error_log("get_malloc_leak_info: Allocations not being tracked, to enable "
- "set the option 'backtrace'.");
+ error_log(
+ "get_malloc_leak_info: Allocations not being tracked, to enable "
+ "set the option 'backtrace'.");
return;
}
- g_debug->track->GetInfo(info, overall_size, info_size, total_memory, backtrace_size);
+ PointerData::GetInfo(info, overall_size, info_size, total_memory, backtrace_size);
}
void debug_free_malloc_leak_info(uint8_t* info) {
g_dispatch->free(info);
}
-static size_t internal_malloc_usable_size(void* pointer) {
- if (g_debug->need_header()) {
- Header* header = g_debug->GetHeader(pointer);
- if (header->tag != DEBUG_TAG) {
- LogTagError(header, pointer, "malloc_usable_size");
- return 0;
- }
-
- return header->usable_size;
- } else {
- return g_dispatch->malloc_usable_size(pointer);
- }
-}
-
size_t debug_malloc_usable_size(void* pointer) {
if (DebugCallsDisabled() || pointer == nullptr) {
return g_dispatch->malloc_usable_size(pointer);
}
ScopedDisableDebugCalls disable;
- return internal_malloc_usable_size(pointer);
+ if (!VerifyPointer(pointer, "malloc_usable_size")) {
+ return 0;
+ }
+
+ return InternalMallocUsableSize(pointer);
}
-static void *internal_malloc(size_t size) {
- if ((g_debug->config().options() & BACKTRACE) && g_debug->backtrace->ShouldDumpAndReset()) {
- debug_dump_heap(
- android::base::StringPrintf("%s.%d.txt",
- g_debug->config().backtrace_dump_prefix().c_str(),
- getpid()).c_str());
+static void* InternalMalloc(size_t size) {
+ if ((g_debug->config().options() & BACKTRACE) && g_debug->pointer->ShouldDumpAndReset()) {
+ debug_dump_heap(android::base::StringPrintf(
+ "%s.%d.txt", g_debug->config().backtrace_dump_prefix().c_str(), getpid())
+ .c_str());
}
if (size == 0) {
@@ -318,15 +325,15 @@
return nullptr;
}
- void* pointer;
- if (g_debug->need_header()) {
- if (size > Header::max_size()) {
- errno = ENOMEM;
- return nullptr;
- }
+ if (size > PointerInfoType::MaxSize()) {
+ errno = ENOMEM;
+ return nullptr;
+ }
- Header* header = reinterpret_cast<Header*>(
- g_dispatch->memalign(MINIMUM_ALIGNMENT_BYTES, real_size));
+ void* pointer;
+ if (g_debug->HeaderEnabled()) {
+ Header* header =
+ reinterpret_cast<Header*>(g_dispatch->memalign(MINIMUM_ALIGNMENT_BYTES, real_size));
if (header == nullptr) {
return nullptr;
}
@@ -335,11 +342,17 @@
pointer = g_dispatch->malloc(real_size);
}
- if (pointer != nullptr && g_debug->config().options() & FILL_ON_ALLOC) {
- size_t bytes = internal_malloc_usable_size(pointer);
- size_t fill_bytes = g_debug->config().fill_on_alloc_bytes();
- bytes = (bytes < fill_bytes) ? bytes : fill_bytes;
- memset(pointer, g_debug->config().fill_alloc_value(), bytes);
+ if (pointer != nullptr) {
+ if (g_debug->TrackPointers()) {
+ PointerData::Add(pointer, size);
+ }
+
+ if (g_debug->config().options() & FILL_ON_ALLOC) {
+ size_t bytes = InternalMallocUsableSize(pointer);
+ size_t fill_bytes = g_debug->config().fill_on_alloc_bytes();
+ bytes = (bytes < fill_bytes) ? bytes : fill_bytes;
+ memset(pointer, g_debug->config().fill_alloc_value(), bytes);
+ }
}
return pointer;
}
@@ -350,7 +363,7 @@
}
ScopedDisableDebugCalls disable;
- void* pointer = internal_malloc(size);
+ void* pointer = InternalMalloc(size);
if (g_debug->config().options() & RECORD_ALLOCS) {
g_debug->record->AddEntry(new MallocEntry(pointer, size));
@@ -359,23 +372,18 @@
return pointer;
}
-static void internal_free(void* pointer) {
- if ((g_debug->config().options() & BACKTRACE) && g_debug->backtrace->ShouldDumpAndReset()) {
- debug_dump_heap(
- android::base::StringPrintf("%s.%d.txt",
- g_debug->config().backtrace_dump_prefix().c_str(),
- getpid()).c_str());
+static void InternalFree(void* pointer) {
+ if ((g_debug->config().options() & BACKTRACE) && g_debug->pointer->ShouldDumpAndReset()) {
+ debug_dump_heap(android::base::StringPrintf(
+ "%s.%d.txt", g_debug->config().backtrace_dump_prefix().c_str(), getpid())
+ .c_str());
}
void* free_pointer = pointer;
size_t bytes;
Header* header;
- if (g_debug->need_header()) {
+ if (g_debug->HeaderEnabled()) {
header = g_debug->GetHeader(pointer);
- if (header->tag != DEBUG_TAG) {
- LogTagError(header, pointer, "free");
- return;
- }
free_pointer = header->orig_pointer;
if (g_debug->config().options() & FRONT_GUARD) {
@@ -389,14 +397,6 @@
}
}
- if (g_debug->config().options() & TRACK_ALLOCS) {
- bool backtrace_found = false;
- if (g_debug->config().options() & BACKTRACE) {
- BacktraceHeader* back_header = g_debug->GetAllocBacktrace(header);
- backtrace_found = back_header->num_frames > 0;
- }
- g_debug->track->Remove(header, backtrace_found);
- }
header->tag = DEBUG_FREE_TAG;
bytes = header->usable_size;
@@ -410,13 +410,23 @@
memset(pointer, g_debug->config().fill_free_value(), bytes);
}
+ if (g_debug->TrackPointers()) {
+ PointerData::Remove(pointer);
+ }
+
if (g_debug->config().options() & FREE_TRACK) {
// Do not add the allocation until we are done modifying the pointer
// itself. This avoids a race if a lot of threads are all doing
// frees at the same time and we wind up trying to really free this
// pointer from another thread, while still trying to free it in
// this function.
- g_debug->free_track->Add(header);
+ pointer = PointerData::AddFreed(pointer);
+ if (pointer != nullptr) {
+ if (g_debug->HeaderEnabled()) {
+ pointer = g_debug->GetHeader(pointer)->orig_pointer;
+ }
+ g_dispatch->free(pointer);
+ }
} else {
g_dispatch->free(free_pointer);
}
@@ -432,7 +442,11 @@
g_debug->record->AddEntry(new FreeEntry(pointer));
}
- internal_free(pointer);
+ if (!VerifyPointer(pointer, "free")) {
+ return;
+ }
+
+ InternalFree(pointer);
}
void* debug_memalign(size_t alignment, size_t bytes) {
@@ -445,13 +459,13 @@
bytes = 1;
}
- void* pointer;
- if (g_debug->need_header()) {
- if (bytes > Header::max_size()) {
- errno = ENOMEM;
- return nullptr;
- }
+ if (bytes > PointerInfoType::MaxSize()) {
+ errno = ENOMEM;
+ return nullptr;
+ }
+ void* pointer;
+ if (g_debug->HeaderEnabled()) {
// Make the alignment a power of two.
if (!powerof2(alignment)) {
alignment = BIONIC_ROUND_UP_POWER_OF_2(alignment);
@@ -493,15 +507,21 @@
pointer = g_dispatch->memalign(alignment, real_size);
}
- if (pointer != nullptr && g_debug->config().options() & FILL_ON_ALLOC) {
- size_t bytes = internal_malloc_usable_size(pointer);
- size_t fill_bytes = g_debug->config().fill_on_alloc_bytes();
- bytes = (bytes < fill_bytes) ? bytes : fill_bytes;
- memset(pointer, g_debug->config().fill_alloc_value(), bytes);
- }
+ if (pointer != nullptr) {
+ if (g_debug->TrackPointers()) {
+ PointerData::Add(pointer, bytes);
+ }
- if (g_debug->config().options() & RECORD_ALLOCS) {
- g_debug->record->AddEntry(new MemalignEntry(pointer, bytes, alignment));
+ if (g_debug->config().options() & FILL_ON_ALLOC) {
+ size_t bytes = InternalMallocUsableSize(pointer);
+ size_t fill_bytes = g_debug->config().fill_on_alloc_bytes();
+ bytes = (bytes < fill_bytes) ? bytes : fill_bytes;
+ memset(pointer, g_debug->config().fill_alloc_value(), bytes);
+ }
+
+ if (g_debug->config().options() & RECORD_ALLOCS) {
+ g_debug->record->AddEntry(new MemalignEntry(pointer, bytes, alignment));
+ }
}
return pointer;
@@ -514,19 +534,23 @@
ScopedDisableDebugCalls disable;
if (pointer == nullptr) {
- pointer = internal_malloc(bytes);
+ pointer = InternalMalloc(bytes);
if (g_debug->config().options() & RECORD_ALLOCS) {
g_debug->record->AddEntry(new ReallocEntry(pointer, bytes, nullptr));
}
return pointer;
}
+ if (!VerifyPointer(pointer, "realloc")) {
+ return nullptr;
+ }
+
if (bytes == 0) {
if (g_debug->config().options() & RECORD_ALLOCS) {
g_debug->record->AddEntry(new ReallocEntry(nullptr, bytes, pointer));
}
- internal_free(pointer);
+ InternalFree(pointer);
return nullptr;
}
@@ -540,45 +564,45 @@
}
}
+ if (bytes > PointerInfoType::MaxSize()) {
+ errno = ENOMEM;
+ return nullptr;
+ }
+
void* new_pointer;
size_t prev_size;
- if (g_debug->need_header()) {
- if (bytes > Header::max_size()) {
- errno = ENOMEM;
- return nullptr;
- }
-
- Header* header = g_debug->GetHeader(pointer);
- if (header->tag != DEBUG_TAG) {
- LogTagError(header, pointer, "realloc");
- return nullptr;
- }
-
+ if (g_debug->HeaderEnabled()) {
// Same size, do nothing.
- if (real_size == header->real_size()) {
- // Do not bother recording, this is essentially a nop.
+ Header* header = g_debug->GetHeader(pointer);
+ if (real_size == header->size) {
+ if (g_debug->TrackPointers()) {
+ // Remove and re-add so that the backtrace is updated.
+ PointerData::Remove(pointer);
+ PointerData::Add(pointer, real_size);
+ }
return pointer;
}
// Allocation is shrinking.
if (real_size < header->usable_size) {
header->size = real_size;
- if (*g_malloc_zygote_child) {
- header->set_zygote_child_alloc();
- }
if (g_debug->config().options() & REAR_GUARD) {
// Don't bother allocating a smaller pointer in this case, simply
// change the header usable_size and reset the rear guard.
- header->usable_size = header->real_size();
+ header->usable_size = header->size;
memset(g_debug->GetRearGuard(header), g_debug->config().rear_guard_value(),
g_debug->config().rear_guard_bytes());
}
- // Do not bother recording, this is essentially a nop.
+ if (g_debug->TrackPointers()) {
+ // Remove and re-add so that the backtrace is updated.
+ PointerData::Remove(pointer);
+ PointerData::Add(pointer, real_size);
+ }
return pointer;
}
// Allocate the new size.
- new_pointer = internal_malloc(bytes);
+ new_pointer = InternalMalloc(bytes);
if (new_pointer == nullptr) {
errno = ENOMEM;
return nullptr;
@@ -586,17 +610,25 @@
prev_size = header->usable_size;
memcpy(new_pointer, pointer, prev_size);
- internal_free(pointer);
+ InternalFree(pointer);
} else {
+ if (g_debug->TrackPointers()) {
+ PointerData::Remove(pointer);
+ }
+
prev_size = g_dispatch->malloc_usable_size(pointer);
new_pointer = g_dispatch->realloc(pointer, real_size);
if (new_pointer == nullptr) {
return nullptr;
}
+
+ if (g_debug->TrackPointers()) {
+ PointerData::Add(new_pointer, real_size);
+ }
}
if (g_debug->config().options() & FILL_ON_ALLOC) {
- size_t bytes = internal_malloc_usable_size(new_pointer);
+ size_t bytes = InternalMallocUsableSize(new_pointer);
if (bytes > g_debug->config().fill_on_alloc_bytes()) {
bytes = g_debug->config().fill_on_alloc_bytes();
}
@@ -637,17 +669,16 @@
return nullptr;
}
- void* pointer;
- if (g_debug->need_header()) {
- // The above check will guarantee the multiply will not overflow.
- if (size > Header::max_size()) {
- errno = ENOMEM;
- return nullptr;
- }
+ if (real_size > PointerInfoType::MaxSize()) {
+ errno = ENOMEM;
+ return nullptr;
+ }
+ void* pointer;
+ if (g_debug->HeaderEnabled()) {
// Need to guarantee the alignment of the header.
- Header* header = reinterpret_cast<Header*>(
- g_dispatch->memalign(MINIMUM_ALIGNMENT_BYTES, real_size));
+ Header* header =
+ reinterpret_cast<Header*>(g_dispatch->memalign(MINIMUM_ALIGNMENT_BYTES, real_size));
if (header == nullptr) {
return nullptr;
}
@@ -656,9 +687,14 @@
} else {
pointer = g_dispatch->calloc(1, real_size);
}
+
if (g_debug->config().options() & RECORD_ALLOCS) {
g_debug->record->AddEntry(new CallocEntry(pointer, bytes, nmemb));
}
+
+ if (pointer != nullptr && g_debug->TrackPointers()) {
+ PointerData::Add(pointer, size);
+ }
return pointer;
}
@@ -695,81 +731,45 @@
return (*memptr != nullptr) ? 0 : ENOMEM;
}
-int debug_iterate(uintptr_t base, size_t size,
- void (*callback)(uintptr_t base, size_t size, void* arg), void* arg) {
- // Can't allocate, malloc is disabled
- // Manual capture of the arguments to pass to the lambda below as void* arg
- struct iterate_ctx {
- decltype(callback) callback;
- decltype(arg) arg;
- } ctx = { callback, arg };
+int debug_iterate(uintptr_t base, size_t size, void (*callback)(uintptr_t, size_t, void*),
+ void* arg) {
+ if (g_debug->TrackPointers()) {
+ // Since malloc is disabled, don't bother acquiring any locks.
+ for (auto it = PointerData::begin(); it != PointerData::end(); ++it) {
+ callback(it->first, InternalMallocUsableSize(reinterpret_cast<void*>(it->first)), arg);
+ }
+ return 0;
+ }
- return g_dispatch->iterate(base, size,
- [](uintptr_t base, size_t size, void* arg) {
- const iterate_ctx* ctx = reinterpret_cast<iterate_ctx*>(arg);
- const void* pointer = reinterpret_cast<void*>(base);
- if (g_debug->need_header()) {
- const Header* header = reinterpret_cast<const Header*>(pointer);
- if (g_debug->config().options() & TRACK_ALLOCS) {
- if (g_debug->track->Contains(header)) {
- // Return just the body of the allocation if we're sure the header exists
- ctx->callback(reinterpret_cast<uintptr_t>(g_debug->GetPointer(header)),
- header->usable_size, ctx->arg);
- return;
- }
- }
- }
- // Fall back to returning the whole allocation
- ctx->callback(base, size, ctx->arg);
- }, &ctx);
+ // An option that adds a header will add pointer tracking, so no need to
+ // check if headers are enabled.
+ return g_dispatch->iterate(base, size, callback, arg);
}
void debug_malloc_disable() {
g_dispatch->malloc_disable();
- if (g_debug->track) {
- g_debug->track->PrepareFork();
+ if (g_debug->pointer) {
+ g_debug->pointer->PrepareFork();
}
}
void debug_malloc_enable() {
- if (g_debug->track) {
- g_debug->track->PostForkParent();
+ if (g_debug->pointer) {
+ g_debug->pointer->PostForkParent();
}
g_dispatch->malloc_enable();
}
-ssize_t debug_malloc_backtrace(void* pointer, uintptr_t* frames, size_t frame_count) {
+ssize_t debug_malloc_backtrace(void* pointer, uintptr_t* frames, size_t max_frames) {
if (DebugCallsDisabled() || pointer == nullptr) {
return 0;
}
ScopedDisableDebugCalls disable;
- if (g_debug->need_header()) {
- Header* header;
- if (g_debug->config().options() & TRACK_ALLOCS) {
- header = g_debug->GetHeader(pointer);
- if (!g_debug->track->Contains(header)) {
- return 0;
- }
- } else {
- header = reinterpret_cast<Header*>(pointer);
- }
- if (header->tag != DEBUG_TAG) {
- return 0;
- }
- if (g_debug->config().options() & BACKTRACE) {
- BacktraceHeader* back_header = g_debug->GetAllocBacktrace(header);
- if (back_header->num_frames > 0) {
- if (frame_count > back_header->num_frames) {
- frame_count = back_header->num_frames;
- }
- memcpy(frames, &back_header->frames[0], frame_count * sizeof(uintptr_t));
- return frame_count;
- }
- }
+ if (!(g_debug->config().options() & BACKTRACE)) {
+ return 0;
}
-
- return 0;
+ return PointerData::GetFrames(pointer, frames, max_frames);
}
#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
@@ -821,30 +821,7 @@
fprintf(fp, "Android Native Heap Dump v1.0\n\n");
- std::vector<const Header*> list;
- size_t total_memory;
- g_debug->track->GetListBySizeThenBacktrace(&list, &total_memory);
- fprintf(fp, "Total memory: %zu\n", total_memory);
- fprintf(fp, "Allocation records: %zd\n", list.size());
- fprintf(fp, "Backtrace size: %zu\n", g_debug->config().backtrace_frames());
- fprintf(fp, "\n");
-
- for (const auto& header : list) {
- const BacktraceHeader* back_header = g_debug->GetAllocBacktrace(header);
- fprintf(fp, "z %d sz %8zu num 1 bt", (header->zygote_child_alloc()) ? 1 : 0,
- header->real_size());
- for (size_t i = 0; i < back_header->num_frames; i++) {
- if (back_header->frames[i] == 0) {
- break;
- }
-#ifdef __LP64__
- fprintf(fp, " %016" PRIxPTR, back_header->frames[i]);
-#else
- fprintf(fp, " %08" PRIxPTR, back_header->frames[i]);
-#endif
- }
- fprintf(fp, "\n");
- }
+ PointerData::DumpLiveToFile(fp);
fprintf(fp, "MAPS\n");
std::string content;
diff --git a/libc/malloc_debug/malloc_debug.h b/libc/malloc_debug/malloc_debug.h
index 18a6c2c..ac210e2 100644
--- a/libc/malloc_debug/malloc_debug.h
+++ b/libc/malloc_debug/malloc_debug.h
@@ -37,13 +37,10 @@
// part of the header does not exist, the other parts of the header
// will still be in this order.
// Header (Required)
-// BacktraceHeader (Optional: For the allocation backtrace)
// uint8_t data (Optional: Front guard, will be a multiple of MINIMUM_ALIGNMENT_BYTES)
// allocation data
// uint8_t data (Optional: End guard)
//
-// If backtracing is enabled, then both BacktraceHeaders will be present.
-//
// In the initialization function, offsets into the header will be set
// for each different header location. The offsets are always from the
// beginning of the Header section.
@@ -52,10 +49,6 @@
void* orig_pointer;
size_t size;
size_t usable_size;
- size_t real_size() const { return size & ~(1U << 31); }
- void set_zygote_child_alloc() { size |= 1U << 31; }
- bool zygote_child_alloc() const { return size & (1U << 31); }
- static size_t max_size() { return (1U << 31) - 1; }
} __attribute__((packed));
struct BacktraceHeader {
diff --git a/libc/malloc_debug/tests/malloc_debug_config_tests.cpp b/libc/malloc_debug/tests/malloc_debug_config_tests.cpp
index ee8fe06..4603535 100644
--- a/libc/malloc_debug/tests/malloc_debug_config_tests.cpp
+++ b/libc/malloc_debug/tests/malloc_debug_config_tests.cpp
@@ -135,6 +135,10 @@
"6 malloc_debug This option only has meaning if the record_allocs options has been specified.\n"
"6 malloc_debug This is the name of the file to which recording information will be dumped.\n"
"6 malloc_debug The default is /data/local/tmp/record_allocs.txt.\n"
+ "6 malloc_debug \n"
+ "6 malloc_debug verify_pointers\n"
+ "6 malloc_debug A lightweight way to verify that free/malloc_usable_size/realloc\n"
+ "6 malloc_debug are passed valid pointers.\n"
);
TEST_F(MallocDebugConfigTest, unknown_option) {
@@ -250,15 +254,15 @@
TEST_F(MallocDebugConfigTest, front_guard) {
ASSERT_TRUE(InitConfig("front_guard=48")) << getFakeLogPrint();
- ASSERT_EQ(FRONT_GUARD, config->options());
+ ASSERT_EQ(FRONT_GUARD | TRACK_ALLOCS, config->options());
ASSERT_EQ(48U, config->front_guard_bytes());
ASSERT_TRUE(InitConfig("front_guard")) << getFakeLogPrint();
- ASSERT_EQ(FRONT_GUARD, config->options());
+ ASSERT_EQ(FRONT_GUARD | TRACK_ALLOCS, config->options());
ASSERT_EQ(32U, config->front_guard_bytes());
ASSERT_TRUE(InitConfig("front_guard=39")) << getFakeLogPrint();
- ASSERT_EQ(FRONT_GUARD, config->options());
+ ASSERT_EQ(FRONT_GUARD | TRACK_ALLOCS, config->options());
#if defined(__LP64__)
ASSERT_EQ(48U, config->front_guard_bytes());
#else
@@ -266,7 +270,7 @@
#endif
ASSERT_TRUE(InitConfig("front_guard=41")) << getFakeLogPrint();
- ASSERT_EQ(FRONT_GUARD, config->options());
+ ASSERT_EQ(FRONT_GUARD | TRACK_ALLOCS, config->options());
ASSERT_EQ(48U, config->front_guard_bytes());
ASSERT_STREQ("", getFakeLogBuf().c_str());
@@ -275,11 +279,11 @@
TEST_F(MallocDebugConfigTest, rear_guard) {
ASSERT_TRUE(InitConfig("rear_guard=50")) << getFakeLogPrint();
- ASSERT_EQ(REAR_GUARD, config->options());
+ ASSERT_EQ(REAR_GUARD | TRACK_ALLOCS, config->options());
ASSERT_EQ(50U, config->rear_guard_bytes());
ASSERT_TRUE(InitConfig("rear_guard")) << getFakeLogPrint();
- ASSERT_EQ(REAR_GUARD, config->options());
+ ASSERT_EQ(REAR_GUARD | TRACK_ALLOCS, config->options());
ASSERT_EQ(32U, config->rear_guard_bytes());
ASSERT_STREQ("", getFakeLogBuf().c_str());
@@ -288,12 +292,12 @@
TEST_F(MallocDebugConfigTest, guard) {
ASSERT_TRUE(InitConfig("guard=32")) << getFakeLogPrint();
- ASSERT_EQ(FRONT_GUARD | REAR_GUARD, config->options());
+ ASSERT_EQ(FRONT_GUARD | REAR_GUARD | TRACK_ALLOCS, config->options());
ASSERT_EQ(32U, config->front_guard_bytes());
ASSERT_EQ(32U, config->rear_guard_bytes());
ASSERT_TRUE(InitConfig("guard")) << getFakeLogPrint();
- ASSERT_EQ(FRONT_GUARD | REAR_GUARD, config->options());
+ ASSERT_EQ(FRONT_GUARD | REAR_GUARD | TRACK_ALLOCS, config->options());
ASSERT_EQ(32U, config->front_guard_bytes());
ASSERT_EQ(32U, config->rear_guard_bytes());
@@ -465,13 +469,13 @@
TEST_F(MallocDebugConfigTest, free_track) {
ASSERT_TRUE(InitConfig("free_track=1234")) << getFakeLogPrint();
- ASSERT_EQ(FREE_TRACK | FILL_ON_FREE, config->options());
+ ASSERT_EQ(FREE_TRACK | FILL_ON_FREE | TRACK_ALLOCS, config->options());
ASSERT_EQ(1234U, config->free_track_allocations());
ASSERT_EQ(SIZE_MAX, config->fill_on_free_bytes());
ASSERT_EQ(16U, config->free_track_backtrace_num_frames());
ASSERT_TRUE(InitConfig("free_track")) << getFakeLogPrint();
- ASSERT_EQ(FREE_TRACK | FILL_ON_FREE, config->options());
+ ASSERT_EQ(FREE_TRACK | FILL_ON_FREE | TRACK_ALLOCS, config->options());
ASSERT_EQ(100U, config->free_track_allocations());
ASSERT_EQ(SIZE_MAX, config->fill_on_free_bytes());
ASSERT_EQ(16U, config->free_track_backtrace_num_frames());
@@ -482,20 +486,20 @@
TEST_F(MallocDebugConfigTest, free_track_and_fill_on_free) {
ASSERT_TRUE(InitConfig("free_track=1234 fill_on_free=32")) << getFakeLogPrint();
- ASSERT_EQ(FREE_TRACK | FILL_ON_FREE, config->options());
+ ASSERT_EQ(FREE_TRACK | FILL_ON_FREE | TRACK_ALLOCS, config->options());
ASSERT_EQ(1234U, config->free_track_allocations());
ASSERT_EQ(32U, config->fill_on_free_bytes());
ASSERT_EQ(16U, config->free_track_backtrace_num_frames());
ASSERT_TRUE(InitConfig("free_track fill_on_free=60")) << getFakeLogPrint();
- ASSERT_EQ(FREE_TRACK | FILL_ON_FREE, config->options());
+ ASSERT_EQ(FREE_TRACK | FILL_ON_FREE | TRACK_ALLOCS, config->options());
ASSERT_EQ(100U, config->free_track_allocations());
ASSERT_EQ(60U, config->fill_on_free_bytes());
ASSERT_EQ(16U, config->free_track_backtrace_num_frames());
// Now reverse the arguments.
ASSERT_TRUE(InitConfig("fill_on_free=32 free_track=1234")) << getFakeLogPrint();
- ASSERT_EQ(FREE_TRACK | FILL_ON_FREE, config->options());
+ ASSERT_EQ(FREE_TRACK | FILL_ON_FREE | TRACK_ALLOCS, config->options());
ASSERT_EQ(1234U, config->free_track_allocations());
ASSERT_EQ(32U, config->fill_on_free_bytes());
ASSERT_EQ(16U, config->free_track_backtrace_num_frames());
@@ -530,11 +534,11 @@
TEST_F(MallocDebugConfigTest, free_track_backtrace_num_frames_and_free_track) {
ASSERT_TRUE(InitConfig("free_track free_track_backtrace_num_frames=123")) << getFakeLogPrint();
- ASSERT_EQ(FREE_TRACK | FILL_ON_FREE, config->options());
+ ASSERT_EQ(FREE_TRACK | FILL_ON_FREE | TRACK_ALLOCS, config->options());
ASSERT_EQ(123U, config->free_track_backtrace_num_frames());
ASSERT_TRUE(InitConfig("free_track free_track_backtrace_num_frames")) << getFakeLogPrint();
- ASSERT_EQ(FREE_TRACK | FILL_ON_FREE, config->options());
+ ASSERT_EQ(FREE_TRACK | FILL_ON_FREE | TRACK_ALLOCS, config->options());
ASSERT_EQ(16U, config->free_track_backtrace_num_frames());
ASSERT_STREQ("", getFakeLogBuf().c_str());
@@ -559,6 +563,24 @@
ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str());
}
+TEST_F(MallocDebugConfigTest, verify_pointers) {
+ ASSERT_TRUE(InitConfig("verify_pointers")) << getFakeLogPrint();
+ ASSERT_EQ(TRACK_ALLOCS, config->options());
+
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+ ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugConfigTest, verify_pointers_fail) {
+ ASSERT_FALSE(InitConfig("verify_pointers=200")) << getFakeLogPrint();
+
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+ std::string log_msg(
+ "6 malloc_debug malloc_testing: value set for option 'verify_pointers' "
+ "which does not take a value\n");
+ ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str());
+}
+
TEST_F(MallocDebugConfigTest, record_allocs) {
ASSERT_TRUE(InitConfig("record_allocs=1234")) << getFakeLogPrint();
ASSERT_EQ(RECORD_ALLOCS, config->options());
diff --git a/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp b/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
index 0e4a7d8..8b28188 100644
--- a/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
+++ b/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
@@ -72,15 +72,8 @@
constexpr char DIVIDER[] =
"6 malloc_debug *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n";
-constexpr uint32_t BACKTRACE_HEADER = 0x1;
-
-static size_t get_tag_offset(uint32_t flags = 0, size_t backtrace_frames = 0) {
- size_t offset = __BIONIC_ALIGN(sizeof(Header), MINIMUM_ALIGNMENT_BYTES);
- if (flags & BACKTRACE_HEADER) {
- offset += __BIONIC_ALIGN(sizeof(BacktraceHeader) + sizeof(uintptr_t) * backtrace_frames,
- MINIMUM_ALIGNMENT_BYTES);
- }
- return offset;
+static size_t get_tag_offset() {
+ return __BIONIC_ALIGN(sizeof(Header), MINIMUM_ALIGNMENT_BYTES);
}
static constexpr const char RECORD_ALLOCS_FILE[] = "/data/local/tmp/record_allocs.txt";
@@ -111,6 +104,10 @@
void BacktraceDumpOnSignal(bool trigger_with_alloc);
+ static size_t GetInfoEntrySize(size_t max_frames) {
+ return 2 * sizeof(size_t) + max_frames * sizeof(uintptr_t);
+ }
+
bool initialized;
int zygote;
@@ -140,6 +137,16 @@
aligned_alloc,
};
+std::string ShowDiffs(uint8_t* a, uint8_t* b, size_t size) {
+ std::string diff;
+ for (size_t i = 0; i < size; i++) {
+ if (a[i] != b[i]) {
+ diff += android::base::StringPrintf("Byte %zu: 0x%x 0x%x\n", i, a[i], b[i]);
+ }
+ }
+ return diff;
+}
+
void VerifyAllocCalls(bool backtrace_enabled) {
size_t alloc_size = 1024;
@@ -335,7 +342,8 @@
uint8_t* pointer = reinterpret_cast<uint8_t*>(debug_malloc(100));
ASSERT_TRUE(pointer != nullptr);
- ASSERT_TRUE(memcmp(buffer.data(), &pointer[-buffer.size()], buffer.size()) == 0);
+ ASSERT_TRUE(memcmp(buffer.data(), &pointer[-buffer.size()], buffer.size()) == 0)
+ << ShowDiffs(buffer.data(), &pointer[-buffer.size()], buffer.size());
memset(pointer, 0xff, 100);
debug_free(pointer);
@@ -343,7 +351,8 @@
for (size_t alignment = 1; alignment <= 256; alignment++) {
pointer = reinterpret_cast<uint8_t*>(debug_memalign(alignment, 100));
ASSERT_TRUE(pointer != nullptr);
- ASSERT_TRUE(memcmp(buffer.data(), &pointer[-buffer.size()], buffer.size()) == 0);
+ ASSERT_TRUE(memcmp(buffer.data(), &pointer[-buffer.size()], buffer.size()) == 0)
+ << ShowDiffs(buffer.data(), &pointer[-buffer.size()], buffer.size());
size_t alignment_mask = alignment - 1;
if (!powerof2(alignment)) {
alignment_mask = BIONIC_ROUND_UP_POWER_OF_2(alignment) - 1;
@@ -355,7 +364,8 @@
pointer = reinterpret_cast<uint8_t*>(debug_calloc(1, 100));
ASSERT_TRUE(pointer != nullptr);
- ASSERT_TRUE(memcmp(buffer.data(), &pointer[-buffer.size()], buffer.size()) == 0);
+ ASSERT_TRUE(memcmp(buffer.data(), &pointer[-buffer.size()], buffer.size()) == 0)
+ << ShowDiffs(buffer.data(), &pointer[-buffer.size()], buffer.size());
for (size_t i = 0; i < 100; i++) {
ASSERT_EQ(0, pointer[i]) << "debug_calloc non-zero byte at " << i;
}
@@ -363,10 +373,12 @@
pointer = reinterpret_cast<uint8_t*>(debug_realloc(nullptr, 100));
ASSERT_TRUE(pointer != nullptr);
- ASSERT_TRUE(memcmp(buffer.data(), &pointer[-buffer.size()], buffer.size()) == 0);
+ ASSERT_TRUE(memcmp(buffer.data(), &pointer[-buffer.size()], buffer.size()) == 0)
+ << ShowDiffs(buffer.data(), &pointer[-buffer.size()], buffer.size());
memset(pointer, 0xff, 100);
pointer = reinterpret_cast<uint8_t*>(debug_realloc(pointer, 200));
- ASSERT_TRUE(memcmp(buffer.data(), &pointer[-buffer.size()], buffer.size()) == 0);
+ ASSERT_TRUE(memcmp(buffer.data(), &pointer[-buffer.size()], buffer.size()) == 0)
+ << ShowDiffs(buffer.data(), &pointer[-buffer.size()], buffer.size());
memset(pointer, 0xff, 200);
pointer = reinterpret_cast<uint8_t*>(debug_realloc(pointer, 0));
ASSERT_TRUE(pointer == nullptr);
@@ -427,7 +439,8 @@
uint8_t* pointer = reinterpret_cast<uint8_t*>(debug_malloc(100));
ASSERT_TRUE(pointer != nullptr);
ASSERT_EQ(100U, debug_malloc_usable_size(pointer));
- ASSERT_TRUE(memcmp(buffer.data(), &pointer[100], buffer.size()) == 0);
+ ASSERT_TRUE(memcmp(buffer.data(), &pointer[100], buffer.size()) == 0)
+ << ShowDiffs(buffer.data(), &pointer[100], buffer.size());
memset(pointer, 0xff, 100);
debug_free(pointer);
@@ -436,7 +449,8 @@
pointer = reinterpret_cast<uint8_t*>(debug_memalign(alignment, 100));
ASSERT_TRUE(pointer != nullptr);
ASSERT_EQ(100U, debug_malloc_usable_size(pointer));
- ASSERT_TRUE(memcmp(buffer.data(), &pointer[100], buffer.size()) == 0);
+ ASSERT_TRUE(memcmp(buffer.data(), &pointer[100], buffer.size()) == 0)
+ << ShowDiffs(buffer.data(), &pointer[100], buffer.size());
size_t alignment_mask = alignment - 1;
if (!powerof2(alignment)) {
alignment_mask = BIONIC_ROUND_UP_POWER_OF_2(alignment) - 1;
@@ -450,7 +464,8 @@
pointer = reinterpret_cast<uint8_t*>(debug_calloc(1, 100));
ASSERT_TRUE(pointer != nullptr);
ASSERT_EQ(100U, debug_malloc_usable_size(pointer));
- ASSERT_TRUE(memcmp(buffer.data(), &pointer[100], buffer.size()) == 0);
+ ASSERT_TRUE(memcmp(buffer.data(), &pointer[100], buffer.size()) == 0)
+ << ShowDiffs(buffer.data(), &pointer[100], buffer.size());
for (size_t i = 0; i < 100; i++) {
ASSERT_EQ(0, pointer[i]) << "debug_calloc non-zero byte at " << i;
}
@@ -458,10 +473,12 @@
pointer = reinterpret_cast<uint8_t*>(debug_realloc(nullptr, 100));
ASSERT_TRUE(pointer != nullptr);
- ASSERT_TRUE(memcmp(buffer.data(), &pointer[100], buffer.size()) == 0);
+ ASSERT_TRUE(memcmp(buffer.data(), &pointer[100], buffer.size()) == 0)
+ << ShowDiffs(buffer.data(), &pointer[100], buffer.size());
memset(pointer, 0xff, 100);
pointer = reinterpret_cast<uint8_t*>(debug_realloc(pointer, 200));
- ASSERT_TRUE(memcmp(buffer.data(), &pointer[200], buffer.size()) == 0);
+ ASSERT_TRUE(memcmp(buffer.data(), &pointer[200], buffer.size()) == 0)
+ << ShowDiffs(buffer.data(), &pointer[200], buffer.size());
for (size_t i = 0; i < 100; i++) {
ASSERT_EQ(0xff, pointer[i]) << "debug_realloc not copied byte at " << i;
}
@@ -829,7 +846,7 @@
}
TEST_F(MallocDebugTest, free_track_use_after_free_with_backtrace) {
- Init("free_track=100");
+ Init("free_track=100 rear_guard");
// Free backtrace.
backtrace_fake_add(std::vector<uintptr_t> {0xfa, 0xeb, 0xdc});
@@ -860,7 +877,7 @@
}
TEST_F(MallocDebugTest, free_track_use_after_free_call_realloc) {
- Init("free_track=100");
+ Init("free_track=100 rear_guard");
// Free backtrace.
backtrace_fake_add(std::vector<uintptr_t> {0xfa, 0xeb, 0xdc});
@@ -894,7 +911,7 @@
}
TEST_F(MallocDebugTest, free_track_use_after_free_call_free) {
- Init("free_track=100");
+ Init("free_track=100 rear_guard");
// Free backtrace.
backtrace_fake_add(std::vector<uintptr_t> {0xfa, 0xeb, 0xdc});
@@ -926,7 +943,7 @@
}
TEST_F(MallocDebugTest, free_track_header_tag_corrupted) {
- Init("free_track=100 free_track_backtrace_num_frames=0");
+ Init("free_track=100 free_track_backtrace_num_frames=0 rear_guard");
uint8_t* pointer = reinterpret_cast<uint8_t*>(debug_malloc(100));
ASSERT_TRUE(pointer != nullptr);
@@ -1053,7 +1070,7 @@
Init("backtrace");
// Create the expected info buffer.
- size_t individual_size = 2 * sizeof(size_t) + 16 * sizeof(uintptr_t);
+ size_t individual_size = GetInfoEntrySize(16);
std::vector<uint8_t> expected_info(individual_size);
memset(expected_info.data(), 0, individual_size);
@@ -1082,7 +1099,8 @@
ASSERT_EQ(individual_size, info_size);
ASSERT_EQ(200U, total_memory);
ASSERT_EQ(16U, backtrace_size);
- ASSERT_TRUE(memcmp(expected_info.data(), info, overall_size) == 0);
+ ASSERT_TRUE(memcmp(expected_info.data(), info, overall_size) == 0)
+ << ShowDiffs(expected_info.data(), info, overall_size);
debug_free_malloc_leak_info(info);
@@ -1099,7 +1117,7 @@
Init("backtrace=16");
// Create the expected info buffer.
- size_t individual_size = 2 * sizeof(size_t) + 16 * sizeof(uintptr_t);
+ size_t individual_size = GetInfoEntrySize(16);
std::vector<uint8_t> expected_info(individual_size * 3);
memset(expected_info.data(), 0, individual_size * 3);
@@ -1162,7 +1180,8 @@
ASSERT_EQ(individual_size, info_size);
ASSERT_EQ(500U + 4100U + 9000U, total_memory);
ASSERT_EQ(16U, backtrace_size);
- ASSERT_TRUE(memcmp(expected_info.data(), info, overall_size) == 0);
+ ASSERT_TRUE(memcmp(expected_info.data(), info, overall_size) == 0)
+ << ShowDiffs(expected_info.data(), info, overall_size);
debug_free_malloc_leak_info(info);
@@ -1177,52 +1196,13 @@
ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
}
-TEST_F(MallocDebugTest, get_malloc_leak_info_multi_skip_empty_backtrace) {
- Init("backtrace=16");
+TEST_F(MallocDebugTest, get_malloc_backtrace_with_header) {
+ Init("backtrace=16 guard");
- // Create the expected info buffer.
- size_t individual_size = 2 * sizeof(size_t) + 16 * sizeof(uintptr_t);
- std::vector<uint8_t> expected_info(individual_size * 2);
- memset(expected_info.data(), 0, individual_size * 2);
-
- InfoEntry* entry0 = reinterpret_cast<InfoEntry*>(expected_info.data());
- InfoEntry* entry1 = reinterpret_cast<InfoEntry*>(
- reinterpret_cast<uintptr_t>(entry0) + individual_size);
-
- // These values will be in the reverse order that we create.
- entry1->size = 500;
- entry1->num_allocations = 1;
- entry1->frames[0] = 0xf;
- entry1->frames[1] = 0xe;
- entry1->frames[2] = 0xd;
- entry1->frames[3] = 0xc;
-
- backtrace_fake_add(std::vector<uintptr_t> {0xf, 0xe, 0xd, 0xc});
-
- uint8_t* pointers[3];
-
- pointers[0] = reinterpret_cast<uint8_t*>(debug_malloc(entry1->size));
- ASSERT_TRUE(pointers[0] != nullptr);
- memset(pointers[0], 0, entry1->size);
-
- entry0->size = 4100;
- entry0->num_allocations = 1;
- for (size_t i = 0; i < 16; i++) {
- entry0->frames[i] = 0xbc000 + i;
- }
-
- backtrace_fake_add(
- std::vector<uintptr_t> {0xbc000, 0xbc001, 0xbc002, 0xbc003, 0xbc004, 0xbc005,
- 0xbc006, 0xbc007, 0xbc008, 0xbc009, 0xbc00a, 0xbc00b,
- 0xbc00c, 0xbc00d, 0xbc00e, 0xbc00f, 0xffff});
-
- pointers[1] = reinterpret_cast<uint8_t*>(debug_malloc(entry0->size));
- ASSERT_TRUE(pointers[1] != nullptr);
- memset(pointers[1], 0, entry0->size);
-
- pointers[2] = reinterpret_cast<uint8_t*>(debug_malloc(10000));
- ASSERT_TRUE(pointers[2] != nullptr);
- memset(pointers[2], 0, 10000);
+ void* pointer = debug_malloc(100);
+ ASSERT_TRUE(pointer != nullptr);
+ memset(pointer, 0, 100);
+ EXPECT_EQ(100U, debug_malloc_usable_size(pointer));
uint8_t* info;
size_t overall_size;
@@ -1231,18 +1211,18 @@
size_t backtrace_size;
debug_get_malloc_leak_info(&info, &overall_size, &info_size, &total_memory, &backtrace_size);
- ASSERT_TRUE(info != nullptr);
- ASSERT_EQ(individual_size * 2, overall_size);
- ASSERT_EQ(individual_size, info_size);
- ASSERT_EQ(500U + 4100U, total_memory);
- ASSERT_EQ(16U, backtrace_size);
- ASSERT_TRUE(memcmp(expected_info.data(), info, overall_size) == 0);
-
+ EXPECT_TRUE(info != nullptr);
+ EXPECT_EQ(GetInfoEntrySize(16), overall_size);
+ EXPECT_EQ(GetInfoEntrySize(16), info_size);
+ EXPECT_EQ(100U, total_memory);
+ EXPECT_EQ(16U, backtrace_size);
debug_free_malloc_leak_info(info);
- debug_free(pointers[0]);
- debug_free(pointers[1]);
- debug_free(pointers[2]);
+ debug_free(pointer);
+
+ // There should be no pointers that have leaked.
+ debug_finalize();
+ initialized = false;
ASSERT_STREQ("", getFakeLogBuf().c_str());
std::string expected_log = android::base::StringPrintf(
@@ -1338,19 +1318,19 @@
"Backtrace size: 4\n"
"\n"
#if defined(__LP64__)
- "z 0 sz 5 num 1 bt 000000000000a300 000000000000b300\n"
- "z 0 sz 10 num 1 bt 000000000000a000 000000000000b000\n"
"z 0 sz 50 num 1 bt 000000000000a100 000000000000b200\n"
- "z 1 sz 40 num 1 bt 0000000000000300 0000000000000400\n"
- "z 1 sz 100 num 1 bt 0000000000000100 0000000000000200\n"
+ "z 0 sz 10 num 1 bt 000000000000a000 000000000000b000\n"
+ "z 0 sz 5 num 1 bt 000000000000a300 000000000000b300\n"
"z 1 sz 200 num 1 bt 0000000000000500 0000000000000600\n"
+ "z 1 sz 100 num 1 bt 0000000000000100 0000000000000200\n"
+ "z 1 sz 40 num 1 bt 0000000000000300 0000000000000400\n"
#else
- "z 0 sz 5 num 1 bt 0000a300 0000b300\n"
- "z 0 sz 10 num 1 bt 0000a000 0000b000\n"
"z 0 sz 50 num 1 bt 0000a100 0000b200\n"
- "z 1 sz 40 num 1 bt 00000300 00000400\n"
- "z 1 sz 100 num 1 bt 00000100 00000200\n"
+ "z 0 sz 10 num 1 bt 0000a000 0000b000\n"
+ "z 0 sz 5 num 1 bt 0000a300 0000b300\n"
"z 1 sz 200 num 1 bt 00000500 00000600\n"
+ "z 1 sz 100 num 1 bt 00000100 00000200\n"
+ "z 1 sz 40 num 1 bt 00000300 00000400\n"
#endif
"MAPS\n"
"MAP_DATA\n"
@@ -1410,13 +1390,13 @@
"Backtrace size: 4\n"
"\n"
#if defined(__LP64__)
- "z 0 sz 300 num 1 bt 0000000000000100 0000000000000200\n"
- "z 0 sz 400 num 1 bt 000000000000a000 000000000000b000\n"
"z 0 sz 500 num 1 bt 000000000000a000 000000000000b000 000000000000c000\n"
+ "z 0 sz 400 num 1 bt 000000000000a000 000000000000b000\n"
+ "z 0 sz 300 num 1 bt 0000000000000100 0000000000000200\n"
#else
- "z 0 sz 300 num 1 bt 00000100 00000200\n"
- "z 0 sz 400 num 1 bt 0000a000 0000b000\n"
"z 0 sz 500 num 1 bt 0000a000 0000b000 0000c000\n"
+ "z 0 sz 400 num 1 bt 0000a000 0000b000\n"
+ "z 0 sz 300 num 1 bt 00000100 00000200\n"
#endif
"MAPS\n"
"MAP_DATA\n"
@@ -1427,6 +1407,58 @@
ASSERT_STREQ("", getFakeLogPrint().c_str());
}
+TEST_F(MallocDebugTest, backtrace_dump_on_exit_shared_backtrace) {
+ pid_t pid;
+ if ((pid = fork()) == 0) {
+ Init("backtrace=4 backtrace_dump_on_exit");
+ backtrace_fake_add(std::vector<uintptr_t> {0x100, 0x200});
+ backtrace_fake_add(std::vector<uintptr_t> {0xa000, 0xb000, 0xc000});
+ backtrace_fake_add(std::vector<uintptr_t> {0x100, 0x200});
+
+ std::vector<void*> pointers;
+ pointers.push_back(debug_malloc(300));
+ pointers.push_back(debug_malloc(400));
+ pointers.push_back(debug_malloc(300));
+
+ // Call the exit function manually.
+ debug_finalize();
+ exit(0);
+ }
+ ASSERT_NE(-1, pid);
+ ASSERT_EQ(pid, TEMP_FAILURE_RETRY(waitpid(pid, nullptr, 0)));
+
+ // Read all of the contents.
+ std::string actual;
+ std::string name = android::base::StringPrintf("%s.%d.exit.txt", BACKTRACE_DUMP_PREFIX, pid);
+ ASSERT_TRUE(android::base::ReadFileToString(name, &actual));
+ ASSERT_EQ(0, unlink(name.c_str()));
+
+ std::string sanitized(SanitizeHeapData(actual));
+
+ std::string expected =
+ "Android Native Heap Dump v1.0\n"
+ "\n"
+ "Total memory: 1000\n"
+ "Allocation records: 2\n"
+ "Backtrace size: 4\n"
+ "\n"
+#if defined(__LP64__)
+ "z 0 sz 400 num 1 bt 000000000000a000 000000000000b000 000000000000c000\n"
+ "z 0 sz 300 num 2 bt 0000000000000100 0000000000000200\n"
+#else
+ "z 0 sz 400 num 1 bt 0000a000 0000b000 0000c000\n"
+ "z 0 sz 300 num 2 bt 00000100 00000200\n"
+#endif
+ "MAPS\n"
+ "MAP_DATA\n"
+ "END\n\n";
+ ASSERT_STREQ(expected.c_str(), sanitized.c_str()) << "Actual data: \n" << actual;
+
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+ ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+
TEST_F(MallocDebugTest, realloc_usable_size) {
Init("front_guard");
@@ -1453,7 +1485,7 @@
TEST_F(MallocDebugTest, backtrace_enable_on_signal) {
Init("backtrace_enable_on_signal=20");
- size_t individual_size = 2 * sizeof(size_t) + 20 * sizeof(uintptr_t);
+ size_t individual_size = GetInfoEntrySize(20);
backtrace_fake_add(std::vector<uintptr_t> {0xbc000, 0xecd00, 0x12000});
backtrace_fake_add(std::vector<uintptr_t> {0x100, 0x200, 0x300, 0x400});
@@ -1532,6 +1564,198 @@
ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
}
+TEST_F(MallocDebugTest, backtrace_same_stack) {
+ Init("backtrace=4");
+
+ size_t individual_size = GetInfoEntrySize(4);
+
+ backtrace_fake_add(std::vector<uintptr_t> {0xbc000, 0xecd00, 0x12000});
+ backtrace_fake_add(std::vector<uintptr_t> {0xbc000, 0xecd00, 0x12000});
+ backtrace_fake_add(std::vector<uintptr_t> {0xbc000, 0xecd00, 0x12000});
+ backtrace_fake_add(std::vector<uintptr_t> {0xbc000, 0xecd00, 0x12000});
+
+ void* pointers[4];
+ pointers[0] = debug_malloc(10);
+ ASSERT_TRUE(pointers[0] != nullptr);
+ pointers[1] = debug_malloc(10);
+ ASSERT_TRUE(pointers[1] != nullptr);
+ pointers[2] = debug_malloc(10);
+ ASSERT_TRUE(pointers[2] != nullptr);
+ pointers[3] = debug_malloc(100);
+ ASSERT_TRUE(pointers[3] != nullptr);
+
+ uint8_t* info;
+ size_t overall_size;
+ size_t info_size;
+ size_t total_memory;
+ size_t backtrace_size;
+
+ debug_get_malloc_leak_info(&info, &overall_size, &info_size, &total_memory, &backtrace_size);
+ ASSERT_TRUE(info != nullptr);
+ ASSERT_EQ(individual_size * 2, overall_size);
+ ASSERT_EQ(individual_size, info_size);
+ EXPECT_EQ(130U, total_memory);
+ EXPECT_EQ(4U, backtrace_size);
+ EXPECT_EQ(100U, *reinterpret_cast<size_t*>(&info[0]));
+ EXPECT_EQ(1U, *reinterpret_cast<size_t*>(&info[sizeof(size_t)]));
+ uintptr_t* ips = reinterpret_cast<uintptr_t*>(&info[2 * sizeof(size_t)]);
+ EXPECT_EQ(0xbc000U, ips[0]);
+ EXPECT_EQ(0xecd00U, ips[1]);
+ EXPECT_EQ(0x12000U, ips[2]);
+
+ EXPECT_EQ(10U, *reinterpret_cast<size_t*>(&info[individual_size]));
+ EXPECT_EQ(3U, *reinterpret_cast<size_t*>(&info[sizeof(size_t) + individual_size]));
+ ips = reinterpret_cast<uintptr_t*>(&info[2 * sizeof(size_t) + individual_size]);
+ EXPECT_EQ(0xbc000U, ips[0]);
+ EXPECT_EQ(0xecd00U, ips[1]);
+ EXPECT_EQ(0x12000U, ips[2]);
+
+ debug_free_malloc_leak_info(info);
+
+ debug_free(pointers[0]);
+ debug_free(pointers[1]);
+ debug_free(pointers[2]);
+ debug_free(pointers[3]);
+
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+ std::string expected_log = android::base::StringPrintf(
+ "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
+ SIGRTMAX - 17, getpid());
+ ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugTest, backtrace_same_stack_zygote) {
+ Init("backtrace=4");
+
+ size_t individual_size = GetInfoEntrySize(4);
+
+ backtrace_fake_add(std::vector<uintptr_t> {0xbc000, 0xecd00, 0x12000});
+ backtrace_fake_add(std::vector<uintptr_t> {0xbc000, 0xecd00, 0x12000});
+ backtrace_fake_add(std::vector<uintptr_t> {0xbc000, 0xecd00, 0x12000});
+ backtrace_fake_add(std::vector<uintptr_t> {0xbc000});
+
+ zygote = 1;
+
+ void* pointers[4];
+ pointers[0] = debug_malloc(100);
+ ASSERT_TRUE(pointers[0] != nullptr);
+ pointers[1] = debug_malloc(100);
+ ASSERT_TRUE(pointers[1] != nullptr);
+ pointers[2] = debug_malloc(100);
+ ASSERT_TRUE(pointers[2] != nullptr);
+ pointers[3] = debug_malloc(100);
+ ASSERT_TRUE(pointers[3] != nullptr);
+
+ uint8_t* info;
+ size_t overall_size;
+ size_t info_size;
+ size_t total_memory;
+ size_t backtrace_size;
+
+ debug_get_malloc_leak_info(&info, &overall_size, &info_size, &total_memory, &backtrace_size);
+ ASSERT_TRUE(info != nullptr);
+ ASSERT_EQ(individual_size * 2, overall_size);
+ EXPECT_EQ(individual_size, info_size);
+ EXPECT_EQ(400U, total_memory);
+ EXPECT_EQ(4U, backtrace_size);
+
+ EXPECT_EQ(0x80000064U, *reinterpret_cast<size_t*>(&info[0]));
+ EXPECT_EQ(3U, *reinterpret_cast<size_t*>(&info[sizeof(size_t)]));
+ uintptr_t* ips = reinterpret_cast<uintptr_t*>(&info[2 * sizeof(size_t)]);
+ EXPECT_EQ(0xbc000U, ips[0]);
+ EXPECT_EQ(0xecd00U, ips[1]);
+ EXPECT_EQ(0x12000U, ips[2]);
+
+ EXPECT_EQ(0x80000064U, *reinterpret_cast<size_t*>(&info[individual_size]));
+ EXPECT_EQ(1U, *reinterpret_cast<size_t*>(&info[sizeof(size_t) + individual_size]));
+ ips = reinterpret_cast<uintptr_t*>(&info[2 * sizeof(size_t) + individual_size]);
+ EXPECT_EQ(0xbc000U, ips[0]);
+ EXPECT_EQ(0U, ips[1]);
+
+ debug_free_malloc_leak_info(info);
+
+ debug_free(pointers[0]);
+ debug_free(pointers[1]);
+ debug_free(pointers[2]);
+ debug_free(pointers[3]);
+
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+ std::string expected_log = android::base::StringPrintf(
+ "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
+ SIGRTMAX - 17, getpid());
+ ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugTest, backtrace_same_stack_mix_zygote) {
+ Init("backtrace=4");
+
+ size_t individual_size = GetInfoEntrySize(4);
+
+ backtrace_fake_add(std::vector<uintptr_t> {0xbc000, 0xecd00, 0x12000});
+ backtrace_fake_add(std::vector<uintptr_t> {0xbc000, 0xecd00, 0x12000});
+ backtrace_fake_add(std::vector<uintptr_t> {0xbc000, 0xecd00, 0x12000});
+ backtrace_fake_add(std::vector<uintptr_t> {0xbc000});
+
+ zygote = 1;
+ void* pointers[4];
+ pointers[0] = debug_malloc(40);
+ ASSERT_TRUE(pointers[0] != nullptr);
+ pointers[1] = debug_malloc(40);
+ ASSERT_TRUE(pointers[1] != nullptr);
+
+ zygote = 0;
+ pointers[2] = debug_malloc(40);
+ ASSERT_TRUE(pointers[2] != nullptr);
+ pointers[3] = debug_malloc(100);
+ ASSERT_TRUE(pointers[3] != nullptr);
+
+ uint8_t* info;
+ size_t overall_size;
+ size_t info_size;
+ size_t total_memory;
+ size_t backtrace_size;
+
+ debug_get_malloc_leak_info(&info, &overall_size, &info_size, &total_memory, &backtrace_size);
+ ASSERT_TRUE(info != nullptr);
+ ASSERT_EQ(individual_size * 3, overall_size);
+ ASSERT_EQ(individual_size, info_size);
+ EXPECT_EQ(220U, total_memory);
+ EXPECT_EQ(4U, backtrace_size);
+
+ EXPECT_EQ(100U, *reinterpret_cast<size_t*>(&info[0]));
+ EXPECT_EQ(1U, *reinterpret_cast<size_t*>(&info[sizeof(size_t)]));
+ uintptr_t* ips = reinterpret_cast<uintptr_t*>(&info[2 * sizeof(size_t)]);
+ EXPECT_EQ(0xbc000U, ips[0]);
+ EXPECT_EQ(0U, ips[1]);
+
+ EXPECT_EQ(40U, *reinterpret_cast<size_t*>(&info[individual_size]));
+ EXPECT_EQ(1U, *reinterpret_cast<size_t*>(&info[sizeof(size_t) + individual_size]));
+ ips = reinterpret_cast<uintptr_t*>(&info[2 * sizeof(size_t) + individual_size]);
+ EXPECT_EQ(0xbc000U, ips[0]);
+ EXPECT_EQ(0xecd00U, ips[1]);
+ EXPECT_EQ(0x12000U, ips[2]);
+
+ EXPECT_EQ(0x80000028U, *reinterpret_cast<size_t*>(&info[2 * individual_size]));
+ EXPECT_EQ(2U, *reinterpret_cast<size_t*>(&info[sizeof(size_t) + 2 * individual_size]));
+ ips = reinterpret_cast<uintptr_t*>(&info[2 * sizeof(size_t) + 2 * individual_size]);
+ EXPECT_EQ(0xbc000U, ips[0]);
+ EXPECT_EQ(0xecd00U, ips[1]);
+ EXPECT_EQ(0x12000U, ips[2]);
+
+ debug_free_malloc_leak_info(info);
+
+ debug_free(pointers[0]);
+ debug_free(pointers[1]);
+ debug_free(pointers[2]);
+ debug_free(pointers[3]);
+
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+ std::string expected_log = android::base::StringPrintf(
+ "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
+ SIGRTMAX - 17, getpid());
+ ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+}
+
TEST_F(MallocDebugTest, overflow) {
Init("guard fill_on_free");
@@ -1601,7 +1825,8 @@
ASSERT_EQ(expected_info_size, info_size);
ASSERT_EQ(memory_bytes, total_memory);
ASSERT_EQ(16U, backtrace_size);
- ASSERT_TRUE(memcmp(info, expected_info.data(), expected_info_size) == 0);
+ ASSERT_TRUE(memcmp(info, expected_info.data(), expected_info_size) == 0)
+ << ShowDiffs(info, expected_info.data(), expected_info_size);
debug_free_malloc_leak_info(info);
}
@@ -1619,6 +1844,7 @@
ASSERT_EQ(100U, debug_malloc_usable_size(pointer));
memset(pointer, 0, 100);
VerifyZygoteSet(100);
+ ASSERT_FALSE(HasFatalFailure());
debug_free(pointer);
backtrace_fake_add(std::vector<uintptr_t> {0x1});
@@ -1626,6 +1852,7 @@
ASSERT_TRUE(pointer != nullptr);
ASSERT_EQ(200U, debug_malloc_usable_size(pointer));
VerifyZygoteSet(200);
+ ASSERT_FALSE(HasFatalFailure());
debug_free(pointer);
backtrace_fake_add(std::vector<uintptr_t> {0x1});
@@ -1634,6 +1861,7 @@
ASSERT_EQ(300U, debug_malloc_usable_size(pointer));
memset(pointer, 0, 300);
VerifyZygoteSet(300);
+ ASSERT_FALSE(HasFatalFailure());
debug_free(pointer);
backtrace_fake_add(std::vector<uintptr_t> {0x1});
@@ -1642,12 +1870,14 @@
ASSERT_EQ(500U, debug_malloc_usable_size(pointer));
memset(pointer, 0, 500);
VerifyZygoteSet(500);
+ ASSERT_FALSE(HasFatalFailure());
backtrace_fake_add(std::vector<uintptr_t> {0x1});
pointer = debug_realloc(pointer, 300);
ASSERT_TRUE(pointer != nullptr);
ASSERT_EQ(300U, debug_malloc_usable_size(pointer));
VerifyZygoteSet(300);
+ ASSERT_FALSE(HasFatalFailure());
debug_free(pointer);
ASSERT_STREQ("", getFakeLogBuf().c_str());
@@ -1984,3 +2214,62 @@
RECORD_ALLOCS_FILE);
ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
}
+
+TEST_F(MallocDebugTest, verify_pointers) {
+ Init("verify_pointers");
+
+ void* pointer = debug_malloc(10);
+ memset(pointer, 0, 10);
+ debug_free(pointer);
+
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+ ASSERT_STREQ("", getFakeLogPrint().c_str());
+
+ debug_free(pointer);
+ ASSERT_EQ(0U, debug_malloc_usable_size(pointer));
+ ASSERT_EQ(nullptr, debug_realloc(pointer, 1000));
+
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+ std::string free_pointer_str(
+ android::base::StringPrintf("6 malloc_debug +++ ALLOCATION %p UNKNOWN POINTER (free)\n",
+ pointer));
+ std::string usable_pointer_str(
+ android::base::StringPrintf("6 malloc_debug +++ ALLOCATION %p UNKNOWN POINTER (malloc_usable_size)\n",
+ pointer));
+ std::string realloc_pointer_str(
+ android::base::StringPrintf("6 malloc_debug +++ ALLOCATION %p UNKNOWN POINTER (realloc)\n",
+ pointer));
+ std::string backtrace_str("6 malloc_debug Backtrace failed to get any frames.\n");
+
+ std::string expected_log(DIVIDER + free_pointer_str + backtrace_str + DIVIDER);
+ expected_log += DIVIDER + usable_pointer_str + backtrace_str + DIVIDER;
+ expected_log += DIVIDER + realloc_pointer_str + backtrace_str + DIVIDER;
+ ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+
+ resetLogs();
+
+ backtrace_fake_add(std::vector<uintptr_t> {0x100, 0x200});
+ backtrace_fake_add(std::vector<uintptr_t> {0x300, 0x400});
+ backtrace_fake_add(std::vector<uintptr_t> {0x500, 0x600});
+ debug_free(pointer);
+ ASSERT_EQ(0U, debug_malloc_usable_size(pointer));
+ ASSERT_EQ(nullptr, debug_realloc(pointer, 1000));
+
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+ expected_log = DIVIDER + free_pointer_str;
+ expected_log += "6 malloc_debug Backtrace at time of failure:\n";
+ expected_log += "6 malloc_debug #00 pc 0x100\n";
+ expected_log += "6 malloc_debug #01 pc 0x200\n";
+ expected_log += DIVIDER;
+ expected_log += DIVIDER + usable_pointer_str;
+ expected_log += "6 malloc_debug Backtrace at time of failure:\n";
+ expected_log += "6 malloc_debug #00 pc 0x300\n";
+ expected_log += "6 malloc_debug #01 pc 0x400\n";
+ expected_log += DIVIDER;
+ expected_log += DIVIDER + realloc_pointer_str;
+ expected_log += "6 malloc_debug Backtrace at time of failure:\n";
+ expected_log += "6 malloc_debug #00 pc 0x500\n";
+ expected_log += "6 malloc_debug #01 pc 0x600\n";
+ expected_log += DIVIDER;
+ ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+}
diff --git a/libc/seccomp/arm64_app_policy.cpp b/libc/seccomp/arm64_app_policy.cpp
index f7f0dc4..e3dab49 100644
--- a/libc/seccomp/arm64_app_policy.cpp
+++ b/libc/seccomp/arm64_app_policy.cpp
@@ -5,24 +5,22 @@
#include "seccomp_bpfs.h"
const sock_filter arm64_app_filter[] = {
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 0, 0, 58),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 153, 29, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 101, 15, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 0, 0, 56),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 153, 27, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 101, 13, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 52, 7, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 41, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 19, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 18, 52, 51), //io_setup|io_destroy|io_submit|io_cancel|io_getevents|setxattr|lsetxattr|fsetxattr|getxattr|lgetxattr|fgetxattr|listxattr|llistxattr|flistxattr|removexattr|lremovexattr|fremovexattr|getcwd
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 39, 51, 50), //eventfd2|epoll_create1|epoll_ctl|epoll_pwait|dup|dup3|fcntl|inotify_init1|inotify_add_watch|inotify_rm_watch|ioctl|ioprio_set|ioprio_get|flock|mknodat|mkdirat|unlinkat|symlinkat|linkat|renameat
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 18, 50, 49), //io_setup|io_destroy|io_submit|io_cancel|io_getevents|setxattr|lsetxattr|fsetxattr|getxattr|lgetxattr|fgetxattr|listxattr|llistxattr|flistxattr|removexattr|lremovexattr|fremovexattr|getcwd
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 39, 49, 48), //eventfd2|epoll_create1|epoll_ctl|epoll_pwait|dup|dup3|fcntl|inotify_init1|inotify_add_watch|inotify_rm_watch|ioctl|ioprio_set|ioprio_get|flock|mknodat|mkdirat|unlinkat|symlinkat|linkat|renameat
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 43, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 42, 49, 48), //pivot_root
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 51, 48, 47), //statfs|fstatfs|truncate|ftruncate|fallocate|faccessat|chdir|fchdir
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 42, 47, 46), //pivot_root
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 51, 46, 45), //statfs|fstatfs|truncate|ftruncate|fallocate|faccessat|chdir|fchdir
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 90, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 59, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 58, 45, 44), //fchmod|fchmodat|fchownat|fchown|openat|close
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 89, 44, 43), //pipe2|quotactl|getdents64|lseek|read|write|readv|writev|pread64|pwrite64|preadv|pwritev|sendfile|pselect6|ppoll|signalfd4|vmsplice|splice|tee|readlinkat|newfstatat|fstat|sync|fsync|fdatasync|sync_file_range|timerfd_create|timerfd_settime|timerfd_gettime|utimensat
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 92, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 91, 42, 41), //capget
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 99, 41, 40), //personality|exit|exit_group|waitid|set_tid_address|unshare|futex
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 58, 43, 42), //fchmod|fchmodat|fchownat|fchown|openat|close
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 89, 42, 41), //pipe2|quotactl|getdents64|lseek|read|write|readv|writev|pread64|pwrite64|preadv|pwritev|sendfile|pselect6|ppoll|signalfd4|vmsplice|splice|tee|readlinkat|newfstatat|fstat|sync|fsync|fdatasync|sync_file_range|timerfd_create|timerfd_settime|timerfd_gettime|utimensat
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 99, 41, 40), //capget|capset|personality|exit|exit_group|waitid|set_tid_address|unshare|futex
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 143, 7, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 113, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 107, 1, 0),
@@ -32,9 +30,9 @@
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 116, 34, 33), //clock_gettime|clock_getres|clock_nanosleep
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 142, 33, 32), //ptrace|sched_setparam|sched_setscheduler|sched_getscheduler|sched_getparam|sched_setaffinity|sched_getaffinity|sched_yield|sched_get_priority_max|sched_get_priority_min|sched_rr_get_interval|restart_syscall|kill|tkill|tgkill|sigaltstack|rt_sigsuspend|rt_sigaction|rt_sigprocmask|rt_sigpending|rt_sigtimedwait|rt_sigqueueinfo|rt_sigreturn|setpriority|getpriority
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 150, 3, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 148, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 147, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 144, 30, 29), //setregid
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 149, 29, 28), //getresuid
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 149, 29, 28), //setresuid|getresuid
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 151, 28, 27), //getresgid
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 226, 13, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 198, 7, 0),
diff --git a/libc/seccomp/arm_app_policy.cpp b/libc/seccomp/arm_app_policy.cpp
index b5d98dc..ea9eb58 100644
--- a/libc/seccomp/arm_app_policy.cpp
+++ b/libc/seccomp/arm_app_policy.cpp
@@ -5,89 +5,85 @@
#include "seccomp_bpfs.h"
const sock_filter arm_app_filter[] = {
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 0, 0, 132),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 183, 65, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 85, 33, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 45, 17, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 26, 9, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 19, 5, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 0, 0, 128),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 172, 63, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 77, 31, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 41, 15, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 24, 7, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 10, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 8, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 7, 124, 123), //restart_syscall|exit|fork|read|write|open|close
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 9, 123, 122), //creat
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 13, 122, 121), //unlink|execve|chdir
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 24, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 21, 120, 119), //lseek|getpid
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 25, 119, 118), //getuid
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 36, 3, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 33, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 27, 116, 115), //ptrace
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 34, 115, 114), //access
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 41, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 40, 113, 112), //sync|kill|rename|mkdir
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 44, 112, 111), //dup|pipe|times
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 63, 7, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 57, 3, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 54, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 46, 108, 107), //brk
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 56, 107, 106), //ioctl|fcntl
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 60, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 58, 105, 104), //setpgid
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 61, 104, 103), //umask
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 75, 3, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 66, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 65, 101, 100), //dup2|getppid
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 68, 100, 99), //setsid|sigaction
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 77, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 76, 98, 97), //setrlimit
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 79, 97, 96), //getrusage|gettimeofday
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 122, 15, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 104, 7, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 94, 3, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 91, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 86, 92, 91), //readlink
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 93, 91, 90), //munmap|truncate
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 96, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 95, 89, 88), //fchmod
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 98, 88, 87), //getpriority|setpriority
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 116, 3, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 114, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 106, 85, 84), //setitimer|getitimer
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 115, 84, 83), //wait4
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 118, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 117, 82, 81), //sysinfo
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 121, 81, 80), //fsync|sigreturn|clone
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 140, 7, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 131, 3, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 125, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 123, 77, 76), //uname
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 126, 76, 75), //mprotect
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 136, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 134, 74, 73), //quotactl|getpgid|fchdir
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 137, 73, 72), //personality
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 168, 3, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 150, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 149, 70, 69), //_llseek|getdents|_newselect|flock|msync|readv|writev|getsid|fdatasync
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 164, 69, 68), //mlock|munlock|mlockall|munlockall|sched_setparam|sched_getparam|sched_setscheduler|sched_getscheduler|sched_yield|sched_get_priority_max|sched_get_priority_min|sched_rr_get_interval|nanosleep|mremap
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 172, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 169, 67, 66), //poll
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 182, 66, 65), //prctl|rt_sigreturn|rt_sigaction|rt_sigprocmask|rt_sigpending|rt_sigtimedwait|rt_sigqueueinfo|rt_sigsuspend|pread64|pwrite64
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 290, 33, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 219, 17, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 207, 9, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 199, 5, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 7, 121, 120), //restart_syscall|exit|fork|read|write|open|close
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 9, 120, 119), //creat
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 19, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 13, 118, 117), //unlink|execve|chdir
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 21, 117, 116), //lseek|getpid
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 33, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 26, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 25, 114, 113), //getuid
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 27, 113, 112), //ptrace
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 36, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 34, 111, 110), //access
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 40, 110, 109), //sync|kill|rename|mkdir
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 60, 7, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 54, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 45, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 44, 106, 105), //dup|pipe|times
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 46, 105, 104), //brk
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 57, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 56, 103, 102), //ioctl|fcntl
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 58, 102, 101), //setpgid
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 66, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 63, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 61, 99, 98), //umask
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 65, 98, 97), //dup2|getppid
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 75, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 68, 96, 95), //setsid|sigaction
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 76, 95, 94), //setrlimit
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 118, 15, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 96, 7, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 91, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 85, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 79, 90, 89), //getrusage|gettimeofday
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 86, 89, 88), //readlink
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 94, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 93, 87, 86), //munmap|truncate
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 95, 86, 85), //fchmod
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 114, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 104, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 98, 83, 82), //getpriority|setpriority
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 106, 82, 81), //setitimer|getitimer
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 116, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 115, 80, 79), //wait4
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 117, 79, 78), //sysinfo
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 136, 7, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 125, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 122, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 121, 75, 74), //fsync|sigreturn|clone
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 123, 74, 73), //uname
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 131, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 126, 72, 71), //mprotect
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 134, 71, 70), //quotactl|getpgid|fchdir
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 150, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 140, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 137, 68, 67), //personality
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 149, 67, 66), //_llseek|getdents|_newselect|flock|msync|readv|writev|getsid|fdatasync
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 168, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 164, 65, 64), //mlock|munlock|mlockall|munlockall|sched_setparam|sched_getparam|sched_setscheduler|sched_getscheduler|sched_yield|sched_get_priority_max|sched_get_priority_min|sched_rr_get_interval|nanosleep|mremap
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 169, 64, 63), //poll
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 290, 31, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 219, 15, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 204, 7, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 190, 3, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 186, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 185, 59, 58), //getcwd|capget
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 188, 58, 57), //sigaltstack|sendfile
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 198, 57, 56), //vfork|ugetrlimit|mmap2|truncate64|ftruncate64|stat64|lstat64|fstat64
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 204, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 203, 55, 54), //getuid32|getgid32|geteuid32|getegid32
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 206, 54, 53), //setregid32|getgroups32
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 183, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 182, 58, 57), //prctl|rt_sigreturn|rt_sigaction|rt_sigprocmask|rt_sigpending|rt_sigtimedwait|rt_sigqueueinfo|rt_sigsuspend|pread64|pwrite64
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 188, 57, 56), //getcwd|capget|capset|sigaltstack|sendfile
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 199, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 198, 55, 54), //vfork|ugetrlimit|mmap2|truncate64|ftruncate64|stat64|lstat64|fstat64
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 203, 54, 53), //getuid32|getgid32|geteuid32|getegid32
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 211, 3, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 209, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 208, 51, 50), //fchown32
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 210, 50, 49), //getresuid32
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 207, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 206, 51, 50), //setregid32|getgroups32
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 210, 50, 49), //fchown32|setresuid32|getresuid32
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 217, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 212, 48, 47), //getresgid32
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 218, 47, 46), //getdents64
diff --git a/libc/seccomp/mips64_app_policy.cpp b/libc/seccomp/mips64_app_policy.cpp
index 6ff4d9a..e5d69cf 100644
--- a/libc/seccomp/mips64_app_policy.cpp
+++ b/libc/seccomp/mips64_app_policy.cpp
@@ -5,65 +5,63 @@
#include "seccomp_bpfs.h"
const sock_filter mips64_app_filter[] = {
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5000, 0, 100),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5137, 49, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5000, 0, 98),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5151, 49, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5091, 25, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5038, 13, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5023, 7, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5005, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5003, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5002, 93, 92), //read|write
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5004, 92, 91), //close
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5002, 91, 90), //read|write
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5004, 90, 89), //close
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5008, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5006, 90, 89), //fstat
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5020, 89, 88), //lseek|mmap|mprotect|munmap|brk|rt_sigaction|rt_sigprocmask|ioctl|pread64|pwrite64|readv|writev
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5006, 88, 87), //fstat
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5020, 87, 86), //lseek|mmap|mprotect|munmap|brk|rt_sigaction|rt_sigprocmask|ioctl|pread64|pwrite64|readv|writev
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5034, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5031, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5028, 86, 85), //sched_yield|mremap|msync|mincore|madvise
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5032, 85, 84), //dup
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5037, 84, 83), //nanosleep|getitimer|setitimer
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5028, 84, 83), //sched_yield|mremap|msync|mincore|madvise
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5032, 83, 82), //dup
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5037, 82, 81), //nanosleep|getitimer|setitimer
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5070, 5, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5057, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5043, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5042, 80, 79), //getpid|sendfile|socket|connect
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5056, 79, 78), //sendto|recvfrom|sendmsg|recvmsg|shutdown|bind|listen|getsockname|getpeername|socketpair|setsockopt|getsockopt|clone
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5062, 78, 77), //execve|exit|wait4|kill|uname
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5042, 78, 77), //getpid|sendfile|socket|connect
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5056, 77, 76), //sendto|recvfrom|sendmsg|recvmsg|shutdown|bind|listen|getsockname|getpeername|socketpair|setsockopt|getsockopt|clone
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5062, 76, 75), //execve|exit|wait4|kill|uname
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5089, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5077, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5076, 75, 74), //fcntl|flock|fsync|fdatasync|truncate|ftruncate
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5080, 74, 73), //getcwd|chdir|fchdir
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5090, 73, 72), //fchmod
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5116, 11, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5076, 73, 72), //fcntl|flock|fsync|fdatasync|truncate|ftruncate
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5080, 72, 71), //getcwd|chdir|fchdir
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5090, 71, 70), //fchmod
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5115, 11, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5105, 5, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5102, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5093, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5092, 68, 67), //fchown
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5101, 67, 66), //umask|gettimeofday|getrlimit|getrusage|sysinfo|times|ptrace|getuid
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5103, 66, 65), //getgid
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5092, 66, 65), //fchown
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5101, 65, 64), //umask|gettimeofday|getrlimit|getrusage|sysinfo|times|ptrace|getuid
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5103, 64, 63), //getgid
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5112, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5110, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5109, 63, 62), //geteuid|getegid|setpgid|getppid
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5111, 62, 61), //setsid
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5114, 61, 60), //setregid|getgroups
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5125, 5, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5109, 61, 60), //geteuid|getegid|setpgid|getppid
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5111, 60, 59), //setsid
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5114, 59, 58), //setregid|getgroups
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5132, 5, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5122, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5118, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5117, 57, 56), //getresuid
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5120, 56, 55), //getresgid|getpgid
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5124, 55, 54), //getsid|capget
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5134, 3, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5132, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5130, 52, 51), //rt_sigpending|rt_sigtimedwait|rt_sigqueueinfo|rt_sigsuspend|sigaltstack
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5133, 51, 50), //personality
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5136, 50, 49), //statfs|fstatfs
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5237, 25, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5194, 13, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5157, 7, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5153, 3, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5151, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5150, 44, 43), //getpriority|setpriority|sched_setparam|sched_getparam|sched_setscheduler|sched_getscheduler|sched_get_priority_max|sched_get_priority_min|sched_rr_get_interval|mlock|munlock|mlockall|munlockall
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5152, 43, 42), //pivot_root
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5155, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5117, 55, 54), //setresuid|getresuid
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5120, 54, 53), //getresgid|getpgid
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5130, 53, 52), //getsid|capget|capset|rt_sigpending|rt_sigtimedwait|rt_sigqueueinfo|rt_sigsuspend|sigaltstack
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5137, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5134, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5133, 50, 49), //personality
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5136, 49, 48), //statfs|fstatfs
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5150, 48, 47), //getpriority|setpriority|sched_setparam|sched_getparam|sched_setscheduler|sched_getscheduler|sched_get_priority_max|sched_get_priority_min|sched_rr_get_interval|mlock|munlock|mlockall|munlockall
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5237, 23, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5194, 11, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5157, 5, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5155, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5153, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5152, 42, 41), //pivot_root
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5154, 41, 40), //prctl
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5156, 40, 39), //setrlimit
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5178, 3, 0),
diff --git a/libc/seccomp/mips_app_policy.cpp b/libc/seccomp/mips_app_policy.cpp
index bc1a924..c1ec0e2 100644
--- a/libc/seccomp/mips_app_policy.cpp
+++ b/libc/seccomp/mips_app_policy.cpp
@@ -5,92 +5,88 @@
#include "seccomp_bpfs.h"
const sock_filter mips_app_filter[] = {
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4001, 0, 118),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4136, 59, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4001, 0, 114),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4131, 57, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4063, 29, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4041, 15, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4024, 7, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4010, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4008, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4007, 111, 110), //exit|fork|read|write|open|close
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4009, 110, 109), //creat
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4007, 107, 106), //exit|fork|read|write|open|close
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4009, 106, 105), //creat
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4019, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4013, 108, 107), //unlink|execve|chdir
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4021, 107, 106), //lseek|getpid
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4013, 104, 103), //unlink|execve|chdir
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4021, 103, 102), //lseek|getpid
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4033, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4026, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4025, 104, 103), //getuid
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4027, 103, 102), //ptrace
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4025, 100, 99), //getuid
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4027, 99, 98), //ptrace
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4036, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4034, 101, 100), //access
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4040, 100, 99), //sync|kill|rename|mkdir
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4034, 97, 96), //access
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4040, 96, 95), //sync|kill|rename|mkdir
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4054, 7, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4047, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4045, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4044, 96, 95), //dup|pipe|times
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4046, 95, 94), //brk
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4044, 92, 91), //dup|pipe|times
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4046, 91, 90), //brk
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4049, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4048, 93, 92), //getgid
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4051, 92, 91), //geteuid|getegid
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4048, 89, 88), //getgid
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4051, 88, 87), //geteuid|getegid
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4060, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4057, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4056, 89, 88), //ioctl|fcntl
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4058, 88, 87), //setpgid
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4061, 87, 86), //umask
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4104, 15, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4056, 85, 84), //ioctl|fcntl
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4058, 84, 83), //setpgid
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4061, 83, 82), //umask
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4094, 13, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4080, 7, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4071, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4066, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4065, 82, 81), //dup2|getppid
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4068, 81, 80), //setsid|sigaction
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4065, 78, 77), //dup2|getppid
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4068, 77, 76), //setsid|sigaction
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4075, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4072, 79, 78), //setregid
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4079, 78, 77), //setrlimit|getrlimit|getrusage|gettimeofday
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4072, 75, 74), //setregid
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4079, 74, 73), //setrlimit|getrlimit|getrusage|gettimeofday
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4090, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4085, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4081, 75, 74), //getgroups
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4086, 74, 73), //readlink
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4094, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4093, 72, 71), //mmap|munmap|truncate
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4098, 71, 70), //fchmod|fchown|getpriority|setpriority
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4122, 7, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4116, 3, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4114, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4106, 67, 66), //setitimer|getitimer
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4115, 66, 65), //wait4
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4118, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4117, 64, 63), //sysinfo
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4121, 63, 62), //fsync|sigreturn|clone
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4131, 3, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4125, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4123, 60, 59), //uname
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4126, 59, 58), //mprotect
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4134, 58, 57), //quotactl|getpgid|fchdir
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4248, 29, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4188, 15, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4169, 7, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4151, 3, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4140, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4137, 52, 51), //personality
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4148, 51, 50), //_llseek|getdents|_newselect|flock|msync|readv|writev|cacheflush
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4154, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4153, 49, 48), //getsid|fdatasync
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4168, 48, 47), //mlock|munlock|mlockall|munlockall|sched_setparam|sched_getparam|sched_setscheduler|sched_getscheduler|sched_yield|sched_get_priority_max|sched_get_priority_min|sched_rr_get_interval|nanosleep|mremap
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4179, 3, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4176, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4175, 45, 44), //bind|connect|getpeername|getsockname|getsockopt|listen
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4178, 44, 43), //recvfrom|recvmsg
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4186, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4185, 42, 41), //sendmsg|sendto|setsockopt|shutdown|socket|socketpair
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4187, 41, 40), //getresuid
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4081, 71, 70), //getgroups
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4086, 70, 69), //readlink
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4093, 69, 68), //mmap|munmap|truncate
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4118, 7, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4114, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4104, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4098, 65, 64), //fchmod|fchown|getpriority|setpriority
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4106, 64, 63), //setitimer|getitimer
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4116, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4115, 62, 61), //wait4
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4117, 61, 60), //sysinfo
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4125, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4122, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4121, 58, 57), //fsync|sigreturn|clone
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4123, 57, 56), //uname
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4126, 56, 55), //mprotect
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4248, 27, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4179, 13, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4154, 7, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4140, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4136, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4134, 50, 49), //quotactl|getpgid|fchdir
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4137, 49, 48), //personality
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4151, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4148, 47, 46), //_llseek|getdents|_newselect|flock|msync|readv|writev|cacheflush
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4153, 46, 45), //getsid|fdatasync
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4176, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4169, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4168, 43, 42), //mlock|munlock|mlockall|munlockall|sched_setparam|sched_getparam|sched_setscheduler|sched_getscheduler|sched_yield|sched_get_priority_max|sched_get_priority_min|sched_rr_get_interval|nanosleep|mremap
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4175, 42, 41), //bind|connect|getpeername|getsockname|getsockopt|listen
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4178, 41, 40), //recvfrom|recvmsg
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4210, 7, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4203, 3, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4191, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4189, 37, 36), //poll
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4202, 36, 35), //getresgid|prctl|rt_sigreturn|rt_sigaction|rt_sigprocmask|rt_sigpending|rt_sigtimedwait|rt_sigqueueinfo|rt_sigsuspend|pread64|pwrite64
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4206, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4205, 34, 33), //getcwd|capget
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4208, 33, 32), //sigaltstack|sendfile
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4191, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4188, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4187, 37, 36), //sendmsg|sendto|setsockopt|shutdown|socket|socketpair|setresuid|getresuid
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4189, 36, 35), //poll
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4203, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4202, 34, 33), //getresgid|prctl|rt_sigreturn|rt_sigaction|rt_sigprocmask|rt_sigpending|rt_sigtimedwait|rt_sigqueueinfo|rt_sigsuspend|pread64|pwrite64
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4208, 33, 32), //getcwd|capget|capset|sigaltstack|sendfile
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4222, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4217, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4216, 30, 29), //mmap2|truncate64|ftruncate64|stat64|lstat64|fstat64
diff --git a/libc/seccomp/x86_64_app_policy.cpp b/libc/seccomp/x86_64_app_policy.cpp
index b90124b..26a970f 100644
--- a/libc/seccomp/x86_64_app_policy.cpp
+++ b/libc/seccomp/x86_64_app_policy.cpp
@@ -5,92 +5,90 @@
#include "seccomp_bpfs.h"
const sock_filter x86_64_app_filter[] = {
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 0, 0, 104),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 155, 51, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 0, 0, 102),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 157, 51, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 93, 25, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 38, 13, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 24, 7, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 3, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 2, 97, 96), //read|write
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4, 96, 95), //close
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 2, 95, 94), //read|write
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4, 94, 93), //close
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 8, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 6, 94, 93), //fstat
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 21, 93, 92), //lseek|mmap|mprotect|munmap|brk|rt_sigaction|rt_sigprocmask|rt_sigreturn|ioctl|pread64|pwrite64|readv|writev
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 6, 92, 91), //fstat
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 21, 91, 90), //lseek|mmap|mprotect|munmap|brk|rt_sigaction|rt_sigprocmask|rt_sigreturn|ioctl|pread64|pwrite64|readv|writev
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 35, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 32, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 29, 90, 89), //sched_yield|mremap|msync|mincore|madvise
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 33, 89, 88), //dup
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 37, 88, 87), //nanosleep|getitimer
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 29, 88, 87), //sched_yield|mremap|msync|mincore|madvise
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 33, 87, 86), //dup
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 37, 86, 85), //nanosleep|getitimer
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 72, 5, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 58, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 44, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 43, 84, 83), //setitimer|getpid|sendfile|socket|connect
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 57, 83, 82), //sendto|recvfrom|sendmsg|recvmsg|shutdown|bind|listen|getsockname|getpeername|socketpair|setsockopt|getsockopt|clone
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 64, 82, 81), //vfork|execve|exit|wait4|kill|uname
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 43, 82, 81), //setitimer|getpid|sendfile|socket|connect
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 57, 81, 80), //sendto|recvfrom|sendmsg|recvmsg|shutdown|bind|listen|getsockname|getpeername|socketpair|setsockopt|getsockopt|clone
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 64, 80, 79), //vfork|execve|exit|wait4|kill|uname
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 91, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 79, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 78, 79, 78), //fcntl|flock|fsync|fdatasync|truncate|ftruncate
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 82, 78, 77), //getcwd|chdir|fchdir
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 92, 77, 76), //fchmod
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 78, 77, 76), //fcntl|flock|fsync|fdatasync|truncate|ftruncate
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 82, 76, 75), //getcwd|chdir|fchdir
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 92, 75, 74), //fchmod
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 120, 13, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 112, 7, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 104, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 95, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 94, 72, 71), //fchown
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 103, 71, 70), //umask|gettimeofday|getrlimit|getrusage|sysinfo|times|ptrace|getuid
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 94, 70, 69), //fchown
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 103, 69, 68), //umask|gettimeofday|getrlimit|getrusage|sysinfo|times|ptrace|getuid
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 107, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 105, 69, 68), //getgid
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 111, 68, 67), //geteuid|getegid|setpgid|getppid
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 118, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 105, 67, 66), //getgid
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 111, 66, 65), //geteuid|getegid|setpgid|getppid
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 117, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 114, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 113, 65, 64), //setsid
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 116, 64, 63), //setregid|getgroups
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 119, 63, 62), //getresuid
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 135, 5, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 127, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 113, 63, 62), //setsid
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 116, 62, 61), //setregid|getgroups
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 119, 61, 60), //setresuid|getresuid
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 137, 5, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 135, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 124, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 122, 59, 58), //getresgid|getpgid
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 126, 58, 57), //getsid|capget
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 132, 57, 56), //rt_sigpending|rt_sigtimedwait|rt_sigqueueinfo|rt_sigsuspend|sigaltstack
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 140, 3, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 137, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 136, 54, 53), //personality
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 139, 53, 52), //statfs|fstatfs
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 153, 52, 51), //getpriority|setpriority|sched_setparam|sched_getparam|sched_setscheduler|sched_getscheduler|sched_get_priority_max|sched_get_priority_min|sched_rr_get_interval|mlock|munlock|mlockall|munlockall
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 251, 25, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 206, 13, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 179, 7, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 160, 3, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 157, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 156, 46, 45), //pivot_root
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 159, 45, 44), //prctl|arch_prctl
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 162, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 122, 57, 56), //getresgid|getpgid
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 132, 56, 55), //getsid|capget|capset|rt_sigpending|rt_sigtimedwait|rt_sigqueueinfo|rt_sigsuspend|sigaltstack
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 136, 55, 54), //personality
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 155, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 140, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 139, 52, 51), //statfs|fstatfs
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 153, 51, 50), //getpriority|setpriority|sched_setparam|sched_getparam|sched_setscheduler|sched_getscheduler|sched_get_priority_max|sched_get_priority_min|sched_rr_get_interval|mlock|munlock|mlockall|munlockall
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 156, 50, 49), //pivot_root
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 254, 25, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 217, 13, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 186, 7, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 162, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 160, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 159, 44, 43), //prctl|arch_prctl
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 161, 43, 42), //setrlimit
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 163, 42, 41), //sync
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 202, 3, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 186, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 180, 39, 38), //quotactl
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 201, 38, 37), //gettid|readahead|setxattr|lsetxattr|fsetxattr|getxattr|lgetxattr|fgetxattr|listxattr|llistxattr|flistxattr|removexattr|lremovexattr|fremovexattr|tkill
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 205, 37, 36), //futex|sched_setaffinity|sched_getaffinity
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 228, 5, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 221, 3, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 217, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 211, 33, 32), //io_setup|io_destroy|io_getevents|io_submit|io_cancel
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 220, 32, 31), //getdents64|set_tid_address|restart_syscall
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 227, 31, 30), //fadvise64|timer_create|timer_settime|timer_gettime|timer_getoverrun|timer_delete
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 247, 3, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 233, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 232, 28, 27), //clock_gettime|clock_getres|clock_nanosleep|exit_group
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 235, 27, 26), //epoll_ctl|tgkill
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 248, 26, 25), //waitid
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 285, 13, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 275, 7, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 257, 3, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 254, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 253, 21, 20), //ioprio_set|ioprio_get
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 256, 20, 19), //inotify_add_watch|inotify_rm_watch
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 262, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 179, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 163, 41, 40), //sync
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 180, 40, 39), //quotactl
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 206, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 202, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 201, 37, 36), //gettid|readahead|setxattr|lsetxattr|fsetxattr|getxattr|lgetxattr|fgetxattr|listxattr|llistxattr|flistxattr|removexattr|lremovexattr|fremovexattr|tkill
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 205, 36, 35), //futex|sched_setaffinity|sched_getaffinity
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 211, 35, 34), //io_setup|io_destroy|io_getevents|io_submit|io_cancel
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 233, 5, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 228, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 221, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 220, 31, 30), //getdents64|set_tid_address|restart_syscall
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 227, 30, 29), //fadvise64|timer_create|timer_settime|timer_gettime|timer_getoverrun|timer_delete
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 232, 29, 28), //clock_gettime|clock_getres|clock_nanosleep|exit_group
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 251, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 247, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 235, 26, 25), //epoll_ctl|tgkill
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 248, 25, 24), //waitid
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 253, 24, 23), //ioprio_set|ioprio_get
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 285, 11, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 275, 5, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 262, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 257, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 256, 19, 18), //inotify_add_watch|inotify_rm_watch
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 261, 18, 17), //openat|mkdirat|mknodat|fchownat
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 273, 17, 16), //newfstatat|unlinkat|renameat|linkat|symlinkat|readlinkat|fchmodat|faccessat|pselect6|ppoll|unshare
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 283, 3, 0),
diff --git a/libc/seccomp/x86_app_policy.cpp b/libc/seccomp/x86_app_policy.cpp
index 5131efa..1cea07e 100644
--- a/libc/seccomp/x86_app_policy.cpp
+++ b/libc/seccomp/x86_app_policy.cpp
@@ -5,99 +5,95 @@
#include "seccomp_bpfs.h"
const sock_filter x86_app_filter[] = {
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 0, 0, 124),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 150, 61, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 77, 31, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 0, 0, 120),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 140, 59, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 75, 29, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 41, 15, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 24, 7, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 10, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 8, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 7, 117, 116), //restart_syscall|exit|fork|read|write|open|close
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 9, 116, 115), //creat
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 7, 113, 112), //restart_syscall|exit|fork|read|write|open|close
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 9, 112, 111), //creat
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 19, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 13, 114, 113), //unlink|execve|chdir
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 21, 113, 112), //lseek|getpid
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 13, 110, 109), //unlink|execve|chdir
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 21, 109, 108), //lseek|getpid
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 33, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 26, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 25, 110, 109), //getuid
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 27, 109, 108), //ptrace
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 25, 106, 105), //getuid
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 27, 105, 104), //ptrace
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 36, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 34, 107, 106), //access
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 40, 106, 105), //sync|kill|rename|mkdir
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 34, 103, 102), //access
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 40, 102, 101), //sync|kill|rename|mkdir
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 60, 7, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 54, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 45, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 44, 102, 101), //dup|pipe|times
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 46, 101, 100), //brk
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 44, 98, 97), //dup|pipe|times
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 46, 97, 96), //brk
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 57, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 56, 99, 98), //ioctl|fcntl
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 58, 98, 97), //setpgid
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 56, 95, 94), //ioctl|fcntl
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 58, 94, 93), //setpgid
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 66, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 63, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 61, 95, 94), //umask
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 65, 94, 93), //dup2|getppid
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 75, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 68, 92, 91), //setsid|sigaction
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 76, 91, 90), //setrlimit
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 116, 15, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 96, 7, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 90, 3, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 85, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 79, 86, 85), //getrusage|gettimeofday
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 86, 85, 84), //readlink
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 94, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 93, 83, 82), //mmap|munmap|truncate
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 95, 82, 81), //fchmod
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 104, 3, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 102, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 98, 79, 78), //getpriority|setpriority
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 103, 78, 77), //socketcall
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 114, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 106, 76, 75), //setitimer|getitimer
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 115, 75, 74), //wait4
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 131, 7, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 122, 3, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 118, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 117, 71, 70), //sysinfo
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 121, 70, 69), //fsync|sigreturn|clone
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 125, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 123, 68, 67), //uname
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 126, 67, 66), //mprotect
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 140, 3, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 136, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 134, 64, 63), //quotactl|getpgid|fchdir
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 137, 63, 62), //personality
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 149, 62, 61), //_llseek|getdents|_newselect|flock|msync|readv|writev|getsid|fdatasync
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 265, 31, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 61, 91, 90), //umask
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 65, 90, 89), //dup2|getppid
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 68, 89, 88), //setsid|sigaction
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 114, 15, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 94, 7, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 85, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 77, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 76, 84, 83), //setrlimit
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 79, 83, 82), //getrusage|gettimeofday
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 90, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 86, 81, 80), //readlink
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 93, 80, 79), //mmap|munmap|truncate
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 102, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 96, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 95, 77, 76), //fchmod
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 98, 76, 75), //getpriority|setpriority
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 104, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 103, 74, 73), //socketcall
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 106, 73, 72), //setitimer|getitimer
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 125, 7, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 118, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 116, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 115, 69, 68), //wait4
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 117, 68, 67), //sysinfo
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 122, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 121, 66, 65), //fsync|sigreturn|clone
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 123, 65, 64), //uname
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 136, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 131, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 126, 62, 61), //mprotect
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 134, 61, 60), //quotactl|getpgid|fchdir
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 137, 60, 59), //personality
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 265, 29, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 207, 15, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 186, 7, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 172, 3, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 168, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 164, 56, 55), //mlock|munlock|mlockall|munlockall|sched_setparam|sched_getparam|sched_setscheduler|sched_getscheduler|sched_yield|sched_get_priority_max|sched_get_priority_min|sched_rr_get_interval|nanosleep|mremap
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 169, 55, 54), //poll
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 183, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 182, 53, 52), //prctl|rt_sigreturn|rt_sigaction|rt_sigprocmask|rt_sigpending|rt_sigtimedwait|rt_sigqueueinfo|rt_sigsuspend|pread64|pwrite64
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 185, 52, 51), //getcwd|capget
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 183, 7, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 168, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 150, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 149, 54, 53), //_llseek|getdents|_newselect|flock|msync|readv|writev|getsid|fdatasync
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 164, 53, 52), //mlock|munlock|mlockall|munlockall|sched_setparam|sched_getparam|sched_setscheduler|sched_getscheduler|sched_yield|sched_get_priority_max|sched_get_priority_min|sched_rr_get_interval|nanosleep|mremap
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 172, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 169, 51, 50), //poll
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 182, 50, 49), //prctl|rt_sigreturn|rt_sigaction|rt_sigprocmask|rt_sigpending|rt_sigtimedwait|rt_sigqueueinfo|rt_sigsuspend|pread64|pwrite64
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 199, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 190, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 188, 49, 48), //sigaltstack|sendfile
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 198, 48, 47), //vfork|ugetrlimit|mmap2|truncate64|ftruncate64|stat64|lstat64|fstat64
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 188, 47, 46), //getcwd|capget|capset|sigaltstack|sendfile
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 198, 46, 45), //vfork|ugetrlimit|mmap2|truncate64|ftruncate64|stat64|lstat64|fstat64
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 204, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 203, 46, 45), //getuid32|getgid32|geteuid32|getegid32
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 206, 45, 44), //setregid32|getgroups32
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 224, 7, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 211, 3, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 209, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 208, 41, 40), //fchown32
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 210, 40, 39), //getresuid32
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 218, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 203, 44, 43), //getuid32|getgid32|geteuid32|getegid32
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 206, 43, 42), //setregid32|getgroups32
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 245, 7, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 218, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 211, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 210, 39, 38), //fchown32|setresuid32|getresuid32
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 212, 38, 37), //getresgid32
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 222, 37, 36), //mincore|madvise|getdents64|fcntl64
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 252, 3, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 245, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 244, 34, 33), //gettid|readahead|setxattr|lsetxattr|fsetxattr|getxattr|lgetxattr|fgetxattr|listxattr|llistxattr|flistxattr|removexattr|lremovexattr|fremovexattr|tkill|sendfile64|futex|sched_setaffinity|sched_getaffinity|set_thread_area
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 250, 33, 32), //io_setup|io_destroy|io_getevents|io_submit|io_cancel
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 254, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 224, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 222, 36, 35), //mincore|madvise|getdents64|fcntl64
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 244, 35, 34), //gettid|readahead|setxattr|lsetxattr|fsetxattr|getxattr|lgetxattr|fgetxattr|listxattr|llistxattr|flistxattr|removexattr|lremovexattr|fremovexattr|tkill|sendfile64|futex|sched_setaffinity|sched_getaffinity|set_thread_area
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 254, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 252, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 250, 32, 31), //io_setup|io_destroy|io_getevents|io_submit|io_cancel
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 253, 31, 30), //exit_group
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 264, 30, 29), //epoll_create|epoll_ctl|epoll_wait|remap_file_pages|set_tid_address|timer_create|timer_settime|timer_gettime|timer_getoverrun|timer_delete
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 322, 15, 0),
diff --git a/tests/Android.bp b/tests/Android.bp
index eb3b5f4..fb0e8b1 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -498,8 +498,10 @@
"libdl_preempt_test_1",
"libdl_preempt_test_2",
"libdl_test_df_1_global",
+ "libelf-tls-library",
"libgnu-hash-table-library",
"libsysv-hash-table-library",
+ "libtestshared",
"libtest_atexit",
"libtest_check_order_dlsym_1_left",
"libtest_check_order_dlsym_2_right",
@@ -524,6 +526,7 @@
"libtest_check_order_reloc_siblings_f",
"libtest_check_order_reloc_siblings",
"libtest_check_rtld_next_from_library",
+ "libtest_dlopen_df_1_global",
"libtest_dlopen_from_ctor_main",
"libtest_dlopen_from_ctor",
"libtest_dlopen_weak_undefined_func",
@@ -534,11 +537,17 @@
"libtest_dlsym_weak_func",
"libtest_dt_runpath_d",
"libtest_empty",
+ "libtest_ifunc_variable_impl",
+ "libtest_ifunc_variable",
"libtest_ifunc",
"libtest_init_fini_order_child",
"libtest_init_fini_order_grand_child",
"libtest_init_fini_order_root2",
"libtest_init_fini_order_root",
+ "libtest_missing_symbol_child_public",
+ "libtest_missing_symbol_child_private",
+ "libtest_missing_symbol_root",
+ "libtest_missing_symbol",
"libtest_nodelete_1",
"libtest_nodelete_2",
"libtest_nodelete_dt_flags_1",
@@ -573,6 +582,7 @@
"libtest_invalid-zero_shstrndx.so",
"libtest_invalid-textrels.so",
"libtest_invalid-textrels2.so",
+ "libtest_thread_local_dtor",
"preinit_getauxval_test_helper",
"preinit_syscall_test_helper",
"libnstest_private_external",
@@ -586,6 +596,13 @@
"libnstest_ns_a_public1_internal",
"libnstest_ns_b_public2",
"libnstest_ns_b_public3",
+ "ld_preload_test_helper",
+ "ld_preload_test_helper_lib1",
+ "ld_preload_test_helper_lib2",
+ "ld_config_test_helper",
+ "ld_config_test_helper_lib1",
+ "ld_config_test_helper_lib2",
+ "ld_config_test_helper_lib3",
],
}