Skip to content

Commit 36e19c9

Browse files
committed
Bug #43177: If an eval() has a parse error, the overall exit status and return code should not be affected.
Without this fix, a webpage using eval() may return code 500. That might display fine and the 500 go unnoticed, but using AJAX or wget, the 500 will cause problems.
1 parent dd288f9 commit 36e19c9

File tree

3 files changed

+134
-36
lines changed

3 files changed

+134
-36
lines changed

Zend/zend.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1238,7 +1238,13 @@ ZEND_API void zend_error(int type, const char *format, ...) /* {{{ */
12381238
va_end(args);
12391239

12401240
if (type == E_PARSE) {
1241-
EG(exit_status) = 255;
1241+
/* eval() errors do not affect exit_status */
1242+
if (!(EG(current_execute_data) &&
1243+
EG(current_execute_data)->opline &&
1244+
EG(current_execute_data)->opline->opcode == ZEND_INCLUDE_OR_EVAL &&
1245+
EG(current_execute_data)->opline->extended_value == ZEND_EVAL)) {
1246+
EG(exit_status) = 255;
1247+
}
12421248
zend_init_compiler_data_structures(TSRMLS_C);
12431249
}
12441250
}

main/main.c

Lines changed: 45 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ static void php_disable_classes(TSRMLS_D)
257257

258258
/* {{{ php_binary_init
259259
*/
260-
static void php_binary_init(TSRMLS_D)
260+
static void php_binary_init(TSRMLS_D)
261261
{
262262
char *binary_location;
263263
#ifdef PHP_WIN32
@@ -845,7 +845,7 @@ PHPAPI void php_verror(const char *docref, const char *params, int type, const c
845845
efree(docref_buf);
846846
}
847847

848-
if (PG(track_errors) && module_initialized &&
848+
if (PG(track_errors) && module_initialized &&
849849
(!EG(user_error_handler) || !(EG(user_error_handler_error_reporting) & type))) {
850850
if (!EG(active_symbol_table)) {
851851
zend_rebuild_symbol_table(TSRMLS_C);
@@ -962,7 +962,7 @@ static void php_error_cb(int type, const char *error_filename, const uint error_
962962
/* store the error if it has changed */
963963
if (display) {
964964
#ifdef ZEND_SIGNALS
965-
HANDLE_BLOCK_INTERRUPTIONS();
965+
HANDLE_BLOCK_INTERRUPTIONS();
966966
#endif
967967
if (PG(last_error_message)) {
968968
free(PG(last_error_message));
@@ -1133,11 +1133,20 @@ static void php_error_cb(int type, const char *error_filename, const uint error_
11331133
case E_PARSE:
11341134
case E_COMPILE_ERROR:
11351135
case E_USER_ERROR:
1136-
EG(exit_status) = 255;
1136+
{ /* new block to allow variable definition */
1137+
/* eval() errors do not affect exit_status or response code */
1138+
zend_bool during_eval = (type == E_PARSE) && (EG(current_execute_data) &&
1139+
EG(current_execute_data)->opline &&
1140+
EG(current_execute_data)->opline->opcode == ZEND_INCLUDE_OR_EVAL &&
1141+
EG(current_execute_data)->opline->extended_value == ZEND_EVAL);
1142+
if (!during_eval) {
1143+
EG(exit_status) = 255;
1144+
}
11371145
if (module_initialized) {
11381146
if (!PG(display_errors) &&
11391147
!SG(headers_sent) &&
1140-
SG(sapi_headers).http_response_code == 200
1148+
SG(sapi_headers).http_response_code == 200 &&
1149+
!during_eval
11411150
) {
11421151
sapi_header_line ctr = {0};
11431152

@@ -1158,6 +1167,7 @@ static void php_error_cb(int type, const char *error_filename, const uint error_
11581167
}
11591168
}
11601169
break;
1170+
}
11611171
}
11621172

11631173
/* Log if necessary */
@@ -1211,7 +1221,7 @@ PHPAPI char *php_get_current_user(TSRMLS_D)
12111221
name[len] = '\0';
12121222
SG(request_info).current_user_length = len;
12131223
SG(request_info).current_user = estrndup(name, len);
1214-
return SG(request_info).current_user;
1224+
return SG(request_info).current_user;
12151225
#else
12161226
struct passwd *pwd;
12171227
#if defined(ZTS) && defined(HAVE_GETPWUID_R) && defined(_SC_GETPW_R_SIZE_MAX)
@@ -1239,9 +1249,9 @@ PHPAPI char *php_get_current_user(TSRMLS_D)
12391249
#if defined(ZTS) && defined(HAVE_GETPWUID_R) && defined(_SC_GETPW_R_SIZE_MAX)
12401250
efree(pwbuf);
12411251
#endif
1242-
return SG(request_info).current_user;
1252+
return SG(request_info).current_user;
12431253
#endif
1244-
}
1254+
}
12451255
}
12461256
/* }}} */
12471257

@@ -1256,7 +1266,7 @@ PHP_FUNCTION(set_time_limit)
12561266
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &new_timeout) == FAILURE) {
12571267
return;
12581268
}
1259-
1269+
12601270
new_timeout_strlen = zend_spprintf(&new_timeout_str, 0, "%ld", new_timeout);
12611271

12621272
if (zend_alter_ini_entry_ex("max_execution_time", sizeof("max_execution_time"), new_timeout_str, new_timeout_strlen, PHP_INI_USER, PHP_INI_STAGE_RUNTIME, 0 TSRMLS_CC) == SUCCESS) {
@@ -1890,7 +1900,7 @@ static void core_globals_dtor(php_core_globals *core_globals TSRMLS_DC)
18901900
PHP_MINFO_FUNCTION(php_core) { /* {{{ */
18911901
php_info_print_table_start();
18921902
php_info_print_table_row(2, "PHP Version", PHP_VERSION);
1893-
php_info_print_table_end();
1903+
php_info_print_table_end();
18941904
DISPLAY_INI_ENTRIES();
18951905
}
18961906
/* }}} */
@@ -2166,7 +2176,7 @@ int php_module_startup(sapi_module_struct *sf, zend_module_entry *additional_mod
21662176
return FAILURE;
21672177
}
21682178

2169-
/* initialize registry for images to be used in phpinfo()
2179+
/* initialize registry for images to be used in phpinfo()
21702180
(this uses configuration parameters from php.ini)
21712181
*/
21722182
if (php_init_info_logos() == FAILURE) {
@@ -2212,7 +2222,7 @@ int php_module_startup(sapi_module_struct *sf, zend_module_entry *additional_mod
22122222
EG(current_module) = NULL;
22132223
}
22142224
}
2215-
2225+
22162226
/* disable certain classes and functions as requested by php.ini */
22172227
php_disable_functions(TSRMLS_C);
22182228
php_disable_classes(TSRMLS_C);
@@ -2247,38 +2257,38 @@ int php_module_startup(sapi_module_struct *sf, zend_module_entry *additional_mod
22472257
const char *directives[16]; /* Remember to change this if the number of directives change */
22482258
} directives[2] = {
22492259
{
2250-
E_DEPRECATED,
2251-
"Directive '%s' is deprecated in PHP 5.3 and greater",
2260+
E_DEPRECATED,
2261+
"Directive '%s' is deprecated in PHP 5.3 and greater",
22522262
{
22532263
NULL
22542264
}
2255-
},
2265+
},
22562266
{
2257-
E_CORE_ERROR,
2258-
"Directive '%s' is no longer available in PHP",
2267+
E_CORE_ERROR,
2268+
"Directive '%s' is no longer available in PHP",
22592269
{
22602270
"allow_call_time_pass_reference",
2261-
"define_syslog_variables",
2262-
"highlight.bg",
2263-
"magic_quotes_gpc",
2264-
"magic_quotes_runtime",
2265-
"magic_quotes_sybase",
2266-
"register_globals",
2267-
"register_long_arrays",
2268-
"safe_mode",
2269-
"safe_mode_gid",
2270-
"safe_mode_include_dir",
2271-
"safe_mode_exec_dir",
2272-
"safe_mode_allowed_env_vars",
2273-
"safe_mode_protected_env_vars",
2274-
"zend.ze1_compatibility_mode",
2271+
"define_syslog_variables",
2272+
"highlight.bg",
2273+
"magic_quotes_gpc",
2274+
"magic_quotes_runtime",
2275+
"magic_quotes_sybase",
2276+
"register_globals",
2277+
"register_long_arrays",
2278+
"safe_mode",
2279+
"safe_mode_gid",
2280+
"safe_mode_include_dir",
2281+
"safe_mode_exec_dir",
2282+
"safe_mode_allowed_env_vars",
2283+
"safe_mode_protected_env_vars",
2284+
"zend.ze1_compatibility_mode",
22752285
NULL
22762286
}
22772287
}
22782288
};
22792289

22802290
unsigned int i;
2281-
2291+
22822292
zend_try {
22832293
/* 2 = Count of deprecation structs */
22842294
for (i = 0; i < 2; i++) {
@@ -2298,7 +2308,7 @@ int php_module_startup(sapi_module_struct *sf, zend_module_entry *additional_mod
22982308
retval = FAILURE;
22992309
} zend_end_try();
23002310
}
2301-
2311+
23022312
sapi_deactivate(TSRMLS_C);
23032313
module_startup = 0;
23042314

@@ -2353,7 +2363,7 @@ void php_module_shutdown(TSRMLS_D)
23532363
sapi_flush(TSRMLS_C);
23542364

23552365
zend_shutdown(TSRMLS_C);
2356-
2366+
23572367
/* Destroys filter & transport registries too */
23582368
php_shutdown_stream_wrappers(module_number TSRMLS_CC);
23592369

@@ -2396,7 +2406,7 @@ PHPAPI int php_execute_script(zend_file_handle *primary_file TSRMLS_DC)
23962406
{
23972407
zend_file_handle *prepend_file_p, *append_file_p;
23982408
zend_file_handle prepend_file = {0}, append_file = {0};
2399-
#if HAVE_BROKEN_GETCWD
2409+
#if HAVE_BROKEN_GETCWD
24002410
int old_cwd_fd = -1;
24012411
#else
24022412
char *old_cwd;

sapi/cli/tests/bug43177.phpt

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
--TEST--
2+
Bug #61977 Test exit code for various errors
3+
--SKIPIF--
4+
<?php
5+
include "skipif.inc";
6+
?>
7+
--FILE--
8+
<?php
9+
include "php_cli_server.inc";
10+
php_cli_server_start(<<<'SCRIPT'
11+
ini_set('display_errors', 0);
12+
switch($_SERVER["REQUEST_URI"]) {
13+
case "/parse":
14+
eval("this is a parse error");
15+
echo "OK\n";
16+
break;
17+
case "/fatal":
18+
eval("foo();");
19+
echo "OK\n";
20+
break;
21+
case "/compile":
22+
eval("class foo { final private final function bar() {} }");
23+
echo "OK\n";
24+
break;
25+
case "/fatal2":
26+
foo();
27+
echo "OK\n";
28+
break;
29+
default:
30+
return false;
31+
}
32+
SCRIPT
33+
);
34+
35+
list($host, $port) = explode(':', PHP_CLI_SERVER_ADDRESS);
36+
$port = intval($port)?:80;
37+
38+
foreach(array("parse", "fatal", "fatal2", "compile") as $url) {
39+
$fp = fsockopen($host, $port, $errno, $errstr, 0.5);
40+
if (!$fp) {
41+
die("connect failed");
42+
}
43+
44+
if(fwrite($fp, <<<HEADER
45+
GET /$url HTTP/1.1
46+
Host: {$host}
47+
48+
49+
HEADER
50+
)) {
51+
while (!feof($fp)) {
52+
echo fgets($fp);
53+
}
54+
}
55+
}
56+
57+
?>
58+
--EXPECTF--
59+
HTTP/1.1 200 OK
60+
Host: localhost
61+
Connection: close
62+
X-Powered-By: %s
63+
Content-type: text/html
64+
65+
OK
66+
HTTP/1.0 500 Internal Server Error
67+
Host: localhost
68+
Connection: close
69+
X-Powered-By: %s
70+
Content-type: text/html
71+
72+
HTTP/1.0 500 Internal Server Error
73+
Host: localhost
74+
Connection: close
75+
X-Powered-By: %s
76+
Content-type: text/html
77+
78+
HTTP/1.0 500 Internal Server Error
79+
Host: localhost
80+
Connection: close
81+
X-Powered-By: %s
82+
Content-type: text/html

0 commit comments

Comments
 (0)