none
What!? Assert on: "This function must be called in the default domain".

    General discussion

  • Hi,

    I have an application which hosts several sub-applications where each subapplication lives in its own AppDomain.

    Each subApp makes use of unmanaged C++ code.

    In the C++ code there is a local static variable that gets initialized. In addition to this, the compiler adds code which registers the static variable's virtual destructor as an exit handler to be called when the process exits.

    However, when it tries to register the destructor it asserts!!

    extern "C" int __clrcall _atexit_m( _CPVFV func)
    {
        MANAGED_ASSERT(AppDomain::CurrentDomain->IsDefaultAppDomain(), "This function must be called in the default domain");

        return _atexit_helper(func, &__exit_list_size, &__onexitend, &__onexitbegin);
    }

     

    To test that I don't have any other confilcting issues causing this troublesome situation, I made a small stripped down project from scratch with an extra AppDomain and with unmanged C++ code. Unfortunately, or maybe fortunately... this little code sample also asserted on this very same thing.

     

    Is this a known BUG?

    Is it a known limitiation, i.e. is it stated somewhere in the docs that local statics in unmanaged code are not allowed if they are used in an AppDomain other than the default one?

    How could I work around this issue?

     

    Thanks in advance!

     

    Regards Tommy

     

     

    Ps. I'm using dotNet3.0

     

    The local static variable is defined like this:

    GlobalWorld& Asn1::World(Solar* solar)

    {

     static GlobalWorld theWorld(solar);  // The ASSERT occurs here!

     return theWorld;

    }

     

    I.e. the World method of Asn1 returns the one and only GlobalWorld object.

     

    class Solar

    {

    };

     

    class GlobalWorld

    {

    private:

      Solar* solar;

    public:

      GlobalWorld(Solar* solar)

      {

        this->solar = solar;

      }

      virtual ~GlobalWorld()

      {

        delete solar;

      }

    };

     

    Friday, April 20, 2007 9:12 AM

All replies

  • It's not a bug, it is a limitation.  The problem statement is "to be called when the process exits".  Unmanaged code has no notion of AppDomains.  Its life-time as packaged in a DLL is the life of the process.  Assemblies can be unloaded from an AppDomain, unmanaged DLLs can't.  Unless it is the default AppDomain, it unloads when the program terminates.  You could possibly take control of unloading with FreeLibrary().  However, code in other AppDomains might still be using it...

    Friday, April 20, 2007 1:00 PM
    Moderator
  • Do you, or more specifically the CLR team, really understand the consequences of this "limitation"? Well, I sure you do... Anyway, I find this limitiation amazing!

    So, fully standard compliant unmanaged C++ code CANNOT be used with AppDomains!! Well, you can say that it CAN be used if this and if that, but seriously, this is a major flaw!

    Has Microsoft an official statement about this issue? I searched the KB without any results...

     

    Even if I manage to workaround my specific issue with my static variable, I still use a library that is out of my control. I have no clue whether any exit handlers are registered or whether anything else in that library does anything that finally results in the assert: "This function must be called in the default domain". Uurk!

     

     

    /Tommy

     

     

    Friday, April 20, 2007 2:51 PM
  • This is not the right place to convey messages to the CLR team.  Talk to them directly through Product Feedback.
    Friday, April 20, 2007 3:30 PM
    Moderator
  • One way to avoid this issue is to make the calling code unmanaged by using "#pragma managed".

    As in your case you cannot modify the underlying C++ code, you'll have to write some wrapper code (in C++/CLI) that forwards to the actual C++ code you want to call and wrap this code into the pragma.

    E.g.

    #pragma managed(push, off)
    void CreateGlobalWorld()
    {
        ...
        Asn1::World(pSolar);
        ...
    }
    #pragma managed(pop)

    That way your static should be registered with the standard _atexit method, rather then the managed one.

    Cheers,

    Mike.
    Wednesday, June 27, 2007 4:40 AM