Game Development Community

Con::executef ... crashes

by David Higgins · in Torque Game Builder · 11/30/2006 (10:29 pm) · 10 replies

I have some code that calls Con::executef() and as soon as the lines are called, I get a debug prompt -- when I debug the process, it takes me to consoleInternal.cc @ 732

Namespace::Entry *Namespace::lookup(StringTableEntry name)
{
[b]   if(mHashSequence != mCacheSequence)[/b]
      buildHashTable();

   U32 index = HashPointer(name) % mHashSize;
   while(mHashTable[index] && mHashTable[index]->mFunctionName != name)
   {
      index++;
      if(index >= mHashSize)
         index = 0;
   }
   return mHashTable[index];
}

The highlighted line would be 732 -- the offending code is:

void MyClass::myMethod(const char *var)
{
  Con::printf("string: %s", var);
  Con::executef(this, 1, "onString");
}

Any ideas?

Also, is it required for the "onString" method to be defined in TorqueScript, or does Con::executef gracefully handle missing callbacks? I can't seem to find any docs on the Con methods that are accessible to TGB users (seems there are docs for TGE users)

#1
12/01/2006 (8:32 am)
You have to send the correct number of parameters for the second argument--at a minimum, it's always 2:

first arg: the object ID the method is to be called on.
second arg: the method to be called.

third and others--any args you want sent to the callback, listed after the name of the function in your call.
#2
12/01/2006 (8:02 pm)
@Stephen, when I update the code like so;

Con::executef(this, 2, "onString");

It still receieve the same crash, same file, same line --

I intend to pass variables into the function call, but figured they were causing the issue -- then removed them and left it at 2, received the error and changed it to 1 when I found some code that was executing with '1' -- but those were probably function callbacks ..

Anyhow, do you have any ideas?
#3
12/01/2006 (11:32 pm)
There doesn't appear to be any issues with the code you've shown here--all I can think of is that some other code you may have written is trashing your string table somehow.
#4
12/02/2006 (10:39 am)
My string table? Can you explain ... ?

My code is basically integrating libexpat into TGB --

Here's the .h

#ifndef XML_STATIC
#define XML_STATIC
#endif

#ifndef _SIMBASE_H_
#include "console/simBase.h"
#endif

#include "../../../lib/expat2/expat.h"

#define XMLOBJECT_BUFFER_SIZE 8192

// wrapper function for C++
void __XMLObjectStartElement(void *userData, const char *name, const char **atts);
void __XMLObjectEndElement(void *userData, const char *name);

class XMLObject: public SimObject
{
protected:
	typedef SimObject Parent;
public:
	XMLObject();
	~XMLObject();

	bool processArguments(S32 argc, const char **argv);
	bool onAdd();
	void onRemove();
	static void initPersistFields();

	bool parseDocument(const char* filename);

	static void XMLCALL startElement(void *userData, const char *name, const char **atts);
	static void XMLCALL endElement(void *userData, const char *name);
	void startElement(const char *name, const char **atts);
	void endElement(const char *name);

private:
	XML_Parser mParser;
	int mDepth;
	int mDone;
	char mBuffer[XMLOBJECT_BUFFER_SIZE];
public:
	DECLARE_CONOBJECT(XMLObject);
};


Here's the .cc

#include "XMLObject.h"
#include "console/simBase.h"
#include "console/consoleInternal.h"
#include "core/fileStream.h"
#include <STDLIB.H>
#include <STDIO.H>

IMPLEMENT_CONOBJECT(XMLObject);

XMLObject::XMLObject() {}

XMLObject::~XMLObject() {}

bool XMLObject::processArguments(S32 argc, const char **argv)
{
   if(argc == 0)
      return true;
   else 
      return true;

   return false;
}

bool XMLObject::onAdd()
{
   if (!Parent::onAdd())
      return false;

   const char *name = getName();
   if(name && name[0] && getClassRep())
   {
      Namespace *parent = getClassRep()->getNameSpace();
      Con::linkNamespaces(parent->mName, name);
      mNameSpace = Con::lookupNamespace(name);
   
   }

   return true;
}

// This is the function that gets called when an instance
// of your object is being removed from the system and being
// destroyed.  Use this to do your clean up and what not.
void XMLObject::onRemove()
{
	Parent::onRemove();
}

// To be honest i'm not 100% sure on when this is called yet.
// Basically its used to set the values of any persistant fields
// the object has.  Similiar to the way datablocks work.  I'm
// just not sure how and when this gets called.
void XMLObject::initPersistFields()
{
   Parent::initPersistFields();
}


bool XMLObject::parseDocument(const char* filename)
{
	mParser = XML_ParserCreate(NULL);
	XML_SetUserData(mParser, &mDepth);
	//XML_SetElementHandler(mParser, XMLObject::startElement, XMLObject::endElement);
	XML_SetStartElementHandler(mParser, &XMLObject::startElement);
	XML_SetEndElementHandler(mParser, &XMLObject::endElement);
	FILE *file = fopen(filename, "rb");
	if(file == NULL)
	{
		Con::printf("File == NULL");
		return false;
	}

	while(!feof(file))
	{
		int len = fread(mBuffer, 1, XMLOBJECT_BUFFER_SIZE, file);
		if(ferror(file))
		{
			Con::errorf("File Read Error");
			break;
		}
		int done = feof(file);
		if (! XML_Parse(mParser, mBuffer, len, done)) {
			fprintf(stderr, "Parse error at line %d:\n%s\n",
				XML_GetCurrentLineNumber(mParser),
				XML_ErrorString(XML_GetErrorCode(mParser)));
			break;
		}
	}
	fclose(file);
	free(mBuffer);
	XML_ParserFree(mParser);
	return true;
}


void XMLObject::startElement(const char *name, const char **atts)
{
	Con::printf("startElement: %s", name);
	Con::executef(this, 2, "onElementStart");
}
void XMLObject::startElement(void *userData, const char *name, const char **atts)
{
	XMLObject *obj = (XMLObject *)userData;
	obj->startElement(name, atts);
}
void XMLObject::endElement(const char *name)
{
	Con::printf("endElement: %s", name);
	Con::executef(this, 2, "onElementEnd");
}
void XMLObject::endElement(void *userData, const char *name)
{
	XMLObject *obj = (XMLObject *)userData;
	obj->endElement(name);
}

// Console Methods
ConsoleMethod(XMLObject, parseDocument, bool, 3, 3, "(const char* filename) Opens the database specifed by filename.  Returns true or false.")
{
   return object->parseDocument(argv[2]);
}


As I said, if I remove the Con::executef statements, everything works fine -- ie; the Con::printf statements work great.

I've also written test code where I built a string around the parsed XML, and printed that out -- basically, rebuilding the XML while it was being parsed -- which worked fine.
#5
12/02/2006 (10:41 am)
Oh -- if it helps, other hacks i've made to the source are the SQLiteObject which I did by reading one of the resources here on the site -- it's the latest 3.3.8 SQLite lib, using the resource to integrate 3.3.7

#6
12/03/2006 (12:18 pm)
I created the following code,

ZCTestObject.h
#ifndef _SIMBASE_H_
#include "console/simBase.h"
#endif

class ZCTest: public SimObject
{
public:
	typedef SimObject Parent;

	void doCallback();

	ZCTest::ZCTest();
	ZCTest::~ZCTest();
public:
	static int mInstances;
public:
	DECLARE_CONOBJECT(ZCTest);
};

ZCTestObject.cc
#include "ZCTestObject.h"
#include "console/simBase.h"

IMPLEMENT_CONOBJECT(ZCTest);

void ZCTest::doCallback()
{
	Con::executef(this, 3, "callBack", "param");
}

ZCTest::ZCTest()
{
}

ZCTest::~ZCTest()
{
}

// Console Methods
ConsoleMethod(ZCTest, doCallback, void, 2, 2, "(const char* filename) Opens the database specifed by filename.  Returns true or false.")
{
   return object->doCallback();
}

demo.cs
function ZCTest::callBack(%this, %param)
{
   echo("Callback ...");
   echo("%param = " @ %param);
}

%test = new ZCTest();
%test.doCallback();


-- this code works just fine, no problems at all -- it echos out to the console "%param = param" as expected -- now, why doesn't the XMLObject work this way? :)

#7
12/03/2006 (12:29 pm)
UPDATE: I added a param to the ZCTest::doCallback(const char *name) to mimic the XMLObject -- I also added this param to the callback, and it works fine -- so why's my XML object crash the engine?
#8
02/01/2007 (4:16 am)
I notice you have some namespace linking code in onAdd and it is breaking on the namespace lookup part of the code. Perhaps that is a place to start looking?
#9
02/01/2007 (8:02 am)
Quote:
I notice you have some namespace linking code in onAdd and it is breaking on the namespace lookup part of the code. Perhaps that is a place to start looking?

Interestingly, I ran into this exact same problem myself just a few days ago, and Neo is right--it has to do with linking your namespaces properly, which is normally performed in the c++ ::onAdd() method.

If you are still having issues, check the return values of the various levels of ::onAdd() and make sure you are getting what you expect.
#10
02/03/2007 (5:21 pm)
I have released the above resource in a .plan a while back, and would just like to thank everyone who helped with it.

You can download this resource here;

www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=11955