From patchwork Fri Jan 29 11:40:12 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bernd Schmidt X-Patchwork-Id: 575596 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 CCE93140BA3 for ; Fri, 29 Jan 2016 22:40:28 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b=lIxNb+vA; 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 :references:to:from:subject:message-id:date:mime-version :in-reply-to:content-type; q=dns; s=default; b=jB4uJ/3JPPEKlSem7 ZanpIkJIxhsHnAvE/qmVDYIf9Bxhc8xPLdMMzS8EgIjbVvNKN/1ae/jjTrvm7tDJ QuQXMB+p8/yWG4swgH9jjdZr2uTk8e/KPdYzutGJgY3ohH/oeALjsA60InG/R8p6 nTk51+hULngkpw9DcyqnvIQHfA= 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 :references:to:from:subject:message-id:date:mime-version :in-reply-to:content-type; s=default; bh=W3NiB97DDQDin70sAA9RcKC wqpQ=; b=lIxNb+vA2dE55FFlPnFhJp2wRJ3QqqJF5k9A9Dsrajf5fk0/KElN5WW d9ZlEEgnWdCkFtMM2f0yL3Jpz+ZzOZafmSoVjiwsNV61tYqRglfTOXM4sUvMROFf YLGouSGmRGXodu1cG/O/jIjatIkTSLchBOB8pjs0wIFCYJDL1WEQ= Received: (qmail 66769 invoked by alias); 29 Jan 2016 11:40:17 -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 66757 invoked by uid 89); 29 Jan 2016 11:40:16 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.9 required=5.0 tests=BAYES_00, RP_MATCHES_RCVD, SPF_HELO_PASS autolearn=ham version=3.3.2 spammy=top-level, 4309, 7, 625, 7, 43097 X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-GCM-SHA384 encrypted) ESMTPS; Fri, 29 Jan 2016 11:40:15 +0000 Received: from int-mx11.intmail.prod.int.phx2.redhat.com (int-mx11.intmail.prod.int.phx2.redhat.com [10.5.11.24]) by mx1.redhat.com (Postfix) with ESMTPS id 3F68449DCC for ; Fri, 29 Jan 2016 11:40:14 +0000 (UTC) Received: from localhost.localdomain (vpn1-5-101.ams2.redhat.com [10.36.5.101]) by int-mx11.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id u0TBeCCq009322 for ; Fri, 29 Jan 2016 06:40:13 -0500 References: <56AB4AE9.7050704@t-online.de> To: GCC Patches From: Bernd Schmidt Subject: Fix c/69522, memory management issue in c-parser X-Forwarded-Message-Id: <56AB4AE9.7050704@t-online.de> Message-ID: <56AB4F9C.3090702@redhat.com> Date: Fri, 29 Jan 2016 12:40:12 +0100 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Thunderbird/38.4.0 MIME-Version: 1.0 In-Reply-To: <56AB4AE9.7050704@t-online.de> X-IsSubscribed: yes Let's say we have struct a { int x[1]; int y[1]; } x = { 0, { 0 } }; ^ When we reach the marked brace, we call into push_init_level, where we notice that we have implicit initializers (for x[]) lying around that we should deal with now that we've seen another open brace. The problem is that we've created a new obstack for the initializer of y, and this is where we also put data for the inits of x, freeing it when we see the close brace for the initialization of y. In the actual testcase, which is a little more complex to actually demonstrate the issue, we end up allocating two init elts at the same address (because of premature freeing) and place them in the same tree, which ends up containing a cycle because of this. Then we hang. Fixed by this patch, which splits off a new function finish_implicit_inits from push_init_level and ensures it's called with the outer obstack instead of the new one in the problematic case. Bootstrapped and tested on x86_64-linux, ok? Bernd c/ PR c/69522 * c-parser.c (c_parser_braced_init): New arg outer_obstack. All callers changed. If nested_p is true, use it to call finish_implicit_inits. * c-tree.h (finish_implicit_inits): Declare. * c-typeck.c (finish_implicit_inits): New function. Move code from ... (push_init_level): ... here. (set_designator, process_init_element): Call finish_implicit_inits. testsuite/ PR c/69522 gcc.dg/pr69522.c: New test. diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index 43c26ae..eac0b1c 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -1284,7 +1284,8 @@ static tree c_parser_simple_asm_expr (c_parser *); static tree c_parser_attributes (c_parser *); static struct c_type_name *c_parser_type_name (c_parser *); static struct c_expr c_parser_initializer (c_parser *); -static struct c_expr c_parser_braced_init (c_parser *, tree, bool); +static struct c_expr c_parser_braced_init (c_parser *, tree, bool, + struct obstack *); static void c_parser_initelt (c_parser *, struct obstack *); static void c_parser_initval (c_parser *, struct c_expr *, struct obstack *); @@ -4289,7 +4290,7 @@ static struct c_expr c_parser_initializer (c_parser *parser) { if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) - return c_parser_braced_init (parser, NULL_TREE, false); + return c_parser_braced_init (parser, NULL_TREE, false, NULL); else { struct c_expr ret; @@ -4309,7 +4310,8 @@ c_parser_initializer (c_parser *parser) top-level initializer in a declaration. */ static struct c_expr -c_parser_braced_init (c_parser *parser, tree type, bool nested_p) +c_parser_braced_init (c_parser *parser, tree type, bool nested_p, + struct obstack *outer_obstack) { struct c_expr ret; struct obstack braced_init_obstack; @@ -4318,7 +4320,10 @@ c_parser_braced_init (c_parser *parser, tree type, bool nested_p) gcc_assert (c_parser_next_token_is (parser, CPP_OPEN_BRACE)); c_parser_consume_token (parser); if (nested_p) - push_init_level (brace_loc, 0, &braced_init_obstack); + { + finish_implicit_inits (brace_loc, outer_obstack); + push_init_level (brace_loc, 0, &braced_init_obstack); + } else really_start_incremental_init (type); if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) @@ -4576,7 +4581,8 @@ c_parser_initval (c_parser *parser, struct c_expr *after, location_t loc = c_parser_peek_token (parser)->location; if (c_parser_next_token_is (parser, CPP_OPEN_BRACE) && !after) - init = c_parser_braced_init (parser, NULL_TREE, true); + init = c_parser_braced_init (parser, NULL_TREE, true, + braced_init_obstack); else { init = c_parser_expr_no_commas (parser, after); @@ -8060,7 +8066,7 @@ c_parser_postfix_expression_after_paren_type (c_parser *parser, error_at (type_loc, "compound literal has variable size"); type = error_mark_node; } - init = c_parser_braced_init (parser, type, false); + init = c_parser_braced_init (parser, type, false, NULL); finish_init (); maybe_warn_string_init (type_loc, type, init); diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index 00e72b1..5902fd2 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -625,6 +625,7 @@ extern void maybe_warn_string_init (location_t, tree, struct c_expr); extern void start_init (tree, tree, int); extern void finish_init (void); extern void really_start_incremental_init (tree); +extern void finish_implicit_inits (location_t, struct obstack *); extern void push_init_level (location_t, int, struct obstack *); extern struct c_expr pop_init_level (location_t, int, struct obstack *); extern void set_init_index (location_t, tree, tree, struct obstack *); diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index a147ac6..e4e2944 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -7447,6 +7447,30 @@ really_start_incremental_init (tree type) } } +/* Called when we see an open brace for a nested initializer. Finish + off any pending levels with implicit braces. */ +void +finish_implicit_inits (location_t loc, struct obstack *braced_init_obstack) +{ + while (constructor_stack->implicit) + { + if (RECORD_OR_UNION_TYPE_P (constructor_type) + && constructor_fields == 0) + process_init_element (input_location, + pop_init_level (loc, 1, braced_init_obstack), + true, braced_init_obstack); + else if (TREE_CODE (constructor_type) == ARRAY_TYPE + && constructor_max_index + && tree_int_cst_lt (constructor_max_index, + constructor_index)) + process_init_element (input_location, + pop_init_level (loc, 1, braced_init_obstack), + true, braced_init_obstack); + else + break; + } +} + /* Push down into a subobject, for initialization. If this is for an explicit set of braces, IMPLICIT is 0. If it is because the next element belongs at a lower level, @@ -7459,33 +7483,6 @@ push_init_level (location_t loc, int implicit, struct constructor_stack *p; tree value = NULL_TREE; - /* If we've exhausted any levels that didn't have braces, - pop them now. If implicit == 1, this will have been done in - process_init_element; do not repeat it here because in the case - of excess initializers for an empty aggregate this leads to an - infinite cycle of popping a level and immediately recreating - it. */ - if (implicit != 1) - { - while (constructor_stack->implicit) - { - if (RECORD_OR_UNION_TYPE_P (constructor_type) - && constructor_fields == 0) - process_init_element (input_location, - pop_init_level (loc, 1, braced_init_obstack), - true, braced_init_obstack); - else if (TREE_CODE (constructor_type) == ARRAY_TYPE - && constructor_max_index - && tree_int_cst_lt (constructor_max_index, - constructor_index)) - process_init_element (input_location, - pop_init_level (loc, 1, braced_init_obstack), - true, braced_init_obstack); - else - break; - } - } - /* Unless this is an explicit brace, we need to preserve previous content if any. */ if (implicit) @@ -7912,6 +7909,7 @@ set_designator (location_t loc, int array, } constructor_designated = 1; + finish_implicit_inits (loc, braced_init_obstack); push_init_level (loc, 2, braced_init_obstack); return 0; } @@ -9295,6 +9293,7 @@ process_init_element (location_t loc, struct c_expr value, bool implicit, p = p->next; if (!p) break; + finish_implicit_inits (loc, braced_init_obstack); push_init_level (loc, 2, braced_init_obstack); p->stack = constructor_stack; if (p->range_end && tree_int_cst_equal (p->index, p->range_end)) Index: gcc/testsuite/gcc.dg/pr69522.c =================================================================== --- gcc/testsuite/gcc.dg/pr69522.c (revision 0) +++ gcc/testsuite/gcc.dg/pr69522.c (working copy) @@ -0,0 +1,9 @@ +/* { dg-do compile } */ +struct str {}; +struct { + struct str b; + float c[1]; + int d[1]; + float e[2]; + int f[1]; +} a = {{}, 0, {0.5}, 0, 0, {0}};