blob: 9bb7226b39d78e9d0a63a831827344f7e83138f7 [file] [edit]
// A non-granule-multiple allocation owns a partial tail histogram counter that
// must be cleared on allocation; otherwise a recycled chunk leaks the previous
// allocation's count into the last bucket.
// RUN: %clangxx_memprof -O0 -mllvm -memprof-histogram -mllvm -memprof-use-callbacks=true %s -o %t
// RUN: %env_memprof_opts=print_text=1:histogram=1:log_path=stdout %run %t 2>&1 | FileCheck %s
#include <stdio.h>
#include <stdlib.h>
// Distinct call sites keep the two allocations as separate (unmerged) MIBs.
__attribute__((noinline)) static char *alloc_first() {
return (char *)malloc(20);
}
__attribute__((noinline)) static char *alloc_second() {
return (char *)malloc(20);
}
int main() {
// Leave a count of 42 in the tail granule (byte 16), then free.
char *a = alloc_first();
if (!a)
return 1;
for (int i = 0; i < 42; ++i)
a[16] = 'A';
free(a);
// The stale-tail bug only manifests on a recycled chunk (a fresh chunk's
// shadow is already zero). memprof has no quarantine, so with no intervening
// same-size-class allocation the allocator returns the just-freed chunk;
// require the reuse so the test can't pass vacuously. Its bucket must read 0.
char *b = alloc_second();
if (b != a)
return 1;
for (int i = 0; i < 5; ++i)
b[0] = 'B';
for (int i = 0; i < 7; ++i)
b[8] = 'C';
free(b);
printf("Test completed successfully\n");
return 0;
}
// CHECK: AccessCountHistogram[3]: 5 7 0
// CHECK: Test completed successfully