Discussion:
[omniORB] Static build with GCC 3.4
Vladimir Panov
2005-02-11 02:37:18 UTC
Permalink
Hi.

When omniORB 4.0.5 (or any 4.0 version, actually) is built with GCC 3.4,
then a statically linked program against it segfaults on startup. The
reason is that the static initializers of the code sets are not executed
(even the ones from libomniORB4.a, not only the ones from
libomniCodeSets4.a). The reason seems to be a new optimization in GCC
3.4 called "unit-at-a-time" which is on by default when using -O2.
As far as I understood, this optimization considers the static
initilizers to be dead code, and GCC doesn't even generate machine code
for them, let alone run them. I tried to fix this in the source
(including the advised way of using the "used" attribute) but miserably
failed. Of course, there should be a way to achieve this in the source
somehow and this would be the best solution.
Another solution is to use -fno-unit-at-a-time, and I have attached a
patch for it against omniORB 4.0.5 (don't forget to run autoreconf after
you apply it). But this should be considered a temporary solution
because the option might be dropped in the future.
Here is the GCC 3.4's changelog which gives some information about the
unit-at-a-time optimization:
http://gcc.gnu.org/gcc-3.4/changes.html

Vlado

-------------- next part --------------
diff -r -u omniORB-4.0.5-orig/acinclude.m4 omniORB-4.0.5/acinclude.m4
--- omniORB-4.0.5-orig/acinclude.m4 2004-10-17 23:14:25.000000000 +0300
+++ omniORB-4.0.5/acinclude.m4 2005-02-06 22:23:57.000000000 +0200
@@ -470,3 +470,14 @@
fi
])

+AC_DEFUN([OMNI_CHECK_NO_UNIT_AT_A_TIME],
+[AC_CACHE_CHECK(whether $CC accepts -fno-unit-at-a-time,
+omni_cv_no_unit_at_a_time,
+[
+ AC_LANG_PUSH(C)
+ save_CFLAGS=$CFLAGS
+ CFLAGS="$CFLAGS -fno-unit-at-a-time"
+ AC_COMPILE_IFELSE(AC_LANG_PROGRAM(,), omni_cv_no_unit_at_a_time="yes", omni_cv_no_unit_at_a_time="no")
+ CFLAGS=$save_CFLAGS
+ AC_LANG_POP
+])])
diff -r -u omniORB-4.0.5-orig/configure.ac omniORB-4.0.5/configure.ac
--- omniORB-4.0.5-orig/configure.ac 2004-10-18 03:44:55.000000000 +0300
+++ omniORB-4.0.5/configure.ac 2005-02-06 23:02:15.000000000 +0200
@@ -26,6 +26,12 @@

AC_LANG(C++)

+OMNI_CHECK_NO_UNIT_AT_A_TIME
+if test "x$omni_cv_no_unit_at_a_time" = "xyes"
+then
+ EXTRA_GCC_CXXFLAGS="-fno-unit-at-a-time"
+fi
+AC_SUBST(EXTRA_GCC_CXXFLAGS)

dnl ** Libraries

diff -r -u omniORB-4.0.5-orig/mk/beforeauto.mk.in omniORB-4.0.5/mk/beforeauto.mk.in
--- omniORB-4.0.5-orig/mk/beforeauto.mk.in 2004-10-18 03:44:56.000000000 +0300
+++ omniORB-4.0.5/mk/beforeauto.mk.in 2005-02-06 23:00:46.000000000 +0200
@@ -733,7 +733,7 @@
ifdef Compiler_GCC
CMAKEDEPEND += -D__GNUC__
CXXMAKEDEPEND += -D__GNUG__ -D__GNUC__
-CXXOPTIONS = -Wall -Wno-unused -fexceptions
+CXXOPTIONS = -Wall -Wno-unused -fexceptions @EXTRA_GCC_CXXFLAGS@
EgcsMajorVersion = 1
EgcsMinorVersion = 1
SHAREDLIB_CPPFLAGS = -fPIC
Duncan Grisby
2005-03-03 18:29:02 UTC
Permalink
Post by Vladimir Panov
When omniORB 4.0.5 (or any 4.0 version, actually) is built with GCC
3.4, then a statically linked program against it segfaults on
startup. The reason is that the static initializers of the code sets
are not executed (even the ones from libomniORB4.a, not only the ones
from libomniCodeSets4.a). The reason seems to be a new optimization in
GCC 3.4 called "unit-at-a-time" which is on by default when using -O2.
Thanks for your patch. I've checked it in. Have you reported the problem
to the GCC developers?

Cheers,

Duncan.
--
-- Duncan Grisby --
-- ***@grisby.org --
-- http://www.grisby.org --
Vladimir Panov
2005-03-03 18:38:13 UTC
Permalink
Post by Duncan Grisby
Post by Vladimir Panov
When omniORB 4.0.5 (or any 4.0 version, actually) is built with GCC
3.4, then a statically linked program against it segfaults on
startup. The reason is that the static initializers of the code sets
are not executed (even the ones from libomniORB4.a, not only the ones
from libomniCodeSets4.a). The reason seems to be a new optimization in
GCC 3.4 called "unit-at-a-time" which is on by default when using -O2.
Thanks for your patch. I've checked it in. Have you reported the problem
to the GCC developers?
Cheers,
Duncan.
Hi, Duncan.

Actually, it is not a bug. They are fully aware of the problems this
optimization might introduce.
omniORB's problem is that -fno-unit-at-a-time might be dropped in the
future (as stated in the realease notes of GCC 3.4). I tried to fix the
source so that -fno-unit-at-a-time is not needed, but failed. If I try
again and succeed, I will send a patch.

Vlado
Vladimir Panov
2006-10-22 03:53:21 UTC
Permalink
Post by Duncan Grisby
Post by Vladimir Panov
When omniORB 4.0.5 (or any 4.0 version, actually) is built with GCC
3.4, then a statically linked program against it segfaults on
startup. The reason is that the static initializers of the code sets
are not executed (even the ones from libomniORB4.a, not only the ones
from libomniCodeSets4.a). The reason seems to be a new optimization in
GCC 3.4 called "unit-at-a-time" which is on by default when using -O2.
Thanks for your patch. I've checked it in. Have you reported the problem
to the GCC developers?
Cheers,
Duncan.
Hi, Duncan.

I have found that there are more cases to fix (because of using
"CXXOPTIONS =" rather than "CXXOPTIONS +="), for example Darwin.
I have attached a patch against omniORB 4.0.7
(omniORB-4.0.7-EXTRA_GCC_CXXFLAGS.patch).

However, -fno-unit-at-a-time is not enough when using GCC 4. It ignores
unused static global variables and functions. I have found two solutions:
a) Use non-static variables to reference the export symbol. We have to
ensure a unique-per-source-file name for the variable but I couldn't
figure out how to do it automatically. Manually doing this is not
possible because OMNI_FORCE_LINK is used indirectly (in headers).
b) Do something on the export symbol, like ++. This way, the compiler
will still ignore the unused global static variable but because code
must be generated for the ++ operator it won't discard the reference.
The downside is that the code will actually be executed. I have attached
a patch against omniORB 4.0.7 (omniORB-4.0.7-linkHacks.patch). If it is
applied then -fno-unit-at-a-time is not required and
OMNI_CHECK_NO_UNIT_AT_A_TIME can be removed from configure.ac.

Vlado

-------------- next part --------------
diff -u -r -u -N omniORB-4.0.7-orig/mk/beforeauto.mk.in omniORB-4.0.7/mk/beforeauto.mk.in
--- omniORB-4.0.7-orig/mk/beforeauto.mk.in 2005-03-22 15:53:41.000000000 +0200
+++ omniORB-4.0.7/mk/beforeauto.mk.in 2006-10-21 00:17:55.000000000 +0300
@@ -870,7 +870,7 @@
# /opt/aCC/lbin/ld: Unsatisfied symbols:
# fstreambase::cma_close(void)(code)
CXXOPTIONS = -fhandle-exceptions -Wall -Wno-unused \
- -D_CMA_NOWRAPPERS_
+ -D_CMA_NOWRAPPERS_ @EXTRA_GCC_CXXFLAGS@
endif

ifdef Compiler_aCC
@@ -958,7 +958,7 @@
OMNITHREAD_POSIX_CPPFLAGS = -DPthreadDraftVersion=10 \
-DPthreadSupportThreadPriority -DNoNanoSleep

-CXXOPTIONS = -fno-common -bind_at_load
+CXXOPTIONS = -fno-common -bind_at_load @EXTRA_GCC_CXXFLAGS@
SHAREDLIB_SUFFIX = dylib

SharedLibraryFullNameTemplate = lib$$1$$2.$$3.$$4.$(SHAREDLIB_SUFFIX)



-------------- next part --------------
diff -u -r -N omniORB-4.0.7-orig/include/omniORB4/linkHacks.h omniORB-4.0.7/include/omniORB4/linkHacks.h
--- omniORB-4.0.7-orig/include/omniORB4/linkHacks.h 2003-02-17 04:03:07.000000000 +0200
+++ omniORB-4.0.7/include/omniORB4/linkHacks.h 2006-10-21 22:39:48.000000000 +0300
@@ -63,8 +63,8 @@

#define OMNI_FORCE_LINK(modname) \
extern int _omni_ ## modname ## _should_be_linked_but_is_not_; \
- static int* _omni_ ## modname ## _forcelink_ = \
- &_omni_ ## modname ## _should_be_linked_but_is_not_; \
+ static int _omni_ ## modname ## _forcelink_ = \
+ _omni_ ## modname ## _should_be_linked_but_is_not_++; \
static int _omni_ ## modname ## _value_ () { \
return *(_omni_ ## modname ## _forcelink_); \
}
@@ -73,8 +73,8 @@

#define OMNI_FORCE_LINK(modname) \
extern int _omni_ ## modname ## _should_be_linked_but_is_not_; \
- static int* _omni_ ## modname ## _forcelink_ = \
- &_omni_ ## modname ## _should_be_linked_but_is_not_
+ static int _omni_ ## modname ## _forcelink_ = \
+ _omni_ ## modname ## _should_be_linked_but_is_not_++

#endif
Duncan Grisby
2005-03-03 18:43:17 UTC
Permalink
Post by Vladimir Panov
Actually, it is not a bug. They are fully aware of the problems this
optimization might introduce.
They might be fully aware of the problems, but I'd still say it's a
bug. Surely it violates the C++ specification?

Cheers,

Duncan.
--
-- Duncan Grisby --
-- ***@grisby.org --
-- http://www.grisby.org --
Vladimir Panov
2005-03-03 19:14:59 UTC
Permalink
Post by Duncan Grisby
Post by Vladimir Panov
Actually, it is not a bug. They are fully aware of the problems this
optimization might introduce.
They might be fully aware of the problems, but I'd still say it's a
bug. Surely it violates the C++ specification?
Cheers,
Duncan.
Hi, Duncan.

I'm not sure. It seems to me that the constructor of a static variable
should always be generated and executed, no matter what optimizations
are done because this changes execution semantics; it is definitely not
the same as dropping an unused static function).
But the GCC developers should know better (and I don't even have the
standard).
I find it interesting (and unexplainable :-) that only the static link
is affected. Maybe it's not a matter of changing the static
initialization variables, but some improvement in
linkHacks.h. Again, if I find a solution, I'll send it.

Vlado
Visscher, Bruce
2005-03-04 00:45:38 UTC
Permalink
Post by Vladimir Panov
I'm not sure. It seems to me that the constructor of a static
variable
should always be generated and executed,
Unfortunately (IMHO), I don't think it is a simple as that. I
seem to recall wording to the effect that the initialization of
static instances can be deferred until the first use within a
compilation unit. If the instance is never "apparently" used
then maybe it doesn't have to do it at all. Side effects don't
count, so in fact, this breaks some popular design patterns.

It gets worse. I have recently come to the conclusion that the
following idiom no longer works for the initialization of singletons:

class SingletonLock; // implementation not shown.

class Singleton {
public:
static Singleton& instance() {
static Singleton* p=0;
if (!p) {
SingletonLock lock;
if (!p) {
static Singleton inst;
p=&inst;
}
}
return *p;
}
//...
};

This no longer works not because of compiler optimization but because
of optimizations that are being performed at the chip level.

<soapbox>
I think the above can be fixed using volatile and/or memory barriers
and/or by the elimination of the "double check then lock" idiom but
it was very disturbing to me to learn that something that I had determined
to be the "proper" way to do something after considerable thought and study
was now broken by an on-chip optimization that doesn't have access to the
original source code and so knows nothing about sequence points or anything
else.
</soapbox>

See the thread "Can C++ local static objects be made thread safe?":

http://groups-beta.google.com/group/comp.programming.threads/browse_frm/thread/087f35c382969e7b

Note that the optimzations I refer to are only supposed to affect multi-processor
machines but I don't believe that.

Bruce

-----------------------------------------
CONFIDENTIALITY NOTE: This e-mail message, including any attachment(s),
contains information that may be confidential, protected by the attorney-
client or other legal privileges, and/or proprietary non-public
information. If you are not an intended recipient of this message or an
authorized assistant to an intended recipient, please notify the sender by
replying to this message and then delete it from your system. Use,
dissemination, distribution, or reproduction of this message and/or any of
its attachments (if any) by unintended recipients is not authorized and
may be unlawful.
Harri Pasanen
2005-03-04 14:41:07 UTC
Permalink
Ouch, sounds bad. Can you say which chip you are talking about?

Actually I've noticed similar issues in the code I deal with, and
subsequently striven towards design where everything 'static' is
initialized via function call. Unfortunately it is not always
possible, especially with third party libs...

-Harri
Post by Visscher, Bruce
Post by Vladimir Panov
I'm not sure. It seems to me that the constructor of a static
variable
should always be generated and executed,
Unfortunately (IMHO), I don't think it is a simple as that. I
seem to recall wording to the effect that the initialization of
static instances can be deferred until the first use within a
compilation unit. If the instance is never "apparently" used
then maybe it doesn't have to do it at all. Side effects don't
count, so in fact, this breaks some popular design patterns.
It gets worse. I have recently come to the conclusion that the
following idiom no longer works for the initialization of
class SingletonLock; // implementation not shown.
class Singleton {
static Singleton& instance() {
static Singleton* p=0;
if (!p) {
SingletonLock lock;
if (!p) {
static Singleton inst;
p=&inst;
}
}
return *p;
}
//...
};
This no longer works not because of compiler optimization but
because of optimizations that are being performed at the chip
level.
<soapbox>
I think the above can be fixed using volatile and/or memory
barriers and/or by the elimination of the "double check then lock"
idiom but it was very disturbing to me to learn that something that
I had determined to be the "proper" way to do something after
considerable thought and study was now broken by an on-chip
optimization that doesn't have access to the original source code
and so knows nothing about sequence points or anything else.
</soapbox>
http://groups-beta.google.com/group/comp.programming.threads/browse
_frm/thread/087f35c382969e7b
Note that the optimzations I refer to are only supposed to affect
multi-processor machines but I don't believe that.
Bruce
-----------------------------------------
CONFIDENTIALITY NOTE: This e-mail message, including any
attachment(s), contains information that may be confidential,
protected by th attorney-
client or other legal privileges, and/or proprietary non-public
information. If you are not an intended recipient of this message
or an authorized assistant to an intended recipient, please notify
the sender by replying to this message and then delete it from
your system. Use, dissemination, distribution, or reproduction of
this message and/or any of its attachments (if any) by unintended
recipients is not authorized and may be unlawful.
_______________________________________________
omniORB-list mailing list
http://www.omniorb-support.com/mailman/listinfo/omniorb-list
This message, including any attachments, is intended only for the person(s) to whom it is addressed. If you received it in error, please let us know and delete the message from your system. This message may be confidential and may fall under the duty of non-disclosure. Any use by others than the intended addressee is prohibited. Trema shall not be liable for any damage related to the electronic transmission of this message, such as failure or delay of its delivery, interception or manipulation by third parties, or transmission of viruses or other malicious code.
Okeefe, Michael K
2005-03-07 22:39:40 UTC
Permalink
Post by Visscher, Bruce
Post by Vladimir Panov
I'm not sure. It seems to me that the constructor of a static
variable
should always be generated and executed,
Unfortunately (IMHO), I don't think it is a simple as that. I
seem to recall wording to the effect that the initialization of
static instances can be deferred until the first use within a
compilation unit. If the instance is never "apparently" used
then maybe it doesn't have to do it at all. Side effects don't
count, so in fact, this breaks some popular design patterns.
It gets worse. I have recently come to the conclusion that the
following idiom no longer works for the initialization of
class SingletonLock; // implementation not shown.
class Singleton {
static Singleton& instance() {
static Singleton* p=0;
if (!p) {
SingletonLock lock;
if (!p) {
static Singleton inst;
p=&inst;
}
}
return *p;
}
//...
};
Interesting - I thought this was only a JVM issue:

The "Double-Checked Locking is broken" declaration
http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html

It seems there is either the same, or at least a very similar issue with
C++:

(Article from Scott Meyers and Andrei Alexandrescu - C++ and the Perils
of Double-Checked Locking )
"Oh, Odysseus, don't let thyself be lured by sirens' voices; for much
trouble is waiting for thou and thy mates!"
http://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf
Post by Visscher, Bruce
This no longer works not because of compiler optimization but
because of optimizations that are being performed at the chip
level.
<soapbox>
I think the above can be fixed using volatile and/or memory
barriers and/or by the elimination of the "double check then lock"
idiom but it was very disturbing to me to learn that something that
I had determined to be the "proper" way to do something after
considerable thought and study was now broken by an on-chip
optimization that doesn't have access to the original source code
and so knows nothing about sequence points or anything else.
</soapbox>
[snip]
There were a few articles (at least for Java) where DCL was a "best
practice".

Mike
Duncan Grisby
2006-11-02 17:03:42 UTC
Permalink
Post by Vladimir Panov
b) Do something on the export symbol, like ++. This way, the compiler
will still ignore the unused global static variable but because code
must be generated for the ++ operator it won't discard the
reference. The downside is that the code will actually be executed. I
have attached a patch against omniORB 4.0.7
(omniORB-4.0.7-linkHacks.patch). If it is applied then
-fno-unit-at-a-time is not required and OMNI_CHECK_NO_UNIT_AT_A_TIME
can be removed from configure.ac.
Thanks. I've applied your patch to the 4.1 tree, and removed the
configure checks for -fno-unit-at-a-time.

Cheers,

Duncan.
--
-- Duncan Grisby --
-- ***@grisby.org --
-- http://www.grisby.org --
Continue reading on narkive:
Loading...