This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

typeof woes in symbol renaming, or glibc x gcc


A recent change in glibc exposed a latent bug in GCC.  Glibc uses some
tricks to rename symbols, that have worked on functions for a while,
but that had never been used on data symbols, and they happened to
malfunction on platforms that defined ASM_OUTPUT_EXTERNAL (IA64, MIPS
and a few others).  It failed because, given the following code:

extern int foo;
extern __typeof(foo) foo asm("bar");
int foo = 1;

we'd call assemble_external() while processing the reference to `foo'
within typeof, where we clearly don't need to be concerned about
emitting external declarations in the assembler.  The ill effect was
that the decl for foo would be bound to the name `foo' within
assemble_external().  This was a bit too early for asm("bar") to take
effect.  When we get to the point of processing the second declaration
of foo, that would give it the name bar, the RTL already generated for
the first decl is reused, so we keep on generating foo when
referencing it, instead of using the new name.

The solution I implemented that fixed the problem was to arrange for
typeof to enter skip_evaluation mode (I was surprised to find out it
didn't) and then arrange for no RTL or assembly code to be generated
for references that occur while in skip_evaluation mode.

An earlier version of this patch, that only modified the C front-end,
passed bootstrap in IA64 (thanks, Jakub!).  Jakub also noticed that
the problem affected C++ too, and kindly wrote testcases for me
(thanks again! :-).  I've tested this patch myself on
athlon-pc-linux-gnu-x-mips-elf.

Ok to install?

Index: gcc/ChangeLog
from  Alexandre Oliva  <aoliva@redhat.com>

	* c-tree.h (skip_evaluation): Move declaration...
	* c-common.h: ... here.
	* c-typeck.c (build_external_ref): Don't assemble_external nor
	mark a tree as used if skip_evaluation is set.
	* c-parse.in (typeof): New non-terminal to set skip_evaluation
	around TYPEOF.
	(typespec_nonreserved_nonattr): Use it.

Index: gcc/c-tree.h
===================================================================
RCS file: /cvs/uberbaum/gcc/c-tree.h,v
retrieving revision 1.104
diff -u -p -r1.104 c-tree.h
--- gcc/c-tree.h 10 Aug 2002 02:18:27 -0000 1.104
+++ gcc/c-tree.h 12 Aug 2002 20:57:29 -0000
@@ -311,11 +311,6 @@ extern int current_function_returns_null
 
 extern int current_function_returns_abnormally;
 
-/* Nonzero means the expression being parsed will never be evaluated.
-   This is a count, since unevaluated expressions can nest.  */
-
-extern int skip_evaluation;
-
 /* Nonzero means we are reading code that came from a system header file.  */
 
 extern int system_header_p;
Index: gcc/c-common.h
===================================================================
RCS file: /cvs/uberbaum/gcc/c-common.h,v
retrieving revision 1.152
diff -u -p -r1.152 c-common.h
--- gcc/c-common.h 12 Aug 2002 06:02:52 -0000 1.152
+++ gcc/c-common.h 12 Aug 2002 20:57:29 -0000
@@ -790,6 +790,11 @@ extern int warn_deprecated;
 
 extern int max_tinst_depth;
 
+/* Nonzero means the expression being parsed will never be evaluated.
+   This is a count, since unevaluated expressions can nest.  */
+
+extern int skip_evaluation;
+
 /* C types are partitioned into three subsets: object, function, and
    incomplete types.  */
 #define C_TYPE_OBJECT_P(type) \
Index: gcc/c-typeck.c
===================================================================
RCS file: /cvs/uberbaum/gcc/c-typeck.c,v
retrieving revision 1.202
diff -u -p -r1.202 c-typeck.c
--- gcc/c-typeck.c 10 Aug 2002 02:18:27 -0000 1.202
+++ gcc/c-typeck.c 12 Aug 2002 20:57:33 -0000
@@ -1441,7 +1441,8 @@ build_external_ref (id, fun)
   if (TREE_TYPE (ref) == error_mark_node)
     return error_mark_node;
 
-  assemble_external (ref);
+  if (!skip_evaluation)
+    assemble_external (ref);
   TREE_USED (ref) = 1;
 
   if (TREE_CODE (ref) == CONST_DECL)
Index: gcc/c-parse.in
===================================================================
RCS file: /cvs/uberbaum/gcc/c-parse.in,v
retrieving revision 1.151
diff -u -p -r1.151 c-parse.in
--- gcc/c-parse.in 10 Aug 2002 02:18:27 -0000 1.151
+++ gcc/c-parse.in 12 Aug 2002 20:57:35 -0000
@@ -562,6 +562,10 @@ alignof:
 	ALIGNOF { skip_evaluation++; }
 	;
 
+typeof:
+	TYPEOF { skip_evaluation++; }
+	;
+
 cast_expr:
 	unary_expr
 	| '(' typename ')' cast_expr  %prec UNARY
@@ -1394,10 +1398,10 @@ ifobjc
         | non_empty_protocolrefs
                 { $$ = get_object_reference ($1); }
 end ifobjc
-	| TYPEOF '(' expr ')'
-		{ $$ = TREE_TYPE ($3); }
-	| TYPEOF '(' typename ')'
-		{ $$ = groktypename ($3); }
+	| typeof '(' expr ')'
+		{ skip_evaluation--; $$ = TREE_TYPE ($3); }
+	| typeof '(' typename ')'
+		{ skip_evaluation--; $$ = groktypename ($3); }
 	;
 
 /* typespec_nonreserved_attr does not exist.  */
Index: gcc/cp/ChangeLog
from  Alexandre Oliva  <aoliva@redhat.com>

	* parse.y (sizeof, alignof, typeof): New non-terminals to
	increment skip_evaluation.  Replace terminals with them and
	decrement skip_evaluation at the end of rules using them.
	* decl2.c (mark_used): Don't assemble_external if
	skipping evaluation.

Index: gcc/cp/parse.y
===================================================================
RCS file: /cvs/uberbaum/gcc/cp/parse.y,v
retrieving revision 1.277
diff -u -p -r1.277 parse.y
--- gcc/cp/parse.y 11 Aug 2002 18:30:24 -0000 1.277
+++ gcc/cp/parse.y 12 Aug 2002 20:57:47 -0000
@@ -1277,16 +1277,20 @@ unary_expr:
 	/* Refer to the address of a label as a pointer.  */
 	| ANDAND identifier
 		{ $$ = finish_label_address_expr ($2); }
-	| SIZEOF unary_expr  %prec UNARY
-		{ $$ = finish_sizeof ($2); }
-	| SIZEOF '(' type_id ')'  %prec HYPERUNARY
+	| sizeof unary_expr  %prec UNARY
+		{ $$ = finish_sizeof ($2);
+		  skip_evaluation--; }
+	| sizeof '(' type_id ')'  %prec HYPERUNARY
 		{ $$ = finish_sizeof (groktypename ($3.t));
-		  check_for_new_type ("sizeof", $3); }
-	| ALIGNOF unary_expr  %prec UNARY
-		{ $$ = finish_alignof ($2); }
-	| ALIGNOF '(' type_id ')'  %prec HYPERUNARY
+		  check_for_new_type ("sizeof", $3);
+		  skip_evaluation--; }
+	| alignof unary_expr  %prec UNARY
+		{ $$ = finish_alignof ($2);
+		  skip_evaluation--; }
+	| alignof '(' type_id ')'  %prec HYPERUNARY
 		{ $$ = finish_alignof (groktypename ($3.t));
-		  check_for_new_type ("alignof", $3); }
+		  check_for_new_type ("alignof", $3);
+		  skip_evaluation--; }
 
 	/* The %prec EMPTY's here are required by the = init initializer
 	   syntax extension; see below.  */
@@ -2004,6 +2008,18 @@ reserved_typespecquals:
 		{ $$ = tree_cons ($1, NULL_TREE, NULL_TREE); }
 	;
 
+sizeof:
+	SIZEOF { skip_evaluation++; }
+	;
+
+alignof:
+	ALIGNOF { skip_evaluation++; }
+	;
+
+typeof:
+	TYPEOF { skip_evaluation++; }
+	;
+
 /* A typespec (but not a type qualifier).
    Once we have seen one of these in a declaration,
    if a typedef name appears then it is being redeclared.  */
@@ -2015,12 +2031,14 @@ typespec:
 		{ $$.t = $1; $$.new_type_flag = 0; $$.lookups = NULL_TREE; }
 	| complete_type_name
 		{ $$.t = $1; $$.new_type_flag = 0; $$.lookups = NULL_TREE; }
-	| TYPEOF '(' expr ')'
+	| typeof '(' expr ')'
 		{ $$.t = finish_typeof ($3);
-		  $$.new_type_flag = 0; $$.lookups = NULL_TREE; }
-	| TYPEOF '(' type_id ')'
+		  $$.new_type_flag = 0; $$.lookups = NULL_TREE;
+		  skip_evaluation--; }
+	| typeof '(' type_id ')'
 		{ $$.t = groktypename ($3.t);
-		  $$.new_type_flag = 0; $$.lookups = NULL_TREE; }
+		  $$.new_type_flag = 0; $$.lookups = NULL_TREE;
+		  skip_evaluation--; }
 	| SIGOF '(' expr ')'
 		{ tree type = TREE_TYPE ($3);
 
Index: gcc/cp/decl2.c
===================================================================
RCS file: /cvs/uberbaum/gcc/cp/decl2.c,v
retrieving revision 1.559
diff -u -p -r1.559 decl2.c
--- gcc/cp/decl2.c 11 Aug 2002 18:30:24 -0000 1.559
+++ gcc/cp/decl2.c 12 Aug 2002 20:57:51 -0000
@@ -4717,7 +4717,8 @@ mark_used (decl)
   TREE_USED (decl) = 1;
   if (processing_template_decl)
     return;
-  assemble_external (decl);
+  if (!skip_evaluation)
+    assemble_external (decl);
 
   /* Is it a synthesized method that needs to be synthesized?  */
   if (TREE_CODE (decl) == FUNCTION_DECL
Index: gcc/testsuite/ChangeLog
from  Jakub Jelinek  <jakub@redhat.com>

	* gcc.dg/typeof-1.c: New test.
	* g++.dg/ext/typeof2.C: New test.

Index: gcc/testsuite/gcc.dg/typeof-1.c
===================================================================
RCS file: gcc/testsuite/gcc.dg/typeof-1.c
diff -N gcc/testsuite/gcc.dg/typeof-1.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gcc/testsuite/gcc.dg/typeof-1.c 12 Aug 2002 20:57:56 -0000
@@ -0,0 +1,27 @@
+/* Test typeof with __asm redirection. */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+extern int foo1;
+extern int foo1 __asm ("bar1");
+int foo1 = 1;
+
+extern int foo2 (int);
+extern int foo2 (int) __asm ("bar2");
+int foo2 (int x)
+{
+  return x;
+}
+
+extern int foo3;
+extern __typeof (foo3) foo3 __asm ("bar3");
+int foo3 = 1;
+
+extern int foo4 (int);
+extern __typeof (foo4) foo4 __asm ("bar4");
+int foo4 (int x)
+{
+  return x;
+}
+
+// { dg-final { scan-assembler-not "foo" } }
Index: gcc/testsuite/g++.dg/ext/typeof2.C
===================================================================
RCS file: gcc/testsuite/g++.dg/ext/typeof2.C
diff -N gcc/testsuite/g++.dg/ext/typeof2.C
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gcc/testsuite/g++.dg/ext/typeof2.C 12 Aug 2002 20:57:56 -0000
@@ -0,0 +1,29 @@
+// Test typeof with __asm redirection
+// { dg-do compile }
+// { dg-options "-O2" }
+
+extern "C" {
+  extern int foo1;
+  extern int foo1 __asm ("bar1");
+  int foo1 = 1;
+
+  extern int foo2 (int);
+  extern int foo2 (int) __asm ("bar2");
+  int foo2 (int x)
+  {
+    return x;
+  }
+
+  extern int foo3;
+  extern __typeof (foo3) foo3 __asm ("bar3");
+  int foo3 = 1;
+
+  extern int foo4 (int);
+  extern __typeof (foo4) foo4 __asm ("bar4");
+  int foo4 (int x)
+  {
+    return x;
+  }
+}
+
+// { dg-final { scan-assembler-not "foo" } }
-- 
Alexandre Oliva   Enjoy Guarana', see http://www.ic.unicamp.br/~oliva/
Red Hat GCC Developer                 aoliva@{redhat.com, gcc.gnu.org}
CS PhD student at IC-Unicamp        oliva@{lsd.ic.unicamp.br, gnu.org}
Free Software Evangelist                Professional serial bug killer

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]