// RUN: %clang_dfsan -mllvm -dfsan-combine-pointer-labels-on-load=false %s -o %t && %run %t
// RUN: %clang_dfsan -DORIGIN_TRACKING -mllvm -dfsan-track-origins=1 -mllvm -dfsan-combine-pointer-labels-on-load=false %s -o %t && %run %t
//
// Tests custom implementations of various glibc functions.
#include <sanitizer/dfsan_interface.h>
#include <assert.h>
#include <malloc.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#define ASSERT_ZERO_LABEL(data) \
assert(0 == dfsan_get_label((long) (data)))
#define ASSERT_READ_ZERO_LABEL(ptr, size) \
assert(0 == dfsan_read_label(ptr, size))
const int kAlignment = 8;
const int kSize = 16;
void test_aligned_alloc() {
char *p = (char *) aligned_alloc(kAlignment, kSize);
ASSERT_ZERO_LABEL(p);
ASSERT_READ_ZERO_LABEL(p, kSize);
free(p);
}
void test_calloc() {
char *p = (char *) calloc(kSize, 1);
ASSERT_ZERO_LABEL(p);
ASSERT_READ_ZERO_LABEL(p, kSize);
free(p);
}
void test_cfree() {
// The current glibc does not support cfree.
}
void test_free() {
char *p = (char *) malloc(kSize);
dfsan_set_label(1, p, kSize);
free(p);
ASSERT_READ_ZERO_LABEL(p, kSize);
}
void test_mallinfo() {
// The mallinfo interceptor takes an argument instead of returning a struct.
// This doesn't work on AArch64 which uses different registers for the two
// function types.
#if defined(__GLIBC__) && !defined(__aarch64__)
struct mallinfo mi = mallinfo();
for (int i = 0; i < sizeof(struct mallinfo); ++i) {
char c = ((char *)(&mi))[i];
assert(!c);
ASSERT_ZERO_LABEL(c);
}
#endif
}
void test_malloc() {
char *p = (char *) malloc(kSize);
ASSERT_ZERO_LABEL(p);
ASSERT_READ_ZERO_LABEL(p, kSize);
free(p);
}
void test_malloc_stats() {
// Only ensures it does not crash. Our interceptor of malloc_stats is empty.
malloc_stats();
}
void test_malloc_usable_size() {
char *p = (char *) malloc(kSize);
size_t s = malloc_usable_size(p);
assert(s == kSize);
ASSERT_ZERO_LABEL(s);
free(p);
}
void test_mallopt() {
int r = mallopt(0, 0);
assert(!r);
ASSERT_ZERO_LABEL(r);
}
void test_memalign() {
char *p = (char *) memalign(kAlignment, kSize);
ASSERT_ZERO_LABEL(p);
ASSERT_READ_ZERO_LABEL(p, kSize);
free(p);
}
void test_mmap() {
char *p = mmap(NULL, kSize, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
ASSERT_READ_ZERO_LABEL(p, kSize);
char val = 0xff;
dfsan_set_label(1, &val, sizeof(val));
memset(p, val, kSize);
p = mmap(p, kSize, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
ASSERT_READ_ZERO_LABEL(p, kSize);
munmap(p, kSize);
}
void test_mmap64() {
// The current glibc does not support mmap64.
}
void test_unmmap() {
char *p = mmap(NULL, kSize, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
char val = 0xff;
dfsan_set_label(1, &val, sizeof(val));
memset(p, val, kSize);
munmap(p, kSize);
ASSERT_READ_ZERO_LABEL(p, kSize);
}
void test_posix_memalign() {
char *p;
dfsan_set_label(1, &p, sizeof(p));
int r = posix_memalign((void **)&p, kAlignment, kSize);
assert(!r);
ASSERT_ZERO_LABEL(p);
ASSERT_READ_ZERO_LABEL(p, kSize);
free(p);
}
void test_pvalloc() {
char *p = (char *) pvalloc(kSize);
ASSERT_ZERO_LABEL(p);
ASSERT_READ_ZERO_LABEL(p, kSize);
free(p);
}
void test_realloc() {
char *p = (char *) malloc(kSize);
char *q = (char *) realloc(p, kSize * 2);
ASSERT_ZERO_LABEL(q);
ASSERT_READ_ZERO_LABEL(q, kSize * 2);
char *x = (char *) realloc(q, kSize);
ASSERT_ZERO_LABEL(x);
ASSERT_READ_ZERO_LABEL(x, kSize);
free(x);
}
void test_reallocarray() {
// The current glibc does not support reallocarray.
}
void test_valloc() {
char *p = (char *) valloc(kSize);
ASSERT_ZERO_LABEL(p);
ASSERT_READ_ZERO_LABEL(p, kSize);
free(p);
}
void test___libc_memalign() {
// The current glibc does not support __libc_memalign.
}
void test___tls_get_addr() {
// The current glibc does not support __tls_get_addr.
}
int main(void) {
// With any luck this sequence of calls will cause allocators to return the
// same pointer. This is probably the best we can do to test these functions.
test_aligned_alloc();
test_calloc();
test_cfree();
test_free();
test_mallinfo();
test_malloc();
test_malloc_stats();
test_malloc_usable_size();
test_mallopt();
test_memalign();
test_mmap();
test_mmap64();
test_unmmap();
test_posix_memalign();
test_pvalloc();
test_realloc();
test_reallocarray();
test_valloc();
test___libc_memalign();
test___tls_get_addr();
}