Understanding the classloader

Please post support and help requests here.
StrangeMan
Posts: 10
Joined: 22 Jul 2012, 12:40

Re: Understanding the classloader

Postby StrangeMan » 29 Aug 2012, 10:27

Hi there again!

Is there any option to find out, what causes the "unloadLibrary()" call to crash? so Far, thats what my code looks like now:

Code: Select all

try
   {
      PluginLoader loader;
      std::string libName("GameOfLife");
      libName += Poco::SharedLibrary::suffix(); // append .dll or .so
      loader.loadLibrary(libName);
      { // this is to be sure, the iterators are out of scope, when the lib gets unloaded
         PluginLoader::Iterator it(loader.begin());
         PluginLoader::Iterator end(loader.end());
         for (; it != end; ++it)
         {
            PluginManifest::Iterator itMan(it->second->begin());
            PluginManifest::Iterator endMan(it->second->end());
            for (; itMan != endMan; ++itMan)
               Log::logLine("AppManager","Found " + String(itMan->name()));;
         }
      }
      { // same as above...
         App* pPluginA = loader.create("AppGameOfLife");
         Log::logLine("AppManager","Name=" + pPluginA->getName());
         loader.destroy("AppGameOfLife", pPluginA);
         pPluginA = nullptr;
         Log::logLine("AppManager","Deleted");
      }
      loader.unloadLibrary(libName);
      Log::logLine("AppManager","Lib unloaded");
   }
   catch (exception &e)
   {
      Log::logLine("AppManager","Exception occured while loading plugin libraries: " + String(e.what()));
   }
   catch (...)
   {
      Log::logLine("AppManager","General Exception occured while loading plugin libraries.");
   }


It loads the library and logs the name of the class found inside. It creates an object of that class and calls a function of it. It even destroys the object. Then, at the "unalodLibrary" it crashes. No exception, no error message.

What am I missing?!

Thanks in advance,
StrangeMan

StrangeMan
Posts: 10
Joined: 22 Jul 2012, 12:40

Re: Understanding the classloader

Postby StrangeMan » 30 Aug 2012, 10:50

I found out, where exactly the call crashes: This is code from ClassLoader.h:

Code: Select all

void unloadLibrary(const std::string& path)
      /// Unloads the given library.
      /// Be extremely cautious when unloading shared libraries.
      /// If objects from the library are still referenced somewhere,
      /// a total crash is very likely.
      /// If the library exports a function named "pocoUninitializeLibrary",
      /// this function is executed before it is unloaded.
      /// If loadLibrary() has been called multiple times for the same
      /// library, the number of calls to unloadLibrary() must be the same
      /// for the library to become unloaded.
   {
      FastMutex::ScopedLock lock(_mutex);

      typename LibraryMap::iterator it = _map.find(path);
      if (it != _map.end())
      {
         if (--it->second.refCount == 0)
         {
            if (it->second.pLibrary->hasSymbol("pocoUninitializeLibrary"))
            {
               UninitializeLibraryFunc uninitializeLibrary = (UninitializeLibraryFunc) it->second.pLibrary->getSymbol("pocoUninitializeLibrary");
               uninitializeLibrary();
            }

            delete it->second.pManifest; // <========== It crashes on this line!
            it->second.pLibrary->unload();
            delete it->second.pLibrary;
            _map.erase(it);
         }
      }

Any idea why?

Thanks in advance,
StrangeMan

StrangeMan
Posts: 10
Joined: 22 Jul 2012, 12:40

Re: Understanding the classloader

Postby StrangeMan » 31 Aug 2012, 09:38

Though no ones answering, I think it's good to write my progress down here, so at least others who might stumble upon a similar situation can find a bit of help from this topic.

So in the meantime I studied the code from ClassLoader.h and tried to find out, why and when a "delete" operation could cause a crash. IMHO there are generally two cases: 1. The object/whatever that delete is trying to destroy does not exist (invalid pointer/null pointer). 2. The object/whatever was allocated on a different heap and (more importantly) by a different heap allocator.
I checked the code in ClassLoader.h and it seems the Manifest (which is, what can't be deleted) is created by the main application and is then passed to the library to fill it with its actual data. I checked my Manifest macros in the library and they seem to be fine (just three lines, like those in the pdf-example for the class loader). So reason no. 2 is not the case.
I added an if-statement to check, whether the manifest pointer is a nullptr, but thats also not the case. So IMHO the only reason left is that the manifest has been destroyed somewhere else before. And here is where I'm stuck so far.

StrangeMan
Posts: 10
Joined: 22 Jul 2012, 12:40

Re: Understanding the classloader

Postby StrangeMan » 31 Aug 2012, 18:12

Well, it looks like a heap problem now. I created a new project that compiles to a simple executable, so I can attach a debugger to it. I does exactly what I posted above and crashes at the same line.
Now, at the line with "delete ..." I showed two posts ago, it stops and shows this: HEAP[PluginTest.exe]: Invalid address specified to RtlValidateHeap( 001B0000, 035B6570 )

I installed Windows debugging tools and enabled different options related to the heap, e.g. heap tagging andenable page heap. Honestly, I have no idea what these actually do but different posts in different forums point into that direction. Right now, my head is smoking...

Can someone give me a hint?
StrangeMan

------------------------------------------Edit---------------------------------------------------------------

Nice, I found out, how to display a stack trace. Now I see, that the actual problem is appearing when deleting a string. Why is there a string being deleted, when the manifest is deleted? Well, when the manifest is filled with information (done by the dll) it will create an entry for each class. Part of this entry is the name of the class, stored as a string. This is done in the following macro:

Code: Select all

#define POCO_EXPORT_CLASS(cls) \
    pManifest->insert(new Poco::MetaObject<cls, _Base>(#cls));
And this string can't be deleted by the main application because it "works" with a different heap allocator.

So here, we have the problem! Unfortunately I have no idea how to fix this without editing code from the Poco code base.

See the attached image.
Attachments
Calls.png
Calls.png (69.66 KiB) Viewed 819 times

Parikshit225
Posts: 5
Joined: 11 Feb 2015, 11:15

Re: Understanding the classloader

Postby Parikshit225 » 11 Feb 2015, 11:19

Hi,

Even i am facing same issue. Did you get any solution ?
Poco guys please answer on this as we cannot unload the library due to this.

Regards,
parikshit.

Parikshit225
Posts: 5
Joined: 11 Feb 2015, 11:15

Re: Understanding the classloader

Postby Parikshit225 » 11 Feb 2015, 11:34

anyone not facing this issue of unloadlibrary ?

Parikshit225
Posts: 5
Joined: 11 Feb 2015, 11:15

Re: Understanding the classloader

Postby Parikshit225 » 11 Feb 2015, 11:50

Alex, StrangeMan

i am facing the same issue when i call unloadlibrary(). Alex, i am using debug dll in my debug exe. So there is no question of debug/release mismatch.Also i am using VS2010 for both to build and run.
Any solution?
Not sure how to unload the library ?

-Parikshit

alex
Posts: 1246
Joined: 11 Jul 2006, 16:27
Location: United_States

Re: Understanding the classloader

Postby alex » 11 Feb 2015, 16:37

If you need help, then please post a small, concise, compilable example that is reproducing this behavior; then we can look at it and find out whether there is a problem and what it is exactly.

Parikshit225
Posts: 5
Joined: 11 Feb 2015, 11:15

Re: Understanding the classloader

Postby Parikshit225 » 12 Feb 2015, 08:10

Alex, here is the code

Exe code -

#include <iostream>
using namespace std;

#include "Poco/ClassLoader.h"
#include "Poco/Manifest.h"
#include "c:\Users\nangrpar\documents\visual studio 2010\Projects\ClassLoaderDll\ClassLoaderDll\AbstractPlugin.h"

typedef Poco::ClassLoader<AbstractPlugin> PluginLoader;
typedef Poco::Manifest<AbstractPlugin> PluginManifest;

int main(int argc, char** argv)
{
PluginLoader loader;

std::string libName( "ClassLoaderDll.dll" );
loader.loadLibrary( libName );


loader.unloadLibrary( libName ); // crashes on this line
return 0;
}
/**
crash in _metaMap.clear(); function of clear function of Manifest.h file
/**/

------------------------------------------------------------------------------------------------------------------------------------------
Dll code -

#include <iostream>
using namespace std;

File - AbstractPlugin.h
class AbstractPlugin
{
public:
AbstractPlugin();
virtual ~AbstractPlugin();
virtual std::string name() = 0;
};
------------------------------------------------------------------------------------------------------------------------------------------

File - AbstractPlugin.cpp

#include "AbstractPlugin.h"

AbstractPlugin::AbstractPlugin()
{
}
AbstractPlugin::~AbstractPlugin()
{
}
------------------------------------------------------------------------------------------------------------------------------------------

File - PluginLibrary.cpp

#include "AbstractPlugin.h"

#include "Poco/ClassLibrary.h"

class PluginA: public AbstractPlugin
{
public:
std::string name()
{
return "PluginA";
}
};

class PluginB: public AbstractPlugin
{
public:

std::string name()
{
return "PluginB";
}
};


POCO_BEGIN_MANIFEST(AbstractPlugin)
POCO_EXPORT_CLASS(PluginA)
POCO_EXPORT_CLASS(PluginB)
POCO_END_MANIFEST

// optional set up and clean up functions

void pocoInitializeLibrary()
{
std::cout << "PluginLibrary initializing" << std::endl;
}

void pocoUninitializeLibrary()
{
std::cout << "PluginLibrary uninitializing" << std::endl;
}

alex
Posts: 1246
Joined: 11 Jul 2006, 16:27
Location: United_States

Re: Understanding the classloader

Postby alex » 13 Feb 2015, 06:26

I can't reproduce this problem. Here's is the equivalent of your code:

Code: Select all

#include "Poco/ClassLoader.h"
#include "../testsuite/src/TestPlugin.h"

typedef Poco::ClassLoader<TestPlugin> PluginLoader;

int main()
{
   PluginLoader loader;
   std::string libName("C:\\poco\\Foundation\\testsuite\\bin64\\TestLibraryd.dll");
   loader.loadLibrary(libName);
   loader.unloadLibrary(libName);
   return 0;
}


BTW, when I wrote "small, concise, compilable example", the above is what I meant.

Copy/paste the code into one of Foundation samples .cpp, compile and run - no errors whatsoever:

Code: Select all

TestLibrary initializing
TestLibrary uninitialzing
Press any key to continue . . .


Return to “Support”

Who is online

Users browsing this forum: No registered users and 1 guest

cron