From patchwork Mon Feb 5 19:28:34 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Paolo Bonzini X-Patchwork-Id: 869488 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="catRXLVr"; dkim-atps=neutral Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3zZypR32Fmz9sBW for ; Tue, 6 Feb 2018 06:49:19 +1100 (AEDT) Received: from localhost ([::1]:54887 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1eimlR-0005wl-FZ for incoming@patchwork.ozlabs.org; Mon, 05 Feb 2018 14:49:17 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:44749) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1eimSJ-0004UI-MW for qemu-devel@nongnu.org; Mon, 05 Feb 2018 14:29:33 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1eimSI-00050f-8j for qemu-devel@nongnu.org; Mon, 05 Feb 2018 14:29:31 -0500 Received: from mail-wm0-x242.google.com ([2a00:1450:400c:c09::242]:37745) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1eimSH-00050Q-V2 for qemu-devel@nongnu.org; Mon, 05 Feb 2018 14:29:30 -0500 Received: by mail-wm0-x242.google.com with SMTP id v71so28090748wmv.2 for ; Mon, 05 Feb 2018 11:29:29 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=VDZrU5NcX76pwOo12ryQxmZ0w8YromSY7jk4bGoI6pk=; b=catRXLVrGCV7t8Qk3/pFZ/uSvy4KdqhEF/Znm1eFH7Y4AmlIPHBZTgkZ7DgZ9xBQe1 FdfGIpwZ/sdzpZwbQsXHJtOTBVVhNfmRYAQH3cicPhTX2T0Tc23f8EwbbPK/oz14kAF0 rbE6JQ1RWQoHTlzE2ErWywSjMnmba52MMtiffpavy41cDIFguT9yaeBfmfVVIWxyvsTS ua5tXvQfE9AwRngE6iCHYkY2c8NZhxVR591zAYE1vXL+993tpxFD39kaMUSgpk+qp8kR kptyXb4tztySQ+Wz0dCG8dR1fqGwFf/Qls7W/b5wlniXTdPyzH2ttm8UbPCD4Ag/G+v2 706Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references:mime-version:content-transfer-encoding; bh=VDZrU5NcX76pwOo12ryQxmZ0w8YromSY7jk4bGoI6pk=; b=FvYJtq0DfeF7UbDnQXIPJRiKkEYofZwkVz3ZVe5InlPSGIHf4LhS6DkSmjdJll/8+D Pqyn7INGX81he2h3se3S7wTisvZNFK3lhE5lOUhXD9hLM8YmG9AC5DtYihiaDu2ocP73 Y3CWtp8Z3yp4UZG4rSJLZ0JUrpJTpteF1/gNLsRlGZe8IFml0ecqDgLs74miOn+Mov9g Z7e509mKuobIT3ndMV2lF1fU8YRxrsPcEq3Bu/JDQsdF0jTNh9BDEyRWlVCkwy07ALs/ 9c2Uk1g4dKjozE6UF8BlomsGs+18GfKZuTm3jtSlbw32HZc0yUH9vbdXARwLH9jmNQe6 0FIQ== X-Gm-Message-State: APf1xPDGno2xxUiC2a/PuHoq9FWXlazlkdPWWzyZTGLYMe/vTsJGNM1i ZEXqK25YaOkPFZxFsiDrRnAjz5SI X-Google-Smtp-Source: AH8x226f0QhghLSBXLnHL1CRPdzDBzqF6Mt9QsANJZjEk1+/R0gVsX+bMG4Yd/i9T0l/9oCfuRi79w== X-Received: by 10.28.193.7 with SMTP id r7mr269317wmf.153.1517858968468; Mon, 05 Feb 2018 11:29:28 -0800 (PST) Received: from 640k.lan ([82.84.122.246]) by smtp.gmail.com with ESMTPSA id g8sm20029891wra.18.2018.02.05.11.29.27 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 05 Feb 2018 11:29:27 -0800 (PST) From: Paolo Bonzini To: qemu-devel@nongnu.org Date: Mon, 5 Feb 2018 20:28:34 +0100 Message-Id: <1517858941-5538-21-git-send-email-pbonzini@redhat.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1517858941-5538-1-git-send-email-pbonzini@redhat.com> References: <1517858941-5538-1-git-send-email-pbonzini@redhat.com> MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2a00:1450:400c:c09::242 Subject: [Qemu-devel] [PULL 20/47] ucontext: annotate coroutine stack for ASAN X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" From: Marc-André Lureau It helps ASAN to detect more leaks on coroutine stacks, and to get rid of some extra warnings. Before: tests/test-coroutine -p /basic/lifecycle /basic/lifecycle: ==20781==WARNING: ASan doesn't fully support makecontext/swapcontext functions and may produce false positives in some cases! ==20781==WARNING: ASan is ignoring requested __asan_handle_no_return: stack top: 0x7ffcb184d000; bottom 0x7ff6c4cfd000; size: 0x0005ecb50000 (25446121472) False positive error reports may follow For details see https://github.com/google/sanitizers/issues/189 OK After: tests/test-coroutine -p /basic/lifecycle /basic/lifecycle: ==21110==WARNING: ASan doesn't fully support makecontext/swapcontext functions and may produce false positives in some cases! OK A similar work would need to be done for sigaltstack & windows fibers to have similar coverage. Since ucontext is preferred, I didn't bother checking the other coroutine implementations for now. Update travis to fix the build with ASAN annotations. Signed-off-by: Marc-André Lureau Message-Id: <20180116151152.4040-4-marcandre.lureau@redhat.com> Signed-off-by: Paolo Bonzini --- .travis.yml | 3 ++- configure | 30 +++++++++++++++++++++++++++++ include/qemu/compiler.h | 4 ++++ util/coroutine-ucontext.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 84 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index f583839..f2291e8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,12 +13,13 @@ addons: - libattr1-dev - libbrlapi-dev - libcap-ng-dev + - libgcc-6-dev - libgnutls-dev - libgtk-3-dev - libiscsi-dev - liblttng-ust-dev - - libnfs-dev - libncurses5-dev + - libnfs-dev - libnss3-dev - libpixman-1-dev - libpng12-dev diff --git a/configure b/configure index bbfcd9f..0b5c812 100755 --- a/configure +++ b/configure @@ -5213,6 +5213,8 @@ write_c_skeleton have_asan=no have_ubsan=no +have_asan_iface_h=no +have_asan_iface_fiber=no # enable sanitizers by default if --enable-debug if test "$sanitizers" = "" -a "$debug" = "yes"; then @@ -5226,12 +5228,29 @@ if test "$sanitizers" = "yes" ; then if compile_prog "$CPU_CFLAGS -Werror -fsanitize=undefined" ""; then have_ubsan=yes fi + + if check_include "sanitizer/asan_interface.h" ; then + have_asan_iface_h=yes + fi + + cat > $TMPC << EOF +#include +int main(void) { + __sanitizer_start_switch_fiber(0, 0, 0); + return 0; +} +EOF + if compile_prog "$CPU_CFLAGS -Werror -fsanitize=address" "" ; then + have_asan_iface_fiber=yes + fi fi ########################################## # End of CC checks # After here, no more $cc or $ld runs +write_c_skeleton + if test "$gcov" = "yes" ; then CFLAGS="-fprofile-arcs -ftest-coverage -g $CFLAGS" LDFLAGS="-fprofile-arcs -ftest-coverage $LDFLAGS" @@ -5254,6 +5273,13 @@ fi if test "$have_asan" = "yes"; then CFLAGS="-fsanitize=address $CFLAGS" + if test "$have_asan_iface_h" = "no" ; then + echo "ASAN build enabled, but ASAN header missing." \ + "Without code annotation, the report may be inferior." + elif test "$have_asan_iface_fiber" = "no" ; then + echo "ASAN build enabled, but ASAN header is too old." \ + "Without code annotation, the report may be inferior." + fi fi if test "$have_ubsan" = "yes"; then CFLAGS="-fsanitize=undefined $CFLAGS" @@ -6242,6 +6268,10 @@ if test "$valgrind_h" = "yes" ; then echo "CONFIG_VALGRIND_H=y" >> $config_host_mak fi +if test "$have_asan_iface_fiber" = "yes" ; then + echo "CONFIG_ASAN_IFACE_FIBER=y" >> $config_host_mak +fi + if test "$has_environ" = "yes" ; then echo "CONFIG_HAS_ENVIRON=y" >> $config_host_mak fi diff --git a/include/qemu/compiler.h b/include/qemu/compiler.h index 340e5fd..5fcc4f7 100644 --- a/include/qemu/compiler.h +++ b/include/qemu/compiler.h @@ -111,4 +111,8 @@ #define GCC_FMT_ATTR(n, m) #endif +#ifndef __has_feature +#define __has_feature(x) 0 /* compatibility with non-clang compilers */ +#endif + #endif /* COMPILER_H */ 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 #endif +#if defined(__SANITIZE_ADDRESS__) || __has_feature(address_sanitizer) +#ifdef CONFIG_ASAN_IFACE_FIBER +#define CONFIG_ASAN 1 +#include +#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; }