It feels like there is a bug in php somewhere. I'm trying to debug
this myself before filing a report and am in over my head. The
short version of my question may be "How do I set a watch on
SG(sapi_headers).http_response_code in the gdb?"
I think I need to debug it myself because I haven't been able to
reproduce it in a simple case. The following simple case works:
<?php
// In the real application there is a lot of code before this.
$x = eval('$y=0+;');
if ($x === false) {
$x = 'Unknown';
}
// In the real application there is a lot of code between the
// above and the below.
print "x is $x\n";
?>
That always gives success.
In my big ugly application, I get a response code 500 if the eval
is given poorly formed code. The exact same request is processed
happily if the eval of poorly formed code is commented out or
replaced with an eval of good code. The poorly formed code can be
as simple as the above example ('$y=0+;').
I've rebuilt apache 1.3.37 so that I can use gdb. (I'm using
php 5.4.3) After about 10 hours I've only gotten as far as
learning that r->status becomes 500 while the headers are being
prepared at the time of the print. That happens in mod_php5.c
on line 231: r->status = SG(sapi_headers).http_response_code;
I guess my next step is to find out when
SG(sapi_headers).http_response_code became 500. Given that
the problem appears/goes away based on whether the eval is
given bad code, I'm guessing the response_code is being affected
by the eval(), but I'd like to be more concrete about it and
maybe even be able to come up with a fix (or at least a good
enough description that someone who really understands internals
can come up with a fix without much trouble).
Perhaps I've completely misunderstood something about php and
should be directing this to a different list. My confidence
is high that a bad eval() shouldn't ruin the page, so I'm here
looking for debugging advice. If I'm in the wrong place, I
apologize.
Thanks for any pointers!
- Todd
[I'm afraid of getting flamed for how bad the code was in the example
in my first email. I've replaced the example in this email. The
rest is the same. The example still isn't great, but it's better
than before.]
It feels like there is a bug in php somewhere. I'm trying to debug
this myself before filing a report and am in over my head. The
short version of my question may be "How do I set a watch on
SG(sapi_headers).http_response_code in the gdb?"
I think I need to debug it myself because I haven't been able to
reproduce it in a simple case. The following simple case works:
<?php
function f($processed_string) {
// eval returns false on failure (e.g. division by 0)
$eval_result = @eval('$retval=('.$processed_string.');');
if ($eval_result === false) {
return 'Unknown';
}
return $retval;
}
print f('0+5')."\n"; // Good
print f('0(6)')."\n"; // Bad, but shouldn't lead to code 500
print f('0+')."\n"; // Bad, but shouldn't lead to code 500
?>
That example doesn't return code 500. But my big ugly application
does. I get a response code 500 if the eval is given poorly formed
code. The exact same request is processed happily if the eval of
poorly formed code is commented out or replaced with an eval of
good code. The poorly formed code can be as simple as in the above
example.
I've rebuilt apache 1.3.37 so that I can use gdb. (I'm using
php 5.4.3) After about 10 hours I've only gotten as far as
learning that r->status becomes 500 while the headers are being
prepared at the time of the print. That happens in mod_php5.c
on line 231: r->status = SG(sapi_headers).http_response_code;
I guess my next step is to find out when
SG(sapi_headers).http_response_code became 500. Given that
the problem appears/goes away based on whether the eval is
given bad code, I'm guessing the response_code is being affected
by the eval(), but I'd like to be more concrete about it and
maybe even be able to come up with a fix (or at least a good
enough description that someone who really understands internals
can come up with a fix without much trouble).
Perhaps I've completely misunderstood something about php and
should be directing this to a different list. My confidence
is high that a bad eval() shouldn't ruin the page, so I'm here
looking for debugging advice. If I'm in the wrong place, I
apologize.
Thanks for any pointers!
- Todd
eval() does indeed set the response code to 500 upon failure.
Is that a bug? I'll file a report because I don't believe
leaving the response code at 500 is consistent with the
statement from the php.net page about eval():
"If there is a parse error in the evaluated code, eval()
returns FALSE
and execution of the following code continues normally."
I don't think leaving the the response code at 500 is consistent
with "continues normally". I believe the fix is one line, adding
"&& EG(current_execute_data)->opline->extended_value != ZEND_EVAL"
to the "if" clauses before setting the error header in main.c
at line 1132.
In case anyone finds my post from last night while doing a search
of the archives, I'll explain more below and answer my question
about debugging.
What I didn't realize at the time of my post last night is that
browsers don't mind receiving a 500 as long as everything else
looks good. For example, the following web page:
<?php
eval('0+');
print "hello world\n";
?>
looks fine in a browser so I assumed (oops!) that it was returning
code 200. If you try doing a wget on that example, it complains
about the response code 500. (My big ugly application uses AJAX
and the 500 caused my AJAX framework to reject the page.)
Other than the code 500, everything seems to proceed normally.
All of the other code is executed normally. The content of the
web page is normal and is displayed well in a browser unless you
have something checking for unhappy response codes.
The answer to my question about watching the headers in the
debugger turned out to be pretty easy:
watch sapi_globals.sapi_headers
watch sapi_globals.sapi_headers.http_response_code
It would not have been so simple with ZTS on. (In that case,
the TSRM macros come in to play.)