Bug 29087 - [4.1 Regression] More than 35000 switch cases crash cc1plus
Summary: [4.1 Regression] More than 35000 switch cases crash cc1plus
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 4.1.1
: P3 normal
Target Milestone: 4.1.2
Assignee: Steven Bosscher
URL: http://gcc.gnu.org/ml/gcc-patches/200...
Keywords: ice-on-valid-code, patch
Depends on:
Blocks:
 
Reported: 2006-09-14 17:38 UTC by Denis Excoffier
Modified: 2006-09-21 21:32 UTC (History)
4 users (show)

See Also:
Host:
Target:
Build:
Known to work: 4.0.3 4.2.0
Known to fail: 4.1.0 4.1.2
Last reconfirmed: 2006-09-15 16:24:38


Attachments
tentative patch (849 bytes, patch)
2006-09-15 21:01 UTC, Steven Bosscher
Details | Diff
Alternative patch (less obviously safe) (887 bytes, patch)
2006-09-15 23:48 UTC, Steven Bosscher
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Denis Excoffier 2006-09-14 17:38:36 UTC
the exact version of GCC is 4.1.1
the system type is sparc-sun-solaris2.8
the options given when GCC was configured/built:
  --prefix=/tmp/local/unixutil/gcc-4.1.1
  --with-local-prefix=/usr/local/myCompanyName
  ("myCompanyName" is not the exact wording)
  (also, there is a symlink /tmp/local/unixutil/gcc -> gcc-4.1.1)
the complete command line that triggers the bug:
  gcc -Wall -o foo.o -c foo.cc
the compiler output (error messages, warnings, etc.):
  stdout: nothing
  stderr:
    gcc: Internal error: Segmentation Fault (program cc1plus)
    Please submit a full bug report.
    See <URL:http://gcc.gnu.org/bugs.html> for instructions.
  foo.o: not created
the preprocessed file:
  see below; for ease of transmission, the full source is not given;
  to have it, replace the ZZZZZ by the missing 65524 values (in
  increasing order)
additional remarks:
  1) if the file is renamed foo.c (the C language is triggered instead
     of C++), the bug does not show up
  2) if the command is installed in a Makefile:
---Makefile--------------------------
all:
        /tmp/local/unixutil/gcc/bin/gcc -Wall -o foo.o -c foo.cc
-------------------------------------
     then the bug does not show up if the GNU make is used, however the bug
     still shows up if the /usr/ccs/bin/make is used


---foo.ii----------------------------
# 1 "foo.cc"
# 1 "<built-in>"
# 1 "<command line>"
# 1 "foo.cc"
void myfunction(unsigned short localChar) {
  switch (localChar) {
    case 0:
    case 1:
    case 2:
    case 3:
    case 4:
    case 5:
ZZZZZ
    case 65530:
    case 65531:
    case 65532:
    case 65533:
    case 65534:
    case 65535:
      break;
  };
  return;
};
-------------------------------------
Comment 1 Richard Biener 2006-09-15 08:26:42 UTC
Confirmed.  It looks like the C++ frontend recursively parses switch statements...

#1052 0x0815ceae in cp_parser_statement (parser=0xb7d85ea0,
    in_statement_expr=0x0)
    at /space/rguenther/src/svn/gcc-4_1-branch/gcc/cp/parser.c:6101
#1053 0x0815d1f5 in cp_parser_labeled_statement (parser=0xb7d85ea0,
    in_statement_expr=0x0)
    at /space/rguenther/src/svn/gcc-4_1-branch/gcc/cp/parser.c:6274
#1054 0x0815ceae in cp_parser_statement (parser=0xb7d85ea0,
    in_statement_expr=0x0)
    at /space/rguenther/src/svn/gcc-4_1-branch/gcc/cp/parser.c:6101
#1055 0x0815d1f5 in cp_parser_labeled_statement (parser=0xb7d85ea0,
    in_statement_expr=0x0)
    at /space/rguenther/src/svn/gcc-4_1-branch/gcc/cp/parser.c:6274
...

Comment 2 Steven Bosscher 2006-09-15 15:23:42 UTC
Re. comment #1  Yes, it is a _Recursive_ descent parser after all...

Probably the only solution is to parse the label and not descend. This is what the C front end does, see c_parser_statement.


Comment 3 Steven Bosscher 2006-09-15 16:24:38 UTC
Trying a fix (but don't hold your breath, the c++ parser is unexplored territory for me ;-)
Comment 4 Steven Bosscher 2006-09-15 21:01:46 UTC
Created attachment 12279 [details]
tentative patch

This removes the recursion cycle
"cp_parser_statement -> cp_parser_labeled_statement -> cp_parser_statement"
but it does not at this moment solve the whole problem because recursion of the form "cp_parser_statement -> cp_parser_statement" still occurs.  With a minor change, the two new calls in the patch to cp_parser_statement from itself could be replaced with "goto restart;" to hard-code the obvious tail recursion opportunity.  I may try that later.  For now, this patch is being tested (by Eric Christopher at Apple) and I hope we'll get good results with it.
Comment 5 Steven Bosscher 2006-09-15 21:22:58 UTC
Test case:

-------------------------------------
extern void bar ();
extern void baz ();

#define L1(x) \
  case x##0: case x##1: case x##2: case x##3: \
  case x##4: case x##5: case x##6: case x##7
#define L2(x) \
  L1(x##0): L1(x##1): L1(x##2): L1(x##3): \
  L1(x##4): L1(x##5): L1(x##6): L1(x##7)
#define L3(x) \
  L2(x##0): L2(x##1): L2(x##2): L2(x##3): \
  L2(x##4): L2(x##5): L2(x##6): L2(x##7)
#define L4(x) \
  L3(x##0): L3(x##1): L3(x##2): L3(x##3): \
  L3(x##4): L3(x##5): L3(x##6): L3(x##7)
#define L5(x) \
  L4(x##0): L4(x##1): L4(x##2): L4(x##3): \
  L4(x##4): L4(x##5): L4(x##6): L4(x##7)
#define CASES1 L5(00): L5(01): L5(02): L5(03)
#define CASES2 L5(04): L5(05): L5(06): L5(07)

void myfunction(unsigned int localChar) {
  switch (localChar) {
    CASES1:
      bar ();
    CASES2:
      baz ();
      break;
  };
  return;
};
-------------------------------------
Comment 6 Steven Bosscher 2006-09-15 23:48:18 UTC
Created attachment 12281 [details]
Alternative patch (less obviously safe)

This one should resolve the problem completely by not recursing with calls.  Not sure if this is entirely safe.  Will test.
Comment 7 patchapp@dberlin.org 2006-09-16 17:40:27 UTC
Subject: Bug number PR 29087

A patch for this bug has been added to the patch tracker.
The mailing list url for the patch is http://gcc.gnu.org/ml/gcc-patches/2006-09/msg00637.html
Comment 8 Steven Bosscher 2006-09-18 15:32:52 UTC
Subject: Bug 29087

Author: steven
Date: Mon Sep 18 15:32:43 2006
New Revision: 117026

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=117026
Log:
        PR c++/29087
        * parser.c (cp_parser_labeled_statement): Return nothing.  Do
        not take in_statement_expr and in_compound as arguments.  Rename
        to cp_parser_label_for_labeled_statement.  Parse only the label,
        not the statement.
        (cp_parser_statement): Parse the statement of a labeled-statement
        from here, using tail recursion.

Modified:
    trunk/gcc/cp/ChangeLog
    trunk/gcc/cp/parser.c

Comment 9 Steven Bosscher 2006-09-18 15:42:13 UTC
Fix for GCC 4.1 coming later today.
Comment 10 Steven Bosscher 2006-09-21 20:27:51 UTC
Subject: Bug 29087

Author: steven
Date: Thu Sep 21 20:27:36 2006
New Revision: 117120

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=117120
Log:
2006-09-21  Steven Bosscher  <steven@gcc.gnu.org>

        PR c++/29087
        Backport from mainline:
        * parser.c (cp_parser_labeled_statement): Return nothing.  Do
        not take in_statement_expr and in_compound as arguments.  Rename
        to cp_parser_label_for_labeled_statement.  Parse only the label,
        not the statement.
        (cp_parser_statement): Parse the statement of a labeled-statement
        from here, using tail recursion.

Modified:
    branches/gcc-4_1-branch/gcc/cp/ChangeLog
    branches/gcc-4_1-branch/gcc/cp/parser.c

Comment 11 Steven Bosscher 2006-09-21 21:31:51 UTC
Fixed.
Comment 12 Steven Bosscher 2006-09-21 21:32:55 UTC
Denis, this should be fixed in the next release of GCC 4.1 (which will be GCC 4.1.2) and in GCC 4.2.  Thanks for reporting the bug.