tags:

views:

380

answers:

6

Hello everyone,

The application I'm working on (it's a game, actually) uses XML for some of its configuration. Since I'm using CEGUI for the GUI, and it has its own XML parsing objects, I converted my code to use that instead of my own hand-rolled parser class. If the document is missing attributes on certain tags, it throws an exception, which is what I want. However, the exception does not propagate through the C calls on the stack; instead, terminate() is called.

For those of you unfamiliar with CEGUI, it uses a plugin-based system for XML parsing. There are currently plugins for tinyxml, expat, libxml, and xerces. No particular plugin is guaranteed to be present in a specific binary distribution of CEGUI; the only requirement is that at least one is available. So my problem cannot be solved by requiring the use of a C++ parser (tinyxml or xerces).

Does anyone know of a good way to get around this problem that doesn't require me to distribute the source for CEGUI and its XML parser plugin dependencies with my game source?

I should also note that this problem only occurs on OS X; it works fine on GNU/Linux.

Here's some simple example code that demonstrates the issue:

EDIT: Minor code correction http://pastebin.com/m23ba5577

Thanks, Rob

A: 

In the sample code, nothing ever catches the exception. In such a case (where a thrown exception has no matching catch block), the c++ runtime calls std::terminate.

But I don't see how any of this has to do with the body of your question...

Greg Rogers
A: 

Sorry about that; I just added a correction. If you compile and run that code on OS X, you'll noticed it still terminate()s.

What it has to do with my comment is that it's a simple demonstration of the problem without post my entire app's code. =D

A: 

I have the feeling you have answered your own question

http://discussions.apple.com/thread.jspa?threadID=1852579&tstart=0

A: 

That's true, I did get an answer to that question on the Apple development forums. However, that doesn't mean it's the only answer. I've actually arrived at four answers, all of which are suboptimal:

  • Distribute Expat, libxml, and CEGUI with my application and make sure Expat and libxml use -fexceptions when building on OS X.
  • Restrict the parser plugins that my application can use on OS X to the tinyxml and xerces plugins.
  • Wrap my XML reading code in a setjmp/longjmp construct and throw an exception if setjmp returns a truthy value.
  • Get rid of XML and CEGUI in my application altogether.

While each of these answers solves my problem, they all have drawbacks. I'm just trying to get all the answers I can to make an educated decision.

This is information that belongs in the question, not in an answer.
Rob Kennedy
A: 

I'm definitely not an expert but from what I can determine; how the C/C++ run-time will behave with respect to C++ exceptions raised in the presence of C functions on the stack is implementation defined.

I'm curious as to your use of C++ exceptions as the mechanism to handle missing attributes. Do the C XML libraries support the use of C++ exceptions in this fashion? In other words, are the C run-time resources correctly released in the presence of an exception, given that the libraries are designed for the C language?

I would recommend on narrowing down your use of XML libraries to one that supports either C or C++ rather than both so that you can implement one error mechanism.

Henk
+3  A: 

In reference to the source you posted, if you compile test.c with a C++ compiler, things'll work as expected (you'll need to make the functions extern "C", which I understand you can't do outside your example).

The difference in symbols generated sheds light on what's happening:

C++ compiler: g++ -c test.c

00000040 s EH_frame1
         U ___gxx_personality_v0
0000001a T _callIt
0000005c S _callIt.eh
00000088 b _callback
00000000 T _setCallback
00000000 A _setCallback.eh

C compiler: gcc -c test.c

00000019 T _callIt
0000003c b _callback
00000000 T _setCallback

As you can see, there's an additional symbol for each function ending in ".eh", and an EH_frame1 - these contain a description of the call frames that must be unwound if an exception occurs. If they're missing... there's nothing to do except call terminate().

Given that C doesn't support exceptions, the C compiler won't write these symbols to the object file.

So if you don't control how these libraries are compiled, your best bet would be to install a SIGABRT handler prior to parsing, and treat it's invocation as "an exception has occurred". You'll still be missing the actual error information, but you'll know that one occurred.