Refactor the malloc_info code.
malloc_info needs to be per native allocator, but the code treated it like a global function that doesn't depend on the native memory allocator. Update malloc debug to dump the actual pointers that it has been tracking. Test: bionic-unit-tests pass. Test: malloc debug tests pass. Test: malloc hook tests pass. Change-Id: I3b0d4d748489dd84c16d16933479dc8b8d79013e
This commit is contained in:
parent
c32e6747b7
commit
a3656a98b1
|
@ -1089,7 +1089,6 @@ cc_library_static {
|
|||
"bionic/locale.cpp",
|
||||
"bionic/lockf.cpp",
|
||||
"bionic/lstat.cpp",
|
||||
"bionic/malloc_info.cpp",
|
||||
"bionic/mblen.cpp",
|
||||
"bionic/mbrtoc16.cpp",
|
||||
"bionic/mbrtoc32.cpp",
|
||||
|
|
|
@ -34,6 +34,7 @@ int je_mallctl(const char *name, void *oldp, size_t *oldlenp, void *newp, size_t
|
|||
struct mallinfo je_mallinfo();
|
||||
void je_malloc_disable();
|
||||
void je_malloc_enable();
|
||||
int je_malloc_info(int options, FILE* fp);
|
||||
int je_mallopt(int, int);
|
||||
void* je_memalign_round_up_boundary(size_t, size_t);
|
||||
void* je_pvalloc(size_t);
|
||||
|
|
|
@ -19,8 +19,9 @@
|
|||
#include <sys/param.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <private/MallocXmlElem.h>
|
||||
|
||||
#include "jemalloc.h"
|
||||
#include "private/bionic_macros.h"
|
||||
|
||||
void* je_pvalloc(size_t bytes) {
|
||||
size_t pagesize = getpagesize();
|
||||
|
@ -116,3 +117,49 @@ int je_mallopt(int param, int value) {
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
size_t __mallinfo_narenas();
|
||||
size_t __mallinfo_nbins();
|
||||
struct mallinfo __mallinfo_arena_info(size_t);
|
||||
struct mallinfo __mallinfo_bin_info(size_t, size_t);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
int je_malloc_info(int options, FILE* fp) {
|
||||
if (options != 0) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
MallocXmlElem root(fp, "malloc", "version=\"jemalloc-1\"");
|
||||
|
||||
// Dump all of the large allocations in the arenas.
|
||||
for (size_t i = 0; i < __mallinfo_narenas(); i++) {
|
||||
struct mallinfo mi = __mallinfo_arena_info(i);
|
||||
if (mi.hblkhd != 0) {
|
||||
MallocXmlElem arena_elem(fp, "heap", "nr=\"%d\"", i);
|
||||
{
|
||||
MallocXmlElem(fp, "allocated-large").Contents("%zu", mi.ordblks);
|
||||
MallocXmlElem(fp, "allocated-huge").Contents("%zu", mi.uordblks);
|
||||
MallocXmlElem(fp, "allocated-bins").Contents("%zu", mi.fsmblks);
|
||||
|
||||
size_t total = 0;
|
||||
for (size_t j = 0; j < __mallinfo_nbins(); j++) {
|
||||
struct mallinfo mi = __mallinfo_bin_info(i, j);
|
||||
if (mi.ordblks != 0) {
|
||||
MallocXmlElem bin_elem(fp, "bin", "nr=\"%d\"", j);
|
||||
MallocXmlElem(fp, "allocated").Contents("%zu", mi.ordblks);
|
||||
MallocXmlElem(fp, "nmalloc").Contents("%zu", mi.uordblks);
|
||||
MallocXmlElem(fp, "ndalloc").Contents("%zu", mi.fordblks);
|
||||
total += mi.ordblks;
|
||||
}
|
||||
}
|
||||
MallocXmlElem(fp, "bins-total").Contents("%zu", total);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
// write_malloc_leak_info: Writes the leak info data to a file.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <private/bionic_config.h>
|
||||
|
||||
|
@ -93,6 +94,14 @@ extern "C" struct mallinfo mallinfo() {
|
|||
return Malloc(mallinfo)();
|
||||
}
|
||||
|
||||
extern "C" int malloc_info(int options, FILE* fp) {
|
||||
auto dispatch_table = GetDispatchTable();
|
||||
if (__predict_false(dispatch_table != nullptr)) {
|
||||
return dispatch_table->malloc_info(options, fp);
|
||||
}
|
||||
return Malloc(malloc_info)(options, fp);
|
||||
}
|
||||
|
||||
extern "C" int mallopt(int param, int value) {
|
||||
auto dispatch_table = GetDispatchTable();
|
||||
if (__predict_false(dispatch_table != nullptr)) {
|
||||
|
|
|
@ -85,6 +85,7 @@ static constexpr MallocDispatch __libc_malloc_default_dispatch
|
|||
Malloc(malloc_enable),
|
||||
Malloc(mallopt),
|
||||
Malloc(aligned_alloc),
|
||||
Malloc(malloc_info),
|
||||
};
|
||||
|
||||
static constexpr char kHooksSharedLib[] = "libc_malloc_hooks.so";
|
||||
|
@ -146,6 +147,10 @@ static bool InitMallocFunctions(void* impl_handler, MallocDispatch* table, const
|
|||
if (!InitMallocFunction<MallocMalloc>(impl_handler, &table->malloc, prefix, "malloc")) {
|
||||
return false;
|
||||
}
|
||||
if (!InitMallocFunction<MallocMallocInfo>(impl_handler, &table->malloc_info, prefix,
|
||||
"malloc_info")) {
|
||||
return false;
|
||||
}
|
||||
if (!InitMallocFunction<MallocMallocUsableSize>(impl_handler, &table->malloc_usable_size, prefix,
|
||||
"malloc_usable_size")) {
|
||||
return false;
|
||||
|
|
|
@ -108,6 +108,7 @@ static constexpr MallocDispatch __heapprofd_init_dispatch
|
|||
Malloc(malloc_enable),
|
||||
Malloc(mallopt),
|
||||
Malloc(aligned_alloc),
|
||||
Malloc(malloc_info),
|
||||
};
|
||||
|
||||
static void MaybeInstallInitHeapprofdHook(int) {
|
||||
|
|
|
@ -1,94 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "malloc_info.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include "private/bionic_macros.h"
|
||||
|
||||
class __LIBC_HIDDEN__ Elem {
|
||||
public:
|
||||
// name must be valid throughout lifetime of the object.
|
||||
explicit Elem(FILE* fp, const char* name,
|
||||
const char* attr_fmt = nullptr, ...) {
|
||||
this->fp = fp;
|
||||
this->name = name;
|
||||
|
||||
fprintf(fp, "<%s", name);
|
||||
if (attr_fmt != nullptr) {
|
||||
va_list args;
|
||||
va_start(args, attr_fmt);
|
||||
fputc(' ', fp);
|
||||
vfprintf(fp, attr_fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
fputc('>', fp);
|
||||
}
|
||||
|
||||
~Elem() noexcept {
|
||||
fprintf(fp, "</%s>", name);
|
||||
}
|
||||
|
||||
void contents(const char* fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vfprintf(fp, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
private:
|
||||
FILE* fp;
|
||||
const char* name;
|
||||
|
||||
BIONIC_DISALLOW_IMPLICIT_CONSTRUCTORS(Elem);
|
||||
};
|
||||
|
||||
int malloc_info(int options, FILE* fp) {
|
||||
if (options != 0) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
Elem root(fp, "malloc", "version=\"jemalloc-1\"");
|
||||
|
||||
// Dump all of the large allocations in the arenas.
|
||||
for (size_t i = 0; i < __mallinfo_narenas(); i++) {
|
||||
struct mallinfo mi = __mallinfo_arena_info(i);
|
||||
if (mi.hblkhd != 0) {
|
||||
Elem arena_elem(fp, "heap", "nr=\"%d\"", i);
|
||||
{
|
||||
Elem(fp, "allocated-large").contents("%zu", mi.ordblks);
|
||||
Elem(fp, "allocated-huge").contents("%zu", mi.uordblks);
|
||||
Elem(fp, "allocated-bins").contents("%zu", mi.fsmblks);
|
||||
|
||||
size_t total = 0;
|
||||
for (size_t j = 0; j < __mallinfo_nbins(); j++) {
|
||||
struct mallinfo mi = __mallinfo_bin_info(i, j);
|
||||
if (mi.ordblks != 0) {
|
||||
Elem bin_elem(fp, "bin", "nr=\"%d\"", j);
|
||||
Elem(fp, "allocated").contents("%zu", mi.ordblks);
|
||||
Elem(fp, "nmalloc").contents("%zu", mi.uordblks);
|
||||
Elem(fp, "ndalloc").contents("%zu", mi.fordblks);
|
||||
total += mi.ordblks;
|
||||
}
|
||||
}
|
||||
Elem(fp, "bins-total").contents("%zu", total);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <malloc.h>
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
__LIBC_HIDDEN__ size_t __mallinfo_narenas();
|
||||
__LIBC_HIDDEN__ size_t __mallinfo_nbins();
|
||||
__LIBC_HIDDEN__ struct mallinfo __mallinfo_arena_info(size_t);
|
||||
__LIBC_HIDDEN__ struct mallinfo __mallinfo_bin_info(size_t, size_t);
|
||||
|
||||
__END_DECLS
|
|
@ -123,6 +123,7 @@ cc_test {
|
|||
static_libs: [
|
||||
"libc_malloc_debug",
|
||||
"libdemangle",
|
||||
"libtinyxml2",
|
||||
],
|
||||
|
||||
shared_libs: [
|
||||
|
|
|
@ -492,6 +492,17 @@ void PointerData::LogLeaks() {
|
|||
}
|
||||
}
|
||||
|
||||
void PointerData::GetAllocList(std::vector<ListInfoType>* list) {
|
||||
std::lock_guard<std::mutex> pointer_guard(pointer_mutex_);
|
||||
std::lock_guard<std::mutex> frame_guard(frame_mutex_);
|
||||
|
||||
if (pointers_.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
GetList(list, false);
|
||||
}
|
||||
|
||||
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_);
|
||||
|
|
|
@ -132,9 +132,6 @@ class PointerData : public OptionData {
|
|||
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);
|
||||
|
||||
|
@ -151,6 +148,7 @@ class PointerData : public OptionData {
|
|||
static void VerifyFreedPointer(const FreePointerInfoType& info);
|
||||
static void VerifyAllFreed();
|
||||
|
||||
static void GetAllocList(std::vector<ListInfoType>* list);
|
||||
static void LogLeaks();
|
||||
static void DumpLiveToFile(FILE* fp);
|
||||
|
||||
|
@ -165,6 +163,9 @@ class PointerData : public OptionData {
|
|||
static std::string GetHashString(uintptr_t* frames, size_t num_frames);
|
||||
static void LogBacktrace(size_t hash_index);
|
||||
|
||||
static void GetList(std::vector<ListInfoType>* list, bool only_with_backtrace);
|
||||
static void GetUniqueList(std::vector<ListInfoType>* list, bool only_with_backtrace);
|
||||
|
||||
size_t alloc_offset_ = 0;
|
||||
std::vector<uint8_t> cmp_mem_;
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ LIBC_MALLOC_DEBUG {
|
|||
debug_malloc_backtrace;
|
||||
debug_malloc_disable;
|
||||
debug_malloc_enable;
|
||||
debug_malloc_info;
|
||||
debug_malloc_usable_size;
|
||||
debug_mallopt;
|
||||
debug_memalign;
|
||||
|
|
|
@ -14,6 +14,7 @@ LIBC_MALLOC_DEBUG {
|
|||
debug_malloc_backtrace;
|
||||
debug_malloc_disable;
|
||||
debug_malloc_enable;
|
||||
debug_malloc_info;
|
||||
debug_malloc_usable_size;
|
||||
debug_mallopt;
|
||||
debug_memalign;
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <malloc.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/param.h>
|
||||
|
@ -41,6 +42,7 @@
|
|||
#include <android-base/properties.h>
|
||||
#include <android-base/stringprintf.h>
|
||||
#include <private/bionic_malloc_dispatch.h>
|
||||
#include <private/MallocXmlElem.h>
|
||||
|
||||
#include "Config.h"
|
||||
#include "DebugData.h"
|
||||
|
@ -85,6 +87,7 @@ void* debug_realloc(void* pointer, size_t bytes);
|
|||
void* debug_calloc(size_t nmemb, size_t bytes);
|
||||
struct mallinfo debug_mallinfo();
|
||||
int debug_mallopt(int param, int value);
|
||||
int debug_malloc_info(int options, FILE* fp);
|
||||
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);
|
||||
|
@ -725,6 +728,32 @@ int debug_mallopt(int param, int value) {
|
|||
return g_dispatch->mallopt(param, value);
|
||||
}
|
||||
|
||||
int debug_malloc_info(int options, FILE* fp) {
|
||||
if (DebugCallsDisabled() || !g_debug->TrackPointers()) {
|
||||
return g_dispatch->malloc_info(options, fp);
|
||||
}
|
||||
|
||||
MallocXmlElem root(fp, "malloc", "version=\"debug-malloc-1\"");
|
||||
std::vector<ListInfoType> list;
|
||||
PointerData::GetAllocList(&list);
|
||||
|
||||
size_t alloc_num = 0;
|
||||
for (size_t i = 0; i < list.size(); i++) {
|
||||
MallocXmlElem alloc(fp, "allocation", "nr=\"%zu\"", alloc_num);
|
||||
|
||||
size_t total = 1;
|
||||
size_t size = list[i].size;
|
||||
while (i < list.size() - 1 && list[i + 1].size == size) {
|
||||
i++;
|
||||
total++;
|
||||
}
|
||||
MallocXmlElem(fp, "size").Contents("%zu", list[i].size);
|
||||
MallocXmlElem(fp, "total").Contents("%zu", total);
|
||||
alloc_num++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* debug_aligned_alloc(size_t alignment, size_t size) {
|
||||
if (DebugCallsDisabled()) {
|
||||
return g_dispatch->aligned_alloc(alignment, size);
|
||||
|
@ -741,7 +770,7 @@ int debug_posix_memalign(void** memptr, size_t alignment, size_t size) {
|
|||
return g_dispatch->posix_memalign(memptr, alignment, size);
|
||||
}
|
||||
|
||||
if (!powerof2(alignment)) {
|
||||
if (alignment < sizeof(void*) || !powerof2(alignment)) {
|
||||
return EINVAL;
|
||||
}
|
||||
int saved_errno = errno;
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include <malloc.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/cdefs.h>
|
||||
|
@ -25,10 +26,13 @@
|
|||
#include <unistd.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
|
||||
#include <tinyxml2.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <android-base/file.h>
|
||||
|
@ -62,6 +66,7 @@ void debug_free_malloc_leak_info(uint8_t*);
|
|||
|
||||
struct mallinfo debug_mallinfo();
|
||||
int debug_mallopt(int, int);
|
||||
int debug_malloc_info(int, FILE*);
|
||||
|
||||
#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
|
||||
void* debug_pvalloc(size_t);
|
||||
|
@ -136,6 +141,7 @@ MallocDispatch MallocDebugTest::dispatch = {
|
|||
nullptr,
|
||||
mallopt,
|
||||
aligned_alloc,
|
||||
malloc_info,
|
||||
};
|
||||
|
||||
std::string ShowDiffs(uint8_t* a, uint8_t* b, size_t size) {
|
||||
|
@ -2465,3 +2471,82 @@ TEST_F(MallocDebugTest, abort_on_error_header_tag_corrupted) {
|
|||
pointer[-get_tag_offset()] = tag_value;
|
||||
}
|
||||
|
||||
TEST_F(MallocDebugTest, malloc_info_no_pointer_tracking) {
|
||||
Init("fill");
|
||||
|
||||
char* buffer;
|
||||
size_t size;
|
||||
FILE* memstream = open_memstream(&buffer, &size);
|
||||
ASSERT_TRUE(memstream != nullptr);
|
||||
ASSERT_EQ(0, debug_malloc_info(0, memstream));
|
||||
ASSERT_EQ(0, fclose(memstream));
|
||||
|
||||
tinyxml2::XMLDocument doc;
|
||||
ASSERT_EQ(tinyxml2::XML_SUCCESS, doc.Parse(buffer));
|
||||
auto root = doc.FirstChildElement();
|
||||
ASSERT_TRUE(root != nullptr);
|
||||
ASSERT_STREQ("malloc", root->Name());
|
||||
// Don't care what the underyling implementation says, just that it's
|
||||
// not generated by debug malloc.
|
||||
ASSERT_STRNE("debug-malloc-1", root->Attribute("version"));
|
||||
}
|
||||
|
||||
TEST_F(MallocDebugTest, malloc_info_with_pointer_tracking) {
|
||||
Init("verify_pointers");
|
||||
|
||||
std::unique_ptr<void, decltype(debug_free)*> ptr1(debug_malloc(1000), debug_free);
|
||||
ASSERT_TRUE(ptr1.get() != nullptr);
|
||||
std::unique_ptr<void, decltype(debug_free)*> ptr2(debug_malloc(1000), debug_free);
|
||||
ASSERT_TRUE(ptr2.get() != nullptr);
|
||||
std::unique_ptr<void, decltype(debug_free)*> ptr3(debug_malloc(500), debug_free);
|
||||
ASSERT_TRUE(ptr3.get() != nullptr);
|
||||
std::unique_ptr<void, decltype(debug_free)*> ptr4(debug_malloc(1200), debug_free);
|
||||
ASSERT_TRUE(ptr4.get() != nullptr);
|
||||
|
||||
char* buffer;
|
||||
size_t size;
|
||||
FILE* memstream = open_memstream(&buffer, &size);
|
||||
ASSERT_TRUE(memstream != nullptr);
|
||||
ASSERT_EQ(0, debug_malloc_info(0, memstream));
|
||||
ASSERT_EQ(0, fclose(memstream));
|
||||
|
||||
SCOPED_TRACE(testing::Message() << "Output:\n" << buffer);
|
||||
|
||||
tinyxml2::XMLDocument doc;
|
||||
ASSERT_EQ(tinyxml2::XML_SUCCESS, doc.Parse(buffer));
|
||||
auto root = doc.FirstChildElement();
|
||||
ASSERT_TRUE(root != nullptr);
|
||||
ASSERT_STREQ("malloc", root->Name());
|
||||
ASSERT_STREQ("debug-malloc-1", root->Attribute("version"));
|
||||
|
||||
auto alloc = root->FirstChildElement();
|
||||
ASSERT_TRUE(alloc != nullptr);
|
||||
ASSERT_STREQ("allocation", alloc->Name());
|
||||
int val;
|
||||
ASSERT_EQ(tinyxml2::XML_SUCCESS, alloc->QueryIntAttribute("nr", &val));
|
||||
ASSERT_EQ(0, val);
|
||||
ASSERT_EQ(tinyxml2::XML_SUCCESS, alloc->FirstChildElement("size")->QueryIntText(&val));
|
||||
ASSERT_EQ(1200, val);
|
||||
ASSERT_EQ(tinyxml2::XML_SUCCESS, alloc->FirstChildElement("total")->QueryIntText(&val));
|
||||
ASSERT_EQ(1, val);
|
||||
|
||||
alloc = alloc->NextSiblingElement();
|
||||
ASSERT_TRUE(alloc != nullptr);
|
||||
ASSERT_STREQ("allocation", alloc->Name());
|
||||
ASSERT_EQ(tinyxml2::XML_SUCCESS, alloc->QueryIntAttribute("nr", &val));
|
||||
ASSERT_EQ(1, val);
|
||||
ASSERT_EQ(tinyxml2::XML_SUCCESS, alloc->FirstChildElement("size")->QueryIntText(&val));
|
||||
ASSERT_EQ(1000, val);
|
||||
ASSERT_EQ(tinyxml2::XML_SUCCESS, alloc->FirstChildElement("total")->QueryIntText(&val));
|
||||
ASSERT_EQ(2, val);
|
||||
|
||||
alloc = alloc->NextSiblingElement();
|
||||
ASSERT_TRUE(alloc != nullptr);
|
||||
ASSERT_STREQ("allocation", alloc->Name());
|
||||
ASSERT_EQ(tinyxml2::XML_SUCCESS, alloc->QueryIntAttribute("nr", &val));
|
||||
ASSERT_EQ(2, val);
|
||||
ASSERT_EQ(tinyxml2::XML_SUCCESS, alloc->FirstChildElement("size")->QueryIntText(&val));
|
||||
ASSERT_EQ(500, val);
|
||||
ASSERT_EQ(tinyxml2::XML_SUCCESS, alloc->FirstChildElement("total")->QueryIntText(&val));
|
||||
ASSERT_EQ(1, val);
|
||||
}
|
||||
|
|
|
@ -39,14 +39,6 @@ cc_library {
|
|||
// ==============================================================
|
||||
cc_test {
|
||||
name: "malloc_hooks_unit_tests",
|
||||
multilib: {
|
||||
lib32: {
|
||||
suffix: "32",
|
||||
},
|
||||
lib64: {
|
||||
suffix: "64",
|
||||
},
|
||||
},
|
||||
|
||||
srcs: [
|
||||
"tests/malloc_hooks_tests.cpp",
|
||||
|
|
|
@ -13,6 +13,7 @@ LIBC_MALLOC_HOOKS {
|
|||
hooks_malloc_backtrace;
|
||||
hooks_malloc_disable;
|
||||
hooks_malloc_enable;
|
||||
hooks_malloc_info;
|
||||
hooks_malloc_usable_size;
|
||||
hooks_mallopt;
|
||||
hooks_memalign;
|
||||
|
|
|
@ -13,6 +13,7 @@ LIBC_MALLOC_HOOKS {
|
|||
hooks_malloc_backtrace;
|
||||
hooks_malloc_disable;
|
||||
hooks_malloc_enable;
|
||||
hooks_malloc_info;
|
||||
hooks_malloc_usable_size;
|
||||
hooks_mallopt;
|
||||
hooks_memalign;
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include <errno.h>
|
||||
#include <malloc.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/param.h>
|
||||
#include <unistd.h>
|
||||
|
@ -57,6 +58,7 @@ ssize_t hooks_malloc_backtrace(void* pointer, uintptr_t* frames, size_t frame_co
|
|||
void hooks_free_malloc_leak_info(uint8_t* info);
|
||||
size_t hooks_malloc_usable_size(void* pointer);
|
||||
void* hooks_malloc(size_t size);
|
||||
int hooks_malloc_info(int options, FILE* fp);
|
||||
void hooks_free(void* pointer);
|
||||
void* hooks_memalign(size_t alignment, size_t bytes);
|
||||
void* hooks_aligned_alloc(size_t alignment, size_t bytes);
|
||||
|
@ -174,6 +176,10 @@ int hooks_mallopt(int param, int value) {
|
|||
return g_dispatch->mallopt(param, value);
|
||||
}
|
||||
|
||||
int hooks_malloc_info(int options, FILE* fp) {
|
||||
return g_dispatch->malloc_info(options, fp);
|
||||
}
|
||||
|
||||
void* hooks_aligned_alloc(size_t alignment, size_t size) {
|
||||
if (__memalign_hook != nullptr && __memalign_hook != default_memalign_hook) {
|
||||
if (!powerof2(alignment) || (size % alignment) != 0) {
|
||||
|
@ -191,7 +197,7 @@ void* hooks_aligned_alloc(size_t alignment, size_t size) {
|
|||
|
||||
int hooks_posix_memalign(void** memptr, size_t alignment, size_t size) {
|
||||
if (__memalign_hook != nullptr && __memalign_hook != default_memalign_hook) {
|
||||
if (!powerof2(alignment)) {
|
||||
if (alignment < sizeof(void*) || !powerof2(alignment)) {
|
||||
return EINVAL;
|
||||
}
|
||||
*memptr = __memalign_hook(alignment, size, __builtin_return_address(0));
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <private/bionic_macros.h>
|
||||
|
||||
class MallocXmlElem {
|
||||
public:
|
||||
// Name must be valid throughout lifetime of the object.
|
||||
explicit MallocXmlElem(FILE* fp, const char* name,
|
||||
const char* attr_fmt = nullptr, ...) : fp_(fp), name_(name) {
|
||||
fprintf(fp, "<%s", name_);
|
||||
if (attr_fmt != nullptr) {
|
||||
va_list args;
|
||||
va_start(args, attr_fmt);
|
||||
fputc(' ', fp_);
|
||||
vfprintf(fp_, attr_fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
fputc('>', fp_);
|
||||
}
|
||||
|
||||
~MallocXmlElem() noexcept {
|
||||
fprintf(fp_, "</%s>", name_);
|
||||
}
|
||||
|
||||
void Contents(const char* fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vfprintf(fp_, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
private:
|
||||
FILE* fp_;
|
||||
const char* name_;
|
||||
|
||||
BIONIC_DISALLOW_IMPLICIT_CONSTRUCTORS(MallocXmlElem);
|
||||
};
|
|
@ -31,6 +31,7 @@
|
|||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <private/bionic_config.h>
|
||||
|
||||
// Entry in malloc dispatch table.
|
||||
|
@ -38,6 +39,7 @@ typedef void* (*MallocCalloc)(size_t, size_t);
|
|||
typedef void (*MallocFree)(void*);
|
||||
typedef struct mallinfo (*MallocMallinfo)();
|
||||
typedef void* (*MallocMalloc)(size_t);
|
||||
typedef int (*MallocMallocInfo)(int, FILE*);
|
||||
typedef size_t (*MallocMallocUsableSize)(const void*);
|
||||
typedef void* (*MallocMemalign)(size_t, size_t);
|
||||
typedef int (*MallocPosixMemalign)(void**, size_t, size_t);
|
||||
|
@ -73,6 +75,7 @@ struct MallocDispatch {
|
|||
MallocMallocEnable malloc_enable;
|
||||
MallocMallopt mallopt;
|
||||
MallocAlignedAlloc aligned_alloc;
|
||||
MallocMallocInfo malloc_info;
|
||||
} __attribute__((aligned(32)));
|
||||
|
||||
#endif
|
||||
|
|
|
@ -200,7 +200,6 @@ cc_test_library {
|
|||
|
||||
include_dirs: [
|
||||
"bionic/libc",
|
||||
"external/tinyxml2",
|
||||
],
|
||||
|
||||
target: {
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <elf.h>
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <malloc.h>
|
||||
#include <unistd.h>
|
||||
|
@ -348,35 +349,42 @@ TEST(malloc, malloc_info) {
|
|||
auto root = doc.FirstChildElement();
|
||||
ASSERT_NE(nullptr, root);
|
||||
ASSERT_STREQ("malloc", root->Name());
|
||||
ASSERT_STREQ("jemalloc-1", root->Attribute("version"));
|
||||
if (std::string(root->Attribute("version")) == "jemalloc-1") {
|
||||
// Verify jemalloc version of this data.
|
||||
ASSERT_STREQ("jemalloc-1", root->Attribute("version"));
|
||||
|
||||
auto arena = root->FirstChildElement();
|
||||
for (; arena != nullptr; arena = arena->NextSiblingElement()) {
|
||||
int val;
|
||||
auto arena = root->FirstChildElement();
|
||||
for (; arena != nullptr; arena = arena->NextSiblingElement()) {
|
||||
int val;
|
||||
|
||||
ASSERT_STREQ("heap", arena->Name());
|
||||
ASSERT_EQ(tinyxml2::XML_SUCCESS, arena->QueryIntAttribute("nr", &val));
|
||||
ASSERT_EQ(tinyxml2::XML_SUCCESS,
|
||||
arena->FirstChildElement("allocated-large")->QueryIntText(&val));
|
||||
ASSERT_EQ(tinyxml2::XML_SUCCESS,
|
||||
arena->FirstChildElement("allocated-huge")->QueryIntText(&val));
|
||||
ASSERT_EQ(tinyxml2::XML_SUCCESS,
|
||||
arena->FirstChildElement("allocated-bins")->QueryIntText(&val));
|
||||
ASSERT_EQ(tinyxml2::XML_SUCCESS,
|
||||
arena->FirstChildElement("bins-total")->QueryIntText(&val));
|
||||
ASSERT_STREQ("heap", arena->Name());
|
||||
ASSERT_EQ(tinyxml2::XML_SUCCESS, arena->QueryIntAttribute("nr", &val));
|
||||
ASSERT_EQ(tinyxml2::XML_SUCCESS,
|
||||
arena->FirstChildElement("allocated-large")->QueryIntText(&val));
|
||||
ASSERT_EQ(tinyxml2::XML_SUCCESS,
|
||||
arena->FirstChildElement("allocated-huge")->QueryIntText(&val));
|
||||
ASSERT_EQ(tinyxml2::XML_SUCCESS,
|
||||
arena->FirstChildElement("allocated-bins")->QueryIntText(&val));
|
||||
ASSERT_EQ(tinyxml2::XML_SUCCESS,
|
||||
arena->FirstChildElement("bins-total")->QueryIntText(&val));
|
||||
|
||||
auto bin = arena->FirstChildElement("bin");
|
||||
for (; bin != nullptr; bin = bin ->NextSiblingElement()) {
|
||||
if (strcmp(bin->Name(), "bin") == 0) {
|
||||
ASSERT_EQ(tinyxml2::XML_SUCCESS, bin->QueryIntAttribute("nr", &val));
|
||||
ASSERT_EQ(tinyxml2::XML_SUCCESS,
|
||||
bin->FirstChildElement("allocated")->QueryIntText(&val));
|
||||
ASSERT_EQ(tinyxml2::XML_SUCCESS,
|
||||
bin->FirstChildElement("nmalloc")->QueryIntText(&val));
|
||||
ASSERT_EQ(tinyxml2::XML_SUCCESS,
|
||||
bin->FirstChildElement("ndalloc")->QueryIntText(&val));
|
||||
auto bin = arena->FirstChildElement("bin");
|
||||
for (; bin != nullptr; bin = bin ->NextSiblingElement()) {
|
||||
if (strcmp(bin->Name(), "bin") == 0) {
|
||||
ASSERT_EQ(tinyxml2::XML_SUCCESS, bin->QueryIntAttribute("nr", &val));
|
||||
ASSERT_EQ(tinyxml2::XML_SUCCESS,
|
||||
bin->FirstChildElement("allocated")->QueryIntText(&val));
|
||||
ASSERT_EQ(tinyxml2::XML_SUCCESS,
|
||||
bin->FirstChildElement("nmalloc")->QueryIntText(&val));
|
||||
ASSERT_EQ(tinyxml2::XML_SUCCESS,
|
||||
bin->FirstChildElement("ndalloc")->QueryIntText(&val));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Only verify that this is debug-malloc-1, the malloc debug unit tests
|
||||
// verify the output.
|
||||
ASSERT_STREQ("debug-malloc-1", root->Attribute("version"));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue