From: Petr Špaček Date: Mon, 19 Aug 2019 14:17:57 +0000 (+0200) Subject: mempool: pull in simplified version from Knot DNS X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2287d61e6f332e5f8926362d657a54857237342d;p=thirdparty%2Fknot-resolver.git mempool: pull in simplified version from Knot DNS Function kr_pkt_text was only user of mp_printf functions, so these were removed to simplify code. Assumption is that kr_pkt_text is used only for debugging and is not optimized for speed - in the worst case it needs to convert data to text representation twice. --- diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 4e81c2ddd..5339aad2c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -226,7 +226,7 @@ lint:scan-build: script: - export SCANBUILD="scan-build --status-bugs -no-failure-reports $(./scripts/get-scanbuild-args.sh)" - ninja -C build_ci* scan-build || true - - test "$(ls build_ci*/meson-logs/scanbuild/*/report-*.html | wc -l)" = 29 # we have this many errors ATM :-) + - test "$(ls build_ci*/meson-logs/scanbuild/*/report-*.html | wc -l)" = 27 # we have this many errors ATM :-) lint:tidy: <<: *test diff --git a/bench/bench_lru.c b/bench/bench_lru.c index 237be6693..04313a85c 100644 --- a/bench/bench_lru.c +++ b/bench/bench_lru.c @@ -21,7 +21,7 @@ #include #include -#include "contrib/ucw/lib.h" +#include "contrib/macros.h" #include "daemon/engine.h" #include "lib/nsrep.h" diff --git a/contrib/asan.h b/contrib/asan.h new file mode 100644 index 000000000..5feb2c12e --- /dev/null +++ b/contrib/asan.h @@ -0,0 +1,37 @@ +/* Copyright (C) 2015 CZ.NIC, z.s.p.o. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#pragma once + +/* + * see sanitizer/asan_interface.h in compiler-rt (LLVM) + */ +#ifndef __has_feature + #define __has_feature(feature) 0 +#endif +#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__) + void __asan_poison_memory_region(void const volatile *addr, size_t size); + void __asan_unpoison_memory_region(void const volatile *addr, size_t size); + #define ASAN_POISON_MEMORY_REGION(addr, size) \ + __asan_poison_memory_region((addr), (size)) + #define ASAN_UNPOISON_MEMORY_REGION(addr, size) \ + __asan_unpoison_memory_region((addr), (size)) +#else + #define ASAN_POISON_MEMORY_REGION(addr, size) \ + ((void)(addr), (void)(size)) + #define ASAN_UNPOISON_MEMORY_REGION(addr, size) \ + ((void)(addr), (void)(size)) +#endif diff --git a/contrib/macros.h b/contrib/macros.h new file mode 100644 index 000000000..2e80c45ff --- /dev/null +++ b/contrib/macros.h @@ -0,0 +1,48 @@ +/* Copyright (C) 2018 CZ.NIC, z.s.p.o. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +/*! + * \brief Common macros. + */ + +#pragma once + +#define ABS(x) ((x) < 0 ? -(x) : (x)) +#ifndef MIN +/*! \brief Type-safe minimum macro. */ +#define MIN(a, b) \ + __extension__({ \ + __typeof__ (a) _amin = (a); \ + __typeof__ (b) _bmin = (b); \ + _amin < _bmin ? _amin : _bmin; }) + +/*! \brief Type-safe maximum macro. */ +#define MAX(a, b) \ + __extension__({ \ + __typeof__ (a) _amax = (a); \ + __typeof__ (b) _bmax = (b); \ + _amax > _bmax ? _amax : _bmax; }) +#endif + +#ifndef likely +/*! \brief Optimize for x to be true value. */ +#define likely(x) __builtin_expect((x), 1) +#endif + +#ifndef unlikely +/*! \brief Optimize for x to be false value. */ +#define unlikely(x) __builtin_expect((x), 0) +#endif diff --git a/contrib/meson.build b/contrib/meson.build index e69d01754..47268a356 100644 --- a/contrib/meson.build +++ b/contrib/meson.build @@ -5,7 +5,6 @@ contrib_src = files([ 'ccan/ilog/ilog.c', 'ccan/json/json.c', 'ucw/mempool.c', - 'ucw/mempool-fmt.c', 'murmurhash3/murmurhash3.c', 'base32hex.c', 'base64.c' diff --git a/contrib/ucw/alloc.h b/contrib/ucw/alloc.h deleted file mode 100644 index 668c707cc..000000000 --- a/contrib/ucw/alloc.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * UCW Library -- Generic allocators - * - * (c) 2014 Martin Mares - */ - -#ifndef _UCW_ALLOC_H -#define _UCW_ALLOC_H - -/** - * This structure describes a generic allocator. It provides pointers - * to three functions, which handle the actual (re)allocations. - **/ -struct ucw_allocator { - void * (*alloc)(struct ucw_allocator *alloc, size_t size); - void * (*realloc)(struct ucw_allocator *alloc, void *ptr, size_t old_size, size_t new_size); - void (*free)(struct ucw_allocator *alloc, void *ptr); -}; - -/* alloc-std.c */ - -/** - * [[std]] - * This allocator uses <>, <> and <>. The memory - * it allocates is left unitialized. - **/ -extern struct ucw_allocator ucw_allocator_std; - -/** - * [[zeroing]] - * This allocator uses <>, <> and <>. All memory - * is zeroed upon allocation. - **/ -extern struct ucw_allocator ucw_allocator_zeroed; - -#endif diff --git a/contrib/ucw/config.h b/contrib/ucw/config.h deleted file mode 100644 index 5d3cb4fe2..000000000 --- a/contrib/ucw/config.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * UCW Library -- Configuration-Dependent Definitions - * - * (c) 1997--2012 Martin Mares - * (c) 2006 Robert Spalek - * - * This software may be freely distributed and used according to the terms - * of the GNU Lesser General Public License. - */ - -#ifndef _UCW_CONFIG_H -#define _UCW_CONFIG_H - -/* Default page size and pointer alignment */ -#ifndef CPU_PAGE_SIZE -#define CPU_PAGE_SIZE 4096 -#endif -#define CPU_STRUCT_ALIGN sizeof(void *) - -/* Tell libc we're going to use all extensions available */ - -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif - -/* Types (based on standard C99 integers) */ - -#include -#include - -typedef uint8_t byte; /** Exactly 8 bits, unsigned **/ -typedef uint8_t u8; /** Exactly 8 bits, unsigned **/ -typedef int8_t s8; /** Exactly 8 bits, signed **/ -typedef uint16_t u16; /** Exactly 16 bits, unsigned **/ -typedef int16_t s16; /** Exactly 16 bits, signed **/ -typedef uint32_t u32; /** Exactly 32 bits, unsigned **/ -typedef int32_t s32; /** Exactly 32 bits, signed **/ -typedef uint64_t u64; /** Exactly 64 bits, unsigned **/ -typedef int64_t s64; /** Exactly 64 bits, signed **/ - - -#ifndef uint /* Redefining typedef is a C11 feature. */ -typedef unsigned int uint; /** A better pronounceable alias for `unsigned int` **/ -#define uint uint -#endif - -typedef s64 timestamp_t; /** Milliseconds since an unknown epoch **/ - -// FIXME: This should be removed soon -typedef uint uns; /** Backwards compatible alias for `uint' ***/ - -#ifdef CONFIG_UCW_LARGE_FILES -typedef s64 ucw_off_t; /** File position (either 32- or 64-bit, depending on `CONFIG_UCW_LARGE_FILES`). **/ -#else -typedef s32 ucw_off_t; -#endif - -#endif diff --git a/contrib/ucw/lib.h b/contrib/ucw/lib.h deleted file mode 100644 index 506f09b56..000000000 --- a/contrib/ucw/lib.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - * The UCW Library -- Miscellaneous Functions - * - * (c) 1997--2014 Martin Mares - * (c) 2005--2014 Tomas Valla - * (c) 2006 Robert Spalek - * (c) 2007 Pavel Charvat - * - * This software may be freely distributed and used according to the terms - * of the GNU Lesser General Public License. - */ - -#ifndef _UCW_LIB_H -#define _UCW_LIB_H - -#include -#include -#include - -#ifdef CONFIG_UCW_CLEAN_ABI -#define assert_failed ucw_assert_failed -#define assert_failed_msg ucw_assert_failed_msg -#define assert_failed_noinfo ucw_assert_failed_noinfo -#define big_alloc ucw_big_alloc -#define big_alloc_zero ucw_big_alloc_zero -#define big_free ucw_big_free -#define die ucw_die -#define log_die_hook ucw_log_die_hook -#define log_file ucw_log_file -#define log_fork ucw_log_fork -#define log_init ucw_log_init -#define log_pid ucw_log_pid -#define log_title ucw_log_title -#define msg ucw_msg -#define page_alloc ucw_page_alloc -#define page_alloc_zero ucw_page_alloc_zero -#define page_free ucw_page_free -#define page_realloc ucw_page_realloc -#define random_max ucw_random_max -#define random_max_u64 ucw_random_max_u64 -#define random_u32 ucw_random_u32 -#define random_u64 ucw_random_u64 -#define vdie ucw_vdie -#define vmsg ucw_vmsg -#define xfree ucw_xfree -#define xmalloc ucw_xmalloc -#define xmalloc_zero ucw_xmalloc_zero -#define xrealloc ucw_xrealloc -#define xstrdup ucw_xstrdup -#endif - -/*** === Macros for handling structures, offsets and alignment ***/ - -#define CHECK_PTR_TYPE(x, type) ((x)-(type)(x) + (type)(x)) /** Check that a pointer @x is of type @type. Fail compilation if not. **/ -#define PTR_TO(s, i) &((s*)0)->i /** Return OFFSETOF() in form of a pointer. **/ -#define OFFSETOF(s, i) ((uint)offsetof(s, i)) /** Offset of item @i from the start of structure @s **/ -#define SKIP_BACK(s, i, p) ((s *)((char *)p - OFFSETOF(s, i))) /** Given a pointer @p to item @i of structure @s, return a pointer to the start of the struct. **/ - -/** Align an integer @s to the nearest higher multiple of @a (which should be a power of two) **/ -#define ALIGN_TO(s, a) (((s)+a-1)&~(a-1)) - -/** Align a pointer @p to the nearest higher multiple of @s. **/ -#define ALIGN_PTR(p, s) ((uintptr_t)(p) % (s) ? (typeof(p))((uintptr_t)(p) + (s) - (uintptr_t)(p) % (s)) : (p)) - -#define UNALIGNED_PART(ptr, type) (((uintptr_t) (ptr)) % sizeof(type)) - -/*** === Other utility macros ***/ - -#define MIN(a,b) (((a)<(b))?(a):(b)) /** Minimum of two numbers **/ -#define MAX(a,b) (((a)>(b))?(a):(b)) /** Maximum of two numbers **/ -#define CLAMP(x,min,max) ({ typeof(x) _t=x; (_t < min) ? min : (_t > max) ? max : _t; }) /** Clip a number @x to interval [@min,@max] **/ -#define ABS(x) ((x) < 0 ? -(x) : (x)) /** Absolute value **/ -#define ARRAY_SIZE(a) (sizeof(a)/sizeof(*(a))) /** The number of elements of an array **/ -#define STRINGIFY(x) #x /** Convert macro parameter to a string **/ -#define STRINGIFY_EXPANDED(x) STRINGIFY(x) /** Convert an expanded macro parameter to a string **/ -#define GLUE(x,y) x##y /** Glue two tokens together **/ -#define GLUE_(x,y) x##_##y /** Glue two tokens together, separating them by an underscore **/ - -#define COMPARE(x,y) do { if ((x)<(y)) return -1; if ((x)>(y)) return 1; } while(0) /** Numeric comparison function for qsort() **/ -#define REV_COMPARE(x,y) COMPARE(y,x) /** Reverse numeric comparison **/ -#define COMPARE_LT(x,y) do { if ((x)<(y)) return 1; if ((x)>(y)) return 0; } while(0) -#define COMPARE_GT(x,y) COMPARE_LT(y,x) - -#define ROL(x, bits) (((x) << (bits)) | ((uint)(x) >> (sizeof(uint)*8 - (bits)))) /** Bitwise rotation of an unsigned int to the left **/ -#define ROR(x, bits) (((uint)(x) >> (bits)) | ((x) << (sizeof(uint)*8 - (bits)))) /** Bitwise rotation of an unsigned int to the right **/ - -/*** === Shortcuts for GCC Extensions ***/ - -#ifdef __GNUC__ - -#include "ccan/compiler/compiler.h" -#define FORMAT_CHECK(x,y,z) __attribute__((format(x,y,z))) /** Checking of printf-like format strings **/ -#define likely(x) __builtin_expect((x),1) /** Use `if (likely(@x))` if @x is almost always true **/ -#define unlikely(x) __builtin_expect((x),0) /** Use `if (unlikely(@x))` to hint that @x is almost always false **/ - -#if __GNUC__ >= 4 || __GNUC__ == 3 && __GNUC_MINOR__ >= 3 -#define ALWAYS_INLINE inline __attribute__((always_inline)) /** Forcibly inline **/ -#define NO_INLINE __attribute__((noinline)) /** Forcibly uninline **/ -#else -#define ALWAYS_INLINE inline -#endif - -#if __GNUC__ >= 4 -#define LIKE_MALLOC __attribute__((malloc)) /** Function returns a "new" pointer **/ -#define SENTINEL_CHECK __attribute__((sentinel)) /** The last argument must be NULL **/ -#else -#define LIKE_MALLOC -#define SENTINEL_CHECK -#endif - -#else -#error This program requires the GNU C compiler. -#endif - -/*** - * [[logging]] - * - * === Basic logging functions (see <> and for more) - ***/ - -#define DBG(x, ...) do { } while(0) -#define DBG_SPOT do { } while(0) -#define ASSERT(x) - -#endif diff --git a/contrib/ucw/mempool-fmt.c b/contrib/ucw/mempool-fmt.c deleted file mode 100644 index 6c93e1e9a..000000000 --- a/contrib/ucw/mempool-fmt.c +++ /dev/null @@ -1,100 +0,0 @@ -/* - * UCW Library -- Memory Pools (Formatting) - * - * (c) 2005 Martin Mares - * (c) 2007 Pavel Charvat - * - * This software may be freely distributed and used according to the terms - * of the GNU Lesser General Public License. - */ - -#include -#include - -#include -#include - -/* FIXME: migrate to Knot DNS version of mempools. */ -#pragma GCC diagnostic ignored "-Wpointer-arith" - -static char * -mp_vprintf_at(struct mempool *mp, size_t ofs, const char *fmt, va_list args) -{ - char *ret = mp_grow(mp, ofs + 1) + ofs; - va_list args2; - va_copy(args2, args); - int cnt = vsnprintf(ret, mp_avail(mp) - ofs, fmt, args2); - va_end(args2); - if (cnt < 0) - { - /* Our C library doesn't support C99 return value of vsnprintf, so we need to iterate */ - do - { - ret = mp_expand(mp) + ofs; - va_copy(args2, args); - cnt = vsnprintf(ret, mp_avail(mp) - ofs, fmt, args2); - va_end(args2); - } - while (cnt < 0); - } - else if ((uint)cnt >= mp_avail(mp) - ofs) - { - ret = mp_grow(mp, ofs + cnt + 1) + ofs; - va_copy(args2, args); - vsnprintf(ret, cnt + 1, fmt, args2); - va_end(args2); - } - mp_end(mp, ret + cnt + 1); - return ret - ofs; -} - -char * -mp_vprintf(struct mempool *mp, const char *fmt, va_list args) -{ - mp_start(mp, 1); - return mp_vprintf_at(mp, 0, fmt, args); -} - -char * -mp_printf(struct mempool *p, const char *fmt, ...) -{ - va_list args; - va_start(args, fmt); - char *res = mp_vprintf(p, fmt, args); - va_end(args); - return res; -} - -char * -mp_vprintf_append(struct mempool *mp, char *ptr, const char *fmt, va_list args) -{ - size_t ofs = mp_open(mp, ptr); - ASSERT(ofs && !ptr[ofs - 1]); - return mp_vprintf_at(mp, ofs - 1, fmt, args); -} - -char * -mp_printf_append(struct mempool *mp, char *ptr, const char *fmt, ...) -{ - va_list args; - va_start(args, fmt); - char *res = mp_vprintf_append(mp, ptr, fmt, args); - va_end(args); - return res; -} - -#ifdef TEST - -int main(void) -{ - struct mempool *mp = mp_new(64); - char *x = mp_printf(mp, "", "World"); - fputs(x, stdout); - x = mp_printf_append(mp, x, ""); - fputs(x, stdout); - x = mp_printf(mp, "\n", "World"); - fputs(x, stdout); - return 0; -} - -#endif diff --git a/contrib/ucw/mempool.c b/contrib/ucw/mempool.c index 129b7336a..dfc392edc 100644 --- a/contrib/ucw/mempool.c +++ b/contrib/ucw/mempool.c @@ -1,8 +1,9 @@ /* * UCW Library -- Memory Pools (One-Time Allocation) * - * (c) 1997--2014 Martin Mares - * (c) 2007--2015 Pavel Charvat + * (c) 1997--2001 Martin Mares + * (c) 2007 Pavel Charvat + * (c) 2015, 2017 CZ.NIC, z.s.p.o. * * This software may be freely distributed and used according to the terms * of the GNU Lesser General Public License. @@ -10,592 +11,310 @@ #undef LOCAL_DEBUG -#include -#include -#include -#include - #include +#include #include +#include +#include +#include "contrib/asan.h" +#include "contrib/macros.h" +#include "contrib/ucw/mempool.h" -/* FIXME: migrate to Knot DNS version of mempools. */ -#pragma GCC diagnostic ignored "-Wpointer-arith" - +/** Align an integer \p s to the nearest higher multiple of \p a (which should be a power of two) **/ +#define ALIGN_TO(s, a) (((s)+a-1)&~(a-1)) #define MP_CHUNK_TAIL ALIGN_TO(sizeof(struct mempool_chunk), CPU_STRUCT_ALIGN) -#define MP_SIZE_MAX (SIZE_MAX - MP_CHUNK_TAIL - CPU_PAGE_SIZE) - -struct mempool_chunk { -#ifdef CONFIG_DEBUG - struct mempool *pool; // Can be useful when analysing coredump for memory leaks -#endif - struct mempool_chunk *next; - size_t size; -}; +#define MP_SIZE_MAX (~0U - MP_CHUNK_TAIL - CPU_PAGE_SIZE) +#define DBG(s, ...) -static size_t -mp_align_size(size_t size) -{ +/** \note Imported MMAP backend from bigalloc.c */ +#define CONFIG_UCW_POOL_IS_MMAP #ifdef CONFIG_UCW_POOL_IS_MMAP - size = MAX(size, 64 + MP_CHUNK_TAIL); - return ALIGN_TO(size, CPU_PAGE_SIZE) - MP_CHUNK_TAIL; -#else - return ALIGN_TO(size, CPU_STRUCT_ALIGN); -#endif -} - -static void *mp_allocator_alloc(struct ucw_allocator *a, size_t size) +#include +static void * +page_alloc(uint64_t len) { - struct mempool *mp = (struct mempool *) a; - return mp_alloc_fast(mp, size); + if (!len) { + return NULL; + } + if (len > SIZE_MAX) { + return NULL; + } + assert(!(len & (CPU_PAGE_SIZE-1))); + uint8_t *p = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); + if (p == (uint8_t*) MAP_FAILED) { + return NULL; + } + return p; } -static void *mp_allocator_realloc(struct ucw_allocator *a, void *ptr, size_t old_size, size_t new_size) +static void +page_free(void *start, uint64_t len) { - if (new_size <= old_size) - return ptr; - - /* - * In the future, we might want to do something like mp_realloc(), - * but we have to check that it is indeed the last block in the pool. - */ - struct mempool *mp = (struct mempool *) a; - void *new = mp_alloc_fast(mp, new_size); - memcpy(new, ptr, old_size); - return new; + assert(!(len & (CPU_PAGE_SIZE-1))); + assert(!((uintptr_t) start & (CPU_PAGE_SIZE-1))); + munmap(start, len); } +#endif + +struct mempool_chunk { + struct mempool_chunk *next; + unsigned size; +}; -static void mp_allocator_free(struct ucw_allocator *a UNUSED, void *ptr UNUSED) +static unsigned +mp_align_size(unsigned size) { - // Does nothing +#ifdef CONFIG_UCW_POOL_IS_MMAP + return ALIGN_TO(size + MP_CHUNK_TAIL, CPU_PAGE_SIZE) - MP_CHUNK_TAIL; +#else + return ALIGN_TO(size, CPU_STRUCT_ALIGN); +#endif } void -mp_init(struct mempool *pool, size_t chunk_size) +mp_init(struct mempool *pool, unsigned chunk_size) { - chunk_size = mp_align_size(MAX(sizeof(struct mempool), chunk_size)); - *pool = (struct mempool) { - .allocator = { - .alloc = mp_allocator_alloc, - .realloc = mp_allocator_realloc, - .free = mp_allocator_free, - }, - .chunk_size = chunk_size, - .threshold = chunk_size >> 1, - .last_big = &pool->last_big - }; + chunk_size = mp_align_size(MAX(sizeof(struct mempool), chunk_size)); + *pool = (struct mempool) { + .chunk_size = chunk_size, + .threshold = chunk_size >> 1, + .last_big = &pool->last_big + }; } static void * -mp_new_big_chunk(struct mempool *pool, size_t size) +mp_new_big_chunk(unsigned size) { - struct mempool_chunk *chunk; - chunk = malloc(size + MP_CHUNK_TAIL); - if (!chunk) - return NULL; - chunk = (struct mempool_chunk *)((char *)chunk + size); - chunk->size = size; - if (pool) - pool->total_size += size + MP_CHUNK_TAIL; - return chunk; + uint8_t *data = malloc(size + MP_CHUNK_TAIL); + if (!data) { + return NULL; + } + ASAN_POISON_MEMORY_REGION(data, size); + struct mempool_chunk *chunk = (struct mempool_chunk *)(data + size); + chunk->size = size; + return chunk; } static void -mp_free_big_chunk(struct mempool *pool, struct mempool_chunk *chunk) +mp_free_big_chunk(struct mempool_chunk *chunk) { - pool->total_size -= chunk->size + MP_CHUNK_TAIL; - free((void *)chunk - chunk->size); + void *ptr = (uint8_t *)chunk - chunk->size; + ASAN_UNPOISON_MEMORY_REGION(ptr, chunk->size); + free(ptr); } static void * -mp_new_chunk(struct mempool *pool, size_t size) +mp_new_chunk(unsigned size) { #ifdef CONFIG_UCW_POOL_IS_MMAP - struct mempool_chunk *chunk; - chunk = page_alloc(size + MP_CHUNK_TAIL) + size; - chunk->size = size; - if (pool) - pool->total_size += size + MP_CHUNK_TAIL; - return chunk; + uint8_t *data = page_alloc(size + MP_CHUNK_TAIL); + if (!data) { + return NULL; + } + ASAN_POISON_MEMORY_REGION(data, size); + struct mempool_chunk *chunk = (struct mempool_chunk *)(data + size); + chunk->size = size; + return chunk; #else - return mp_new_big_chunk(pool, size); + return mp_new_big_chunk(size); #endif } static void -mp_free_chunk(struct mempool *pool, struct mempool_chunk *chunk) +mp_free_chunk(struct mempool_chunk *chunk) { #ifdef CONFIG_UCW_POOL_IS_MMAP - pool->total_size -= chunk->size + MP_CHUNK_TAIL; - page_free((void *)chunk - chunk->size, chunk->size + MP_CHUNK_TAIL); + uint8_t *data = (uint8_t *)chunk - chunk->size; + ASAN_UNPOISON_MEMORY_REGION(data, chunk->size); + page_free(data, chunk->size + MP_CHUNK_TAIL); #else - mp_free_big_chunk(pool, chunk); + mp_free_big_chunk(chunk); #endif } struct mempool * -mp_new(size_t chunk_size) -{ - chunk_size = mp_align_size(MAX(sizeof(struct mempool), chunk_size)); - struct mempool_chunk *chunk = mp_new_chunk(NULL, chunk_size); - struct mempool *pool = (void *)chunk - chunk_size; - DBG("Creating mempool %p with %u bytes long chunks", pool, chunk_size); - chunk->next = NULL; -#ifdef CONFIG_DEBUG - chunk->pool = pool; -#endif - *pool = (struct mempool) { - .allocator = { - .alloc = mp_allocator_alloc, - .realloc = mp_allocator_realloc, - .free = mp_allocator_free, - }, - .state = { .free = { chunk_size - sizeof(*pool) }, .last = { chunk } }, - .chunk_size = chunk_size, - .threshold = chunk_size >> 1, - .last_big = &pool->last_big, - .total_size = chunk->size + MP_CHUNK_TAIL, - }; - return pool; +mp_new(unsigned chunk_size) +{ + chunk_size = mp_align_size(MAX(sizeof(struct mempool), chunk_size)); + struct mempool_chunk *chunk = mp_new_chunk(chunk_size); + struct mempool *pool = (void *)((char *)chunk - chunk_size); + ASAN_UNPOISON_MEMORY_REGION(pool, sizeof(*pool)); + DBG("Creating mempool %p with %u bytes long chunks", pool, chunk_size); + chunk->next = NULL; + ASAN_POISON_MEMORY_REGION(chunk, sizeof(struct mempool_chunk)); + *pool = (struct mempool) { + .state = { .free = { chunk_size - sizeof(*pool) }, .last = { chunk } }, + .chunk_size = chunk_size, + .threshold = chunk_size >> 1, + .last_big = &pool->last_big + }; + return pool; } static void -mp_free_chain(struct mempool *pool, struct mempool_chunk *chunk) +mp_free_chain(struct mempool_chunk *chunk) { - while (chunk) - { - struct mempool_chunk *next = chunk->next; - mp_free_chunk(pool, chunk); - chunk = next; - } + while (chunk) { + ASAN_UNPOISON_MEMORY_REGION(chunk, sizeof(struct mempool_chunk)); + struct mempool_chunk *next = chunk->next; + mp_free_chunk(chunk); + chunk = next; + } } static void -mp_free_big_chain(struct mempool *pool, struct mempool_chunk *chunk) +mp_free_big_chain(struct mempool_chunk *chunk) { - while (chunk) - { - struct mempool_chunk *next = chunk->next; - mp_free_big_chunk(pool, chunk); - chunk = next; - } + while (chunk) { + ASAN_UNPOISON_MEMORY_REGION(chunk, sizeof(struct mempool_chunk)); + struct mempool_chunk *next = chunk->next; + mp_free_big_chunk(chunk); + chunk = next; + } } void mp_delete(struct mempool *pool) { - DBG("Deleting mempool %p", pool); - mp_free_big_chain(pool, pool->state.last[1]); - mp_free_chain(pool, pool->unused); - mp_free_chain(pool, pool->state.last[0]); // can contain the mempool structure + if (pool == NULL) { + return; + } + DBG("Deleting mempool %p", pool); + mp_free_big_chain(pool->state.last[1]); + mp_free_chain(pool->unused); + mp_free_chain(pool->state.last[0]); // can contain the mempool structure } void mp_flush(struct mempool *pool) { - mp_free_big_chain(pool, pool->state.last[1]); - struct mempool_chunk *chunk, *next; - for (chunk = pool->state.last[0]; chunk && (void *)chunk - chunk->size != pool; chunk = next) - { - next = chunk->next; - chunk->next = pool->unused; - pool->unused = chunk; - } - pool->state.last[0] = chunk; - pool->state.free[0] = chunk ? chunk->size - sizeof(*pool) : 0; - pool->state.last[1] = NULL; - pool->state.free[1] = 0; - pool->state.next = NULL; - pool->last_big = &pool->last_big; + mp_free_big_chain(pool->state.last[1]); + struct mempool_chunk *chunk = pool->state.last[0], *next; + while (chunk) { + ASAN_UNPOISON_MEMORY_REGION(chunk, sizeof(struct mempool_chunk)); + if ((uint8_t *)chunk - chunk->size == (uint8_t *)pool) { + break; + } + next = chunk->next; + chunk->next = pool->unused; + ASAN_POISON_MEMORY_REGION(chunk, sizeof(struct mempool_chunk)); + pool->unused = chunk; + chunk = next; + } + pool->state.last[0] = chunk; + if (chunk) { + pool->state.free[0] = chunk->size - sizeof(*pool); + ASAN_POISON_MEMORY_REGION(chunk, sizeof(struct mempool_chunk)); + } else { + pool->state.free[0] = 0; + } + pool->state.last[1] = NULL; + pool->state.free[1] = 0; + pool->last_big = &pool->last_big; } static void -mp_stats_chain(struct mempool *pool, struct mempool_chunk *chunk, struct mempool_stats *stats, uint idx) -{ - while (chunk) - { - stats->chain_size[idx] += chunk->size + MP_CHUNK_TAIL; - stats->chain_count[idx]++; - if (idx < 2) - { - stats->used_size += chunk->size; - if ((byte *)pool == (byte *)chunk - chunk->size) - stats->used_size -= sizeof(*pool); +mp_stats_chain(struct mempool_chunk *chunk, struct mempool_stats *stats, unsigned idx) +{ + struct mempool_chunk *next; + while (chunk) { + ASAN_UNPOISON_MEMORY_REGION(chunk, sizeof(struct mempool_chunk)); + stats->chain_size[idx] += chunk->size + sizeof(*chunk); + stats->chain_count[idx]++; + next = chunk->next; + ASAN_POISON_MEMORY_REGION(chunk, sizeof(struct mempool_chunk)); + chunk = next; } - chunk = chunk->next; - } - stats->total_size += stats->chain_size[idx]; + stats->total_size += stats->chain_size[idx]; } void mp_stats(struct mempool *pool, struct mempool_stats *stats) { - bzero(stats, sizeof(*stats)); - mp_stats_chain(pool, pool->state.last[0], stats, 0); - mp_stats_chain(pool, pool->state.last[1], stats, 1); - mp_stats_chain(pool, pool->unused, stats, 2); - stats->used_size -= pool->state.free[0] + pool->state.free[1]; - ASSERT(stats->total_size == pool->total_size); - ASSERT(stats->used_size <= stats->total_size); + bzero(stats, sizeof(*stats)); + mp_stats_chain(pool->state.last[0], stats, 0); + mp_stats_chain(pool->state.last[1], stats, 1); + mp_stats_chain(pool->unused, stats, 2); } -u64 +uint64_t mp_total_size(struct mempool *pool) { - return pool->total_size; -} - -void -mp_shrink(struct mempool *pool, u64 min_total_size) -{ - while (1) - { - struct mempool_chunk *chunk = pool->unused; - if (!chunk || pool->total_size - (chunk->size + MP_CHUNK_TAIL) < min_total_size) - break; - pool->unused = chunk->next; - mp_free_chunk(pool, chunk); - } + struct mempool_stats stats; + mp_stats(pool, &stats); + return stats.total_size; } -void * -mp_alloc_internal(struct mempool *pool, size_t size) -{ - struct mempool_chunk *chunk; - if (size <= pool->threshold) - { - pool->idx = 0; - if (pool->unused) - { - chunk = pool->unused; - pool->unused = chunk->next; - } - else - { - chunk = mp_new_chunk(pool, pool->chunk_size); -#ifdef CONFIG_DEBUG - chunk->pool = pool; -#endif +static void * +mp_alloc_internal(struct mempool *pool, unsigned size) +{ + struct mempool_chunk *chunk; + if (size <= pool->threshold) { + pool->idx = 0; + if (pool->unused) { + chunk = pool->unused; + ASAN_UNPOISON_MEMORY_REGION(chunk, sizeof(struct mempool_chunk)); + pool->unused = chunk->next; + } else { + chunk = mp_new_chunk(pool->chunk_size); + } + chunk->next = pool->state.last[0]; + ASAN_POISON_MEMORY_REGION(chunk, sizeof(struct mempool_chunk)); + pool->state.last[0] = chunk; + pool->state.free[0] = pool->chunk_size - size; + return (uint8_t *)chunk - pool->chunk_size; + } else if (size <= MP_SIZE_MAX) { + pool->idx = 1; + unsigned aligned = ALIGN_TO(size, CPU_STRUCT_ALIGN); + chunk = mp_new_big_chunk(aligned); + if (!chunk) { + return NULL; + } + chunk->next = pool->state.last[1]; + ASAN_POISON_MEMORY_REGION(chunk, sizeof(struct mempool_chunk)); + pool->state.last[1] = chunk; + pool->state.free[1] = aligned - size; + return pool->last_big = (uint8_t *)chunk - aligned; + } else { + fprintf(stderr, "Cannot allocate %u bytes from a mempool", size); + assert(0); + return NULL; } - chunk->next = pool->state.last[0]; - pool->state.last[0] = chunk; - pool->state.free[0] = pool->chunk_size - size; - return (void *)chunk - pool->chunk_size; - } - else if (likely(size <= MP_SIZE_MAX)) - { - pool->idx = 1; - size_t aligned = ALIGN_TO(size, CPU_STRUCT_ALIGN); - chunk = mp_new_big_chunk(pool, aligned); - chunk->next = pool->state.last[1]; -#ifdef CONFIG_DEBUG - chunk->pool = pool; -#endif - pool->state.last[1] = chunk; - pool->state.free[1] = aligned - size; - return pool->last_big = (void *)chunk - aligned; - } - else - return NULL; -} - -void * -mp_alloc(struct mempool *pool, size_t size) -{ - return mp_alloc_fast(pool, size); -} - -void * -mp_alloc_noalign(struct mempool *pool, size_t size) -{ - return mp_alloc_fast_noalign(pool, size); -} - -void * -mp_alloc_zero(struct mempool *pool, size_t size) -{ - void *ptr = mp_alloc_fast(pool, size); - bzero(ptr, size); - return ptr; -} - -void * -mp_start_internal(struct mempool *pool, size_t size) -{ - void *ptr = mp_alloc_internal(pool, size); - if (!ptr) - return NULL; - pool->state.free[pool->idx] += size; - return ptr; } void * -mp_start(struct mempool *pool, size_t size) -{ - return mp_start_fast(pool, size); -} - -void * -mp_start_noalign(struct mempool *pool, size_t size) -{ - return mp_start_fast_noalign(pool, size); -} - -void * -mp_grow_internal(struct mempool *pool, size_t size) -{ - if (unlikely(size > MP_SIZE_MAX)) - return NULL; - size_t avail = mp_avail(pool); - void *ptr = mp_ptr(pool); - if (pool->idx) - { - size_t amortized = likely(avail <= MP_SIZE_MAX / 2) ? avail * 2 : MP_SIZE_MAX; - amortized = MAX(amortized, size); - amortized = ALIGN_TO(amortized, CPU_STRUCT_ALIGN); - struct mempool_chunk *chunk = pool->state.last[1], *next = chunk->next; - pool->total_size = pool->total_size - chunk->size + amortized; - void *nptr = realloc(ptr, amortized + MP_CHUNK_TAIL); - if (!nptr) - return NULL; - ptr = nptr; - chunk = ptr + amortized; - chunk->next = next; - chunk->size = amortized; - pool->state.last[1] = chunk; - pool->state.free[1] = amortized; - pool->last_big = ptr; - return ptr; - } - else - { - void *p = mp_start_internal(pool, size); - memcpy(p, ptr, avail); - return p; - } -} - -size_t -mp_open(struct mempool *pool, void *ptr) -{ - return mp_open_fast(pool, ptr); -} - -void * -mp_realloc(struct mempool *pool, void *ptr, size_t size) -{ - return mp_realloc_fast(pool, ptr, size); +mp_alloc(struct mempool *pool, unsigned size) +{ + unsigned avail = pool->state.free[0] & ~(CPU_STRUCT_ALIGN - 1); + void *ptr = NULL; + if (size <= avail) { + pool->state.free[0] = avail - size; + ptr = (uint8_t*)pool->state.last[0] - avail; + } else { + ptr = mp_alloc_internal(pool, size); + } + ASAN_UNPOISON_MEMORY_REGION(ptr, size); + return ptr; } void * -mp_realloc_zero(struct mempool *pool, void *ptr, size_t size) -{ - size_t old_size = mp_open_fast(pool, ptr); - ptr = mp_grow(pool, size); - if (size > old_size) - bzero(ptr + old_size, size - old_size); - mp_end(pool, ptr + size); - return ptr; +mp_alloc_noalign(struct mempool *pool, unsigned size) +{ + void *ptr = NULL; + if (size <= pool->state.free[0]) { + ptr = (uint8_t*)pool->state.last[0] - pool->state.free[0]; + pool->state.free[0] -= size; + } else { + ptr = mp_alloc_internal(pool, size); + } + ASAN_UNPOISON_MEMORY_REGION(ptr, size); + return ptr; } void * -mp_spread_internal(struct mempool *pool, void *p, size_t size) -{ - void *old = mp_ptr(pool); - void *new = mp_grow_internal(pool, p-old+size); - if (!new) { - return NULL; - } - return p-old+new; -} - -void -mp_restore(struct mempool *pool, struct mempool_state *state) +mp_alloc_zero(struct mempool *pool, unsigned size) { - struct mempool_chunk *chunk, *next; - struct mempool_state s = *state; - for (chunk = pool->state.last[0]; chunk != s.last[0]; chunk = next) - { - next = chunk->next; - chunk->next = pool->unused; - pool->unused = chunk; - } - for (chunk = pool->state.last[1]; chunk != s.last[1]; chunk = next) - { - next = chunk->next; - mp_free_big_chunk(pool, chunk); - } - pool->state = s; - pool->last_big = &pool->last_big; + void *ptr = mp_alloc(pool, size); + bzero(ptr, size); + return ptr; } - -struct mempool_state * -mp_push(struct mempool *pool) -{ - struct mempool_state state = pool->state; - struct mempool_state *p = mp_alloc_fast(pool, sizeof(*p)); - *p = state; - pool->state.next = p; - return p; -} - -void -mp_pop(struct mempool *pool) -{ - ASSERT(pool->state.next); - mp_restore(pool, pool->state.next); -} - -#ifdef TEST - -#include -#include -#include -#include - -static void -fill(byte *ptr, uint len, uint magic) -{ - while (len--) - *ptr++ = (magic++ & 255); -} - -static void -check(byte *ptr, uint len, uint magic, uint align) -{ - ASSERT(!((uintptr_t)ptr & (align - 1))); - while (len--) - if (*ptr++ != (magic++ & 255)) - ASSERT(0); -} - -int main(int argc, char **argv) -{ - srand(time(NULL)); - log_init(argv[0]); - cf_def_file = NULL; - if (cf_getopt(argc, argv, CF_SHORT_OPTS, CF_NO_LONG_OPTS, NULL) >= 0 || argc != optind) - die("Invalid usage"); - - uint max = 1000, n = 0, m = 0, can_realloc = 0; - void *ptr[max]; - struct mempool_state *state[max]; - uint len[max], num[max], align[max]; - struct mempool *mp = mp_new(128), mp_static; - - for (uint i = 0; i < 5000; i++) - { - for (uint j = 0; j < n; j++) - check(ptr[j], len[j], j, align[j]); -#if 0 - DBG("free_small=%u free_big=%u idx=%u chunk_size=%u last_big=%p", mp->state.free[0], mp->state.free[1], mp->idx, mp->chunk_size, mp->last_big); - for (struct mempool_chunk *ch = mp->state.last[0]; ch; ch = ch->next) - DBG("small %p %p %p %d", (byte *)ch - ch->size, ch, ch + 1, ch->size); - for (struct mempool_chunk *ch = mp->state.last[1]; ch; ch = ch->next) - DBG("big %p %p %p %d", (byte *)ch - ch->size, ch, ch + 1, ch->size); -#endif - int r = random_max(100); - if ((r -= 1) < 0) - { - DBG("flush"); - mp_flush(mp); - n = m = 0; - } - else if ((r -= 1) < 0) - { - DBG("delete & new"); - mp_delete(mp); - if (random_max(2)) - mp = mp_new(random_max(0x1000) + 1); - else - mp = &mp_static, mp_init(mp, random_max(512) + 1); - n = m = 0; - } - else if (n < max && (r -= 30) < 0) - { - len[n] = random_max(0x2000); - DBG("alloc(%u)", len[n]); - align[n] = random_max(2) ? CPU_STRUCT_ALIGN : 1; - ptr[n] = (align[n] == 1) ? mp_alloc_fast_noalign(mp, len[n]) : mp_alloc_fast(mp, len[n]); - DBG(" -> (%p)", ptr[n]); - fill(ptr[n], len[n], n); - n++; - can_realloc = 1; - } - else if (n < max && (r -= 20) < 0) - { - len[n] = random_max(0x2000); - DBG("start(%u)", len[n]); - align[n] = random_max(2) ? CPU_STRUCT_ALIGN : 1; - ptr[n] = (align[n] == 1) ? mp_start_fast_noalign(mp, len[n]) : mp_start_fast(mp, len[n]); - DBG(" -> (%p)", ptr[n]); - fill(ptr[n], len[n], n); - n++; - can_realloc = 1; - goto grow; - } - else if (can_realloc && n && (r -= 10) < 0) - { - if (mp_open(mp, ptr[n - 1]) != len[n - 1]) - ASSERT(0); -grow: - { - uint k = n - 1; - for (uint i = random_max(4); i--; ) - { - uint l = len[k]; - len[k] = random_max(0x2000); - DBG("grow(%u)", len[k]); - ptr[k] = mp_grow(mp, len[k]); - DBG(" -> (%p)", ptr[k]); - check(ptr[k], MIN(l, len[k]), k, align[k]); - fill(ptr[k], len[k], k); - } - mp_end(mp, ptr[k] + len[k]); - } - } - else if (can_realloc && n && (r -= 20) < 0) - { - uint i = n - 1, l = len[i]; - DBG("realloc(%p, %u)", ptr[i], len[i]); - ptr[i] = mp_realloc(mp, ptr[i], len[i] = random_max(0x2000)); - DBG(" -> (%p, %u)", ptr[i], len[i]); - check(ptr[i], MIN(len[i], l), i, align[i]); - fill(ptr[i], len[i], i); - } - else if (m < max && (r -= 5) < 0) - { - DBG("push(%u)", m); - num[m] = n; - state[m++] = mp_push(mp); - can_realloc = 0; - } - else if (m && (r -= 2) < 0) - { - m--; - DBG("pop(%u)", m); - mp_pop(mp); - n = num[m]; - can_realloc = 0; - } - else if (m && (r -= 1) < 0) - { - uint i = random_max(m); - DBG("restore(%u)", i); - mp_restore(mp, state[i]); - n = num[m = i]; - can_realloc = 0; - } - else if (can_realloc && n && (r -= 5) < 0) - ASSERT(mp_size(mp, ptr[n - 1]) == len[n - 1]); - else - { - struct mempool_stats stats; - mp_stats(mp, &stats); - } - } - - mp_delete(mp); - return 0; -} - -#endif diff --git a/contrib/ucw/mempool.h b/contrib/ucw/mempool.h index aa621e346..46dc9d7c6 100644 --- a/contrib/ucw/mempool.h +++ b/contrib/ucw/mempool.h @@ -1,55 +1,25 @@ /* * UCW Library -- Memory Pools * - * (c) 1997--2015 Martin Mares + * (c) 1997--2005 Martin Mares * (c) 2007 Pavel Charvat + * (c) 2015, 2017 CZ.NIC, z.s.p.o. * * This software may be freely distributed and used according to the terms * of the GNU Lesser General Public License. */ -#ifndef _UCW_POOLS_H -#define _UCW_POOLS_H +#pragma once -#include "lib/defines.h" -#include -#include -#include #include +#include + +#include "lib/defines.h" -#ifdef CONFIG_UCW_CLEAN_ABI -#define mp_alloc ucw_mp_alloc -#define mp_alloc_internal ucw_mp_alloc_internal -#define mp_alloc_noalign ucw_mp_alloc_noalign -#define mp_alloc_zero ucw_mp_alloc_zero -#define mp_delete ucw_mp_delete -#define mp_flush ucw_mp_flush -#define mp_grow_internal ucw_mp_grow_internal -#define mp_init ucw_mp_init -#define mp_memdup ucw_mp_memdup -#define mp_multicat ucw_mp_multicat -#define mp_new ucw_mp_new -#define mp_open ucw_mp_open -#define mp_pop ucw_mp_pop -#define mp_printf ucw_mp_printf -#define mp_printf_append ucw_mp_printf_append -#define mp_push ucw_mp_push -#define mp_realloc ucw_mp_realloc -#define mp_realloc_zero ucw_mp_realloc_zero -#define mp_restore ucw_mp_restore -#define mp_shrink ucw_mp_shrink -#define mp_spread_internal ucw_mp_spread_internal -#define mp_start ucw_mp_start -#define mp_start_internal ucw_mp_start_internal -#define mp_start_noalign ucw_mp_start_noalign -#define mp_stats ucw_mp_stats -#define mp_str_from_mem ucw_mp_str_from_mem -#define mp_strdup ucw_mp_strdup -#define mp_strjoin ucw_mp_strjoin -#define mp_total_size ucw_mp_total_size -#define mp_vprintf ucw_mp_vprintf -#define mp_vprintf_append ucw_mp_vprintf_append -#endif +/** \todo This shouldn't be precalculated, but computed on load. */ +#define CPU_PAGE_SIZE 4096 + +#define CPU_STRUCT_ALIGN (sizeof(void*)) /*** * [[defs]] @@ -58,13 +28,12 @@ ***/ /** - * Memory pool state (see @mp_push(), ...). + * Memory pool state (see mp_push(), ...). * You should use this one as an opaque handle only, the insides are internal. **/ struct mempool_state { - size_t free[2]; - void *last[2]; - struct mempool_state *next; + unsigned free[2]; + void *last[2]; }; /** @@ -72,19 +41,15 @@ struct mempool_state { * You should use this one as an opaque handle only, the insides are internal. **/ struct mempool { - struct ucw_allocator allocator; // This must be the first element - struct mempool_state state; - void *unused, *last_big; - size_t chunk_size, threshold; - uint idx; - u64 total_size; + struct mempool_state state; + void *unused, *last_big; + unsigned chunk_size, threshold, idx; }; -struct mempool_stats { /** Mempool statistics. See @mp_stats(). **/ - u64 total_size; /* Real allocated size in bytes */ - u64 used_size; /* Estimated size allocated from mempool to application */ - uint chain_count[3]; /* Number of allocated chunks in small/big/unused chains */ - u64 chain_size[3]; /* Size of allocated chunks in small/big/unused chains */ +struct mempool_stats { /** Mempool statistics. See mp_stats(). **/ + uint64_t total_size; /** Real allocated size in bytes. */ + unsigned chain_count[3]; /** Number of allocated chunks in small/big/unused chains. */ + unsigned chain_size[3]; /** Size of allocated chunks in small/big/unused chains. */ }; /*** @@ -95,62 +60,45 @@ struct mempool_stats { /** Mempool statistics. See @mp_stats(). **/ /** * Initialize a given mempool structure. - * @chunk_size must be in the interval `[1, SIZE_MAX / 2]`. + * \p chunk_size must be in the interval `[1, UINT_MAX / 2]`. * It will allocate memory by this large chunks and take * memory to satisfy requests from them. * * Memory pools can be treated as <>, see <>. **/ -KR_EXPORT -void mp_init(struct mempool *pool, size_t chunk_size); +KR_EXPORT void mp_init(struct mempool *pool, unsigned chunk_size); /** * Allocate and initialize a new memory pool. - * See @mp_init() for @chunk_size limitations. + * See \ref mp_init() for \p chunk_size limitations. * * The new mempool structure is allocated on the new mempool. * * Memory pools can be treated as <>, see <>. **/ -KR_EXPORT -struct mempool *mp_new(size_t chunk_size); +KR_EXPORT struct mempool *mp_new(unsigned chunk_size); /** * Cleanup mempool initialized by mp_init or mp_new. * Frees all the memory allocated by this mempool and, - * if created by @mp_new(), the @pool itself. + * if created by \ref mp_new(), the \p pool itself. **/ -KR_EXPORT -void mp_delete(struct mempool *pool); +KR_EXPORT void mp_delete(struct mempool *pool); /** * Frees all data on a memory pool, but leaves it working. * It can keep some of the chunks allocated to serve - * further allocation requests. Leaves the @pool alive, - * even if it was created with @mp_new(). + * further allocation requests. Leaves the \p pool alive, + * even if it was created with \ref mp_new(). **/ -KR_EXPORT -void mp_flush(struct mempool *pool); +KR_EXPORT void mp_flush(struct mempool *pool); /** * Compute some statistics for debug purposes. * See the definition of the <>. - * This function scans the chunk list, so it can be slow. If you are interested - * in total memory consumption only, mp_total_size() is faster. - **/ -void mp_stats(struct mempool *pool, struct mempool_stats *stats); - -/** - * Return how many bytes were allocated by the pool, including unused parts - * of chunks. This function runs in constant time. - **/ -u64 mp_total_size(struct mempool *pool); - -/** - * Release unused chunks of memory reserved for further allocation - * requests, but stop if mp_total_size() would drop below @min_total_size. **/ -void mp_shrink(struct mempool *pool, u64 min_total_size); +KR_EXPORT void mp_stats(struct mempool *pool, struct mempool_stats *stats); +KR_EXPORT uint64_t mp_total_size(struct mempool *pool); /** How many bytes were allocated by the pool. **/ /*** * [[alloc]] @@ -158,12 +106,9 @@ void mp_shrink(struct mempool *pool, u64 min_total_size); * ------------------- ***/ -/* For internal use only, do not call directly */ -void *mp_alloc_internal(struct mempool *pool, size_t size) LIKE_MALLOC; - /** - * The function allocates new @size bytes on a given memory pool. - * If the @size is zero, the resulting pointer is undefined, + * The function allocates new \p size bytes on a given memory pool. + * If the \p size is zero, the resulting pointer is undefined, * but it may be safely reallocated or used as the parameter * to other functions below. * @@ -171,403 +116,14 @@ void *mp_alloc_internal(struct mempool *pool, size_t size) LIKE_MALLOC; * `CPU_STRUCT_ALIGN` bytes and this condition remains true also * after future reallocations. **/ -KR_EXPORT -void *mp_alloc(struct mempool *pool, size_t size); - -/** - * The same as @mp_alloc(), but the result may be unaligned. - **/ -void *mp_alloc_noalign(struct mempool *pool, size_t size); - -/** - * The same as @mp_alloc(), but fills the newly allocated memory with zeroes. - **/ -void *mp_alloc_zero(struct mempool *pool, size_t size); - -/** - * Inlined version of @mp_alloc(). - **/ -static inline void *mp_alloc_fast(struct mempool *pool, size_t size) -{ - size_t avail = pool->state.free[0] & ~(size_t)(CPU_STRUCT_ALIGN - 1); - if (size <= avail) - { - pool->state.free[0] = avail - size; - return (byte *)pool->state.last[0] - avail; - } - else - return mp_alloc_internal(pool, size); -} - -/** - * Inlined version of @mp_alloc_noalign(). - **/ -static inline void *mp_alloc_fast_noalign(struct mempool *pool, size_t size) -{ - if (size <= pool->state.free[0]) - { - void *ptr = (byte *)pool->state.last[0] - pool->state.free[0]; - pool->state.free[0] -= size; - return ptr; - } - else - return mp_alloc_internal(pool, size); -} - -/** - * Return a generic allocator representing the given mempool. - **/ -static inline struct ucw_allocator *mp_get_allocator(struct mempool *mp) -{ - return &mp->allocator; -} - -/*** - * [[gbuf]] - * Growing buffers - * --------------- - * - * You do not need to know, how a buffer will need to be large, - * you can grow it incrementally to needed size. You can grow only - * one buffer at a time on a given mempool. - * - * Similar functionality is provided by <> module. - ***/ - -/* For internal use only, do not call directly */ -void *mp_start_internal(struct mempool *pool, size_t size) LIKE_MALLOC; -void *mp_grow_internal(struct mempool *pool, size_t size); -void *mp_spread_internal(struct mempool *pool, void *p, size_t size); - -static inline uint mp_idx(struct mempool *pool, void *ptr) -{ - return ptr == pool->last_big; -} - -/** - * Open a new growing buffer (at least @size bytes long). - * If the @size is zero, the resulting pointer is undefined, - * but it may be safely reallocated or used as the parameter - * to other functions below. - * - * The resulting pointer is always aligned to a multiple of - * `CPU_STRUCT_ALIGN` bytes and this condition remains true also - * after future reallocations. There is an unaligned version as well. - * - * Keep in mind that you can't make any other pool allocations - * before you "close" the growing buffer with @mp_end(). - */ -void *mp_start(struct mempool *pool, size_t size); -void *mp_start_noalign(struct mempool *pool, size_t size); - -/** - * Inlined version of @mp_start(). - **/ -static inline void *mp_start_fast(struct mempool *pool, size_t size) -{ - size_t avail = pool->state.free[0] & ~(size_t)(CPU_STRUCT_ALIGN - 1); - if (size <= avail) - { - pool->idx = 0; - pool->state.free[0] = avail; - return (byte *)pool->state.last[0] - avail; - } - else - return mp_start_internal(pool, size); -} +KR_EXPORT void *mp_alloc(struct mempool *pool, unsigned size); /** - * Inlined version of @mp_start_noalign(). + * The same as \ref mp_alloc(), but the result may be unaligned. **/ -static inline void *mp_start_fast_noalign(struct mempool *pool, size_t size) -{ - if (size <= pool->state.free[0]) - { - pool->idx = 0; - return (byte *)pool->state.last[0] - pool->state.free[0]; - } - else - return mp_start_internal(pool, size); -} - -/** - * Return start pointer of the growing buffer allocated by latest @mp_start() or a similar function. - **/ -static inline void *mp_ptr(struct mempool *pool) -{ - return (byte *)pool->state.last[pool->idx] - pool->state.free[pool->idx]; -} - -/** - * Return the number of bytes available for extending the growing buffer. - * (Before a reallocation will be needed). - **/ -static inline size_t mp_avail(struct mempool *pool) -{ - return pool->state.free[pool->idx]; -} - -/** - * Grow the buffer allocated by @mp_start() to be at least @size bytes long - * (@size may be less than @mp_avail(), even zero). Reallocated buffer may - * change its starting position. The content will be unchanged to the minimum - * of the old and new sizes; newly allocated memory will be uninitialized. - * Multiple calls to mp_grow() have amortized linear cost wrt. the maximum value of @size. */ -static inline void *mp_grow(struct mempool *pool, size_t size) -{ - return (size <= mp_avail(pool)) ? mp_ptr(pool) : mp_grow_internal(pool, size); -} +KR_EXPORT void *mp_alloc_noalign(struct mempool *pool, unsigned size); /** - * Grow the buffer by at least one byte -- equivalent to <>`(@pool, @mp_avail(pool) + 1)`. + * The same as \ref mp_alloc(), but fills the newly allocated memory with zeroes. **/ -static inline void *mp_expand(struct mempool *pool) -{ - return mp_grow_internal(pool, mp_avail(pool) + 1); -} - -/** - * Ensure that there is at least @size bytes free after @p, - * if not, reallocate and adjust @p. - **/ -static inline void *mp_spread(struct mempool *pool, void *p, size_t size) -{ - return (((size_t)((byte *)pool->state.last[pool->idx] - (byte *)p) >= size) ? p : mp_spread_internal(pool, p, size)); -} - -/** - * Append a character to the growing buffer. Called with @p pointing after - * the last byte in the buffer, returns a pointer after the last byte - * of the new (possibly reallocated) buffer. - **/ -static inline char *mp_append_char(struct mempool *pool, char *p, uint c) -{ - p = mp_spread(pool, p, 1); - *p++ = c; - return p; -} - -/** - * Append a memory block to the growing buffer. Called with @p pointing after - * the last byte in the buffer, returns a pointer after the last byte - * of the new (possibly reallocated) buffer. - **/ -static inline void *mp_append_block(struct mempool *pool, void *p, const void *block, size_t size) -{ - char *q = mp_spread(pool, p, size); - memcpy(q, block, size); - return q + size; -} - -/** - * Append a string to the growing buffer. Called with @p pointing after - * the last byte in the buffer, returns a pointer after the last byte - * of the new (possibly reallocated) buffer. - **/ -static inline void *mp_append_string(struct mempool *pool, void *p, const char *str) -{ - return mp_append_block(pool, p, str, strlen(str)); -} - -/** - * Close the growing buffer. The @end must point just behind the data, you want to keep - * allocated (so it can be in the interval `[@mp_ptr(@pool), @mp_ptr(@pool) + @mp_avail(@pool)]`). - * Returns a pointer to the beginning of the just closed block. - **/ -static inline void *mp_end(struct mempool *pool, void *end) -{ - void *p = mp_ptr(pool); - pool->state.free[pool->idx] = (byte *)pool->state.last[pool->idx] - (byte *)end; - return p; -} - -/** - * Close the growing buffer as a string. That is, append a zero byte and call mp_end(). - **/ -static inline char *mp_end_string(struct mempool *pool, void *end) -{ - end = mp_append_char(pool, end, 0); - return mp_end(pool, end); -} - -/** - * Return size in bytes of the last allocated memory block (with @mp_alloc() or @mp_end()). - **/ -static inline size_t mp_size(struct mempool *pool, void *ptr) -{ - uint idx = mp_idx(pool, ptr); - return ((byte *)pool->state.last[idx] - (byte *)ptr) - pool->state.free[idx]; -} - -/** - * Open the last memory block (allocated with @mp_alloc() or @mp_end()) - * for growing and return its size in bytes. The contents and the start pointer - * remain unchanged. Do not forget to call @mp_end() to close it. - **/ -size_t mp_open(struct mempool *pool, void *ptr); - -/** - * Inlined version of @mp_open(). - **/ -static inline size_t mp_open_fast(struct mempool *pool, void *ptr) -{ - pool->idx = mp_idx(pool, ptr); - size_t size = ((byte *)pool->state.last[pool->idx] - (byte *)ptr) - pool->state.free[pool->idx]; - pool->state.free[pool->idx] += size; - return size; -} - -/** - * Reallocate the last memory block (allocated with @mp_alloc() or @mp_end()) - * to the new @size. Behavior is similar to @mp_grow(), but the resulting - * block is closed. - **/ -void *mp_realloc(struct mempool *pool, void *ptr, size_t size); - -/** - * The same as @mp_realloc(), but fills the additional bytes (if any) with zeroes. - **/ -void *mp_realloc_zero(struct mempool *pool, void *ptr, size_t size); - -/** - * Inlined version of @mp_realloc(). - **/ -static inline void *mp_realloc_fast(struct mempool *pool, void *ptr, size_t size) -{ - mp_open_fast(pool, ptr); - ptr = mp_grow(pool, size); - mp_end(pool, (byte *)ptr + size); - return ptr; -} - -/*** - * [[store]] - * Storing and restoring state - * --------------------------- - * - * Mempools can remember history of what was allocated and return back - * in time. - ***/ - -/** - * Save the current state of a memory pool. - * Do not call this function with an opened growing buffer. - **/ -static inline void mp_save(struct mempool *pool, struct mempool_state *state) -{ - *state = pool->state; - pool->state.next = state; -} - -/** - * Save the current state to a newly allocated mempool_state structure. - * Do not call this function with an opened growing buffer. - **/ -struct mempool_state *mp_push(struct mempool *pool); - -/** - * Restore the state saved by @mp_save() or @mp_push() and free all - * data allocated after that point (including the state structure itself). - * You can't reallocate the last memory block from the saved state. - **/ -void mp_restore(struct mempool *pool, struct mempool_state *state); - -/** - * Inlined version of @mp_restore(). - **/ -static inline void mp_restore_fast(struct mempool *pool, struct mempool_state *state) -{ - if (pool->state.last[0] != state->last[0] || pool->state.last[1] != state->last[1]) - mp_restore(pool, state); - else - { - pool->state = *state; - pool->last_big = &pool->last_big; - } -} - -/** - * Restore the state saved by the last call to @mp_push(). - * @mp_pop() and @mp_push() works as a stack so you can push more states safely. - **/ -void mp_pop(struct mempool *pool); - - -/*** - * [[string]] - * String operations - * ----------------- - ***/ - -char *mp_strdup(struct mempool *, const char *) LIKE_MALLOC; /** Makes a copy of a string on a mempool. Returns NULL for NULL string. **/ -void *mp_memdup(struct mempool *, const void *, size_t) LIKE_MALLOC; /** Makes a copy of a memory block on a mempool. **/ -/** - * Concatenates all passed strings. The last parameter must be NULL. - * This will concatenate two strings: - * - * char *message = mp_multicat(pool, "hello ", "world", NULL); - **/ -char *mp_multicat(struct mempool *, ...) LIKE_MALLOC SENTINEL_CHECK; -/** - * Concatenates two strings and stores result on @mp. - */ -static inline char *LIKE_MALLOC mp_strcat(struct mempool *mp, const char *x, const char *y) -{ - return mp_multicat(mp, x, y, NULL); -} -/** - * Join strings and place @sep between each two neighboring. - * @p is the mempool to provide memory, @a is array of strings and @n - * tells how many there is of them. - **/ -char *mp_strjoin(struct mempool *p, char **a, uint n, uint sep) LIKE_MALLOC; -/** - * Convert memory block to a string. Makes a copy of the given memory block - * in the mempool @p, adding an extra terminating zero byte at the end. - **/ -char *mp_str_from_mem(struct mempool *p, const void *mem, size_t len) LIKE_MALLOC; - - -/*** - * [[format]] - * Formatted output - * --------------- - ***/ - -/** - * printf() into a in-memory string, allocated on the memory pool. - **/ -KR_EXPORT -char *mp_printf(struct mempool *mp, const char *fmt, ...) FORMAT_CHECK(printf,2,3) LIKE_MALLOC; -/** - * Like @mp_printf(), but uses `va_list` for parameters. - **/ -char *mp_vprintf(struct mempool *mp, const char *fmt, va_list args) LIKE_MALLOC; -/** - * Like @mp_printf(), but it appends the data at the end of string - * pointed to by @ptr. The string is @mp_open()ed, so you have to - * provide something that can be. - * - * Returns pointer to the beginning of the string (the pointer may have - * changed due to reallocation). - * - * In some versions of LibUCW, this function was called mp_append_printf(). However, - * this name turned out to be confusing -- unlike other appending functions, this one is - * not called on an opened growing buffer. The old name will be preserved for backward - * compatibility for the time being. - **/ -KR_EXPORT -char *mp_printf_append(struct mempool *mp, char *ptr, const char *fmt, ...) FORMAT_CHECK(printf,3,4); -#define mp_append_printf mp_printf_append -/** - * Like @mp_printf_append(), but uses `va_list` for parameters. - * - * In some versions of LibUCW, this function was called mp_append_vprintf(). However, - * this name turned out to be confusing -- unlike other appending functions, this one is - * not called on an opened growing buffer. The old name will be preserved for backward - * compatibility for the time being. - **/ -char *mp_vprintf_append(struct mempool *mp, char *ptr, const char *fmt, va_list args); -#define mp_append_vprintf mp_vprintf_append - -#endif +KR_EXPORT void *mp_alloc_zero(struct mempool *pool, unsigned size); diff --git a/daemon/io.c b/daemon/io.c index 7c406bea4..9056528c9 100644 --- a/daemon/io.c +++ b/daemon/io.c @@ -16,7 +16,6 @@ #include #include -#include #include #include diff --git a/daemon/session.c b/daemon/session.c index c870d8cd4..a97af4e6e 100644 --- a/daemon/session.c +++ b/daemon/session.c @@ -18,6 +18,7 @@ #include +#include "contrib/macros.h" #include "lib/defines.h" #include "daemon/session.h" #include "daemon/engine.h" @@ -698,16 +699,6 @@ size_t session_wirebuf_get_free_size(struct session *session) return session->wire_buf_size - session->wire_buf_end_idx; } -void session_poison(struct session *session) -{ - kr_asan_poison(session, sizeof(*session)); -} - -void session_unpoison(struct session *session) -{ - kr_asan_unpoison(session, sizeof(*session)); -} - int session_wirebuf_process(struct session *session) { int ret = 0; diff --git a/daemon/session.h b/daemon/session.h index 7b261a4c1..ecf4f12e9 100644 --- a/daemon/session.h +++ b/daemon/session.h @@ -133,11 +133,6 @@ int session_wirebuf_process(struct session *session); ssize_t session_wirebuf_consume(struct session *session, const uint8_t *data, ssize_t len); -/** poison session structure with ASAN. */ -void session_poison(struct session *session); -/** unpoison session structure with ASAN. */ -void session_unpoison(struct session *session); - knot_pkt_t *session_produce_packet(struct session *session, knot_mm_t *mm); int session_discard_packet(struct session *session, const knot_pkt_t *pkt); diff --git a/daemon/tls.c b/daemon/tls.c index f88267626..a2b102234 100644 --- a/daemon/tls.c +++ b/daemon/tls.c @@ -29,8 +29,8 @@ #include #include -#include "contrib/ucw/lib.h" #include "contrib/base64.h" +#include "contrib/macros.h" #include "daemon/io.h" #include "daemon/tls.h" #include "daemon/worker.h" diff --git a/daemon/udp_queue.c b/daemon/udp_queue.c index 586f64d97..df26ae60c 100644 --- a/daemon/udp_queue.c +++ b/daemon/udp_queue.c @@ -17,6 +17,7 @@ #include "kresconfig.h" #include "daemon/udp_queue.h" +#include "contrib/macros.h" #include "daemon/session.h" #include "daemon/worker.h" #include "lib/generic/array.h" diff --git a/daemon/worker.c b/daemon/worker.c index 0cbbcc7c0..23abe92fd 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include #if defined(__GLIBC__) && defined(_GNU_SOURCE) @@ -197,30 +197,6 @@ static void ioreq_kill_pending(struct qr_task *task) task->pending_count = 0; } -/** @cond This memory layout is internal to mempool.c, use only for debugging. */ -#if defined(__SANITIZE_ADDRESS__) -struct mempool_chunk { - struct mempool_chunk *next; - size_t size; -}; -static void mp_poison(struct mempool *mp, bool poison) -{ - if (!poison) { /* @note mempool is part of the first chunk, unpoison it first */ - kr_asan_unpoison(mp, sizeof(*mp)); - } - struct mempool_chunk *chunk = mp->state.last[0]; - void *chunk_off = (uint8_t *)chunk - chunk->size; - if (poison) { - kr_asan_poison(chunk_off, chunk->size); - } else { - kr_asan_unpoison(chunk_off, chunk->size); - } -} -#else -#define mp_poison(mp, enable) -#endif -/** @endcond */ - /** Get a mempool. (Recycle if possible.) */ static inline struct mempool *pool_borrow(struct worker_ctx *worker) { @@ -228,7 +204,6 @@ static inline struct mempool *pool_borrow(struct worker_ctx *worker) if (worker->pool_mp.len > 0) { mp = array_tail(worker->pool_mp); array_pop(worker->pool_mp); - mp_poison(mp, 0); } else { /* No mempool on the freelist, create new one */ mp = mp_new (4 * CPU_PAGE_SIZE); } @@ -241,7 +216,6 @@ static inline void pool_release(struct worker_ctx *worker, struct mempool *mp) if (worker->pool_mp.len < MP_FREELIST_SIZE) { mp_flush(mp); array_push(worker->pool_mp, mp); - mp_poison(mp, 1); } else { mp_delete(mp); } @@ -2013,7 +1987,6 @@ static inline void reclaim_mp_freelist(mp_freelist_t *list) { for (unsigned i = 0; i < list->len; ++i) { struct mempool *e = list->at[i]; - kr_asan_unpoison(e, sizeof(*e)); mp_delete(e); } array_clear(*list); diff --git a/lib/cache/api.c b/lib/cache/api.c index ece97b96d..adc3f3196 100644 --- a/lib/cache/api.c +++ b/lib/cache/api.c @@ -29,7 +29,7 @@ #include "contrib/base32hex.h" #include "contrib/cleanup.h" -#include "contrib/ucw/lib.h" +#include "contrib/macros.h" #include "lib/cache/api.h" #include "lib/cache/cdb_lmdb.h" #include "lib/defines.h" diff --git a/lib/cache/api.h b/lib/cache/api.h index aa34eaa94..029e10008 100644 --- a/lib/cache/api.h +++ b/lib/cache/api.h @@ -21,7 +21,6 @@ #include #include "lib/cache/cdb_api.h" #include "lib/defines.h" -#include "contrib/ucw/config.h" /*uint*/ /** When knot_pkt is passed from cache without ->wire, this is the ->size. */ static const size_t PKT_SIZE_NOWIRE = -1; diff --git a/lib/cache/cdb_lmdb.c b/lib/cache/cdb_lmdb.c index 481296358..7f330763d 100644 --- a/lib/cache/cdb_lmdb.c +++ b/lib/cache/cdb_lmdb.c @@ -25,7 +25,7 @@ #include #include "contrib/cleanup.h" -#include "contrib/ucw/lib.h" +#include "contrib/macros.h" #include "lib/cache/cdb_lmdb.h" #include "lib/cache/cdb_api.h" #include "lib/cache/api.h" diff --git a/lib/cache/entry_pkt.c b/lib/cache/entry_pkt.c index e2fc2689b..3f1ea0590 100644 --- a/lib/cache/entry_pkt.c +++ b/lib/cache/entry_pkt.c @@ -20,6 +20,7 @@ * The packet is stashed in entry_h::data as uint16_t length + full packet wire format. */ +#include "contrib/macros.h" #include "lib/utils.h" #include "lib/layer/iterate.h" /* kr_response_classify */ #include "lib/cache/impl.h" diff --git a/lib/cache/knot_pkt.c b/lib/cache/knot_pkt.c index 56836a60a..e66a25d4f 100644 --- a/lib/cache/knot_pkt.c +++ b/lib/cache/knot_pkt.c @@ -19,6 +19,7 @@ * Prototypes in ./impl.h */ +#include "contrib/macros.h" #include "lib/cache/impl.h" int pkt_renew(knot_pkt_t *pkt, const knot_dname_t *name, uint16_t type) diff --git a/lib/cache/nsec1.c b/lib/cache/nsec1.c index 74b3d349d..590639198 100644 --- a/lib/cache/nsec1.c +++ b/lib/cache/nsec1.c @@ -18,6 +18,8 @@ * Implementation of NSEC (1) handling. Prototypes in ./impl.h */ +#include "contrib/macros.h" + #include "lib/cache/impl.h" #include "lib/dnssec/nsec.h" #include "lib/layer/iterate.h" diff --git a/lib/cache/nsec3.c b/lib/cache/nsec3.c index d2ae72a6d..8f3e51b1b 100644 --- a/lib/cache/nsec3.c +++ b/lib/cache/nsec3.c @@ -21,6 +21,7 @@ #include "lib/cache/impl.h" #include "contrib/base32hex.h" +#include "contrib/macros.h" #include "lib/dnssec/nsec.h" #include "lib/layer/iterate.h" diff --git a/lib/cache/peek.c b/lib/cache/peek.c index 558a594ab..ae710b6f4 100644 --- a/lib/cache/peek.c +++ b/lib/cache/peek.c @@ -16,6 +16,7 @@ #include "lib/cache/impl.h" +#include "contrib/macros.h" #include "lib/dnssec/ta.h" #include "lib/layer/iterate.h" diff --git a/lib/defines.h b/lib/defines.h index 37750c59a..81c4525d8 100644 --- a/lib/defines.h +++ b/lib/defines.h @@ -86,19 +86,6 @@ static inline int KR_COLD kr_error(int x) { # define __SANITIZE_ADDRESS__ 1 # endif #endif -#if defined(__SANITIZE_ADDRESS__) -void __asan_poison_memory_region(void const volatile *addr, size_t size); -void __asan_unpoison_memory_region(void const volatile *addr, size_t size); -#define kr_asan_poison(addr, size) __asan_poison_memory_region((addr), (size)) -#define kr_asan_unpoison(addr, size) __asan_unpoison_memory_region((addr), (size)) -#define kr_asan_custom_poison(fn, addr) fn ##_poison((addr)) -#define kr_asan_custom_unpoison(fn, addr) fn ##_unpoison((addr)) -#else -#define kr_asan_poison(addr, size) -#define kr_asan_unpoison(addr, size) -#define kr_asan_custom_poison(fn, addr) -#define kr_asan_custom_unpoison(fn, addr) -#endif #if defined(__SANITIZE_ADDRESS__) && defined(_FORTIFY_SOURCE) #error "You can't use address sanitizer with _FORTIFY_SOURCE" diff --git a/lib/generic/lru.c b/lib/generic/lru.c index b2d02f0a1..f760681b6 100644 --- a/lib/generic/lru.c +++ b/lib/generic/lru.c @@ -15,6 +15,7 @@ */ #include "lib/generic/lru.h" +#include "contrib/macros.h" #include "contrib/murmurhash3/murmurhash3.h" #include "contrib/ucw/mempool.h" diff --git a/lib/generic/lru.h b/lib/generic/lru.h index 135419a9d..95d6b187c 100644 --- a/lib/generic/lru.h +++ b/lib/generic/lru.h @@ -68,7 +68,6 @@ #include #include -#include "contrib/ucw/lib.h" #include "lib/utils.h" #include "libknot/mm_ctx.h" diff --git a/lib/generic/queue.c b/lib/generic/queue.c index 45657c7c5..72c76d16a 100644 --- a/lib/generic/queue.c +++ b/lib/generic/queue.c @@ -14,6 +14,7 @@ along with this program. If not, see . */ +#include "contrib/macros.h" #include "lib/generic/queue.h" #include diff --git a/lib/generic/queue.h b/lib/generic/queue.h index 755e7594d..797fc6405 100644 --- a/lib/generic/queue.h +++ b/lib/generic/queue.h @@ -66,7 +66,7 @@ #pragma once #include "lib/defines.h" -#include "contrib/ucw/lib.h" +#include "contrib/macros.h" #include #include #include diff --git a/lib/generic/trie.c b/lib/generic/trie.c index 41e9acc1a..737db567e 100644 --- a/lib/generic/trie.c +++ b/lib/generic/trie.c @@ -23,7 +23,7 @@ #include "lib/generic/trie.h" #include "lib/utils.h" -#include "contrib/ucw/lib.h" +#include "contrib/macros.h" #if defined(__i386) || defined(__x86_64) || defined(_M_IX86) \ || (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN) \ diff --git a/lib/layer/iterate.c b/lib/layer/iterate.c index 069b34f0e..c58099e10 100644 --- a/lib/layer/iterate.c +++ b/lib/layer/iterate.c @@ -37,6 +37,7 @@ #include #include "kresconfig.h" +#include "contrib/macros.h" #include "lib/layer/iterate.h" #include "lib/resolve.h" #include "lib/rplan.h" diff --git a/lib/nsrep.c b/lib/nsrep.c index 77ef7b802..0852ac40e 100644 --- a/lib/nsrep.c +++ b/lib/nsrep.c @@ -21,12 +21,12 @@ #include +#include "contrib/macros.h" #include "lib/nsrep.h" #include "lib/rplan.h" #include "lib/resolve.h" #include "lib/defines.h" #include "lib/generic/pack.h" -#include "contrib/ucw/lib.h" /** Some built-in unfairness ... */ #ifndef FAVOUR_IPV6 diff --git a/lib/resolve.c b/lib/resolve.c index 6ef20979a..e0b6a97be 100644 --- a/lib/resolve.c +++ b/lib/resolve.c @@ -24,6 +24,7 @@ #include #include #include "kresconfig.h" +#include "contrib/macros.h" #include "lib/resolve.h" #include "lib/layer.h" #include "lib/rplan.h" diff --git a/lib/utils.c b/lib/utils.c index 0725083ff..53186a647 100644 --- a/lib/utils.c +++ b/lib/utils.c @@ -19,6 +19,7 @@ #include "contrib/ccan/asprintf/asprintf.h" #include "contrib/cleanup.h" #include "contrib/ucw/mempool.h" +#include "contrib/macros.h" #include "kresconfig.h" #include "lib/defines.h" #include "lib/generic/array.h" @@ -838,7 +839,10 @@ static void flags_to_str(char *dst, const knot_pkt_t *pkt, size_t maxlen) dst[offset] = 0; } -static char *print_section_opt(struct mempool *mp, char *endp, const knot_rrset_t *rr, const uint8_t rcode) +/** + * Caller must free() strung returned in printp argument. + */ +static int print_section_opt(char *outstr, int outsize, const knot_rrset_t *rr, const uint8_t rcode) { uint8_t ercode = knot_edns_get_ext_rcode(rr); uint16_t ext_rcode_id = knot_edns_whole_rcode(ercode, rcode); @@ -854,7 +858,7 @@ static char *print_section_opt(struct mempool *mp, char *endp, const knot_rrset_ } } - return mp_printf_append(mp, endp, + return snprintf(outstr, outsize, ";; EDNS PSEUDOSECTION:\n;; " "Version: %u; flags: %s; UDP size: %u B; ext-rcode: %s\n\n", knot_edns_get_version(rr), @@ -864,14 +868,12 @@ static char *print_section_opt(struct mempool *mp, char *endp, const knot_rrset_ } -char *kr_pkt_text(const knot_pkt_t *pkt) +static int kr_pkt_text_internal(char *outstr, int outsize, const knot_pkt_t *pkt) { if (!pkt) { - return NULL; + return -1; } - struct mempool *mp = mp_new(512); - static const char * snames[] = { ";; ANSWER SECTION", ";; AUTHORITY SECTION", ";; ADDITIONAL SECTION" }; @@ -884,6 +886,8 @@ char *kr_pkt_text(const knot_pkt_t *pkt) const knot_lookup_t *opcode = knot_lookup_by_id(knot_opcode_names, pkt_opcode); uint16_t qry_id = knot_wire_get_id(pkt->wire); uint16_t qdcount = knot_wire_get_qdcount(pkt->wire); + int totalsize = 0; + int remainingsize = outsize; if (rcode != NULL) { rcode_str = rcode->name; @@ -893,7 +897,7 @@ char *kr_pkt_text(const knot_pkt_t *pkt) } flags_to_str(flags, pkt, sizeof(flags)); - char *ptr = mp_printf(mp, + totalsize = snprintf(outstr, remainingsize, ";; ->>HEADER<<- opcode: %s; status: %s; id: %hu\n" ";; Flags: %s QUERY: %hu; ANSWER: %hu; " "AUTHORITY: %hu; ADDITIONAL: %hu\n\n", @@ -903,18 +907,24 @@ char *kr_pkt_text(const knot_pkt_t *pkt) knot_wire_get_ancount(pkt->wire), knot_wire_get_nscount(pkt->wire), knot_wire_get_arcount(pkt->wire)); + remainingsize = MAX(outsize - totalsize, 0); if (knot_pkt_has_edns(pkt)) { - ptr = print_section_opt(mp, ptr, pkt->opt_rr, knot_wire_get_rcode(pkt->wire)); + totalsize += print_section_opt(outstr + totalsize, remainingsize, + pkt->opt_rr, knot_wire_get_rcode(pkt->wire)); + remainingsize = MAX(outsize - totalsize, 0); } if (qdcount == 1) { KR_DNAME_GET_STR(qname, knot_pkt_qname(pkt)); KR_RRTYPE_GET_STR(rrtype, knot_pkt_qtype(pkt)); - ptr = mp_printf_append(mp, ptr, ";; QUESTION SECTION\n%s\t\t%s\n", qname, rrtype); + totalsize += snprintf(outstr + totalsize, remainingsize, + ";; QUESTION SECTION\n%s\t\t%s\n", qname, rrtype); } else if (qdcount > 1) { - ptr = mp_printf_append(mp, ptr, ";; Warning: unsupported QDCOUNT %hu\n", qdcount); + totalsize += snprintf(outstr + totalsize, remainingsize, + ";; Warning: unsupported QDCOUNT %hu\n", qdcount); } + remainingsize = MAX(outsize - totalsize, 0); for (knot_section_t i = KNOT_ANSWER; i <= KNOT_ADDITIONAL; ++i) { const knot_pktsection_t *sec = knot_pkt_section(pkt, i); @@ -923,23 +933,43 @@ char *kr_pkt_text(const knot_pkt_t *pkt) continue; } - ptr = mp_printf_append(mp, ptr, "\n%s\n", snames[i - KNOT_ANSWER]); + totalsize += snprintf(outstr + totalsize, remainingsize, "\n%s\n", snames[i - KNOT_ANSWER]); + remainingsize = MAX(outsize - totalsize, 0); for (unsigned k = 0; k < sec->count; ++k) { const knot_rrset_t *rr = knot_pkt_rr(sec, k); if (rr->type == KNOT_RRTYPE_OPT) { continue; } auto_free char *rr_text = kr_rrset_text(rr); - ptr = mp_printf_append(mp, ptr, "%s", rr_text); + totalsize += snprintf(outstr + totalsize, remainingsize, "%s", rr_text); + remainingsize = MAX(outsize - totalsize, 0); } } + return totalsize; +} - /* Close growing buffer and duplicate result before deleting */ - char *result = strdup(ptr); - mp_delete(mp); - return result; +char *kr_pkt_text(const knot_pkt_t *pkt) +{ + if (!pkt) { + return NULL; + } + int bufsize = 2048; + while (1) { + int strsize; + auto_free char *buf = malloc(bufsize); + if (!buf) + return NULL; + strsize = kr_pkt_text_internal(buf, bufsize, pkt); + if(strsize < bufsize) + return strdup(buf); + else + /* reallocate and try again */ + bufsize = strsize + 1; + }; } + + char *kr_rrset_text(const knot_rrset_t *rr) { if (!rr) { diff --git a/lib/zonecut.c b/lib/zonecut.c index 248a4c5ce..a9220a111 100644 --- a/lib/zonecut.c +++ b/lib/zonecut.c @@ -17,6 +17,7 @@ #include "lib/zonecut.h" #include "contrib/cleanup.h" +#include "contrib/macros.h" #include "lib/defines.h" #include "lib/generic/pack.h" #include "lib/layer.h"