Merge "Purge memory."
diff --git a/libc/include/fcntl.h b/libc/include/fcntl.h
index 1ea94e6..4ef894b 100644
--- a/libc/include/fcntl.h
+++ b/libc/include/fcntl.h
@@ -111,9 +111,9 @@
* Returns a new file descriptor on success and returns -1 and sets `errno` on
* failure.
*/
-int creat(const char* __path, mode_t __mode);
+int creat(const char* _Nonnull __path, mode_t __mode);
/** See creat(). */
-int creat64(const char* __path, mode_t __mode) __INTRODUCED_IN(21);
+int creat64(const char* _Nonnull __path, mode_t __mode) __INTRODUCED_IN(21);
/**
* [openat(2)](http://man7.org/linux/man-pages/man2/openat.2.html)
@@ -122,9 +122,9 @@
* Returns a new file descriptor on success and returns -1 and sets `errno` on
* failure.
*/
-int openat(int __dir_fd, const char* __path, int __flags, ...);
+int openat(int __dir_fd, const char* _Nonnull __path, int __flags, ...);
/** See openat(). */
-int openat64(int __dir_fd, const char* __path, int __flags, ...) __INTRODUCED_IN(21);
+int openat64(int __dir_fd, const char* _Nonnull __path, int __flags, ...) __INTRODUCED_IN(21);
/**
* [open(2)](http://man7.org/linux/man-pages/man2/open.2.html)
@@ -133,9 +133,9 @@
* Returns a new file descriptor on success and returns -1 and sets `errno` on
* failure.
*/
-int open(const char* __path, int __flags, ...);
+int open(const char* _Nonnull __path, int __flags, ...);
/** See open(). */
-int open64(const char* __path, int __flags, ...) __INTRODUCED_IN(21);
+int open64(const char* _Nonnull __path, int __flags, ...) __INTRODUCED_IN(21);
/**
* [splice(2)](http://man7.org/linux/man-pages/man2/splice.2.html)
@@ -149,7 +149,7 @@
*
* Available since API level 21.
*/
-ssize_t splice(int __in_fd, off64_t* __in_offset, int __out_fd, off64_t* __out_offset, size_t __length, unsigned int __flags) __INTRODUCED_IN(21);
+ssize_t splice(int __in_fd, off64_t* _Null_unspecified __in_offset, int __out_fd, off64_t* _Null_unspecified __out_offset, size_t __length, unsigned int __flags) __INTRODUCED_IN(21);
/**
* [tee(2)](http://man7.org/linux/man-pages/man2/tee.2.html)
@@ -177,7 +177,7 @@
*
* Available since API level 21.
*/
-ssize_t vmsplice(int __fd, const struct iovec* __iov, size_t __count, unsigned int __flags) __INTRODUCED_IN(21);
+ssize_t vmsplice(int __fd, const struct iovec* _Nonnull __iov, size_t __count, unsigned int __flags) __INTRODUCED_IN(21);
/**
* [fallocate(2)](http://man7.org/linux/man-pages/man2/fallocate.2.html)
diff --git a/tests/malloc_test.cpp b/tests/malloc_test.cpp
index e90a824..63ad99d 100644
--- a/tests/malloc_test.cpp
+++ b/tests/malloc_test.cpp
@@ -35,6 +35,7 @@
#include <algorithm>
#include <atomic>
+#include <functional>
#include <thread>
#include <vector>
@@ -1528,3 +1529,157 @@
}
}
}
+
+void VerifyAllocationsAreZero(std::function<void*(size_t)> alloc_func, std::string function_name,
+ std::vector<size_t>& test_sizes, size_t max_allocations) {
+ // Vector of zero'd data used for comparisons. Make it twice the largest size.
+ std::vector<char> zero(test_sizes.back() * 2, 0);
+
+ SCOPED_TRACE(testing::Message() << function_name << " failed to zero memory");
+
+ for (size_t test_size : test_sizes) {
+ std::vector<void*> ptrs(max_allocations);
+ for (size_t i = 0; i < ptrs.size(); i++) {
+ SCOPED_TRACE(testing::Message() << "size " << test_size << " at iteration " << i);
+ ptrs[i] = alloc_func(test_size);
+ ASSERT_TRUE(ptrs[i] != nullptr);
+ size_t alloc_size = malloc_usable_size(ptrs[i]);
+ ASSERT_LE(alloc_size, zero.size());
+ ASSERT_EQ(0, memcmp(ptrs[i], zero.data(), alloc_size));
+
+ // Set the memory to non-zero to make sure if the pointer
+ // is reused it's still zero.
+ memset(ptrs[i], 0xab, alloc_size);
+ }
+ // Free the pointers.
+ for (size_t i = 0; i < ptrs.size(); i++) {
+ free(ptrs[i]);
+ }
+ for (size_t i = 0; i < ptrs.size(); i++) {
+ SCOPED_TRACE(testing::Message() << "size " << test_size << " at iteration " << i);
+ ptrs[i] = malloc(test_size);
+ ASSERT_TRUE(ptrs[i] != nullptr);
+ size_t alloc_size = malloc_usable_size(ptrs[i]);
+ ASSERT_LE(alloc_size, zero.size());
+ ASSERT_EQ(0, memcmp(ptrs[i], zero.data(), alloc_size));
+ }
+ // Free all of the pointers later to maximize the chance of reusing from
+ // the first loop.
+ for (size_t i = 0; i < ptrs.size(); i++) {
+ free(ptrs[i]);
+ }
+ }
+}
+
+// Verify that small and medium allocations are always zero.
+TEST(malloc, zeroed_allocations_small_medium_sizes) {
+#if !defined(__BIONIC__)
+ GTEST_SKIP() << "Only valid on bionic";
+#endif
+
+ if (IsLowRamDevice()) {
+ GTEST_SKIP() << "Skipped on low memory devices.";
+ }
+
+ constexpr size_t kMaxAllocations = 1024;
+ std::vector<size_t> test_sizes = {16, 48, 128, 1024, 4096, 65536};
+ VerifyAllocationsAreZero([](size_t size) -> void* { return malloc(size); }, "malloc", test_sizes,
+ kMaxAllocations);
+
+ VerifyAllocationsAreZero([](size_t size) -> void* { return memalign(64, size); }, "memalign",
+ test_sizes, kMaxAllocations);
+
+ VerifyAllocationsAreZero(
+ [](size_t size) -> void* {
+ void* ptr;
+ if (posix_memalign(&ptr, 64, size) == 0) {
+ return ptr;
+ }
+ return nullptr;
+ },
+ "posix_memalign", test_sizes, kMaxAllocations);
+}
+
+// Verify that large allocations are always zero.
+TEST(malloc, zeroed_allocations_large_sizes) {
+#if !defined(__BIONIC__)
+ GTEST_SKIP() << "Only valid on bionic";
+#endif
+
+ if (IsLowRamDevice()) {
+ GTEST_SKIP() << "Skipped on low memory devices.";
+ }
+
+ constexpr size_t kMaxAllocations = 20;
+ std::vector<size_t> test_sizes = {1000000, 2000000, 3000000, 4000000};
+ VerifyAllocationsAreZero([](size_t size) -> void* { return malloc(size); }, "malloc", test_sizes,
+ kMaxAllocations);
+
+ VerifyAllocationsAreZero([](size_t size) -> void* { return memalign(64, size); }, "memalign",
+ test_sizes, kMaxAllocations);
+
+ VerifyAllocationsAreZero(
+ [](size_t size) -> void* {
+ void* ptr;
+ if (posix_memalign(&ptr, 64, size) == 0) {
+ return ptr;
+ }
+ return nullptr;
+ },
+ "posix_memalign", test_sizes, kMaxAllocations);
+}
+
+TEST(malloc, zeroed_allocations_realloc) {
+#if !defined(__BIONIC__)
+ GTEST_SKIP() << "Only valid on bionic";
+#endif
+
+ if (IsLowRamDevice()) {
+ GTEST_SKIP() << "Skipped on low memory devices.";
+ }
+
+ // Vector of zero'd data used for comparisons.
+ constexpr size_t kMaxMemorySize = 131072;
+ std::vector<char> zero(kMaxMemorySize, 0);
+
+ constexpr size_t kMaxAllocations = 1024;
+ std::vector<size_t> test_sizes = {16, 48, 128, 1024, 4096, 65536};
+ // Do a number of allocations and set them to non-zero.
+ for (size_t test_size : test_sizes) {
+ std::vector<void*> ptrs(kMaxAllocations);
+ for (size_t i = 0; i < kMaxAllocations; i++) {
+ ptrs[i] = malloc(test_size);
+ ASSERT_TRUE(ptrs[i] != nullptr);
+
+ // Set the memory to non-zero to make sure if the pointer
+ // is reused it's still zero.
+ memset(ptrs[i], 0xab, malloc_usable_size(ptrs[i]));
+ }
+ // Free the pointers.
+ for (size_t i = 0; i < kMaxAllocations; i++) {
+ free(ptrs[i]);
+ }
+ }
+
+ // Do the reallocs to a larger size and verify the rest of the allocation
+ // is zero.
+ constexpr size_t kInitialSize = 8;
+ for (size_t test_size : test_sizes) {
+ std::vector<void*> ptrs(kMaxAllocations);
+ for (size_t i = 0; i < kMaxAllocations; i++) {
+ ptrs[i] = malloc(kInitialSize);
+ ASSERT_TRUE(ptrs[i] != nullptr);
+ size_t orig_alloc_size = malloc_usable_size(ptrs[i]);
+
+ ptrs[i] = realloc(ptrs[i], test_size);
+ ASSERT_TRUE(ptrs[i] != nullptr);
+ size_t new_alloc_size = malloc_usable_size(ptrs[i]);
+ char* ptr = reinterpret_cast<char*>(ptrs[i]);
+ ASSERT_EQ(0, memcmp(&ptr[orig_alloc_size], zero.data(), new_alloc_size - orig_alloc_size))
+ << "realloc from " << kInitialSize << " to size " << test_size << " at iteration " << i;
+ }
+ for (size_t i = 0; i < kMaxAllocations; i++) {
+ free(ptrs[i]);
+ }
+ }
+}
diff --git a/tests/utils.cpp b/tests/utils.cpp
index 8258833..92ab145 100644
--- a/tests/utils.cpp
+++ b/tests/utils.cpp
@@ -28,6 +28,10 @@
#include "utils.h"
+#include <string>
+
+#include <android-base/properties.h>
+
void RunGwpAsanTest(const char* test_name) {
ExecTestHelper eh;
eh.SetEnv({"GWP_ASAN_SAMPLE_RATE=1", "GWP_ASAN_PROCESS_SAMPLING=1", "GWP_ASAN_MAX_ALLOCS=40000",
@@ -53,3 +57,9 @@
// |expected_output_regex|, ensure at least one test ran:
R"(\[ PASSED \] [1-9]+0? test)");
}
+
+bool IsLowRamDevice() {
+ return android::base::GetBoolProperty("ro.config.low_ram", false) ||
+ (android::base::GetBoolProperty("ro.debuggable", false) &&
+ android::base::GetBoolProperty("debug.force_low_ram", false));
+}
diff --git a/tests/utils.h b/tests/utils.h
index 81869e3..2e00cc1 100644
--- a/tests/utils.h
+++ b/tests/utils.h
@@ -313,3 +313,5 @@
return false;
#endif
}
+
+bool IsLowRamDevice();