Solved

Intermitent crash on CoUninitialize();

Posted on 2002-07-17
14
1,092 Views
Last Modified: 2012-05-04
Hi everybody,

I use a COM object that export one method. Since I want to use it in few places in the program, I've made a wrapper in order to do the "com initialisation stuff" in only one file.

Here's what I do : In a .cpp file I create a static object. In its constructor, I initialize COM and create an instance of this object. In the destructor, I release the object and uninitialize COM. Since that object is static, its ctor is called at the beginning of the program and its dtor is called at the end of the prog.
The ctor and dtor are called from the main thread.

A crash happend -rarely- on the CoInitialize()...

Here are some extra info to help you look the good direction :
- Windows NT sp6a.
- VC++ 6.0.
- The problem happen even if the COM object is not registred, so not created and "myExportedFunction" is never called.
- The main thread is CoInitialized with : CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
- No other COM objects are created in the main thread (or in that app).
- The code resides in a .lib that is staticly link with the main exe.
- Here is the stack of the crash :
073c8d20()
USER32! 77e71303()
USER32! 77e71962()
NTDLL! 77f763ef()
USER32! 77e755a8()
OLE32! 77b44e21()
OLE32! 77b45185()
MyWrapperObj::~MyWrapperObj() line 123 <-= The CoUninitialize() line.
$E24() + 13 bytes
doexit(int 0, int 0, int 0) line 353
exit(int 0) line 279 + 13 bytes
WinMainCRTStartup() line 345
KERNEL32! 77f1b9ea()

Here's the .cpp code :

#include "MyCOMWrapper.h"
#include "atlbase.h"
#import  "ACOMObject.dll" named_guids no_namespace

class MyWrapperObj{
  public:
    bool mIsReady;  
    IACOMObject*  mpACOMObject;

  public:
    MyWrapperObj(void)
    {
      HRESULT hr;
      mpACOMObject = NULL;
   
      hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);

      if ( SUCCEEDED(hr) )
      {
        hr = CoCreateInstance(CLSID_ACOMObject, NULL,
             CLSCTX_ALL, IID_ACOMObject,
            (void**)&mpACOMObject );
        mIsReady   = SUCCEEDED(hr);
      }
    }

    ~MyWrapperObj(void)
    {
      mIsReady = false;
      if (mpACOMObject != NULL)
      {
        mpACOMObject->Release();
      }
      CoUninitialize();
    }    
};

static MyWrapperObj theObject;

void myExportedFunction()
{
  if (mIsReady)
  {
    theObject.mpACOMObject->doStuff();
  }
}


Et voilà ! I think I included all important information. I ask your help because my solution bag is now empty and I hope yours contains the answer I need.

Thanks ans good luck,

renam00


0
Comment
Question by:renam00
  • 5
  • 4
  • 3
  • +1
14 Comments
 
LVL 86

Expert Comment

by:jkr
ID: 7159949
Install the NT4 SP6a Debug Symbols first (http://www.microsoft.com/ntserver/nts/downloads/recommended/SP6/debug/default.asp) - this will make an analysis much easier, as we could see the actual function names instead of

073c8d20()
USER32! 77e71303()
USER32! 77e71962()
NTDLL! 77f763ef()
USER32! 77e755a8()
OLE32! 77b44e21()
OLE32! 77b45185()
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 7160192
I believe that C++ does not guarantee any order of execution of static constructors and destructors.  You could try being more explicit about creating and destroying the object.

What if your static object just did the CoInitialize and CoUnititialize, and you used CreateCreateInstance only when you need the object?

-- Dan
0
 
LVL 22

Expert Comment

by:ambience
ID: 7161338
I believe that you must call CoUninitialize before process termination begins i.e. before WinMain/main returns.

try something like

MyWrapperObj* p_theObject = 0;

void main()
{
    MyWrapperObj theObject;
    p_theObject = &theObject;

}

see if there are any more errors ?
correct me if wrong
0
 
LVL 22

Expert Comment

by:ambience
ID: 7161341
oops, i didnt realize it resides in a lib file. Are yuo using CoInit and CoUninit in your main file too ?
0
 

Author Comment

by:renam00
ID: 7162259
Hi everybody and thanks to you all.

jkr :
-----
Installing the symbols was agood idea. I did it but when a crash happen the stack was very different :
077c8d20()
USER32! DispatchClientMessage@20 + 42 bytes
USER32! __fnDWORD@4 + 36 bytes
NTDLL! KiUserCallbackDispatcher@12 + 19 bytes
USER32! DispatchClientMessage@20 address 0x77e712d9
SXLRT233D! 1000c72e()

Is there a different version of the symbols depending of the server or workstation nature of windows ? From the ms web site, I say no.

DanRollins
----------
Create and destroy the object at every call is not an option since it would be too time consuming and because I want to understand the cause of the problem.
Also, even if the creation\destruction order is not garantee, I know that the ctor is called only once at the beginning of the program and the the dtor is called only once at the end. And sometimes it crashes.

Ambiance
--------
I call CoInitialize/CoUnInitialize on every thread that may use COM object. But keep in mind that in my load test, the component "ACOMObject.dll" is not registred and no COM call is made. It's just a "startup & shutdown" scenario.
But one remark get my attention, you say that I must call CoUninitialize before process termination begins. Can you be more precise about this information. Maybe give me some reference. Since in the (original) stack  I have the two following calls :
doexit(int 0, int 0, int 0) line 353
exit(int 0) line 279 + 13 bytes
I let me think that the process terminaison begins, what do you think ?


So thank again everybody and I'm open to any clue, tracks or ritual sacrifice you may suggest !

renam00
0
 
LVL 86

Expert Comment

by:jkr
ID: 7162270
>>Is there a different version of the symbols depending of
>>the server or workstation nature of windows

No, not at all. Do you have the "High-Encryprion Pack" installed (or not)? You will have to pick the correspoding symbols...
0
 

Author Comment

by:renam00
ID: 7162275
Hi everybody and thanks to you all.

jkr :
-----
Installing the symbols was agood idea. I did it but when a crash happen the stack was very different :
077c8d20()
USER32! DispatchClientMessage@20 + 42 bytes
USER32! __fnDWORD@4 + 36 bytes
NTDLL! KiUserCallbackDispatcher@12 + 19 bytes
USER32! DispatchClientMessage@20 address 0x77e712d9
SXLRT233D! 1000c72e()

Is there a different version of the symbols depending of the server or workstation nature of windows ? From the ms web site, I say no.

DanRollins
----------
Create and destroy the object at every call is not an option since it would be too time consuming and because I want to understand the cause of the problem.
Also, even if the creation\destruction order is not garantee, I know that the ctor is called only once at the beginning of the program and the the dtor is called only once at the end. And sometimes it crashes.

Ambiance
--------
I call CoInitialize/CoUnInitialize on every thread that may use COM object. But keep in mind that in my load test, the component "ACOMObject.dll" is not registred and no COM call is made. It's just a "startup & shutdown" scenario.
But one remark get my attention, you say that I must call CoUninitialize before process termination begins. Can you be more precise about this information. Maybe give me some reference. Since in the (original) stack  I have the two following calls :
doexit(int 0, int 0, int 0) line 353
exit(int 0) line 279 + 13 bytes
I let me think that the process terminaison begins, what do you think ?


So thank again everybody and I'm open to any clue, tracks or ritual sacrifice you may suggest !

renam00
0
What Security Threats Are You Missing?

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

 

Author Comment

by:renam00
ID: 7162285
I installed the high-encryption pack symbols since the aboutbox of ms explorer say "cypher strength 128 bits". I had this stack few times, always the same, always on shutdown and alwaws on the main thread. I don't understand because I used symbols on othe version of windows and it worked well. Also, I get the sp6a info from the "winver" command, so It should be true.
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 7163025
It could be a little bit like a problem I had with ODBC.  After I deleted my CDatabase object, I would get a callback into it from the ODBC manager.  Ihis sat squarely in the realm of the metaphysical, kind of like Houdini from the grave or maybe ET phoning home (my metaphor engine is on the blink again).

>.and I'm open to any clue, tracks or ritual sacrifice you may suggest !
In the API documentation for DllMain, there is some interesting warnings about what should not take place directly upon startup and shutdown.  I don't know if it applies, but it's awful scary so I always do most construction and teardowns elsewhere in the program (I provide some sort of Open and Close fn).

-- Dan
0
 

Author Comment

by:renam00
ID: 7163376
I changed my program a little bit and insted of a static object, I use explicit initialization and finalization functions. I was confident but... I crash on the CoUninitialize again ! So basicly, the program do not use, create or delete any COM object at all. The "only" it does is at the begining of the program, CoInitialize is call on the main thread and before the program exits (e.g. inside the WinMain fnct) CoUninitialize is call. And sometimes it crashes. Always the same stack.
In this minimal scenario, the callback from nowhere is not possible. I don't know what to think.
0
 
LVL 22

Expert Comment

by:ambience
ID: 7163906
is it possible that you are doing multiple CoInitialize and CoUninitialize on your primary thread, although this should not be an issue but maybe you can try to reduce those calls to once per thread.

I remember some problems pertaining to that very situation, so i think its worth a try
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 7164034
Check the return value from ::CoInitializeEx().  It will be S_FALSE if you are calling it a second time.  It will pass the SUCCEEDED test, but be 1)  Looking at the code that you provided, that would allow your program to CoCreateInstance the object multiple times.

In your last test did you comment out the call to CoCreateInstance?

Do you know what SXLRT233D! 1000c72e() is?

Maybe the COM object is misbehaving and doing some screwball stuff in its own DllMain.  Like what if it was instantiating a cached object of quick access.  The CoUninitialze would need to pump a bunch of messages until that object was shut down.

-- Dan
0
 
LVL 49

Accepted Solution

by:
DanRollins earned 500 total points
ID: 7200006
Hi renam00,
Do you have any additional questions?  Do any comments need clarification?
-- Dan
0
 

Author Comment

by:renam00
ID: 7200760
Hi Dan,

I solved the problem but I don't quite understand why : The ONLY way the intermitent crash do not hapen is when I get ride of the static object and I used explcit initialization\finalization function AND when I use OleInitialize and OleUninitialize instead of of regular function. I do not make sense since no object is created...

Anyway, I appreciated you help and suggestions, I will give you the "big reward"...

Thanks too to everybody that helped me.

renam00
0

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

In days of old, returning something by value from a function in C++ was necessarily avoided because it would, invariably, involve one or even two copies of the object being created and potentially costly calls to a copy-constructor and destructor. A…
Container Orchestration platforms empower organizations to scale their apps at an exceptional rate. This is the reason numerous innovation-driven companies are moving apps to an appropriated datacenter wide platform that empowers them to scale at a …
The viewer will learn additional member functions of the vector class. Specifically, the capacity and swap member functions will be introduced.
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.

708 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now