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
The highlighted line would be 732 -- the offending code is:
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)
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)
About the author
#2
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?
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
My code is basically integrating libexpat into TGB --
Here's the .h
Here's the .cc
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.
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
ZCTestObject.h
ZCTestObject.cc
demo.cs
-- 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? :)
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
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.
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
You can download this resource here;
www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=11955
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
Torque 3D Owner Stephen Zepp
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.