Bug 31775 - static object mangling conflicts with extern object
Summary: static object mangling conflicts with extern object
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 4.3.0
: P3 normal
Target Milestone: 4.3.0
Assignee: Geoff Keating
URL:
Keywords: wrong-code
Depends on:
Blocks:
 
Reported: 2007-05-01 19:53 UTC by Geoff Keating
Modified: 2010-01-07 07:04 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2007-05-02 01:46:13


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Geoff Keating 2007-05-01 19:53:25 UTC
In [basic.link] paragraph 6, there's an example that shows that (unlike in C) it is permissible to define an object 'static' in a namespace scope and then have another object which is 'extern', and reference both in the same translation unit.

The compiler optimises that example so that there's no way to see the incorrect behaviour, but a slightly modified version is:

extern "C" void abort();
static int i;
int *p = &i;
int main()
{ 
  int i;
  { 
    extern int i;
    i = 1;
    *p = 2;
    if (i == 2)
      abort ();
  }
  return 0;
}

I believe this should fail to compile with a link error, because the extern version of 'i' is never defined.  On Darwin, what this does (apparently) is crash with a bus error trying to write to the first instruction of main, which is probably a linker bug; I expect that on other OSs it will call abort().

The basic problem is that 'static int i' needs to be a different name in the assembly than 'extern int i'.
Comment 1 Geoff Keating 2007-05-01 19:56:18 UTC
This testcase is the same principle, but might use a different code path in the compiler:

extern "C" void abort();
extern int *p;
int main()
{ 
  extern int i;
  i = 1;
  *p = 2;
  if (i == 2)
    abort ();
  return 0;
}

static int i;
int *p = &i;
Comment 2 Richard Biener 2007-05-01 20:44:06 UTC
How do you define main"::"i?  That is, how'd you make the testcase work from a
second translation unit if it would fail now?
Comment 3 Geoff Keating 2007-05-02 00:54:12 UTC
You would add a translation unit that says

int i;

or similar.  It's not "main::i", it's "::i", because of [basic.link] paragraph 7:

When a block scope declaration of an entity with linkage is not found to refer to some other declaration, 
then that entity is a member of the innermost enclosing namespace.
Comment 4 Geoff Keating 2007-05-02 01:46:13 UTC
I just happen to have a patch which fixes this.
Comment 5 Geoff Keating 2007-05-06 01:01:49 UTC
Subject: Bug 31775

Author: geoffk
Date: Sun May  6 00:01:36 2007
New Revision: 124467

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=124467
Log:
Index: libiberty/ChangeLog
2007-05-04  Geoffrey Keating  <geoffk@apple.com>

	* cp-demangle.c (d_name): Detect local-source-name.
	(d_prefix): Likewise.
	(d_unqualified_name): Implement local-source-name.

Index: gcc/cp/ChangeLog
2007-05-04  Geoffrey Keating  <geoffk@apple.com>

	PR 31775
	* mangle.c (write_mangled_name): Mangle static variable names.
	(write_unqualified_name): Use local-source-name for
	namespace-scope static variables.

Index: gcc/testsuite/ChangeLog
2007-05-04  Geoffrey Keating  <geoffk@apple.com>

	PR 31775
	* g++.dg/other/nested-extern.cc: New.
	* g++.dg/other/nested-extern-1.C: New.
	* g++.dg/other/nested-extern-2.C: New.

Added:
    trunk/gcc/testsuite/g++.dg/other/nested-extern-1.C
    trunk/gcc/testsuite/g++.dg/other/nested-extern-2.C
    trunk/gcc/testsuite/g++.dg/other/nested-extern.cc
Modified:
    trunk/gcc/cp/ChangeLog
    trunk/gcc/cp/mangle.c
    trunk/gcc/testsuite/ChangeLog
    trunk/libiberty/ChangeLog
    trunk/libiberty/cp-demangle.c
    trunk/libiberty/testsuite/demangle-expected

Comment 6 Geoff Keating 2007-05-06 01:27:08 UTC
That should do it.
Comment 7 Dirk Mueller 2008-02-29 13:57:00 UTC
how about 

extern "C" void abort();
extern "C" { static int i; }
int *p = &i;
int main()
{ 
  int i;
  { 
    extern int i;
    i = 1;
    *p = 2;
    if (i == 2)
      abort ();
  }
  return 0;
}

in this case, the "i" name should not be mangled, right?
Comment 8 Geoff Keating 2008-03-01 04:05:34 UTC
Subject: Re:  static object mangling conflicts with extern object


On 29/02/2008, at 5:57 AM, mueller at gcc dot gnu dot org wrote:

> extern "C" void abort();
> extern "C" { static int i; }
> int *p = &i;
> int main()
> {
>  int i;
>  {
>    extern int i;
>    i = 1;
>    *p = 2;
>    if (i == 2)
>      abort ();
>  }
>  return 0;
> }
>
> in this case, the "i" name should not be mangled, right?

It should be mangled, because there are still three different things  
named 'i' declared in this program, and so the two that have assembler  
names have to have different names, and I don't think we want to start  
mangling non-static variable names.
Comment 9 pinskia@gmail.com 2008-03-01 04:19:33 UTC
Subject: Re:  static object mangling conflicts with extern object

Sent from my iPhone

On Feb 29, 2008, at 20:05, "geoffk at geoffk dot org" <gcc-bugzilla@gcc.gnu.org 
 > wrote:

>
>
> ------- Comment #8 from geoffk at geoffk dot org  2008-03-01 04:05  
> ----
>>
>
> It should be mangled, because there are still three different things
> named 'i' declared in this program, and so the two that have assembler
> names have to have different names, and I don't think we want to start
> mangling non-static variable names.

Also mangling non-static variables will cause an ABI change.

Thanks,
Andrew Pinski