Merge "Nullability check for link module"
diff --git a/benchmarks/malloc_benchmark.cpp b/benchmarks/malloc_benchmark.cpp
index 18ba523..e733cd0 100644
--- a/benchmarks/malloc_benchmark.cpp
+++ b/benchmarks/malloc_benchmark.cpp
@@ -36,11 +36,11 @@
#if defined(__BIONIC__)
-static void BM_mallopt_purge(benchmark::State& state) {
+static void RunMalloptPurge(benchmark::State& state, int purge_value) {
static size_t sizes[] = {8, 16, 32, 64, 128, 1024, 4096, 16384, 65536, 131072, 1048576};
static int pagesize = getpagesize();
mallopt(M_DECAY_TIME, 1);
- mallopt(M_PURGE, 0);
+ mallopt(M_PURGE_ALL, 0);
for (auto _ : state) {
state.PauseTiming();
std::vector<void*> ptrs;
@@ -63,10 +63,19 @@
ptrs.clear();
state.ResumeTiming();
- mallopt(M_PURGE, 0);
+ mallopt(purge_value, 0);
}
mallopt(M_DECAY_TIME, 0);
}
+
+static void BM_mallopt_purge(benchmark::State& state) {
+ RunMalloptPurge(state, M_PURGE);
+}
BIONIC_BENCHMARK(BM_mallopt_purge);
+static void BM_mallopt_purge_all(benchmark::State& state) {
+ RunMalloptPurge(state, M_PURGE_ALL);
+}
+BIONIC_BENCHMARK(BM_mallopt_purge_all);
+
#endif
diff --git a/benchmarks/malloc_map_benchmark.cpp b/benchmarks/malloc_map_benchmark.cpp
index ba4d62c..5757325 100644
--- a/benchmarks/malloc_map_benchmark.cpp
+++ b/benchmarks/malloc_map_benchmark.cpp
@@ -69,7 +69,7 @@
for (auto _ : state) {
#if defined(__BIONIC__)
state.PauseTiming();
- mallopt(M_PURGE, 0);
+ mallopt(M_PURGE_ALL, 0);
uint64_t rss_bytes_before = 0;
Gather(&rss_bytes_before);
state.ResumeTiming();
@@ -80,7 +80,7 @@
}
#if defined(__BIONIC__)
state.PauseTiming();
- mallopt(M_PURGE, 0);
+ mallopt(M_PURGE_ALL, 0);
Gather(&rss_bytes);
// Try and record only the memory used in the map.
rss_bytes -= rss_bytes_before;
diff --git a/benchmarks/malloc_rss_benchmark.cpp b/benchmarks/malloc_rss_benchmark.cpp
index 58f61d9..4b34e72 100644
--- a/benchmarks/malloc_rss_benchmark.cpp
+++ b/benchmarks/malloc_rss_benchmark.cpp
@@ -112,7 +112,7 @@
// Do an explicit purge to ensure we will be more likely to get the actual
// in-use memory.
- mallopt(M_PURGE, 0);
+ mallopt(M_PURGE_ALL, 0);
android::meminfo::ProcMemInfo proc_mem(getpid());
const std::vector<android::meminfo::Vma>& maps = proc_mem.MapsWithoutUsageStats();
diff --git a/libc/bionic/jemalloc_wrapper.cpp b/libc/bionic/jemalloc_wrapper.cpp
index ef488ee..ce3f314 100644
--- a/libc/bionic/jemalloc_wrapper.cpp
+++ b/libc/bionic/jemalloc_wrapper.cpp
@@ -102,7 +102,7 @@
}
}
return 1;
- } else if (param == M_PURGE) {
+ } else if (param == M_PURGE || param == M_PURGE_ALL) {
// Only clear the current thread cache since there is no easy way to
// clear the caches of other threads.
// This must be done first so that cleared allocations get purged
diff --git a/libc/include/malloc.h b/libc/include/malloc.h
index 02bda60..6a2d380 100644
--- a/libc/include/malloc.h
+++ b/libc/include/malloc.h
@@ -183,7 +183,15 @@
* Available since API level 28.
*/
#define M_PURGE (-101)
-
+/**
+ * mallopt() option to immediately purge all possible memory back to
+ * the kernel. This call can take longer than a normal purge since it
+ * examines everything. In some cases, it can take more than twice the
+ * time of a M_PURGE call. The value is ignored.
+ *
+ * Available since API level 34.
+ */
+#define M_PURGE_ALL (-104)
/**
* mallopt() option to tune the allocator's choice of memory tags to
diff --git a/libc/include/pwd.h b/libc/include/pwd.h
index d481aac..2b17fbf 100644
--- a/libc/include/pwd.h
+++ b/libc/include/pwd.h
@@ -66,31 +66,31 @@
__BEGIN_DECLS
struct passwd {
- char* pw_name;
- char* pw_passwd;
+ char* _Nullable pw_name;
+ char* _Nullable pw_passwd;
uid_t pw_uid;
gid_t pw_gid;
#ifdef __LP64__
- char* pw_gecos;
+ char* _Nullable pw_gecos;
#else
/* Note: On LP32, we define pw_gecos to pw_passwd since they're both NULL. */
# define pw_gecos pw_passwd
#endif
- char* pw_dir;
- char* pw_shell;
+ char* _Nullable pw_dir;
+ char* _Nullable pw_shell;
};
-struct passwd* getpwnam(const char* __name);
-struct passwd* getpwuid(uid_t __uid);
+struct passwd* _Nullable getpwnam(const char* _Nonnull __name);
+struct passwd* _Nullable getpwuid(uid_t __uid);
/* Note: Android has thousands and thousands of ids to iterate through */
-struct passwd* getpwent(void) __INTRODUCED_IN(26);
+struct passwd* _Nullable getpwent(void) __INTRODUCED_IN(26);
void setpwent(void) __INTRODUCED_IN(26);
void endpwent(void) __INTRODUCED_IN(26);
-int getpwnam_r(const char* __name, struct passwd* __pwd, char* __buf, size_t __n, struct passwd** __result);
-int getpwuid_r(uid_t __uid, struct passwd* __pwd, char* __buf, size_t __n, struct passwd** __result);
+int getpwnam_r(const char* _Nonnull __name, struct passwd* _Nonnull __pwd, char* _Nonnull __buf, size_t __n, struct passwd* _Nullable * _Nonnull __result);
+int getpwuid_r(uid_t __uid, struct passwd* _Nonnull __pwd, char* _Nonnull __buf, size_t __n, struct passwd* _Nullable * _Nonnull __result);
__END_DECLS
diff --git a/tests/malloc_test.cpp b/tests/malloc_test.cpp
index 63ad99d..4e7eb7b 100644
--- a/tests/malloc_test.cpp
+++ b/tests/malloc_test.cpp
@@ -36,7 +36,10 @@
#include <algorithm>
#include <atomic>
#include <functional>
+#include <string>
#include <thread>
+#include <unordered_map>
+#include <utility>
#include <vector>
#include <tinyxml2.h>
@@ -695,6 +698,44 @@
#endif
}
+TEST(malloc, mallopt_purge_all) {
+#if defined(__BIONIC__)
+ SKIP_WITH_HWASAN << "hwasan does not implement mallopt";
+ errno = 0;
+ ASSERT_EQ(1, mallopt(M_PURGE_ALL, 0));
+#else
+ GTEST_SKIP() << "bionic-only test";
+#endif
+}
+
+// Verify that all of the mallopt values are unique.
+TEST(malloc, mallopt_unique_params) {
+#if defined(__BIONIC__)
+ std::vector<std::pair<int, std::string>> params{
+ std::make_pair(M_DECAY_TIME, "M_DECAY_TIME"),
+ std::make_pair(M_PURGE, "M_PURGE"),
+ std::make_pair(M_PURGE_ALL, "M_PURGE_ALL"),
+ std::make_pair(M_MEMTAG_TUNING, "M_MEMTAG_TUNING"),
+ std::make_pair(M_THREAD_DISABLE_MEM_INIT, "M_THREAD_DISABLE_MEM_INIT"),
+ std::make_pair(M_CACHE_COUNT_MAX, "M_CACHE_COUNT_MAX"),
+ std::make_pair(M_CACHE_SIZE_MAX, "M_CACHE_SIZE_MAX"),
+ std::make_pair(M_TSDS_COUNT_MAX, "M_TSDS_COUNT_MAX"),
+ std::make_pair(M_BIONIC_ZERO_INIT, "M_BIONIC_ZERO_INIT"),
+ std::make_pair(M_BIONIC_SET_HEAP_TAGGING_LEVEL, "M_BIONIC_SET_HEAP_TAGGING_LEVEL"),
+ };
+
+ std::unordered_map<int, std::string> all_params;
+ for (const auto& param : params) {
+ EXPECT_TRUE(all_params.count(param.first) == 0)
+ << "mallopt params " << all_params[param.first] << " and " << param.second
+ << " have the same value " << param.first;
+ all_params.insert(param);
+ }
+#else
+ GTEST_SKIP() << "bionic-only test";
+#endif
+}
+
#if defined(__BIONIC__)
static void GetAllocatorVersion(bool* allocator_scudo) {
TemporaryFile tf;