/* * custom_c++_operator_new2.cpp - custom allocator demo * * Written by Roland Mainz * * - Compile with: * $ clang++ -std=c++17 -g -Wall /home/rmainz/work/tlsf/try4/TLSF-2.4.6/src/tlsf.o custom_c++_operator_new2.cpp # * * - Watch TLSF-calls with: * $ ltrace -C -x '*' ./a.out # */ #define USE_STATIC_BUFFER_ALLOC 0 #define USE_TLSF_ALLOC 1 #define USE_LIBC_MALLOC 0 #define STATIC_BUFFER_ALLOC_BUFFER_SIZE (512) #include #include #include /* required for |main()| test/demo code */ #include #include #include #include #include #if USE_TLSF_ALLOC extern "C" { #include "/home/rmainz/work/tlsf/try4/TLSF-2.4.6/src/tlsf.h" } #endif /* USE_TLSF_ALLOC */ /* misc */ #define STDERR_MSG(msg) \ (void)write(STDERR_FILENO, (msg), strlen(msg)) #if USE_STATIC_BUFFER_ALLOC extern "C" { static struct { char buffer[STATIC_BUFFER_ALLOC_BUFFER_SIZE]; /* more complex cases would require |pthread_once()| */ char *buf_ptr = buffer; } buf_alloc; void *my_buffer_alloc(size_t size) { #define SIZE_ALIGN(size, align) \ ((size)+((align)-1)-((size)-1)%(align)) void *mem; size_t bs; STDERR_MSG("my_buffer_alloc\n"); bs = SIZE_ALIGN(size, 16); mem = buf_alloc.buf_ptr; buf_alloc.buf_ptr += bs; /* could we satisfy the allocation request ? */ if ((buf_alloc.buf_ptr - buf_alloc.buffer) >= sizeof(buf_alloc.buffer)) return NULL; #if 0 (void)fprintf(stderr, "my_buffer_alloc(size=%ld, bs=%ld, mem=%lx\n", (long)size, (long)bs, (long)mem); #endif return mem; } void my_buffer_dealloc(void *ptr) { /* * range check - pointer must point within |buf_alloc.buffer|! * * We use this simple (and cheap) check to catch invalid * pointers, or (more important) pointers to memory from * other allocators (if we mix&match multiple different * allocators or different memory pools from the same * allocator system). */ ptrdiff_t x = (char *)ptr - buf_alloc.buffer; if ((x < 0) || (x >= (ptrdiff_t)sizeof(buf_alloc.buffer))) { /* BUG: LAZY - we should not use stdio here... */ (void)fprintf(stderr, "delete(): bad pointer %lx!\n", (long)x); } } } /* extern "C" */ #endif /* USE_STATIC_BUFFER_ALLOC */ void * operator new(std::size_t size) // throw(std::bad_alloc) { STDERR_MSG("##new\n"); if (size == 0) size = 1; void* p; #if USE_STATIC_BUFFER_ALLOC if ((p = my_buffer_alloc(size)) == 0) #elif USE_TLSF_ALLOC if ((p = ::tlsf_malloc(size)) == 0) #elif USE_LIBC_MALLOC if ((p = ::malloc(size)) == 0) #else #error No allocator library selected. #endif /* USE_STATIC_BUFFER_ALLOC */ { throw std::bad_alloc(); } return p; } void operator delete(void* ptr) _GLIBCXX_USE_NOEXCEPT { STDERR_MSG("##delete\n"); #if USE_STATIC_BUFFER_ALLOC my_buffer_dealloc(ptr); #elif USE_TLSF_ALLOC if (ptr) ::tlsf_free(ptr); #elif USE_LIBC_MALLOC if (ptr) ::free(ptr); #else #error No allocator library selected #endif /* USE_STATIC_BUFFER_ALLOC */ } /* * static variables: * Their memory is allocated/constructor called before calling * |main()|, and their destructor is called and memory deallocated * after |main()| returned. * This causes some nasty headaches for custom |operator new|, e.g. * in case we want to rely on stdio, C++ iostream, or other * libc/libc++ modules. And don't even start to ask about headaches * related to STL and C++ exceptions... */ static int *s_f = new int(59); static std::string s = "xjsdsqwertzuiopasdfghjklxcvbnm,poiuztrewlkjhgfdmnbvcxjsddljkjklsdfjklsddfljkx"; int main(int ac, char *av[]) { (void)puts("# >> main:start."); int *f = new int(84); std::string s = "13123123123122354245234534534534534534656456456456456456242342341233423423524542hello"; s+=" "; s+="world"; std::cout << s << "#" << *f << "," << *s_f << "#" << std::endl; delete f; #if 0 /* test if pointer validation of |my_buffer_dealloc()| works */ delete (int *)malloc(5); #endif (void)puts("# >> main:done."); return EXIT_SUCCESS; }