diff options
Diffstat (limited to 'util')
-rw-r--r-- | util/coroutine-ucontext.c | 48 | ||||
-rw-r--r-- | util/memfd.c | 78 | ||||
-rw-r--r-- | util/qemu-sockets.c | 44 | ||||
-rw-r--r-- | util/readline.c | 3 |
4 files changed, 139 insertions, 34 deletions
diff --git a/util/coroutine-ucontext.c b/util/coroutine-ucontext.c index 6621f3f..926d340 100644 --- a/util/coroutine-ucontext.c +++ b/util/coroutine-ucontext.c @@ -31,6 +31,13 @@ #include <valgrind/valgrind.h> #endif +#if defined(__SANITIZE_ADDRESS__) || __has_feature(address_sanitizer) +#ifdef CONFIG_ASAN_IFACE_FIBER +#define CONFIG_ASAN 1 +#include <sanitizer/asan_interface.h> +#endif +#endif + typedef struct { Coroutine base; void *stack; @@ -59,11 +66,37 @@ union cc_arg { int i[2]; }; +static void finish_switch_fiber(void *fake_stack_save) +{ +#ifdef CONFIG_ASAN + const void *bottom_old; + size_t size_old; + + __sanitizer_finish_switch_fiber(fake_stack_save, &bottom_old, &size_old); + + if (!leader.stack) { + leader.stack = (void *)bottom_old; + leader.stack_size = size_old; + } +#endif +} + +static void start_switch_fiber(void **fake_stack_save, + const void *bottom, size_t size) +{ +#ifdef CONFIG_ASAN + __sanitizer_start_switch_fiber(fake_stack_save, bottom, size); +#endif +} + static void coroutine_trampoline(int i0, int i1) { union cc_arg arg; CoroutineUContext *self; Coroutine *co; + void *fake_stack_save = NULL; + + finish_switch_fiber(NULL); arg.i[0] = i0; arg.i[1] = i1; @@ -72,9 +105,13 @@ static void coroutine_trampoline(int i0, int i1) /* Initialize longjmp environment and switch back the caller */ if (!sigsetjmp(self->env, 0)) { + start_switch_fiber(&fake_stack_save, + leader.stack, leader.stack_size); siglongjmp(*(sigjmp_buf *)co->entry_arg, 1); } + finish_switch_fiber(fake_stack_save); + while (true) { co->entry(co->entry_arg); qemu_coroutine_switch(co, co->caller, COROUTINE_TERMINATE); @@ -87,6 +124,7 @@ Coroutine *qemu_coroutine_new(void) ucontext_t old_uc, uc; sigjmp_buf old_env; union cc_arg arg = {0}; + void *fake_stack_save = NULL; /* The ucontext functions preserve signal masks which incurs a * system call overhead. sigsetjmp(buf, 0)/siglongjmp() does not @@ -122,8 +160,12 @@ Coroutine *qemu_coroutine_new(void) /* swapcontext() in, siglongjmp() back out */ if (!sigsetjmp(old_env, 0)) { + start_switch_fiber(&fake_stack_save, co->stack, co->stack_size); swapcontext(&old_uc, &uc); } + + finish_switch_fiber(fake_stack_save); + return &co->base; } @@ -169,13 +211,19 @@ qemu_coroutine_switch(Coroutine *from_, Coroutine *to_, CoroutineUContext *from = DO_UPCAST(CoroutineUContext, base, from_); CoroutineUContext *to = DO_UPCAST(CoroutineUContext, base, to_); int ret; + void *fake_stack_save = NULL; current = to_; ret = sigsetjmp(from->env, 0); if (ret == 0) { + start_switch_fiber(action == COROUTINE_TERMINATE ? + NULL : &fake_stack_save, to->stack, to->stack_size); siglongjmp(to->env, action); } + + finish_switch_fiber(fake_stack_save); + return ret; } diff --git a/util/memfd.c b/util/memfd.c index dce61f9..07d579e 100644 --- a/util/memfd.c +++ b/util/memfd.c @@ -27,7 +27,9 @@ #include "qemu/osdep.h" +#include "qapi/error.h" #include "qemu/memfd.h" +#include "qemu/host-utils.h" #if defined CONFIG_LINUX && !defined CONFIG_MEMFD #include <sys/syscall.h> @@ -51,36 +53,59 @@ static int memfd_create(const char *name, unsigned int flags) #define MFD_ALLOW_SEALING 0x0002U #endif -int qemu_memfd_create(const char *name, size_t size, unsigned int seals) +#ifndef MFD_HUGETLB +#define MFD_HUGETLB 0x0004U +#endif + +#ifndef MFD_HUGE_SHIFT +#define MFD_HUGE_SHIFT 26 +#endif + +int qemu_memfd_create(const char *name, size_t size, bool hugetlb, + uint64_t hugetlbsize, unsigned int seals, Error **errp) { - int mfd = -1; + int htsize = hugetlbsize ? ctz64(hugetlbsize) : 0; + + if (htsize && 1 << htsize != hugetlbsize) { + error_setg(errp, "Hugepage size must be a power of 2"); + return -1; + } + + htsize = htsize << MFD_HUGE_SHIFT; #ifdef CONFIG_LINUX + int mfd = -1; unsigned int flags = MFD_CLOEXEC; if (seals) { flags |= MFD_ALLOW_SEALING; } - + if (hugetlb) { + flags |= MFD_HUGETLB; + flags |= htsize; + } mfd = memfd_create(name, flags); if (mfd < 0) { - return -1; + goto err; } if (ftruncate(mfd, size) == -1) { - perror("ftruncate"); - close(mfd); - return -1; + goto err; } if (seals && fcntl(mfd, F_ADD_SEALS, seals) == -1) { - perror("fcntl"); - close(mfd); - return -1; + goto err; } -#endif return mfd; + +err: + if (mfd >= 0) { + close(mfd); + } +#endif + error_setg_errno(errp, errno, "failed to create memfd"); + return -1; } /* @@ -90,14 +115,14 @@ int qemu_memfd_create(const char *name, size_t size, unsigned int seals) * sealing. */ void *qemu_memfd_alloc(const char *name, size_t size, unsigned int seals, - int *fd) + int *fd, Error **errp) { void *ptr; - int mfd = qemu_memfd_create(name, size, seals); + int mfd = qemu_memfd_create(name, size, false, 0, seals, NULL); /* some systems have memfd without sealing */ if (mfd == -1) { - mfd = qemu_memfd_create(name, size, 0); + mfd = qemu_memfd_create(name, size, false, 0, 0, NULL); } if (mfd == -1) { @@ -109,27 +134,26 @@ void *qemu_memfd_alloc(const char *name, size_t size, unsigned int seals, unlink(fname); g_free(fname); - if (mfd == -1) { - perror("mkstemp"); - return NULL; - } - - if (ftruncate(mfd, size) == -1) { - perror("ftruncate"); - close(mfd); - return NULL; + if (mfd == -1 || + ftruncate(mfd, size) == -1) { + goto err; } } ptr = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, mfd, 0); if (ptr == MAP_FAILED) { - perror("mmap"); - close(mfd); - return NULL; + goto err; } *fd = mfd; return ptr; + +err: + error_setg_errno(errp, errno, "failed to allocate shared memory"); + if (mfd >= 0) { + close(mfd); + } + return NULL; } void qemu_memfd_free(void *ptr, size_t size, int fd) @@ -157,7 +181,7 @@ bool qemu_memfd_check(void) int fd; void *ptr; - ptr = qemu_memfd_alloc("test", 4096, 0, &fd); + ptr = qemu_memfd_alloc("test", 4096, 0, &fd, NULL); memfd_check = ptr ? MEMFD_OK : MEMFD_KO; qemu_memfd_free(ptr, 4096, fd); } diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c index d6a1e17..fbbef69 100644 --- a/util/qemu-sockets.c +++ b/util/qemu-sockets.c @@ -554,6 +554,33 @@ err: } /* compatibility wrapper */ +static int inet_parse_flag(const char *flagname, const char *optstr, bool *val, + Error **errp) +{ + char *end; + size_t len; + + end = strstr(optstr, ","); + if (end) { + if (end[1] == ',') { /* Reject 'ipv6=on,,foo' */ + error_setg(errp, "error parsing '%s' flag '%s'", flagname, optstr); + return -1; + } + len = end - optstr; + } else { + len = strlen(optstr); + } + if (len == 0 || (len == 3 && strncmp(optstr, "=on", len) == 0)) { + *val = true; + } else if (len == 4 && strncmp(optstr, "=off", len) == 0) { + *val = false; + } else { + error_setg(errp, "error parsing '%s' flag '%s'", flagname, optstr); + return -1; + } + return 0; +} + int inet_parse(InetSocketAddress *addr, const char *str, Error **errp) { const char *optstr, *h; @@ -561,6 +588,7 @@ int inet_parse(InetSocketAddress *addr, const char *str, Error **errp) char port[33]; int to; int pos; + char *begin; memset(addr, 0, sizeof(*addr)); @@ -602,11 +630,19 @@ int inet_parse(InetSocketAddress *addr, const char *str, Error **errp) addr->has_to = true; addr->to = to; } - if (strstr(optstr, ",ipv4")) { - addr->ipv4 = addr->has_ipv4 = true; + begin = strstr(optstr, ",ipv4"); + if (begin) { + if (inet_parse_flag("ipv4", begin + 5, &addr->ipv4, errp) < 0) { + return -1; + } + addr->has_ipv4 = true; } - if (strstr(optstr, ",ipv6")) { - addr->ipv6 = addr->has_ipv6 = true; + begin = strstr(optstr, ",ipv6"); + if (begin) { + if (inet_parse_flag("ipv6", begin + 5, &addr->ipv6, errp) < 0) { + return -1; + } + addr->has_ipv6 = true; } return 0; } diff --git a/util/readline.c b/util/readline.c index 24ec839..ec91ee0 100644 --- a/util/readline.c +++ b/util/readline.c @@ -510,9 +510,6 @@ void readline_free(ReadLineState *rs) for (i = 0; i < READLINE_MAX_CMDS; i++) { g_free(rs->history[i]); } - for (i = 0; i < READLINE_MAX_COMPLETIONS; i++) { - g_free(rs->completions[i]); - } g_free(rs); } |