Here is basically the same testcase as PR18599 except that we have more switch cases. This testcase segfaults. cc1 is from today's mainline with checking disabled. #define CL0(a) case a: return a; #define CL1(a) CL0(a##0) CL0(a##1) CL0(a##2) CL0(a##3) CL0(a##4) CL0(a##5) \ CL0(a##6) CL0(a##7) CL0(a##8) CL0(a##9) #define CL2(a) CL1(a##0) CL1(a##1) CL1(a##2) CL1(a##3) CL1(a##4) CL1(a##5) \ CL1(a##6) CL1(a##7) CL1(a##8) CL1(a##9) #define CL3(a) CL2(a##0) CL2(a##1) CL2(a##2) CL2(a##3) CL2(a##4) CL2(a##5) \ CL2(a##6) CL2(a##7) CL2(a##8) CL2(a##9) #define CL4(a) CL3(a##0) CL3(a##1) CL3(a##2) CL3(a##3) CL3(a##4) CL3(a##5) \ CL3(a##6) CL3(a##7) CL3(a##8) CL3(a##9) #define CL5(a) CL4(a##0) CL4(a##1) CL4(a##2) CL4(a##3) CL4(a##4) CL4(a##5) \ CL4(a##6) CL4(a##7) CL4(a##8) CL4(a##9) #define CL6(a) CL5(a##0) CL5(a##1) CL5(a##2) CL5(a##3) CL5(a##4) CL5(a##5) \ CL5(a##6) CL5(a##7) CL5(a##8) CL5(a##9) void f(); int a (int b) { switch (b) { CL6(1) } }
Confirmed, the problem is because of stack overflow. Either splay_tree_delete_helper needs a little help or the C/C++ front-end needs to stop using splay trees. #553 0x0033a4a0 in splay_tree_delete_helper (sp=0x414012d0, node=0x1b669380) at /Users/ pinskia/src/local3/gcc/libiberty/splay-tree.c:65
I am not sure what we are supposed to do with this. Any kind of tree traversal and deletion is inherently recursive, and will hit a segfault sooner or later, if you push it hard enough. If an user really needs something degenerate like this, she should probably increase her stack limit. I'm really tempted to mark this as WONTFIX, unless you have a constructive suggestion on what to do.
Use a seperate stack instead of using function stack.
Subject: Re: segfault on a huge switch statement. > Confirmed, the problem is because of stack overflow. Either > splay_tree_delete_helper needs a little help or the C/C++ front-end > needs to stop using splay trees. How about this? /* Deallocate NODE (a member of SP), and all its sub-trees. */ static void splay_tree_delete_helper (sp, node) splay_tree sp; splay_tree_node node; { splay_tree_node pending = 0; splay_tree_node active = 0; if (!node) return; #define KDEL(x) if (sp->delete_key) (*sp->delete_key)(x); #define VDEL(x) if (sp->delete_value) (*sp->delete_value)(x); KDEL (node->key); VDEL (node->value); /* We use the "key" field to hold the "next" pointer. */ node->key = (splay_tree_key)pending; pending = (splay_tree_node)node; /* Now, keep processing the pending list until there aren't any more. This is a little more complicated than just recursing, but it doesn't toast the stack for large trees. */ while (pending) { active = pending; pending = 0; while (active) { splay_tree_node temp; /* active points to a node which has its key and value deallocated, we just need to process left and right. */ if (active->left) { KDEL (active->left->key); VDEL (active->left->value); active->left->key = (splay_tree_key)pending; pending = (splay_tree_node)(active->left); } if (active->right) { KDEL (active->right->key); VDEL (active->right->value); active->right->key = (splay_tree_key)pending; pending = (splay_tree_node)(active->right); } temp = active; active = (splay_tree_node)(temp->key); (*sp->deallocate) ((char*) temp, sp->allocate_data); } } #undef KDEL #undef VDEL }
DJ, are you going to push your new splay_tree_delete_helper? If it works, this fixes a regression wrt. earlier GCCs...
Subject: Re: segfault on a huge switch statement. I have pushed that change out.
I have just verified it was fixed, thanks DJ.