From patchwork Tue Sep 18 14:30:40 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Carlos O'Donell X-Patchwork-Id: 971147 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=sourceware.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=libc-alpha-return-95915-incoming=patchwork.ozlabs.org@sourceware.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; secure) header.d=sourceware.org header.i=@sourceware.org header.b="jU1ZLcsP"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 42F55g3wRxz9sBZ for ; Wed, 19 Sep 2018 00:31:18 +1000 (AEST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:to:from:subject:message-id:date:mime-version :content-type; q=dns; s=default; b=BH+OxpL2RQZxHDiAS8cgsjv+64r+r K0hm5rglxok+grU2fllxH092Ak6hifGygmNuGsGYSkVoCIs4WQJrkzI7WV1LO7AC GsreWY9B3FYIOYG/3Ru+zR/Se4DqyGaD9J038MZAPK+/Q5Le1Ys+r2rKTgWvO4kT zrEglmAcGlSmzY= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:to:from:subject:message-id:date:mime-version :content-type; s=default; bh=pUEdKWd0/yrwMoLAmVHpIN39+ik=; b=jU1 ZLcsPo2unPWbQrSKORBuHyr25ijwSE4+EDwvMMrNntU7L+uYDgbeUPtgdN+pVC3O 6aH+64D7+P/w7M8OmBUy+gGS7HYem5IFy1RhXca/J9evKCMgvNwZnJfl8JqyWjxn +P1JX2VLQDmrAQO8WVrmPxC5VWo2EBkyTwCHn1+w= Received: (qmail 17326 invoked by alias); 18 Sep 2018 14:31:11 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 17113 invoked by uid 89); 18 Sep 2018 14:30:56 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-26.9 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.2 spammy=cet X-HELO: mail-qt0-f180.google.com To: GNU C Library , "H.J. Lu" From: Carlos O'Donell Subject: [PATCH] Fix tst-setcontext9 for optimized small stacks. Openpgp: preference=signencrypt Message-ID: Date: Tue, 18 Sep 2018 10:30:40 -0400 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.9.1 MIME-Version: 1.0 HJ, Can I get a Reviewed-by from you for this? It looks like I'm keeping the relative structure of the original test, but I'm not sure what your intent was here with respect to CET testing. I'm seeing crashes in this test on i686 testing as described in the commit message. ~~~ If the compiler reduces the stack usage in function f1 before calling into function f2, then when we swapcontext back to f1 and continue execution we may overwrite registers that were spilled to the stack while f2 was executing. Later when we return to f2 the corrupt registers will be reloaded from the stack and the test will crash. This was most commonly observed on i686 with __x86.get_pc_thunk.dx and needing to save and restore $edx. Overall i686 has few registers and the spilling to the stack is bound to happen, therefore the solution to making this test robust is to split function f1 into two parts f1a and f1b, and allocate f1b it's own stack such that subsequent execution does not overwrite the stack in use by function f2. Tested on i686 and x86_64. Signed-off-by: Carlos O'Donell Reviewed-by: H.J. Lu From 52d90e0548bee31f3f1cb62d63f40f31de5b1d97 Mon Sep 17 00:00:00 2001 From: Carlos O'Donell Date: Wed, 5 Sep 2018 01:16:42 -0400 Subject: [PATCH] Fix tst-setcontext9 for optimized small stacks. If the compiler reduces the stack usage in function f1 before calling into function f2, then when we swapcontext back to f1 and continue execution we may overwrite registers that were spilled to the stack while f2 was executing. Later when we return to f2 the corrupt registers will be reloaded from the stack and the test will crash. This was most commonly observed on i686 with __x86.get_pc_thunk.dx and needing to save and restore $edx. Overall i686 has few registers and the spilling to the stack is bound to happen, therefore the solution to making this test robust is to split function f1 into two parts f1a and f1b, and allocate f1b it's own stack such that subsequent execution does not overwrite the stack in use by function f2. Tested on i686 and x86_64. Signed-off-by: Carlos O'Donell --- ChangeLog | 6 +++++ stdlib/tst-setcontext9.c | 47 ++++++++++++++++++++++++++++++++-------- 2 files changed, 44 insertions(+), 9 deletions(-) diff --git a/ChangeLog b/ChangeLog index 5f588784cb..7e03407a50 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2018-09-18 Carlos O'Donell + + * stdlib/tst-setcontext9.c (f1): Rename to... + (f1a): ... this. + (f1b): New function implementing lower half of f1 in alternate stack. + 2018-09-18 Joseph Myers * sysdeps/ieee754/ldbl-128ibm/s_ceill.c (ceil): Redirect to diff --git a/stdlib/tst-setcontext9.c b/stdlib/tst-setcontext9.c index 4636ce9030..db8355766c 100644 --- a/stdlib/tst-setcontext9.c +++ b/stdlib/tst-setcontext9.c @@ -41,26 +41,55 @@ f2 (void) } static void -f1 (void) +f1b (void) { - puts ("start f1"); - if (getcontext (&ctx[2]) != 0) - { - printf ("%s: getcontext: %m\n", __FUNCTION__); - exit (EXIT_FAILURE); - } if (done) { - puts ("set context in f1"); + puts ("set context in f1b"); if (setcontext (&ctx[3]) != 0) { printf ("%s: setcontext: %m\n", __FUNCTION__); exit (EXIT_FAILURE); } } + exit (EXIT_FAILURE); +} + +static void +f1a (void) +{ + char st2[32768]; + puts ("start f1a"); + if (getcontext (&ctx[2]) != 0) + { + printf ("%s: getcontext: %m\n", __FUNCTION__); + exit (EXIT_FAILURE); + } + ctx[2].uc_stack.ss_sp = st2; + ctx[2].uc_stack.ss_size = sizeof st2; + ctx[2].uc_link = &ctx[0]; + makecontext (&ctx[2], (void (*) (void)) f1b, 0); f2 (); } +/* The execution path through the test looks like this: + do_test (call) + -> "making contexts" + -> "swap contexts" + f1a (via swapcontext to ctx[1], with alternate stack) + -> "start f1a" + f2 (call) + -> "swap contexts in f2" + f1b (via swapcontext to ctx[2], with alternate stack) + -> "set context in f1b" + do_test (via setcontext to ctx[3], main stack) + -> "setcontext" + f2 (via setcontext to ctx[4], with alternate stack) + -> "end f2" + + We must use an alternate stack for f1b, because if we don't then the + result of executing an earlier caller may overwrite registers + spilled to the stack in f2. */ static int do_test (void) { @@ -79,7 +108,7 @@ do_test (void) ctx[1].uc_stack.ss_sp = st1; ctx[1].uc_stack.ss_size = sizeof st1; ctx[1].uc_link = &ctx[0]; - makecontext (&ctx[1], (void (*) (void)) f1, 0); + makecontext (&ctx[1], (void (*) (void)) f1a, 0); puts ("swap contexts"); if (swapcontext (&ctx[3], &ctx[1]) != 0) { -- 2.17.1