Skip to content

Commit fd08f06

Browse files
diafournikic
authored andcommitted
Fix bug #78323: Code 0 is returned on invalid options
Set CLI exit code to 1 when invalid parameters are passed, and print error to stderr.
1 parent b836d9c commit fd08f06

File tree

11 files changed

+177
-5
lines changed

11 files changed

+177
-5
lines changed

NEWS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ PHP NEWS
66
. Fixed bug #71876 (Memory corruption htmlspecialchars(): charset `*' not
77
supported). (Nikita)
88
. Fixed bug ##79146 (cscript can fail to run on some systems). (clarodeus)
9+
. Fixed bug #78323 (Code 0 is returned on invalid options). (Ivan Mikheykin)
910

1011
- CURL:
1112
. Fixed bug #79078 (Hypothetical use-after-free in curl_multi_add_handle()).

ext/standard/basic_functions.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4478,7 +4478,7 @@ PHP_FUNCTION(getopt)
44784478

44794479
while ((o = php_getopt(argc, argv, opts, &php_optarg, &php_optind, 0, 1)) != -1) {
44804480
/* Skip unknown arguments. */
4481-
if (o == '?') {
4481+
if (o == PHP_GETOPT_INVALID_ARG) {
44824482
continue;
44834483
}
44844484

main/getopt.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#define OPTERRNF (2)
2727
#define OPTERRARG (3)
2828

29+
// Print error message to stderr and return -2 to distinguish it from '?' command line option.
2930
static int php_opt_error(int argc, char * const *argv, int oint, int optchr, int err, int show_err) /* {{{ */
3031
{
3132
if (show_err)
@@ -47,7 +48,7 @@ static int php_opt_error(int argc, char * const *argv, int oint, int optchr, int
4748
break;
4849
}
4950
}
50-
return('?');
51+
return PHP_GETOPT_INVALID_ARG;
5152
}
5253
/* }}} */
5354

main/php_getopt.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ extern PHPAPI int php_optidx;
3535
PHPAPI int php_getopt(int argc, char* const *argv, const opt_struct opts[], char **optarg, int *optind, int show_err, int arg_start);
3636
END_EXTERN_C()
3737

38+
/* php_getopt will return this value if there is an error in arguments */
39+
#define PHP_GETOPT_INVALID_ARG (-2)
40+
3841
#endif
3942

4043
/*

sapi/cgi/cgi_main.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2283,6 +2283,7 @@ consult the installation file that came with this distribution, or visit \n\
22832283
break;
22842284
case 'h':
22852285
case '?':
2286+
case PHP_GETOPT_INVALID_ARG:
22862287
if (request) {
22872288
fcgi_destroy_request(request);
22882289
}
@@ -2292,6 +2293,9 @@ consult the installation file that came with this distribution, or visit \n\
22922293
php_cgi_usage(argv[0]);
22932294
php_output_end_all();
22942295
exit_status = 0;
2296+
if (c == PHP_GETOPT_INVALID_ARG) {
2297+
exit_status = 1;
2298+
}
22952299
goto out;
22962300
}
22972301
}

sapi/cgi/tests/bug78323.phpt

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
--TEST--
2+
Bug #78323 Test exit code and error message for invalid parameters
3+
--SKIPIF--
4+
<?php include "skipif.inc"; ?>
5+
--FILE--
6+
<?php
7+
include "include.inc";
8+
$php = get_cgi_path();
9+
reset_env_vars();
10+
11+
12+
// no argument for option
13+
ob_start();
14+
passthru("$php --memory-limit=1G 2>&1", $exitCode);
15+
$output = ob_get_contents();
16+
ob_end_clean();
17+
18+
$lines = preg_split('/\R/', $output);
19+
echo $lines[0], "\n",
20+
$lines[1], "\n",
21+
"Done: $exitCode\n\n";
22+
23+
24+
// Successful execution
25+
ob_start();
26+
passthru("$php -dmemory-limit=1G -v", $exitCode);
27+
$output = ob_get_contents();
28+
ob_end_clean();
29+
30+
$lines = preg_split('/\R/', $output);
31+
echo $lines[0], "\n",
32+
"Done: $exitCode\n";
33+
34+
?>
35+
--EXPECTF--
36+
Error in argument 1, char 1: no argument for option -
37+
Usage: %s
38+
Done: 1
39+
40+
PHP %s
41+
Done: 0

sapi/cli/php_cli.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1265,7 +1265,7 @@ int main(int argc, char *argv[])
12651265
setmode(_fileno(stderr), O_BINARY); /* make the stdio mode be binary */
12661266
#endif
12671267

1268-
while ((c = php_getopt(argc, argv, OPTIONS, &php_optarg, &php_optind, 0, 2))!=-1) {
1268+
while ((c = php_getopt(argc, argv, OPTIONS, &php_optarg, &php_optind, 1, 2))!=-1) {
12691269
switch (c) {
12701270
case 'c':
12711271
if (ini_path_override) {
@@ -1317,6 +1317,10 @@ int main(int argc, char *argv[])
13171317
case '?':
13181318
php_cli_usage(argv[0]);
13191319
goto out;
1320+
case PHP_GETOPT_INVALID_ARG: /* print usage on bad options, exit 1 */
1321+
php_cli_usage(argv[0]);
1322+
exit_status = 1;
1323+
goto out;
13201324
case 'i': case 'v': case 'm':
13211325
sapi_module = &cli_sapi_module;
13221326
goto exit_loop;

sapi/cli/tests/015.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ $php = getenv('TEST_PHP_EXECUTABLE');
1616
echo `"$php" -n --version | grep built:`;
1717
echo `echo "<?php print_r(\\\$argv);" | "$php" -n -- foo bar baz`, "\n";
1818
echo `"$php" -n --version foo bar baz | grep built:`;
19-
echo `"$php" -n --notexisting foo bar baz | grep Usage:`;
19+
echo `"$php" -n --notexisting foo bar baz 2>&1 | grep Usage:`;
2020

2121
echo "Done\n";
2222
?>

sapi/cli/tests/bug78323.phpt

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
--TEST--
2+
Bug #78323 Test exit code and error message for invalid parameters
3+
--SKIPIF--
4+
<?php
5+
include "skipif.inc";
6+
?>
7+
--FILE--
8+
<?php
9+
$php = getenv('TEST_PHP_EXECUTABLE');
10+
11+
// There are 3 types of option errors:
12+
// 1 : in flags
13+
// 2 option not found
14+
// 3 no argument for option
15+
16+
17+
// colon in flags
18+
ob_start();
19+
passthru("$php -a:Z 2>&1", $exitCode);
20+
$output = ob_get_contents();
21+
ob_end_clean();
22+
23+
$lines = preg_split('/\R/', $output);
24+
echo $lines[0], "\n",
25+
$lines[1], "\n",
26+
"Done: $exitCode\n\n";
27+
28+
29+
// option not found
30+
ob_start();
31+
passthru("$php -Z 2>&1", $exitCode);
32+
$output = ob_get_contents();
33+
ob_end_clean();
34+
35+
$lines = preg_split('/\R/', $output);
36+
echo $lines[0], "\n",
37+
$lines[1], "\n",
38+
"Done: $exitCode\n\n";
39+
40+
41+
// no argument for option
42+
ob_start();
43+
passthru("$php --memory-limit=1G 2>&1", $exitCode);
44+
$output = ob_get_contents();
45+
ob_end_clean();
46+
47+
$lines = preg_split('/\R/', $output);
48+
echo $lines[0], "\n",
49+
$lines[1], "\n",
50+
"Done: $exitCode\n\n";
51+
52+
53+
// Successful execution
54+
ob_start();
55+
passthru("$php -dmemory-limit=1G -v", $exitCode);
56+
$output = ob_get_contents();
57+
ob_end_clean();
58+
59+
$lines = preg_split('/\R/', $output);
60+
echo $lines[0], "\n",
61+
"Done: $exitCode\n";
62+
63+
?>
64+
--EXPECTF--
65+
Error in argument %d, char %d: : in flags
66+
Usage: %s [options] [-f] <file> [--] [args...]
67+
Done: 1
68+
69+
Error in argument %d, char %d: option not found %s
70+
Usage: %s [options] [-f] <file> [--] [args...]
71+
Done: 1
72+
73+
Error in argument %d, char %d: no argument for option %s
74+
Usage: %s [options] [-f] <file> [--] [args...]
75+
Done: 1
76+
77+
PHP %s
78+
Done: 0

sapi/fpm/fpm/fpm_main.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1707,14 +1707,15 @@ int main(int argc, char *argv[])
17071707
default:
17081708
case 'h':
17091709
case '?':
1710+
case PHP_GETOPT_INVALID_ARG:
17101711
cgi_sapi_module.startup(&cgi_sapi_module);
17111712
php_output_activate();
17121713
SG(headers_sent) = 1;
17131714
php_cgi_usage(argv[0]);
17141715
php_output_end_all();
17151716
php_output_deactivate();
17161717
fcgi_shutdown();
1717-
exit_status = (c == 'h') ? FPM_EXIT_OK : FPM_EXIT_USAGE;
1718+
exit_status = (c != PHP_GETOPT_INVALID_ARG) ? FPM_EXIT_OK : FPM_EXIT_USAGE;
17181719
goto out;
17191720

17201721
case 'v': /* show php version & quit */

sapi/fpm/tests/bug78323.phpt

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
--TEST--
2+
FPM: Bug #78323 Test exit code for invalid parameters
3+
--SKIPIF--
4+
<?php include "skipif.inc"; ?>
5+
--FILE--
6+
<?php
7+
8+
require_once "tester.inc";
9+
10+
$php = \FPM\Tester::findExecutable();
11+
12+
// no argument for option
13+
ob_start();
14+
passthru("$php --memory-limit=1G 2>&1", $exitCode);
15+
$output = ob_get_contents();
16+
ob_end_clean();
17+
18+
$lines = preg_split('/\R/', $output);
19+
echo $lines[0], "\n",
20+
"Done: $exitCode\n\n";
21+
22+
23+
// Successful execution
24+
ob_start();
25+
passthru("$php -dmemory-limit=1G -v", $exitCode);
26+
$output = ob_get_contents();
27+
ob_end_clean();
28+
29+
$lines = preg_split('/\R/', $output);
30+
echo $lines[0], "\n",
31+
"Done: $exitCode\n";
32+
33+
?>
34+
--EXPECTF--
35+
Usage: %s
36+
Done: 64
37+
38+
PHP %s
39+
Done: 0

0 commit comments

Comments
 (0)