3

I have a HaxeFlixel project, that is working OK in Debug mode for misc targets, including flash, neko and windows. But Targeting Windows in Release mode, I'm having an unexpected crash, and surprisingly it's happening inside a try-catch block. Here's the crashing function:

/**
 * Will safely scan a parent node's children, search for a child by name, and return it's text.
 * @param   parent an Fast object that is parent of the `nodeNamed` node
 * @param   nodeName the node's name or a comma-separated path to the child (will scan recursively)
 * @return node's text as String, or null if child is not there
 */
public static function getNodeText(parent:Fast, nodeName:String):String {

    try {
        var _node : Fast = getNodeNamed(parent, nodeName);

        //if (_node == null)
        //  return null;

        // next line will crash if _node is null
        var it :Iterator<Xml> = _node.x.iterator();
        if ( it == null || !it.hasNext() )
            return null;
        var v = it.next();
        var n = it.next();
        if( n != null ) {
            if( v.nodeType == Xml.PCData && n.nodeType == Xml.CData && StringTools.trim(v.nodeValue) == "" ) {
                var n2 = it.next();
                if( n2 == null || (n2.nodeType == Xml.PCData && StringTools.trim(n2.nodeValue) == "" && it.next() == null) )
                    return n.nodeValue;
            }
            //does not only have data (has children)
            return null;
        }
        if( v.nodeType != Xml.PCData && v.nodeType != Xml.CData )
            //does not have data";
            return null;
        return v.nodeValue;
    }catch (err:Dynamic) {
        trace("Failed parsing node Text [" + nodeName+"] " + err );
        return null;
    }
}

By enabling if (_node == null) return null; line, It's working safely again. By catching errors as Dynamic I thought I was supposed to catch every possible error type! Why is this happening? And why is it appearing in release mode?

My IDE is FlashDevelop, and I'm using HaxeFlixel 3.3.6, lime 0.9.7 and openFL 1.4.0, if that makes any difference

EDIT: I suspect this has to do with how the translated C++ code missed the Dynamic Exception. The equivalent generated C++ code is:

STATIC_HX_DEFINE_DYNAMIC_FUNC2(BaxXML_obj,_getNodeNamed,return )

::String BaxXML_obj::getNodeText( ::haxe::xml::Fast parent,::String nodeName){
    HX_STACK_FRAME("bax.utils.BaxXML","getNodeText",0x4a152f07,"bax.utils.BaxXML.getNodeText","bax/utils/BaxXML.hx",56,0xf6e2d3cc)
    HX_STACK_ARG(parent,"parent")
    HX_STACK_ARG(nodeName,"nodeName")
    HX_STACK_LINE(56)
    try
    {
    HX_STACK_CATCHABLE(Dynamic, 0);
    {
        HX_STACK_LINE(57)
        ::haxe::xml::Fast _node = ::bax::utils::BaxXML_obj::getNodeNamed(parent,nodeName);      HX_STACK_VAR(_node,"_node");
        HX_STACK_LINE(63)
        Dynamic it = _node->x->iterator();      HX_STACK_VAR(it,"it");
        // ...  Let's skip the irrelevant code
    }
    catch(Dynamic __e){
        {
            HX_STACK_BEGIN_CATCH
            Dynamic err = __e;{
                HX_STACK_LINE(82)
                ::String _g5 = ::Std_obj::string(err);      HX_STACK_VAR(_g5,"_g5");
                HX_STACK_LINE(82)
                ::String _g6 = (((HX_CSTRING("Failed parsing node Text [") + nodeName) + HX_CSTRING("] ")) + _g5);      HX_STACK_VAR(_g6,"_g6");
                HX_STACK_LINE(82)
                ::haxe::Log_obj::trace(_g6,hx::SourceInfo(HX_CSTRING("BaxXML.hx"),82,HX_CSTRING("bax.utils.BaxXML"),HX_CSTRING("getNodeText")));
                HX_STACK_LINE(83)
                return null();
            }
        }
    }
    HX_STACK_LINE(56)
    return null();
}
yannicuLar
  • 3,083
  • 3
  • 32
  • 50

3 Answers3

3

What haxedefs do you have defined?

Adding these to your project.xml might help:

<haxedef name="HXCPP_CHECK_POINTER"/>  <!--makes null references cause errors-->
<haxedef name="HXCPP_STACK_LINE" />    <!--if you want line numbers-->
<haxedef name="HXCPP_STACK_TRACE"/>    <!--if you want stack traces-->

You might also try the crashdumper library: https://github.com/larsiusprime/crashdumper

(Crashdumper will turn on HXCPP_CHECK_POINTER by default as part of it's include.xml, and will set up hooks for both hxcpp's errors and openfl/lime's uncaught error events)

larsiusprime
  • 935
  • 6
  • 14
  • I didn't try the crashdumper, but the haxedefs worked for me just fine, I think this is the way to work with Haxe: It will still crash with a nullPointer Exception, but it provides the stack to track the Exception. Thanx again! – yannicuLar Jun 05 '15 at 15:53
  • Thanks! Did you ever find the final cause of the crash? – larsiusprime Jun 08 '15 at 14:56
  • Sure, check my answer. C++ cannot dereference null-pointer Exceptions, leading to app Crash. I still don't know why it happens on release mode, and not in debug. Tracing down the null pointer exceptions, and putting null checks before accessing null Fast nodes, I solved my crashes – yannicuLar Jun 08 '15 at 16:09
2

I guess this boils down to how C++ handles null-pointer Exceptions. It doesn't!

More info here or here

Community
  • 1
  • 1
yannicuLar
  • 3,083
  • 3
  • 32
  • 50
  • More precisely, it doesn't have null pointer dereference exceptions at all. However, on Windows you can [catch system signals as exceptions](https://msdn.microsoft.com/en-us/library/windows/desktop/ms681409%28v=vs.85%29.aspx). Whether this is a good idea is left to the reader's discretion (hint : no.) – Quentin Jun 04 '15 at 15:38
0

That seems odd, some questions that may help solving it.

  • It looks like you are doing quite some assumptions on how the xml looks (doing some manual it.next()), why is that?
  • Why are you using this big-ass try-catch block?
  • How does getNodeNamed look, it seems it can return null.
  • Do you have an example xml to test with?
Mark Knol
  • 9,663
  • 3
  • 29
  • 44
  • Thanx for your time. This is a part of a generic XML Parser (Utility Class) I've made for myself, that is safely parsing misc types of xml data, where the structure model is loose. E.g, it should handle a missing optional child, returning null instead of crashing (Fast would crash). The getNodeNamed is supposed to return null if the child is not there, and in this case it does, that's why I've put it in a try-catch, I think that the XML is irrelevant. The main issue in this question, is why a NullPointer in `_node.x.iterator();` breaks the try-catch block – yannicuLar Jun 04 '15 at 05:35
  • What I'm trying to explain is that the code is irrelevant since I've narroewd down the exact line where the code is crashing. I've provided some documentation for the function, to help you understand how the 'big-ass-try' works, but honestly I don't think that the function's logic is the issue here. – yannicuLar Jun 04 '15 at 05:52