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
#include <sys/time.h>
#include <unistd.h>
-#include "contrib/ucw/lib.h"
+#include "contrib/macros.h"
#include "daemon/engine.h"
#include "lib/nsrep.h"
--- /dev/null
+/* Copyright (C) 2015 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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 <https://www.gnu.org/licenses/>.
+ */
+
+#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
--- /dev/null
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ 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 <https://www.gnu.org/licenses/>.
+ */
+
+/*!
+ * \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
'ccan/ilog/ilog.c',
'ccan/json/json.c',
'ucw/mempool.c',
- 'ucw/mempool-fmt.c',
'murmurhash3/murmurhash3.c',
'base32hex.c',
'base64.c'
+++ /dev/null
-/*
- * UCW Library -- Generic allocators
- *
- * (c) 2014 Martin Mares <mj@ucw.cz>
- */
-
-#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 <<basics:xmalloc()>>, <<basics:xrealloc()>> and <<basics:xfree()>>. The memory
- * it allocates is left unitialized.
- **/
-extern struct ucw_allocator ucw_allocator_std;
-
-/**
- * [[zeroing]]
- * This allocator uses <<basics:xmalloc()>>, <<basics:xrealloc()>> and <<basics:xfree()>>. All memory
- * is zeroed upon allocation.
- **/
-extern struct ucw_allocator ucw_allocator_zeroed;
-
-#endif
+++ /dev/null
-/*
- * UCW Library -- Configuration-Dependent Definitions
- *
- * (c) 1997--2012 Martin Mares <mj@ucw.cz>
- * (c) 2006 Robert Spalek <robert@ucw.cz>
- *
- * 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 <stddef.h>
-#include <stdint.h>
-
-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
+++ /dev/null
-/*
- * The UCW Library -- Miscellaneous Functions
- *
- * (c) 1997--2014 Martin Mares <mj@ucw.cz>
- * (c) 2005--2014 Tomas Valla <tom@ucw.cz>
- * (c) 2006 Robert Spalek <robert@ucw.cz>
- * (c) 2007 Pavel Charvat <pchar@ucw.cz>
- *
- * 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 <stdarg.h>
-#include <stdbool.h>
-#include <stdlib.h>
-
-#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 <<log:,Logging>> and <ucw/log.h> for more)
- ***/
-
-#define DBG(x, ...) do { } while(0)
-#define DBG_SPOT do { } while(0)
-#define ASSERT(x)
-
-#endif
+++ /dev/null
-/*
- * UCW Library -- Memory Pools (Formatting)
- *
- * (c) 2005 Martin Mares <mj@ucw.cz>
- * (c) 2007 Pavel Charvat <pchar@ucw.cz>
- *
- * This software may be freely distributed and used according to the terms
- * of the GNU Lesser General Public License.
- */
-
-#include <ucw/lib.h>
-#include <ucw/mempool.h>
-
-#include <stdio.h>
-#include <string.h>
-
-/* 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, "<Hello, %s!>", "World");
- fputs(x, stdout);
- x = mp_printf_append(mp, x, "<Appended>");
- fputs(x, stdout);
- x = mp_printf(mp, "<Hello, %50s!>\n", "World");
- fputs(x, stdout);
- return 0;
-}
-
-#endif
/*
* UCW Library -- Memory Pools (One-Time Allocation)
*
- * (c) 1997--2014 Martin Mares <mj@ucw.cz>
- * (c) 2007--2015 Pavel Charvat <pchar@ucw.cz>
+ * (c) 1997--2001 Martin Mares <mj@ucw.cz>
+ * (c) 2007 Pavel Charvat <pchar@ucw.cz>
+ * (c) 2015, 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
*
* This software may be freely distributed and used according to the terms
* of the GNU Lesser General Public License.
#undef LOCAL_DEBUG
-#include <ucw/config.h>
-#include <ucw/lib.h>
-#include <ucw/alloc.h>
-#include <ucw/mempool.h>
-
#include <string.h>
+#include <strings.h>
#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#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 <sys/mman.h>
+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 <ucw/getopt.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <time.h>
-
-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
/*
* UCW Library -- Memory Pools
*
- * (c) 1997--2015 Martin Mares <mj@ucw.cz>
+ * (c) 1997--2005 Martin Mares <mj@ucw.cz>
* (c) 2007 Pavel Charvat <pchar@ucw.cz>
+ * (c) 2015, 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
*
* 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 <ucw/alloc.h>
-#include <ucw/config.h>
-#include <ucw/lib.h>
#include <string.h>
+#include <stdint.h>
+
+#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]]
***/
/**
- * 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];
};
/**
* 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. */
};
/***
/**
* 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 <<trans:respools,resources>>, see <<trans:res_mempool()>>.
**/
-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 <<trans:respools,resources>>, see <<trans:res_mempool()>>.
**/
-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 <<struct_mempool_stats,mempool_stats structure>>.
- * 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]]
* -------------------
***/
-/* 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.
*
* `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 <<growbuf:,growing buffes>> 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 <<mp_grow(),`mp_grow`>>`(@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);
#include <string.h>
#include <libknot/errcode.h>
-#include <contrib/ucw/lib.h>
#include <contrib/ucw/mempool.h>
#include <assert.h>
#include <libknot/packet/pkt.h>
+#include "contrib/macros.h"
#include "lib/defines.h"
#include "daemon/session.h"
#include "daemon/engine.h"
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;
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);
#include <errno.h>
#include <stdlib.h>
-#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"
#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"
#include <lauxlib.h>
#include <libknot/packet/pkt.h>
#include <libknot/descriptor.h>
-#include <contrib/ucw/lib.h>
+#include <contrib/macros.h>
#include <contrib/ucw/mempool.h>
#include <contrib/wire.h>
#if defined(__GLIBC__) && defined(_GNU_SOURCE)
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)
{
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);
}
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);
}
{
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);
#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"
#include <sys/time.h>
#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;
#include <lmdb.h>
#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"
* 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"
* 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)
* 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"
#include "lib/cache/impl.h"
#include "contrib/base32hex.h"
+#include "contrib/macros.h"
#include "lib/dnssec/nsec.h"
#include "lib/layer/iterate.h"
#include "lib/cache/impl.h"
+#include "contrib/macros.h"
#include "lib/dnssec/ta.h"
#include "lib/layer/iterate.h"
# 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"
*/
#include "lib/generic/lru.h"
+#include "contrib/macros.h"
#include "contrib/murmurhash3/murmurhash3.h"
#include "contrib/ucw/mempool.h"
#include <stddef.h>
#include <stdint.h>
-#include "contrib/ucw/lib.h"
#include "lib/utils.h"
#include "libknot/mm_ctx.h"
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include "contrib/macros.h"
#include "lib/generic/queue.h"
#include <string.h>
#pragma once
#include "lib/defines.h"
-#include "contrib/ucw/lib.h"
+#include "contrib/macros.h"
#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
#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) \
#include <libknot/rrtype/rrsig.h>
#include "kresconfig.h"
+#include "contrib/macros.h"
#include "lib/layer/iterate.h"
#include "lib/resolve.h"
#include "lib/rplan.h"
#include <arpa/inet.h>
+#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
#include <libknot/descriptor.h>
#include <ucw/mempool.h>
#include "kresconfig.h"
+#include "contrib/macros.h"
#include "lib/resolve.h"
#include "lib/layer.h"
#include "lib/rplan.h"
#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"
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);
}
}
- 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),
}
-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"
};
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;
}
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",
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);
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) {
#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"