From patchwork Wed Nov 30 19:06:08 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nathan Sidwell X-Patchwork-Id: 701137 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org 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 3tTVJV5j2Jz9t2G for ; Thu, 1 Dec 2016 06:06:34 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="VDgg2Hjb"; dkim-atps=neutral DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:to:cc :from:subject:message-id:date:mime-version:content-type; q=dns; s=default; b=f0stNSY5TTYhnMlSsuzDMGMZQZcFk9PTFk2jTsoQKkxXBsl/Cp IA8N1TYgqMuXnHn1cohJ4lukYeCLp6783Y2HvKUzFjvAPglG2lZa/Cran2FVtUzN SrQyV+3ZlgDvV+HZIMZonPawSgWbGZERrTfnXfCwT0RRfI+T0Wm75BC20= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:to:cc :from:subject:message-id:date:mime-version:content-type; s= default; bh=aSVbkTvkYsybs/YeMxycaNivsRE=; b=VDgg2Hjb1blk0aIaFyNs 0h4302WPU3yzzh5wQElyjTEzBrmtoq/3RxY6/+9KBHF9Qv02CenZeGgC/n1/PBNK un4kIPIIZbkBc6zD2UV/KTojzrU2sgSxiydWctT9ZoIMQ5Zd7V3eqRRKnsQH3JyX HqbttIxs1LdTqk+10q84k6Y= Received: (qmail 116280 invoked by alias); 30 Nov 2016 19:06:23 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 116246 invoked by uid 89); 30 Nov 2016 19:06:22 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.1 required=5.0 tests=BAYES_00, FREEMAIL_FROM, KAM_ASCII_DIVIDERS, RCVD_IN_DNSWL_NONE, SPF_PASS autolearn=no version=3.3.2 spammy=nonexistent, UD:cp-demangle.c, cpdemanglec, cp-demangle.c X-HELO: mail-yw0-f194.google.com Received: from mail-yw0-f194.google.com (HELO mail-yw0-f194.google.com) (209.85.161.194) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 30 Nov 2016 19:06:12 +0000 Received: by mail-yw0-f194.google.com with SMTP id a10so15214865ywa.1 for ; Wed, 30 Nov 2016 11:06:12 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:sender:to:cc:from:subject:message-id:date :user-agent:mime-version; bh=ipK6QgkvZaF90Y3/t+hLLZhBhQPL6zwLv/y0/f0HXcw=; b=TFc7PB8/g3kpHlwfY6MK1IbRFZ/FHZP/bSmvORRr9hxcszQj9Wt18jwOmRzDc4Kb55 vC8yUtfXHXjPnxPIOou0Ks2TF4qGjn8u3/ezVclhQ2Qx1UqmyaNs0gmuJETcia7h0AvL SR+y2PeEuiSpfS+1FBnE3XtCX4oOY7SuxKRuyJUSYHtW76dMbm5rSbfeONTzfLC8x0HO 7bWLbalklXg2YMhUs3HYGVl7gpwbwZF9XQR6b5htxh9zaHza/64xTlChNy+/FANleJIL aK+wTLkXj32Rnukpu+CkkbUOS6JQVKg45ySulcRTDUoFGylemqC73UtwA2p7PiquirSe 5vXw== X-Gm-Message-State: AKaTC03w3c6+RQxbrVqy0LD0Wx0iA/WV940tZSnSJeoCUxgfkk39rKKBnOkdaNW4prdhlw== X-Received: by 10.129.62.24 with SMTP id l24mr36021586ywa.346.1480532771040; Wed, 30 Nov 2016 11:06:11 -0800 (PST) Received: from ?IPv6:2620:10d:c0a3:20fb:f6d0:5ac5:64cd:f102? ([2620:10d:c091:200::8:2a28]) by smtp.googlemail.com with ESMTPSA id p3sm23946686ywc.22.2016.11.30.11.06.09 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 30 Nov 2016 11:06:10 -0800 (PST) To: jason@redhat.com, iant@google.com Cc: nickc@redhat.com, GCC Patches , binutils@sourceware.org, P@draigBrady.com From: Nathan Sidwell Subject: [C++/78252] libiberty demangler crash with lambda (auto) Message-ID: <0cacb244-ba7b-c252-9958-3e30cdcea96a@acm.org> Date: Wed, 30 Nov 2016 14:06:08 -0500 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Thunderbird/45.4.0 MIME-Version: 1.0 This patch fixes a problem in libiberty's symbol demangler. With a templated forwarding function such as std::forward, we can end up emitting mangled function names that encode lambda information. Lambdas with auto argument types have a synthesized templated operator(), and g++ uses that when mangling the lambda. Unfortunately g++ doesn't notice the template parameters there mean 'auto' and emits regular template parameter references. (This is a bug, see below.) But, as the forwarding function itself is a template, and the lambda is part of a template parameter substitution, we can end up with the demangler recursing unboundedly. In other cases we can fail to demangle (returning null), or demangle to an unexpected type (substituting the current template parameter type into the place of the 'auto'). This patch fixes the demangler by noting when it's printing the argument types of a lambda. In that case whenever we encounter a template parameter reference we emit 'auto', and also inhibit some &/&& smushing that needs checking. AFAICT, once inside a lambda argument list we cannot encounter template parameter references that actually refer to an enclosing template argument list. That means we don't have the problem of disabling this additional check within the argument list printing. I don't think we can meet a nested lambda type either, but the ++...-- idiom seemed safer to me. We cannot do this substitution when parsing the mangled name, because g++ applies the usual squangling back references as-if there really was a template parameter reference. Later squangling references to the type containing the lambda argument may or may not require the reference to be to an enclosing template argument, or be auto, depending on the context of the squangle reference. I've also included a c++ testcase to check the mangling of the lambdas that cause this. While this is a g++ bug, it's an ABI-affecting one, and we shouldn't change the behaviour unintentionally. I've not investigated why the mangler's failing to check is_auto, and will look at that later. I imagine a fix will be -fabi-version dependent. I have filed 78621 to track it. ok? Nick, we originally found this when GDB exploded. If you're ok with it, I'll commit to binutils/gdb when approved for gcc. nathan 2016-11-30 Nathan Sidwell gcc/testsuite/ * g++.dg/cpp1y/lambda-mangle-1.C: New. libiberty/ * cp-demangle.c (struct p_print_info): Add is_lambda_arg field. (d_print_init): Initialize it. (d_print_comp_inner) : Check is_lambda_arg for auto. : Skip smashing check when is_lambda_arg. : Increment is_lambda_arg around arg printing. * testsuite/demangle-expected: Add lambda auto mangling cases. Index: gcc/testsuite/g++.dg/cpp1y/lambda-mangle-1.C =================================================================== --- gcc/testsuite/g++.dg/cpp1y/lambda-mangle-1.C (nonexistent) +++ gcc/testsuite/g++.dg/cpp1y/lambda-mangle-1.C (working copy) @@ -0,0 +1,47 @@ +// { dg-do compile { target c++14 } } + +// PR 78252 + +// We erroneously mangle lambda auto parms asif template parameters (T_), +// rather than auto (Da). While that's unfortunate, it'd be best if +// we didn't accidentally change that. + +template class X; + +template +T &&forward (T &v) +{ + return static_cast (v); +} + +template +void eat (T &v) +{ +} + +void Foo () +{ + auto lam = [](auto &) { }; + auto lam_1 = [](int &, auto &) { }; + auto lam_2 = [](auto &, X &) { }; + auto lam_3 = [](auto (*)[5]) { }; + + forward (lam); + forward (lam_1); + forward (lam_2); + forward (lam_3); + + eat (lam); + eat (lam_1); + eat (lam_2); + eat (lam_3); +} + +// { dg-final { scan-assembler "_Z7forwardIZ3FoovEUlRT_E_EOS0_S1_:" } } +// { dg-final { scan-assembler "_Z7forwardIZ3FoovEUlRiRT_E0_EOS1_S2_:" } } +// { dg-final { scan-assembler "_Z7forwardIZ3FoovEUlRT_R1XIiEE1_EOS0_S1_:" } } +// { dg-final { scan-assembler "_Z7forwardIZ3FoovEUlPA5_T_E2_EOS0_RS0_:" } } +// { dg-final { scan-assembler "_Z3eatIZ3FoovEUlRT_E_EvS1_:" } } +// { dg-final { scan-assembler "_Z3eatIZ3FoovEUlRiRT_E0_EvS2_:" } } +// { dg-final { scan-assembler "_Z3eatIZ3FoovEUlRT_R1XIiEE1_EvS1_:" } } +// { dg-final { scan-assembler "_Z3eatIZ3FoovEUlPA5_T_E2_EvRS0_:" } } Index: libiberty/cp-demangle.c =================================================================== --- libiberty/cp-demangle.c (revision 243016) +++ libiberty/cp-demangle.c (working copy) @@ -343,6 +343,12 @@ struct d_print_info struct d_print_mod *modifiers; /* Set to 1 if we saw a demangling error. */ int demangle_failure; + /* Non-zero if we're printing a lambda argument. A template + parameter reference actually means 'auto'. This is a bug in name + mangling, and will demangle to something confusing. + Unfortunately it can also cause infinite recursion, if we don't + interpret this as 'auto'. */ + int is_lambda_arg; /* The current index into any template argument packs we are using for printing, or -1 to print the whole pack. */ int pack_index; @@ -4126,6 +4132,7 @@ d_print_init (struct d_print_info *dpi, dpi->opaque = opaque; dpi->demangle_failure = 0; + dpi->is_lambda_arg = 0; dpi->component_stack = NULL; @@ -4783,33 +4790,35 @@ d_print_comp_inner (struct d_print_info } case DEMANGLE_COMPONENT_TEMPLATE_PARAM: - { - struct d_print_template *hold_dpt; - struct demangle_component *a = d_lookup_template_argument (dpi, dc); - - if (a && a->type == DEMANGLE_COMPONENT_TEMPLATE_ARGLIST) - a = d_index_template_argument (a, dpi->pack_index); + if (dpi->is_lambda_arg) + d_append_buffer (dpi, "auto", 4); + else + { + struct d_print_template *hold_dpt; + struct demangle_component *a = d_lookup_template_argument (dpi, dc); - if (a == NULL) - { - d_print_error (dpi); - return; - } + if (a && a->type == DEMANGLE_COMPONENT_TEMPLATE_ARGLIST) + a = d_index_template_argument (a, dpi->pack_index); - /* While processing this parameter, we need to pop the list of - templates. This is because the template parameter may - itself be a reference to a parameter of an outer - template. */ + if (a == NULL) + { + d_print_error (dpi); + return; + } - hold_dpt = dpi->templates; - dpi->templates = hold_dpt->next; + /* While processing this parameter, we need to pop the list + of templates. This is because the template parameter may + itself be a reference to a parameter of an outer + template. */ - d_print_comp (dpi, options, a); + hold_dpt = dpi->templates; + dpi->templates = hold_dpt->next; - dpi->templates = hold_dpt; + d_print_comp (dpi, options, a); - return; - } + dpi->templates = hold_dpt; + } + return; case DEMANGLE_COMPONENT_CTOR: d_print_comp (dpi, options, dc->u.s_ctor.name); @@ -4946,7 +4955,8 @@ d_print_comp_inner (struct d_print_info { /* Handle reference smashing: & + && = &. */ const struct demangle_component *sub = d_left (dc); - if (sub->type == DEMANGLE_COMPONENT_TEMPLATE_PARAM) + if (!dpi->is_lambda_arg + && sub->type == DEMANGLE_COMPONENT_TEMPLATE_PARAM) { struct d_saved_scope *scope = d_get_saved_scope (dpi, sub); struct demangle_component *a; @@ -5616,7 +5626,14 @@ d_print_comp_inner (struct d_print_info case DEMANGLE_COMPONENT_LAMBDA: d_append_string (dpi, "{lambda("); + /* We need to notice if we're printing a lambda argument type. + When this is true, any template parameter reference is + actually an instance of 'auto'. Fortunately we can't meet + real uses of template parameters inside the lambda + arguments. */ + dpi->is_lambda_arg++; d_print_comp (dpi, options, dc->u.s_unary_num.sub); + dpi->is_lambda_arg--; d_append_string (dpi, ")#"); d_append_num (dpi, dc->u.s_unary_num.num + 1); d_append_char (dpi, '}'); Index: libiberty/testsuite/demangle-expected =================================================================== --- libiberty/testsuite/demangle-expected (revision 243016) +++ libiberty/testsuite/demangle-expected (working copy) @@ -4634,3 +4634,27 @@ _Z12binary_rightIJLi1ELi2ELi3EEEv1AIXfRp # ?: expression with missing third component could crash. AquT_quT_4mxautouT_4mxxx AquT_quT_4mxautouT_4mxxx + +# pr c++/78252 unfortunate bug in g++'s lambda mangling would lead to +# incorrect demangles, and at worst unbounded recursion +_Z7forwardIRZ3FoovEUlRT_E_EOS0_S1_ +Foo()::{lambda(auto&)#1}& forward(Foo()::{lambda(auto&)#1}&) + +_Z7forwardIZ3FoovEUlRiRT_E_EOS1_S2_ +Foo()::{lambda(int&, auto&)#1}&& forward(Foo()::{lambda(int&, auto&)#1}&) + +_Z7forwardIZ3FoovEUlRT_R1XIiEE0_EOS0_S1_ +Foo()::{lambda(auto&, X&)#2}&& forward&)#2}>(Foo()::{lambda(auto&, X&)#2}&) + +_Z7forwardIZ3FoovEUlPA5_T_E1_EOS0_RS0_ +Foo()::{lambda(auto (*&&forward(auto&)) [5])#3} + +_Z3eatIZ3FoovEUlRiRT_E_EvS2_ +void eat(Foo()::{lambda(int&, auto&)#1}&) + +_Z3eatIZ3FoovEUlRT_R1XIiEE0_EvS1_ +void eat&)#2}>(Foo()::{lambda(auto&, X&)#2}&) + +_Z3eatIZ3FoovEUlPA5_T_E1_EvRS0_ +void eat(Foo()::{lambda(auto (*&) [5])#3}) +