Catching PHP fatal errors

classic Classic list List threaded Threaded
15 messages Options
Reply | Threaded
Open this post in threaded view
|

Catching PHP fatal errors

Tomi Maila
Hi,

I'm having problems with catching errors in haXe/PHP when something
unexpected happens. Let me describe the problem.

I've a facebook application running, that needs to contact facebook
Rest-like API using HTTP to query some stuff. Mostly the API works fine,
but sometimes it returns something unexpected. The content should be XML
but apparently it sometimes is not. I'm using a try-catch sequence to
try to handle any unexpected situations and sill be able to show at
least something to the user. However this doesn't seem to work and my
application crashes when Facebook API returns nothing or nonsense.

As a few lines of code tells more than a thousand words, let me show the
code that is causing the problem.

        h.onData = function(d) {  data = Xml.parse(d); };
        h.onError = function(e) { throw e; };
        h.request(true);
        if (data.firstElement().nodeName == 'error_response') throw
error_from_xml(data);
        return data.firstElement();

This all is enclosed inside a try statement and Dynamic type errors are
catched. Dispite this, PHP crashes at line where I try to test if the
nodeName is 'error_response' when the returned data is not valid Xml. My
PHP error logs show the following

PHP Fatal error:  Call to a member function getNodeName() on a
non-object in [class name]

I can surely test if the returned data is an empty string or even try to
validate the returned Xml. The first method is ok but doesn't cover all
possible scenarios. The second consumes expensive time and should not be
needed when Facebook API behaves normally.

So I'm asking is there any general way to handle all possible error
cases like this without letting the application to crash. I simply
cannot know in advance what abnormal scenarios can cause errors similar
to this one.

Cheers,

Tomi


--
haXe - an open source web programming language
http://haxe.org
Reply | Threaded
Open this post in threaded view
|

Re: Catching PHP fatal errors

Franco Ponticelli
The problem is that some errors in PHP are not recoverables and so they cannot be captured in a try/catch block. In this case in practice you are doing something like 

null->getNodeName()

that is a Fatal Error in PHP. So you will have to check for nullness beforehand. If anyone has a better solution for a workaroundI will be glad to hear opinions.

Franco.


On Thu, Oct 23, 2008 at 6:16 PM, Tomi Maila <[hidden email]> wrote:
Hi,

I'm having problems with catching errors in haXe/PHP when something
unexpected happens. Let me describe the problem.

I've a facebook application running, that needs to contact facebook
Rest-like API using HTTP to query some stuff. Mostly the API works fine,
but sometimes it returns something unexpected. The content should be XML
but apparently it sometimes is not. I'm using a try-catch sequence to
try to handle any unexpected situations and sill be able to show at
least something to the user. However this doesn't seem to work and my
application crashes when Facebook API returns nothing or nonsense.

As a few lines of code tells more than a thousand words, let me show the
code that is causing the problem.

       h.onData = function(d) {  data = Xml.parse(d); };
       h.onError = function(e) { throw e; };
       h.request(true);
       if (data.firstElement().nodeName == 'error_response') throw
error_from_xml(data);
       return data.firstElement();

This all is enclosed inside a try statement and Dynamic type errors are
catched. Dispite this, PHP crashes at line where I try to test if the
nodeName is 'error_response' when the returned data is not valid Xml. My
PHP error logs show the following

PHP Fatal error:  Call to a member function getNodeName() on a
non-object in [class name]

I can surely test if the returned data is an empty string or even try to
validate the returned Xml. The first method is ok but doesn't cover all
possible scenarios. The second consumes expensive time and should not be
needed when Facebook API behaves normally.

So I'm asking is there any general way to handle all possible error
cases like this without letting the application to crash. I simply
cannot know in advance what abnormal scenarios can cause errors similar
to this one.

Cheers,

Tomi


--
haXe - an open source web programming language
http://haxe.org


--
haXe - an open source web programming language
http://haxe.org
Reply | Threaded
Open this post in threaded view
|

Re: Catching PHP fatal errors

Tomi Maila
In reply to this post by Tomi Maila
Could haXe generated code test for nullness in context of dynamic
methods and throw an error rather than let PHP crash.

Tomi

> The problem is that some errors in PHP are not recoverables and so they
> cannot be captured in a try/catch block. In this case in practice you are
> doing something like
> null->getNodeName()
>
> that is a Fatal Error in PHP. So you will have to check for nullness
> beforehand. If anyone has a better solution for a workaroundI will be glad
> to hear opinions.
>
> Franco.
>
>  

--
haXe - an open source web programming language
http://haxe.org
Reply | Threaded
Open this post in threaded view
|

Re: Catching PHP fatal errors

Franco Ponticelli
This is not a problem related to dynamic methods but to objects that do not exist. Adding a runtime check for them is possible but it would be performed for any possible occurence, in practice every time you access any field of any object (to be honest some cases could be avoided but most of them no). That would be overkilling.
 should be performed on
 
Franco.

On Thu, Oct 23, 2008 at 6:47 PM, Tomi Maila <[hidden email]> wrote:
Could haXe generated code test for nullness in context of dynamic
methods and throw an error rather than let PHP crash.

Tomi

> The problem is that some errors in PHP are not recoverables and so they
> cannot be captured in a try/catch block. In this case in practice you are
> doing something like
> null->getNodeName()
>
> that is a Fatal Error in PHP. So you will have to check for nullness
> beforehand. If anyone has a better solution for a workaroundI will be glad
> to hear opinions.
>
> Franco.
>
>

--
haXe - an open source web programming language
http://haxe.org


--
haXe - an open source web programming language
http://haxe.org
Reply | Threaded
Open this post in threaded view
|

Catching PHP fatal errors

Tomi Maila
In reply to this post by Tomi Maila
Ok. In this particular case I guess the problem from haXe point of view is that Xml.parse claims to returns
an object of type Xml but the actually returned object is not an object of type Xml. Maybe the null check could be
made in this kind of situations, when returning something that should be of type X but that has a possibility to
be of null or some other incompatible type Y. That is, could it be possible to guarantee that standard library functions
actually return what they should or otherwise throw an error. At least for PHP target where we can have PHP
fatal errors. Surely it is hard to identify these situations by code inspection but I think it is enough if
the community reports when a PHP fatal error is encountered and this hole is then fixed.

Tomi


> Adding a runtime check for them is possible but it would be performed
> for any possible occurence, in practice every time you access any field of
> any object (to be honest some cases could be avoided but most of them no).
> That would be overkilling
>>         h.onData = function(d) {  data = Xml.parse(d); };
>>         h.onError = function(e) { throw e; };
>>         h.request(true);
>>         if (data.firstElement().nodeName == 'error_response') throw error_from_xml(data);
>>         return data.firstElement();


--
haXe - an open source web programming language
http://haxe.org
Reply | Threaded
Open this post in threaded view
|

Re: Catching PHP fatal errors

Franco Ponticelli
Throwing an error would imply anyway that a runtime check is performed, so I don't see a real advantage over having the developer to do the check, when this check can be avoided most of the times.

Franco.

On Thu, Oct 23, 2008 at 8:47 PM, Tomi Maila <[hidden email]> wrote:
Ok. In this particular case I guess the problem from haXe point of view is that Xml.parse claims to returns an object of type Xml but the actually returned object is not an object of type Xml. Maybe the null check could be
made in this kind of situations, when returning something that should be of type X but that has a possibility to
be of null or some other incompatible type Y. That is, could it be possible to guarantee that standard library functions
actually return what they should or otherwise throw an error. At least for PHP target where we can have PHP fatal errors. Surely it is hard to identify these situations by code inspection but I think it is enough if
the community reports when a PHP fatal error is encountered and this hole is then fixed.

Tomi


Adding a runtime check for them is possible but it would be performed
for any possible occurence, in practice every time you access any field of
any object (to be honest some cases could be avoided but most of them no).
That would be overkilling
       h.onData = function(d) {  data = Xml.parse(d); };
       h.onError = function(e) { throw e; };
       h.request(true);
       if (data.firstElement().nodeName == 'error_response') throw error_from_xml(data);
       return data.firstElement();


--
haXe - an open source web programming language
http://haxe.org


--
haXe - an open source web programming language
http://haxe.org
Reply | Threaded
Open this post in threaded view
|

Re: Catching PHP fatal errors

Nicolas Cannasse
In reply to this post by Tomi Maila
Tomi Maila a écrit :
> Ok. In this particular case I guess the problem from haXe point of view
> is that Xml.parse claims to returns an object of type Xml but the
> actually returned object is not an object of type Xml.

The fact that Xml is using another implementation (php.PhpXml__) should
be transparent from an user point of view, please report some example if
it's not the case. Also, Xml.parse shouldn't return "null" in any case.

As for nullable types, we had this discussion earlier this year when I
made the haxe 2.0 proposal. It was ruled out because the existing
JS/Flash/Php/Neko... apis are often returning/using null values, so it
would be very painful to handle all these cases by adding explicit
null-checks while developing apps.

Best,
Nicolas

--
haXe - an open source web programming language
http://haxe.org
Reply | Threaded
Open this post in threaded view
|

Catching PHP fatal errors

Tomi Maila
In reply to this post by Tomi Maila
>
> The fact that Xml is using another implementation (php.PhpXml__) should
> be transparent from an user point of view, please report some example if
> it's not the case. Also, Xml.parse shouldn't return "null" in any case.
>  
Well, the example below crashes PHP and I think it should rather throw
an error. All XML documents have a root element and the root element
always have a name, so firstElement().nodeName should be valid for any
XML document.

Tomi
---
class Test
{

    public static function main() {
        try {
            var d = '';
            trace(d);
            var data = Xml.parse(d);
            trace(data);
            if (data.firstElement().nodeName == 'error_response') throw
'error'; // crash on this line when calling nodeName
            trace('ok');
        } catch ( e : Dynamic) {
            trace(e);
        }
       
    }
}

--
haXe - an open source web programming language
http://haxe.org
Reply | Threaded
Open this post in threaded view
|

Re: Catching PHP fatal errors

Nicolas Cannasse
Tomi Maila a écrit :
>> The fact that Xml is using another implementation (php.PhpXml__) should
>> be transparent from an user point of view, please report some example if
>> it's not the case. Also, Xml.parse shouldn't return "null" in any case.
>>  
> Well, the example below crashes PHP and I think it should rather throw
> an error. All XML documents have a root element and the root element
> always have a name, so firstElement().nodeName should be valid for any
> XML document.

No, the empty Document ("") does not have any element. That's the same
for "ABCD" for instance, it it's a document with only one PCDATA, but no
element.

Nicolas

--
haXe - an open source web programming language
http://haxe.org
Reply | Threaded
Open this post in threaded view
|

Catching PHP fatal errors

Tomi Maila
In reply to this post by Tomi Maila
>
> No, the empty Document ("") does not have any element. That's the same
> for "ABCD" for instance, it it's a document with only one PCDATA, but no
> element.
>
> Nicolas
>  
No, not according to XML specification. XML document is specified in XML
grammar as

document       ::=        prolog  element  Misc*

So in any valid XML document there is exactly one and only one root
element, always. Otherwise it is not a valid XML document.

Tomi

--
haXe - an open source web programming language
http://haxe.org
Reply | Threaded
Open this post in threaded view
|

Re: Catching PHP fatal errors

Tomi Maila
In reply to this post by Tomi Maila
Anyway, irregardless of how Xml is specified, should calling firstChild
or firstElement for an Xml object that doesn't contain any children
throw an error rather than return an empty object. It would be more safe
as the error cases cannot be handled any way if error is not thrown by
haXe.

Tomi

> >/
> />/ No, the empty Document ("") does not have any element. That's the same
> />/ for "ABCD" for instance, it it's a document with only one PCDATA, but no
> />/ element.
> />/
> />/ Nicolas
> />/  
> /No, not according to XML specification. XML document is specified in XML
> grammar as
>
> document       ::=        prolog  element  Misc*
>
> So in any valid XML document there is exactly one and only one root
> element, always. Otherwise it is not a valid XML document.
>
> Tomi
>  

--
haXe - an open source web programming language
http://haxe.org
Reply | Threaded
Open this post in threaded view
|

Re: Catching PHP fatal errors

Nicolas Cannasse
Tomi Maila a écrit :
> Anyway, irregardless of how Xml is specified, should calling firstChild
> or firstElement for an Xml object that doesn't contain any children
> throw an error rather than return an empty object. It would be more safe
> as the error cases cannot be handled any way if error is not thrown by
> haXe.

That would break compatibility with existing APIs, and would need some
additional APIs such hasElement().

Nicolas

--
haXe - an open source web programming language
http://haxe.org
Reply | Threaded
Open this post in threaded view
|

Re: Catching PHP fatal errors

Tomi Maila
In reply to this post by Tomi Maila
I know I sometimes give quite critical feedback but please take it as
constructive and not as a critic against haXe language. After all
criticism is a driving force in  all development.

I am really worried if we allow haXe programs to crash without throwing
errors. We all know that programmers make mistakes and cannot take into
account all possible error conditions. Type systems are important to
avoid this kind of problems, but at least in this case they do not
protect from the problems. I would rather see as much protection from
the type system as possible. After all modern type systems are almost as
flexible as fully dynamic languages but provide much more protection. If
the type system doesn't protect or the programmer cannot rely on the
code to throw errors, then the programmer needs to test for every
possible abnormal condition and bugs become more likely or alternatively
programmers can just ignore abnormal conditions and let their programs
to crash.

So, anytime we allow a function to return a null object, we should at
least document it can return a null object. From my point of view, the
documented return value of Xml.firstChild() should rather Null<Xml>
rather than Xml. That would make it explicit for the developer that
he/she should test for nullness when ever calling a method or using
referring to a property, if the other option would be to allow the
program to crash completely.

I think a little similar problem in haXe type system is where one can
pass an object of type Dynamic when some other specific type is expected
as that can cause very similar problems as objects do not necessarily
have properties and methods your code is expecting. It would be better
if the type checking would be executed at runtime in these cases. Now
there is no type checking at all, if I'm correct. As a result, for
example a module that should guarantee transaction integrity can fail,
just because it cannot know at development time what type of objects the
user can pass to it. The lack of type checking also opens possibility
for security issues as malicious Eve can pass objects that do not
conform the required specifications and haXe generated code would still
execute the methods in the object. Say I would have some sort of
security module that would check for authorization. Now if it is
possible to overwrite a private method for authorization checking, a
malicious user could in principle get control of the system. Although in
principle haXe class system doesn't allow overwriting private methods,
it would be possible by passing a Dynamic object with a method of the
same name instead. As runtime type checking doesn't occur, the malicious
method can be called when private method should be called instead.

Back to the XML issue. Maybe in this particular case we could add an
optional parameter to for example the parse method of Xml class to force
haXe make more runtime checks. This would not break the compatibility
with current APIs.

Tomi

> Tomi Maila a écrit :
> >/ Anyway, irregardless of how Xml is specified, should calling firstChild
> />/ or firstElement for an Xml object that doesn't contain any children
> />/ throw an error rather than return an empty object. It would be more safe
> />/ as the error cases cannot be handled any way if error is not thrown by
> />/ haXe.
> /
> That would break compatibility with existing APIs, and would need some
> additional APIs such hasElement().
>
> Nicolas
>  


--
haXe - an open source web programming language
http://haxe.org
Reply | Threaded
Open this post in threaded view
|

Re: Catching PHP fatal errors

Nicolas Cannasse
Tomi Maila a écrit :
> I know I sometimes give quite critical feedback but please take it as
> constructive and not as a critic against haXe language. After all
> criticism is a driving force in  all development.
>
> I am really worried if we allow haXe programs to crash without throwing
> errors.
[...]

Please note that this is not an haXe issue but a PHP one.

Also, PHP *will* display an error in such case, which will displayed on
the HTML output. The only issue here is that this error is not an
exception and is thus not catchable.

> So, anytime we allow a function to return a null object, we should at
> least document it can return a null object. From my point of view, the
> documented return value of Xml.firstChild() should rather Null<Xml>
> rather than Xml.

I agree with this, using Null<> for such APIs would be helpful. It's not
been done right now for historical reasons, since Null<> was only added
when adding Flash9 platform, and was generalized later.

You're welcome to submit a patch for either the Xml API or more standard
libraries.

> I think a little similar problem in haXe type system is where one can
> pass an object of type Dynamic when some other specific type is expected
> as that can cause very similar problems as objects do not necessarily
> have properties and methods your code is expecting.

Using Dynamic is like playing with fire : you have to know what you're
doing if you don't want to get burn.

There might be runtime checks but it's platform-specific.

> It would be better
> if the type checking would be executed at runtime in these cases.

This is left to the platform implementation. Enforcing such runtime
checks while most of the time you know what you're doing would cost a
lot of CPU.

The general philosophy of haXe is to maximize compile-time checks and
minimize runtime checks. As you point out, the issue might be with
"malicious" input.

The correct way to deal with it is to check the correctness of these
inputs, and only at this point runtime type checking is necessary...

You can use the Reflect and Type APIs in order to perform theses checks.

Best,
Nicolas

--
haXe - an open source web programming language
http://haxe.org
Reply | Threaded
Open this post in threaded view
|

Re: Catching PHP fatal errors

Kostas Michalopoulos
In reply to this post by Tomi Maila
> Back to the XML issue. Maybe in this particular case we could add an
> optional parameter to for example the parse method of Xml class to force
> haXe make more runtime checks. This would not break the compatibility
> with current APIs.

While reading all the above (and other posts) that was exactly what i
had in mind:

haxe -safe ...

Generates potentially much slower but safer code for people who can't or
don't want to be bothered to manually check for such errors.

Kostas "Bad Sector" Michalopoulos

--
haXe - an open source web programming language
http://haxe.org