From 350d0e5fd2e2a869e7dcf03b394f10c5670cac03 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Sat, 6 Apr 2019 20:49:52 -0400 Subject: [PATCH] add real mallinfo implementation for Android Android Q uses the mallinfo implementation in the ART GC: https://android.googlesource.com/platform/art/+/c220f981809d655fb061c92a581fd6fc4df4da5c https://android.googlesource.com/platform/art/+/15752673020e89df2a9353f332bd1409de4cd4b7 --- Android.bp | 1 + Makefile | 6 +++-- h_malloc.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++- test/Makefile | 3 ++- test/mallinfo.c | 21 +++++++++++++++ 5 files changed, 96 insertions(+), 4 deletions(-) create mode 100644 test/mallinfo.c diff --git a/Android.bp b/Android.bp index f311f84..9abe604 100644 --- a/Android.bp +++ b/Android.bp @@ -25,6 +25,7 @@ common_cflags = [ "-DFREE_SLABS_QUARANTINE_RANDOM_LENGTH=32", "-DCONFIG_CLASS_REGION_SIZE=1073741824", // 1GiB "-DN_ARENA=1", + "-DSTATS=false", ] cc_defaults { diff --git a/Makefile b/Makefile index efa239c..26e1a87 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,8 @@ CONFIG_REGION_QUARANTINE_QUEUE_LENGTH := 1024 CONFIG_REGION_QUARANTINE_SKIP_THRESHOLD := 33554432 # 32MiB CONFIG_FREE_SLABS_QUARANTINE_RANDOM_LENGTH := 32 CONFIG_CLASS_REGION_SIZE := 137438953472 # 128GiB -CONFIG_N_ARENA = 1 +CONFIG_N_ARENA := 1 +CONFIG_STATS := false define safe_flag $(shell $(CC) -E $1 - /dev/null 2>&1 && echo $1 || echo $2) @@ -81,7 +82,8 @@ CPPFLAGS += \ -DREGION_QUARANTINE_SKIP_THRESHOLD=$(CONFIG_REGION_QUARANTINE_SKIP_THRESHOLD) \ -DFREE_SLABS_QUARANTINE_RANDOM_LENGTH=$(CONFIG_FREE_SLABS_QUARANTINE_RANDOM_LENGTH) \ -DCONFIG_CLASS_REGION_SIZE=$(CONFIG_CLASS_REGION_SIZE) \ - -DN_ARENA=$(CONFIG_N_ARENA) + -DN_ARENA=$(CONFIG_N_ARENA) \ + -DSTATS=$(CONFIG_STATS) libhardened_malloc.so: $(OBJECTS) $(CC) $(CFLAGS) $(LDFLAGS) -shared $^ $(LDLIBS) -o $@ diff --git a/h_malloc.c b/h_malloc.c index aa03fb0..711bc53 100644 --- a/h_malloc.c +++ b/h_malloc.c @@ -240,6 +240,11 @@ struct __attribute__((aligned(CACHELINE_SIZE))) size_class { struct slab_metadata *free_slabs_tail; struct slab_metadata *free_slabs_quarantine[FREE_SLABS_QUARANTINE_RANDOM_LENGTH]; +#if STATS + size_t allocated; + size_t slab_allocated; +#endif + struct random_state rng; size_t metadata_allocated; size_t metadata_count; @@ -478,6 +483,9 @@ static inline void *allocate_small(size_t requested_size) { set_canary(metadata, p, size); } +#if STATS + c->allocated += size; +#endif mutex_unlock(&c->lock); return p; } @@ -491,6 +499,9 @@ static inline void *allocate_small(size_t requested_size) { mutex_unlock(&c->lock); return NULL; } +#if STATS + c->slab_allocated += slab_size; +#endif c->free_slabs_head = c->free_slabs_head->next; if (c->free_slabs_head == NULL) { @@ -509,6 +520,9 @@ static inline void *allocate_small(size_t requested_size) { set_canary(metadata, p, size); } +#if STATS + c->allocated += size; +#endif mutex_unlock(&c->lock); return p; } @@ -518,6 +532,9 @@ static inline void *allocate_small(size_t requested_size) { mutex_unlock(&c->lock); return NULL; } +#if STATS + c->slab_allocated += slab_size; +#endif metadata->canary_value = get_random_canary(&c->rng); c->partial_slabs = metadata; @@ -529,6 +546,9 @@ static inline void *allocate_small(size_t requested_size) { set_canary(metadata, p, size); } +#if STATS + c->allocated += size; +#endif mutex_unlock(&c->lock); return p; } @@ -551,6 +571,9 @@ static inline void *allocate_small(size_t requested_size) { set_canary(metadata, p, size); } +#if STATS + c->allocated += size; +#endif mutex_unlock(&c->lock); return p; } @@ -611,6 +634,9 @@ static inline void deallocate_small(void *p, const size_t *expected_size) { size_t slab_size = get_slab_size(slots, size); mutex_lock(&c->lock); +#if STATS + c->allocated -= size; +#endif struct slab_metadata *metadata = get_metadata(c, p); void *slab = get_slab(c, slab_size, metadata); @@ -711,6 +737,9 @@ static inline void deallocate_small(void *p, const size_t *expected_size) { if (c->empty_slabs_total + slab_size > max_empty_slabs_total) { if (!memory_map_fixed(slab, slab_size)) { memory_set_name(slab, slab_size, size_class_labels[class]); +#if STATS + c->slab_allocated -= slab_size; +#endif enqueue_free_slab(c, metadata); mutex_unlock(&c->lock); return; @@ -745,6 +774,9 @@ struct region_allocator { struct region_metadata *regions; size_t total; size_t free; +#if STATS + size_t allocated; +#endif struct quarantine_info quarantine_random[REGION_QUARANTINE_RANDOM_LENGTH]; struct quarantine_info quarantine_queue[REGION_QUARANTINE_QUEUE_LENGTH]; size_t quarantine_queue_index; @@ -1110,6 +1142,9 @@ static void *allocate(size_t size) { deallocate_pages(p, size, guard_size); return NULL; } +#if STATS + ra->allocated += size; +#endif mutex_unlock(&ra->lock); return p; @@ -1132,6 +1167,9 @@ static void deallocate_large(void *p, const size_t *expected_size) { } size_t guard_size = region->guard_size; regions_delete(region); +#if STATS + ra->allocated -= size; +#endif mutex_unlock(&ra->lock); regions_quarantine_deallocate_pages(p, size, guard_size); @@ -1534,6 +1572,9 @@ EXPORT int h_malloc_trim(UNUSED size_t pad) { break; } memory_set_name(slab, slab_size, size_class_labels[class]); +#if STATS + c->slab_allocated -= slab_size; +#endif struct slab_metadata *trimmed = iterator; iterator = iterator->next; @@ -1557,7 +1598,33 @@ EXPORT void h_malloc_stats(void) {} #if defined(__GLIBC__) || defined(__ANDROID__) EXPORT struct mallinfo h_mallinfo(void) { - return (struct mallinfo){0}; + struct mallinfo info = {0}; + + // glibc mallinfo type definition and implementation are both broken +#if STATS && !defined(__GLIBC__) + struct region_allocator *ra = ro.region_allocator; + mutex_lock(&ra->lock); + info.hblkhd += ra->allocated; + info.uordblks += ra->allocated; + mutex_unlock(&ra->lock); + + for (unsigned arena = 0; arena < N_ARENA; arena++) { + // skip zero byte size class + for (unsigned class = 1; class < N_SIZE_CLASSES; class++) { + struct size_class *c = &ro.size_class_metadata[arena][class]; + + mutex_lock(&c->lock); + info.hblkhd += c->slab_allocated; + info.uordblks += c->allocated; + mutex_unlock(&c->lock); + } + } + + info.fordblks = info.hblkhd - info.uordblks; + info.usmblks = info.hblkhd; +#endif + + return info; } #endif diff --git a/test/Makefile b/test/Makefile index 42bf111..56b6201 100644 --- a/test/Makefile +++ b/test/Makefile @@ -8,7 +8,8 @@ CPPFLAGS += \ -DSLAB_CANARY=$(CONFIG_SLAB_CANARY) EXECUTABLES := \ - offset + offset \ + mallinfo all: $(EXECUTABLES) diff --git a/test/mallinfo.c b/test/mallinfo.c new file mode 100644 index 0000000..2fc5246 --- /dev/null +++ b/test/mallinfo.c @@ -0,0 +1,21 @@ +#include + +__attribute__((optimize(0))) +int main(void) { + malloc(1024 * 1024 * 1024); + malloc(16); + malloc(32); + malloc(64); + + struct mallinfo info = mallinfo(); + printf("arena: %zu\n", info.arena); + printf("ordblks: %zu\n", info.ordblks); + printf("smblks: %zu\n", info.smblks); + printf("hblks: %zu\n", info.hblks); + printf("hblkhd: %zu\n", info.hblkhd); + printf("usmblks: %zu\n", info.usmblks); + printf("fsmblks: %zu\n", info.fsmblks); + printf("uordblks: %zu\n", info.uordblks); + printf("fordblks: %zu\n", info.fordblks); + printf("keepcost: %zu\n", info.keepcost); +}