Archived

This forum has been archived. Please start a new discussion on GitHub.

Assertion failed

Ice version: 2.0.0 (no problem with the previous one).
Platform: Linux 2.4.21-20
Compiler: gcc 3.2.3; glibc-2.3.2-95.27

The code with Makefile is in the attachment.
This is minimal code I was able to create to reproduce the problem.

Modify Makefile and build the executable 'server'.
Start it:
./server --daemon --noclose --nochdir --Ice.PrintProcessId
and then kill it
kill <pid>

Ice complains with:

server: /home/nsmirnov/public/Ice2/include/IceUtil/Shared.h:300: void IceUtil::Shared::__decRef(): Assertion `ice_atomic_exchange_add(0, &_ref) > 0' failed.

It seems to me that the problem somewhere around the line

static ::IceInternal::UserExceptionFactoryPtr _factory;

from 'class E : public ::Ice::UserException'
generated by Ice from 'shared.ice'.

Regards,
Nikolai

Comments

  • bernard
    bernard Jupiter, FL
    Hi Nikolai,

    Thansk for the bug report. I was able to reproduce this assert on Linux 2.4.x and I am investigating!

    Cheers,
    Bernard
  • I'm currently looking at this. It looks like gcc is generating incorrect code for initialization of static members in some cases. (I'm seeing three calls to the constructor instead of the single one I would expect, and I'm seeing the setting of the variable being lost in between the second and third of the constructor calls.)

    But, even if gcc were to get it right, your program still would have undefined behavior: the generated shared.cpp file contains a static member variable, and the server links with shared.o. Also, the server loads a shared library at run time which also contains shared.o. The net effect is that we end up with the same static member being present twice in the program, once via the shared.o file that is linked into the server, and once via the shared library that is loaded at run time. But this violates the One Definition Rule, so the program has undefined behavior.

    I'm currently looking at changing the generated code to avoid using a static member, which would neatly side-step both the bug in gcc and the violation of ODR.

    Please bear with me while I try to sort this out...

    Thanks,

    Michi.
  • I added the following lines to shared.h (just after 'namespace M {'):

    class GlobInit {
    public:
    GlobInit();
    ~GlobInit();
    private:
    static int n_;
    };

    and replaced in shared.cpp
    ::IceInternal::UserExceptionFactoryPtr M::E::_factory = new __F__M__E;
    with
    ::IceInternal::UserExceptionFactoryPtr M::E::_factory;

    int M::GlobInit::n_;

    M::GlobInit::GlobInit()
    {
    if ( n_++ == 0 ) M::E::_factory = new __F__M__E;
    }

    M::GlobInit::~GlobInit()
    {
    --n_;
    }

    Now it seems it works. The idea is from Stroustrup "C++" from the section about initializing
    globals such as cout.

    Regards, Nikolai
  • Yes, that is the obvious approach (which we use elsewhere in the Ice code), and that is the approach I tried. However, gcc doesn't do the the right thing and ends up calling the constructor more often than it should.

    In addition, as I said in my previous posting, this doesn't really solve the problem if a program links with this compilation unit and then also loads a shared library at run time that contains another copy of this compilation unit, because that violates the ODR. A better solution really is to get rid of the static member altogether.

    Stay tuned...

    Michi.
  • Just to correct myself. When I cut/paste I missed the following from shared.h:

    namespace {
    GlobInit __ginit;
    }
    A better solution really is to get rid of the static member altogether.

    Absolutely agree,

    Nikolai
  • I've posted a patch at http://www.zeroc.com/vbulletin/showthread.php?s=&threadid=1028. That patch works around the bug in gcc and also removes all static class data members, so there are no more problems with the ODR when the same .o file is loaded more than once.

    Cheers,

    Michi.
  • compile error , env:

    [root@mars2 Ice-2.0.0]# gcc -v
    Reading specs from /usr/lib/gcc-lib/i386-redhat-linux/3.2.3/specs
    Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --enable-shared --enable-threads=posix --disable-checking --with-system-zlib --enable-__cxa_atexit --host=i386-redhat-linux
    Thread model: posix
    gcc version 3.2.3 20030502 (Red Hat Linux 3.2.3-34)
    [root@mars2 Ice-2.0.0]#

    after patch:

    making all in Freeze
    make[2]: Entering directory `/root/Ice-2.0.0/src/Freeze'
    c++ -c -I.. -I../../include -DFREEZE_API_EXPORTS -I/usr/local/db-4.2.52.NC/include -O2 -DNDEBUG -ftemplate-depth-128 -fPIC -Wall -D_REENTRANT SharedDbEnv.cpp
    SharedDbEnv.cpp: In constructor `Freeze::SharedDbEnv::SharedDbEnv(const
    std::string&, const Ice::CommunicatorPtr&)':
    SharedDbEnv.cpp:294: `DB_LOG_AUTOREMOVE' undeclared (first use this function)
    SharedDbEnv.cpp:294: (Each undeclared identifier is reported only once for each
    function it appears in.)
    make[2]: *** [SharedDbEnv.o] Error 1
    make[2]: Leaving directory `/root/Ice-2.0.0/src/Freeze'
    make[1]: *** [all] Error 1
    make[1]: Leaving directory `/root/Ice-2.0.0/src'
    make: *** [all] Error 1
  • bernard
    bernard Jupiter, FL
    > SharedDbEnv.cpp:294: `DB_LOG_AUTOREMOVE' undeclared (first use this function)

    This has nothing to do with Michi's patch. You're not using the proper Berkeley DB version: you need 4.2.52 or 4.3 (Ice for Java: 4.2.52 only).

    Cheers,
    Bernard
  • After applying the patch my project works.
    Thanks,
    Nikolai
  • sorry, It's my mistake, I defined wrong DB directory