[omniORB] compiling omniORB3 on NT -- Assertion failure

Ji-Yong D. Chung virtualcyber@erols.com
Sun, 31 Oct 1999 13:53:51 -0500


    Library Involved:  omniORB3_rtd.dll (dll version of orbcore library) and
omniNames.exe
    Platform: NT4.0 (SP4) MSVC++

    As I indicated in my previous email messages, I have built a debug
versions of all the executables and dll's.  When I run my debug version of
omniNames.exe and omniORB3, the program dies, with an assertion failure

    I wish this would be "fixed" -- as it would make future debugging
easier.  This problem, by the way, probably will NOT show up in non-debug
version of omniORB3 and omniNames.  I will explain later why it is desirable
to fix this, even though the problem may not show up in the release version.
.

    The assertion failure happens in omniNames::init(CORBA:: ...) which is
in log.cc (see omniNames files).


void
omniNameslog::init(CORBA::ORB_ptr the_orb, PortableServer::POA_ptr the_poa)
{
    ...
    // stuff

      {
 CORBA::Object_var ref = poa->create_reference(
        CosNaming::NamingContext::_PD_repoId);
 PortableServer::ObjectId_var refid = poa->reference_to_id(ref);

 putCreate(refid, logf);
      }                                    <=== ASSERTION FAILURE #1

    // more stuff

  _omni_set_NameService(rootContext);
  delete p;                           <==== ASSERTION FAILURE #2

    // stuff
}


      The first assertion failure happens just after the execution of
putCreate(refid, logf).  If one looks at the code in that "area," they are
locally scoped within a pair of braces.

    Just after the execution of putCreate(refid, logf), as the execution
point is about to exit the locally scoped area, MSVC debugger checks if it
can delete   refid   .  Before it deletes the variable, however, it first
attempts to validate the wholesomeness of the memory which it is about to
de-allocate.  When the debugger finds that the memory pointer is not what it
should be, it generates an assertion failure.  And the program stops
executing.

    The assertion failure is made within MSVC delete operator (debug
version).  This operator happens to check WHETHER the memory which is about
to be de-allocated was originally allocated FROM the heap of the executing
module (local heap, that is).  Note that this heap (for omniNames.exe) is
not the same as the heap of omniORB3_rtd.dll.

    In the above code, the allocation of memory occurs inside   poa ->
reference_to_id(...)
procedure.  This eventually calls omniORB3_rtd.dll's memory allocation
routines.  Therefore, the memory is from the heap of omniORB3_rtd.dll, NOT
from the local heap.

     Later, refid will be deleted as the execution point moves outside the
braced area.  But the deletion operators that are invoked at this point are
LOCAL to omniNames.  The debug version of these delete operators expect the
de-allocating memory to be from the local heap; but it is not (it is from
omniORB3_rtd.dll's heap).  Thus the assertion failure.

    The reason why the deletion operators are local to omniNames is simple:
omniNames, when it gets built, includes  poa.h.  This  file contains inline
functions that allocates memory and de-allocates memory.  These inline
function get incorporated into omniNames as  local functions.  If the
execution of the above code actually called the delete operators from
omniORB3_rtd.dll, since the calling delete operator's local heap is the same
as that of omniORB3_rtd.dll, there would not be assertion failures.

    In other words, if one were to remove "inline" specifiers" from
constructors/destructors/member functions of ObjectID_var, ObjectId_out, and
ObjectId_var, (all inside poa.cc) the assertion error above would go away.
Of course, poa.cc now would need to contain the definition of those
declarations in poa.h

----------------------------------------------------------------------------
-------------------

    There are other memory assertion failures that occur for the same
reasons described above.  To repeat, these assertions occur because of
inline specifiers in header files that are present in both exporting and
importing dll/libraries.

    It is good idea to remove the inline specifier for these functions and
to move their definitions into implementation files.  There are two good
reasons for doing this.  First, the efficiency gain from saving few function
calls are generally are overshadowed by memory allocation/de-allocation
operations.  The memory allocation and de-allocation operations are about
500 times more expensive than a single machine instruction (of course, a
function call is also more expensive than a single instruction).  The point
here is that the gain in speed is not as great as one might expect.

    The second reason is much more important: these inlined functions that
cross the DLL boundaries make debugging just pure hell --- one dll starts
deleting objects and stuff from another heap, and one cannot trace the
source of error.  As you might expect, debugging omniORB3 may take months
(or perhaps longer).  During all these debugging sessions, one really needs
to be able to narrow down the potential source of problems.