Missing load barrier at the compiler side for C++ local static objects?

r6144 rainy6144@gmail.com
Fri Jun 11 13:07:00 GMT 2010


Hello,

When I compile the following C++ code
==========================================
extern int f(void);

struct A {
  int x;
  A() { this->x = f(); }
};

int g(void)
{
  static A a;
  return a.x;
}
==========================================
with "g++ -fdump-tree-gimple" (with gcc 4.5.0) on x86-64, the generated
GIMPLE code is like this:

==========================================
int g() ()
{
  char * _ZGVZ1gvE1a.0;
  char D.2126;
  bool retval.1;
  int D.2130;
  bool D.2123;
  int D.2138;
  static struct A a;

  _ZGVZ1gvE1a.0 = (char *) &_ZGVZ1gvE1a;
  D.2126 = *_ZGVZ1gvE1a.0;
  if (D.2126 == 0) goto <D.2127>; else goto <D.2128>;
  <D.2127>:
  [__cxa_acquire etc. snipped]
  <D.2128>:
  <D.2137>:
  D.2138 = a.x;
  return D.2138;
}
==========================================
If I'm understanding correctly, to be thread-safe, double-checked
locking in general requires a load barrier between checking the guard
variable and accessing the object.  On x86-64 no CPU-level load barrier
is necessary, but shouldn't one be needed at the compiler level?

Here the guard variable *_ZGBZ1gvE1a.0 is not marked volatile, so can't
the compiler later move the load of a.x before the load of the guard
variable (and redo it if we go the D.2127 path)?  This would clearly be
unsafe, as another thread can do the construction after the first load
of a.x and before loading the guard variable, so the current thread
would see object "a" constructed but will be returning a stale
uninitialized copy of a.x.

Please CC me as I'm not subscribed.

r6144




More information about the Gcc-help mailing list