Collada Crashes when exporting from Maya

I am fairly new to Collada, and I’m hoping that my problem has a simple solution.

I have been using the Collada DOM to output assets from various applications. Until now, I have been working in an application neutral context. As a stand alone executable, my application works fine, creating several Collada files. Unfortunately, when I wrapper the code in a Maya plugin, maya crashes when I attempt to run the command. The issue emmerges during the save() function, where the system crashes.

I have simplified to code down to the most basic elements. Essentially, I create a document and try to save it. Here’s the code:

template <typename DOM_ELT, typename PARENT>
DOM_ELT* createDomElement(PARENT* parent, const daeString& asset_type)
{
  DOM_ELT* new_elt = daeSafeCast<DOM_ELT>(parent->createAndPlace(asset_type));

  if ( new_elt == NULL )
  {
    std::cerr << "Failed to create the library types needed
";
  }
  
  return new_elt;
}

ColladaExportVisitor::ColladaExportVisitor(const std::string& path)
  : my_path(path)
{
  // Initialize our database
  my_database = boost::shared_ptr<DAE>(new DAE());

  my_database->setIOPlugin( NULL );
  my_database->setDatabase( NULL );

  daeDocument *doc = NULL;

  std::string doc_name = "/job/HOME/gwedig/test.txt";
  
  daeInt error = my_database->getDatabase()->insertDocument( doc_name.c_str(), &doc );
  if ( error != DAE_OK || doc == NULL )
  {
    std::cerr << "Failed to create new document " << doc_name << "
";
    return;
  }

  domCOLLADA *collection = daeSafeCast<domCOLLADA>( doc->getDomRoot() );

  std::cout << "ALL1" << std::endl;

  error = my_database->save(doc_name.c_str());
              
  std::cout << "ALL2" << std::endl;
}

The save() function does not return, but instead crashes the program. And I’m at a loss to figure out why.

Has anyone else experienced anything similar, and if so, do you have a solution and/or any information that might help?

Thanks!

Hi Geoff, welcome to COLLADA!

Your code looks ok to me. Can you debug further to see exactly where it’s crashing? I figure memory must be getting stomped somewhere. Are you on Windows or Linux? If Windows with Visual Studio, is your application properly configured to use the Multi-threaded DLL version of the C++ runtime? (more info on this page, search for “runtime”)

Also, I notice you said this is for a Maya plugin. You’re aware that there’s a free COLLADA plugin for Maya available, right?

In this case it’s linux. I’m currently working on a port to Windows to see if that fixes it. Which won’t tell me much, but it’s a good experiment anyway, since I’ll learn something.

I can’t really go much deeper without trying to head into the DOM code, since it’s during a function call. I have tried getting the data out manually, and that seems to work ok, though I only did spot checking. If it’s a dangling pointer or something I almost certainly missed it.

And yeah, I am aware of the Feeling Software stuff. In this case, we need to do some things that software doesn’t, or so I’m told (since I didn’t make the evaluation, I can’t say what features those are). We did try going from source, in the hopes of using it as a springboard, but the lack of detailed tutorials to make FCollada work, and the fact that the compiled tests crashed when I (finally got them to compile and ran them, well, we haven’t given up on it as an option yet.

Is there some multi-threaqding issue with linux as well? I could believe that happening. And right now, I’ve run out of ideas. If necessary, I’ll breakinto save() and start poking, but I really don’t like that idea. I like my black box APIs. :wink:

Thanks for the advice/ideas!

#include <iostream>
#include <string>
#include <memory>
#include <dae.h>
#include <dom/domConstants.h>
#include <dom/domCOLLADA.h>

void saveDoc(const std::string& doc_name)
{
  // Initialize our database
  //my_database = boost::shared_ptr<DAE>(new DAE());
  std::auto_ptr<DAE> my_database(new DAE);
	
  my_database->setIOPlugin( NULL );
  my_database->setDatabase( NULL );

  daeDocument *doc = NULL;

  //std::string doc_name = "/home/sthomas/models/empty.dae";
 
  daeInt error = my_database->getDatabase()->insertDocument( doc_name.c_str(), &doc );
  if ( error != DAE_OK || doc == NULL )
  {
    std::cerr << "Failed to create new document " << doc_name << "
";
    return;
  }

  domCOLLADA *collection = daeSafeCast<domCOLLADA>( doc->getDomRoot() );

  std::cout << "ALL1" << std::endl;

  error = my_database->save(doc_name.c_str());
             
  std::cout << "ALL2" << std::endl;
}


int main() {
  saveDoc("/home/sthomas/models/empty.dae");
  return 0;
}

I run that code on Linux as a stand-alone executable fine. It makes an empty COLLADA model. “ALL1” and “ALL2” are printed during the process. I noticed in your snippet you weren’t using your createDomElement function so I just removed it. You can also run the code as a stand-alone exe, right?

Is there some multi-threading issue with linux as well?
Not that I’m aware of.

If necessary, I’ll breakinto save() and start poking, but I really don’t like that idea. I like my black box APIs.
Yeah I know what you mean, but at this point that’s probably our best bet. It’d also be instructive to see if it crashes on Windows as well.

Yeah, that’s what bugs me. As a standa alone executable, it works just fine. So it’s got to be something about the plug-in-ness of it. Initially I thought that it might be a linking issue, but that seems to have gone ok.

The messages are just debugging output when I was tracking things down, so can be ignored. They’re not important.

I’ve done some poking into the DOM code, though I didn’t get very far. In the save function (dae.cpp, line 200ish), the document comes back ok, but the getDocumentURI() function seems to be a bad pointer. I think, anyway, since calling any of the member function of daeURI causes the crash. The pointer isn’t obviously bad, it’s not NULL or anything.

I’m going to do another run at Windows, but since I haven’t been developing on Windows, it introduces new variables into the debug, which always makes things a little more difficult to pin down to causes. But I’ve got no better ideas at the moment.

Thanks for the help!

I’ve done some poking into the DOM code, though I didn’t get very far. In the save function (dae.cpp, line 200ish), the document comes back ok, but the getDocumentURI() function seems to be a bad pointer. I think, anyway, since calling any of the member function of daeURI causes the crash. The pointer isn’t obviously bad, it’s not NULL or anything.
Sounds like memory’s getting stomped somewhere. Is your code doing anything more than what you posted earlier? What if you reduce it just to

DAE dae;
dae.load("/home/whatever/model.dae");

Does it crash then?

Load doesn’t seem to be a problem it’s just saving.

I’ve reduced the code to the absolute minimum to make it a valid maya command plugin, and it’s still crashing. I’ve checked to make sure I’m using and running the same version of Maya as I’m including (I’ve run into that problem in the past). And I’ve checked with different optimization levels, just in case it was a quirk in the compiler. And yeah, I checked compiler versions too.

I’ve gotten rid of absolutely everything, and put everything into a single function call to avoid any chance that there’s something going on between.

Here’s the complete file I’m working with. There’s nothing else compiled into it, except the libraries being linked in. I’ve only linked in the four collada .so’s and xml2. I don’t think I need iconv (why would I, when it worked as a standalone without?)

// Maya
// ----

#include <maya/MDagPath.h>
#include <maya/MGlobal.h>
#include <maya/MSelectionList.h>
#include <maya/MSyntax.h>
#include <maya/MArgDatabase.h>
#include <maya/MFnDagNode.h>
#include <maya/MItSelectionList.h>
#include <maya/MPxCommand.h>
#include <maya/MFnPlugin.h>

// Collada Includes
// ----

#include <dae.h>
#include <dom/domCOLLADA.h>
#include <dom/domConstants.h>
#include <dae/domAny.h>

#include <string>

//using namespace std;

class x2yExportCmd : public MPxCommand 
{
  public:
    x2yExportCmd();
    virtual ~x2yExportCmd();

    static void* creator();

    virtual MStatus doIt( const MArgList &args );

    virtual bool isUndoable() const { return true; }

  private:
  
};

// constructor
x2yExportCmd::x2yExportCmd()
{
}

// destructor
x2yExportCmd::~x2yExportCmd()
{ }

// create instance
void *x2yExportCmd::creator()
{
   return new x2yExportCmd;
}

// doIt!
MStatus x2yExportCmd::doIt( const MArgList &args )
{
  // Initialize our database
  DAE* database = new DAE();

  database->setIOPlugin( NULL );
  database->setDatabase( NULL );

  daeDocument *doc = NULL;

  std::string doc_name = "/job/HOME/gwedig/test.txt";
  
  daeInt error = database->getDatabase()->insertDocument( doc_name.c_str(), &doc );
  if ( error != DAE_OK || doc == NULL )
  {
    std::cerr << "Failed to create new document " << doc_name << "
";
    return MS::kFailure;
  }

  daeSafeCast<domCOLLADA>( doc->getDomRoot() );

  error = database->save(doc_name.c_str());

  return MS::kSuccess;
}


MStatus initializePlugin( MObject obj )
{
  MFnPlugin plugin( obj, "x2y Hierarchy Translator", "1.0" );

  MStatus stat;
  stat = plugin.registerCommand( "x2yExport", x2yExportCmd::creator );
  if ( !stat )
    stat.perror( "registerCommand failed");

  return stat;
}

MStatus uninitializePlugin( MObject obj )
{
  MFnPlugin plugin( obj );

  MStatus stat;
  stat = plugin.deregisterCommand( "x2yExport" );
  if ( !stat )
    stat.perror( "deregisterCommand failed" );

  return stat;
}

I’m quite frankly, totally stumped at the moment.

The only real information I have is that the is that it seems to be the pointer to the document URI object. That pointer looks valid, but it crashes when used, so it’s probably not.

Now, I haven’t gotten a working version on Windows, mostly because I haven’t gotten Collada’s makefiles to work. Are there any precompiled .lib’s out there? Maybe I could do that.

So, I’m going to try that, and I’m going to try tracing the address of the URI object through teh code. Maybe I can backtrack to where it actually changes, if, in fact, it was ever right. But I’d love to hear some other ideas.

I appreciate the help so far, btw.

Geoff

Now, I haven’t gotten a working version on Windows, mostly because I haven’t gotten Collada’s makefiles to work. Are there any precompiled .lib’s out there? Maybe I could do that.
We don’t have makefiles for Windows I don’t think. Just the VC 2003 and 2005 project files. The DOM installers from here come with binaries.

I don’t think I need iconv (why would I, when it worked as a standalone without?)
Yeah, you don’t need to worry about iconv or zlib on Linux.

So, I’m going to try that, and I’m going to try tracing the address of the URI object through teh code. Maybe I can backtrack to where it actually changes, if, in fact, it was ever right. But I’d love to hear some other ideas.
The daeDocument class has a uri member. It’s initialized in the daeSTLDatabase::createDocument method, which is called by daeSTLDatabase::insertDocument. So at that point it should be valid. I think with gdb you can set a breakpoint to see when that value changes. So if it gets screwed up in between daeSTLDatabase::insertDocument and the daeDocument::getDocumentURI call in DAE::save, your breakpoint should get it.

Sorry, I’m not sure how else to help. I’ll keep thinking about it.

I’ve been doing some exploratory work. Turns out, it was never right. The document’s URI comes up invalid right after it’s created in the daeSTLDatabase::createDocument() function, I put some debugging output immediately following the setID() and validate() functions. When I call the getID() function, that returns an empty string, and the getPath crashes. So any memory stomping happens within the construction of the object.

So it looks like it’s somewhere in the daeURI class. The setURI() method is my most likely suspect, since it’s got a lot of allocation and deallocation code inside it.

I’ll let you know how it goes.

Ok, I have to backtrack. Seems I misunderstood how the system works, due to assuming that daeString was a c++ class, not a const char*. And so I was printing out strings in my output which were nulls, which caused that crash.

Which of course doesn’t solve my problem. Instead, after cleaning up that mess, I’ve delved into the writing code. Mostly, that’s pretty easy to understand. It crashe during the xmlTextWriterSetIndentString() function. This is quite bizarre to me, but hey, at least it’s not Collada, right?

I’m going to start in on the libxml code. See if I can track it down. If you have any advice, that’d be appreciated, but I wouuldn’t be surprised if the Collada people consider the xml stuff to be as much a black box as I would like to consider Collada. :wink:

Thanks for all the help! I’ll post something when I solve the problem, in case it helps anyone else.

I doubt that delving into libxml code is going to help you much unfortunately. Let us know what you find out.

No, it didn’t, but it did actually lead me closer to the problem. It seems that Maya has its own xml2 library, libawxml2.so, which is colliding with the xml2 that’s linked into the plugin. It is sufficiently different that I can’t just not link in xml2, though. It surprises me that a collision like this isn’t being detected, but there it is.

I’ll have to either find header files, so I can compile collada against them or figure a way to get the plugin to call the functions included within rather than going externally. Maybe I can figure out a way to static link it in or something.