diff --git a/NEWS b/NEWS index 7ec4eb4b809e..7d85ff104dcd 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,9 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| -?? ??? ????, PHP 8.6.0alpha3 +?? ??? ????, PHP 8.6.0beta1 + + +30 Jul 2026, PHP 8.6.0alpha3 - Core: . Implemented partial function application RFC. (Arnaud) @@ -16,7 +19,12 @@ PHP NEWS . Fixed bug GH-22825 (DOMElement::setAttribute() fails silently when the DTD declares a default value for the attribute). (iliaal) +- Embed: + . Made php-cli functionality available in embed builds. (henderkes) + - GMP: + . Added gmp_powm_sec(). (Weilin Du) + . Added gmp_prevprime(). (Weilin Du, David Carlier) . Fixed GMP power and shift operators to reject GMP right operands outside the unsigned long range instead of silently truncating them. (Weilin Du) . Fixed GMP integer string parsing to reject strings containing NUL bytes diff --git a/UPGRADING b/UPGRADING index d30a5663274f..7c9473d07b7d 100644 --- a/UPGRADING +++ b/UPGRADING @@ -271,6 +271,14 @@ PHP 8.6 UPGRADE NOTES - Fileinfo: . finfo_file() now works with remote streams. +- GMP: + . Added gmp_powm_sec() for side-channel quiet modular exponentiation. + Requires GNU MP 5.0.0 or later. + . Added gmp_prevprime() to get the largest prime smaller than the given + number. A ValueError is thrown if no such prime exists. This function is + available only when PHP is built against GNU MP 6.3.0 or later; it is not + available on official Windows builds using MPIR. + - Intl: . Added Locale::getDisplayKeyword() and Locale::getDisplayKeywordValue(), with the alias of locale_get_display_keyword() and @@ -421,6 +429,10 @@ PHP 8.6 UPGRADE NOTES 6. New Functions ======================================== +- GMP: + . gmp_powm_sec() + . gmp_prevprime() + - Intl: . grapheme_strrev() RFC: https://wiki.php.net/rfc/grapheme_strrev diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS index 39f5d72e2701..8b4b5912317a 100644 --- a/UPGRADING.INTERNALS +++ b/UPGRADING.INTERNALS @@ -191,6 +191,7 @@ PHP 8.6 INTERNALS UPGRADE NOTES strings from one or more buffers. . Added zend_string_ends_with() and related variants. . Added trait support for internal classes. + . Added do_php_cli(). ======================== 2. Build system changes @@ -227,6 +228,10 @@ PHP 8.6 INTERNALS UPGRADE NOTES . Added a new function CHECK_HEADER() which is intended to be used instead of the CHECK_HEADER_ADD_INCLUDE(). +- Embed: + . The CLI SAPI can not be disabled when building the embed SAPI + (--enable-embed is incompatible with --disable-cli). + ======================== 3. Module changes ======================== @@ -307,3 +312,6 @@ PHP 8.6 INTERNALS UPGRADE NOTES - AG and SCNG are now allocated with ts_allocate_tls_id() and live in native __thread storage on ZTS builds. + +- php-cli functionality is now available in embed builds via the do_php_cli() + function. diff --git a/ext/bcmath/libbcmath/src/str2num.c b/ext/bcmath/libbcmath/src/str2num.c index b6f3d736f8da..925fad06d51f 100644 --- a/ext/bcmath/libbcmath/src/str2num.c +++ b/ext/bcmath/libbcmath/src/str2num.c @@ -179,6 +179,7 @@ bool bc_str2num(bc_num *num, const char *str, const char *end, size_t scale, siz if (str_scale > 0) { const char *fractional_new_end = bc_skip_zero_reverse(fractional_end, fractional_ptr); str_scale -= fractional_end - fractional_new_end; /* fractional_end >= fractional_new_end */ + fractional_end = fractional_new_end; } } } else { diff --git a/ext/bcmath/tests/GHSA-x692-q9x7-8c3f.phpt b/ext/bcmath/tests/GHSA-x692-q9x7-8c3f.phpt new file mode 100644 index 000000000000..b735958bd07a --- /dev/null +++ b/ext/bcmath/tests/GHSA-x692-q9x7-8c3f.phpt @@ -0,0 +1,13 @@ +--TEST-- +GHSA-x692-q9x7-8c3f: bccomp() out-of-bounds write +--CREDITS-- +Recep Asan (recepasan) +--FILE-- + +--EXPECT-- +int(1) diff --git a/ext/gd/libgd/gd_gif_in.c b/ext/gd/libgd/gd_gif_in.c index 5a19a8a3abd1..9de085f93d4c 100644 --- a/ext/gd/libgd/gd_gif_in.c +++ b/ext/gd/libgd/gd_gif_in.c @@ -1308,7 +1308,7 @@ static int LWZReadByte_(gdIOCtx *fd, LZW_STATIC_DATA *sd, char flag, int input_c } for (; i < (1 << MAX_LWZ_BITS); ++i) { - sd->table[0][i] = sd->table[1][0] = 0; + sd->table[0][i] = sd->table[1][i] = 0; } sd->sp = sd->stack; @@ -1363,6 +1363,8 @@ static int LWZReadByte_(gdIOCtx *fd, LZW_STATIC_DATA *sd, char flag, int input_c if (count != 0) { return -2; } + + return -2; } incode = code; @@ -1443,7 +1445,7 @@ static int ReadImage(gdImagePtr im, gdIOCtx *fd, int len, int height, unsigned c unsigned char c; int xpos = 0, ypos = 0, pass = 0; int v, i; - LZW_STATIC_DATA sd; + LZW_STATIC_DATA sd = {0}; /* Initialize the Compression routines */ if (!ReadOK(fd, &c, 1)) { diff --git a/ext/gmp/config.m4 b/ext/gmp/config.m4 index f0f07d377078..f6f2a4a0e9a3 100644 --- a/ext/gmp/config.m4 +++ b/ext/gmp/config.m4 @@ -22,6 +22,7 @@ if test "$PHP_GMP" != "no"; then LIBS="$LIBS $GMP_LIBS" gmp_check=no AC_CHECK_HEADER([gmp.h], [AC_CHECK_FUNC([__gmpz_rootrem], [gmp_check=yes])]) + AC_CHECK_FUNCS([__gmpz_powm_sec __gmpz_prevprime]) CFLAGS=$CFLAGS_SAVED LIBS=$LIBS_SAVED diff --git a/ext/gmp/config.w32 b/ext/gmp/config.w32 index dc0c1e978d31..fc052440417c 100644 --- a/ext/gmp/config.w32 +++ b/ext/gmp/config.w32 @@ -5,6 +5,12 @@ ARG_WITH("gmp", "Include GNU MP support.", "no"); if (PHP_GMP != "no") { if (CHECK_LIB("mpir_a.lib", "gmp", PHP_GMP) && CHECK_HEADER("gmp.h", "CFLAGS_GMP", PHP_GMP + ";" + PHP_PHP_BUILD + "\\include\\mpir")) { + if (GREP_HEADER("gmp.h", "mpz_powm_sec", PHP_GMP + ";" + PHP_PHP_BUILD + "\\include\\mpir")) { + AC_DEFINE('HAVE___GMPZ_POWM_SEC', 1, "Define to 1 if GMP has the 'mpz_powm_sec' function."); + } + if (GREP_HEADER("gmp.h", "mpz_prevprime", PHP_GMP + ";" + PHP_PHP_BUILD + "\\include\\mpir")) { + AC_DEFINE('HAVE___GMPZ_PREVPRIME', 1, "Define to 1 if GMP has the 'mpz_prevprime' function."); + } EXTENSION("gmp", "gmp.c", null, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); PHP_INSTALL_HEADERS("ext/gmp", "php_gmp_int.h"); AC_DEFINE('HAVE_GMP', 1, "Define to 1 if the PHP extension 'gmp' is available."); diff --git a/ext/gmp/gmp.c b/ext/gmp/gmp.c index 7f8799a7ae2d..bf0a77666b6f 100644 --- a/ext/gmp/gmp.c +++ b/ext/gmp/gmp.c @@ -1082,6 +1082,34 @@ GMP_UNARY_OP_FUNCTION(com); /* {{{ Finds next prime of a */ GMP_UNARY_OP_FUNCTION(nextprime); +#ifdef HAVE___GMPZ_PREVPRIME +/* {{{ Finds previous prime of a */ +ZEND_FUNCTION(gmp_prevprime) +{ + mpz_ptr gmpnum_a, gmpnum_result; + int res; + + ZEND_PARSE_PARAMETERS_START(1, 1) + GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_a) + ZEND_PARSE_PARAMETERS_END(); + + if (mpz_cmp_ui(gmpnum_a, 2) <= 0) { + /* + * mpz_prevprime() returns 0 when no previous prime exists, which happens + * for operands not greater than 2. + * https://gmplib.org/manual/Number-Theoretic-Functions#index-mpz_005fprevprime + */ + zend_argument_value_error(1, "must be greater than 2"); + RETURN_THROWS(); + } + + INIT_GMP_RETVAL(gmpnum_result); + res = mpz_prevprime(gmpnum_result, gmpnum_a); + ZEND_ASSERT(res); +} +/* }}} */ +#endif + /* Add a and b */ GMP_BINARY_OP_FUNCTION(add); /* Subtract b from a */ @@ -1189,6 +1217,39 @@ ZEND_FUNCTION(gmp_powm) } /* }}} */ +#ifdef HAVE___GMPZ_POWM_SEC +/* {{{ Raise base to power exp and take result modulo mod using a side-channel quiet algorithm */ +ZEND_FUNCTION(gmp_powm_sec) +{ + mpz_ptr gmpnum_base, gmpnum_exp, gmpnum_mod, gmpnum_result; + + ZEND_PARSE_PARAMETERS_START(3, 3) + GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_base) + GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_exp) + GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_mod) + ZEND_PARSE_PARAMETERS_END(); + + if (mpz_sgn(gmpnum_exp) <= 0) { + zend_argument_value_error(2, "must be greater than 0"); + RETURN_THROWS(); + } + + if (UNEXPECTED(!mpz_odd_p(gmpnum_mod))) { + /* Zero is an even modulus, but report it like gmp_powm() does. */ + if (!mpz_cmp_ui(gmpnum_mod, 0)) { + zend_argument_error(zend_ce_division_by_zero_error, 3, "Modulo by zero"); + } else { + zend_argument_value_error(3, "must be odd"); + } + RETURN_THROWS(); + } + + INIT_GMP_RETVAL(gmpnum_result); + mpz_powm_sec(gmpnum_result, gmpnum_base, gmpnum_exp, gmpnum_mod); +} +/* }}} */ +#endif + /* {{{ Takes integer part of square root of a */ ZEND_FUNCTION(gmp_sqrt) { diff --git a/ext/gmp/gmp.stub.php b/ext/gmp/gmp.stub.php index 75812c62c5ca..f2ea15481748 100644 --- a/ext/gmp/gmp.stub.php +++ b/ext/gmp/gmp.stub.php @@ -125,6 +125,10 @@ function gmp_pow(GMP|int|string $num, int $exponent): GMP {} function gmp_powm(GMP|int|string $num, GMP|int|string $exponent, GMP|int|string $modulus): GMP {} +#ifdef HAVE___GMPZ_POWM_SEC +function gmp_powm_sec(GMP|int|string $num, GMP|int|string $exponent, GMP|int|string $modulus): GMP {} +#endif + function gmp_perfect_square(GMP|int|string $num): bool {} function gmp_perfect_power(GMP|int|string $num): bool {} @@ -183,4 +187,8 @@ function gmp_hamdist(GMP|int|string $num1, GMP|int|string $num2): int {} function gmp_nextprime(GMP|int|string $num): GMP {} +#ifdef HAVE___GMPZ_PREVPRIME +function gmp_prevprime(GMP|int|string $num): GMP {} +#endif + function gmp_binomial(GMP|int|string $n, int $k): GMP {} diff --git a/ext/gmp/gmp_arginfo.h b/ext/gmp/gmp_arginfo.h index 436e3a22ea72..60eec94bb5cf 100644 --- a/ext/gmp/gmp_arginfo.h +++ b/ext/gmp/gmp_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit gmp.stub.php instead. - * Stub hash: 3aabd5a5d2db0df15b249a425465ae718c13ab6b */ + * Stub hash: 57d016aed930bb41ff4357917e3ae8abd612e973 */ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_gmp_init, 0, 1, GMP, 0) ZEND_ARG_TYPE_MASK(0, num, MAY_BE_LONG|MAY_BE_STRING, NULL) @@ -91,6 +91,14 @@ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_gmp_powm, 0, 3, GMP, 0) ZEND_ARG_OBJ_TYPE_MASK(0, modulus, GMP, MAY_BE_LONG|MAY_BE_STRING, NULL) ZEND_END_ARG_INFO() +#if defined(HAVE___GMPZ_POWM_SEC) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_gmp_powm_sec, 0, 3, GMP, 0) + ZEND_ARG_OBJ_TYPE_MASK(0, num, GMP, MAY_BE_LONG|MAY_BE_STRING, NULL) + ZEND_ARG_OBJ_TYPE_MASK(0, exponent, GMP, MAY_BE_LONG|MAY_BE_STRING, NULL) + ZEND_ARG_OBJ_TYPE_MASK(0, modulus, GMP, MAY_BE_LONG|MAY_BE_STRING, NULL) +ZEND_END_ARG_INFO() +#endif + ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_gmp_perfect_square, 0, 1, _IS_BOOL, 0) ZEND_ARG_OBJ_TYPE_MASK(0, num, GMP, MAY_BE_LONG|MAY_BE_STRING, NULL) ZEND_END_ARG_INFO() @@ -179,6 +187,12 @@ ZEND_END_ARG_INFO() #define arginfo_gmp_nextprime arginfo_gmp_neg +#if defined(HAVE___GMPZ_PREVPRIME) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_gmp_prevprime, 0, 1, GMP, 0) + ZEND_ARG_OBJ_TYPE_MASK(0, num, GMP, MAY_BE_LONG|MAY_BE_STRING, NULL) +ZEND_END_ARG_INFO() +#endif + ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_gmp_binomial, 0, 2, GMP, 0) ZEND_ARG_OBJ_TYPE_MASK(0, n, GMP, MAY_BE_LONG|MAY_BE_STRING, NULL) ZEND_ARG_TYPE_INFO(0, k, IS_LONG, 0) @@ -218,6 +232,9 @@ ZEND_FUNCTION(gmp_root); ZEND_FUNCTION(gmp_rootrem); ZEND_FUNCTION(gmp_pow); ZEND_FUNCTION(gmp_powm); +#if defined(HAVE___GMPZ_POWM_SEC) +ZEND_FUNCTION(gmp_powm_sec); +#endif ZEND_FUNCTION(gmp_perfect_square); ZEND_FUNCTION(gmp_perfect_power); ZEND_FUNCTION(gmp_prob_prime); @@ -245,6 +262,9 @@ ZEND_FUNCTION(gmp_scan1); ZEND_FUNCTION(gmp_popcount); ZEND_FUNCTION(gmp_hamdist); ZEND_FUNCTION(gmp_nextprime); +#if defined(HAVE___GMPZ_PREVPRIME) +ZEND_FUNCTION(gmp_prevprime); +#endif ZEND_FUNCTION(gmp_binomial); ZEND_METHOD(GMP, __construct); ZEND_METHOD(GMP, __serialize); @@ -274,6 +294,9 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(gmp_rootrem, arginfo_gmp_rootrem) ZEND_FE(gmp_pow, arginfo_gmp_pow) ZEND_FE(gmp_powm, arginfo_gmp_powm) +#if defined(HAVE___GMPZ_POWM_SEC) + ZEND_FE(gmp_powm_sec, arginfo_gmp_powm_sec) +#endif ZEND_FE(gmp_perfect_square, arginfo_gmp_perfect_square) ZEND_FE(gmp_perfect_power, arginfo_gmp_perfect_power) ZEND_FE(gmp_prob_prime, arginfo_gmp_prob_prime) @@ -301,6 +324,9 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(gmp_popcount, arginfo_gmp_popcount) ZEND_FE(gmp_hamdist, arginfo_gmp_hamdist) ZEND_FE(gmp_nextprime, arginfo_gmp_nextprime) +#if defined(HAVE___GMPZ_PREVPRIME) + ZEND_FE(gmp_prevprime, arginfo_gmp_prevprime) +#endif ZEND_FE(gmp_binomial, arginfo_gmp_binomial) ZEND_FE_END }; diff --git a/ext/gmp/tests/bug80560.phpt b/ext/gmp/tests/bug80560.phpt index 25af4a42d9b9..85f4dff96be4 100644 --- a/ext/gmp/tests/bug80560.phpt +++ b/ext/gmp/tests/bug80560.phpt @@ -24,6 +24,9 @@ $functions1 = [ 'gmp_com', 'gmp_nextprime', ]; +if (function_exists('gmp_prevprime')) { + $functions1[] = 'gmp_prevprime'; +} $functions1_need_int_2 = [ 'gmp_testbit', 'gmp_scan0', @@ -60,6 +63,9 @@ $functions2 = [ $functions3 = [ 'gmp_powm', ]; +if (function_exists('gmp_powm_sec')) { + $functions3[] = 'gmp_powm_sec'; +} echo 'Explicit base with gmp_init:', \PHP_EOL; echo 'Hexadecimal', \PHP_EOL; diff --git a/ext/gmp/tests/gmp_powm_sec.phpt b/ext/gmp/tests/gmp_powm_sec.phpt new file mode 100644 index 000000000000..2c66ff25a5e5 --- /dev/null +++ b/ext/gmp/tests/gmp_powm_sec.phpt @@ -0,0 +1,46 @@ +--TEST-- +gmp_powm_sec() +--EXTENSIONS-- +gmp +--SKIPIF-- + +--FILE-- +getMessage(), \PHP_EOL; + } +} + +try { + var_dump(gmp_powm_sec(4, 13, 0)); +} catch (\DivisionByZeroError $e) { + echo $e::class, ": ", $e->getMessage(), \PHP_EOL; +} + +try { + var_dump(gmp_powm_sec(4, 13, 496)); +} catch (\ValueError $e) { + echo $e::class, ": ", $e->getMessage(), \PHP_EOL; +} + +echo "Done\n"; +?> +--EXPECT-- +string(3) "445" +string(1) "5" +ValueError: gmp_powm_sec(): Argument #2 ($exponent) must be greater than 0 +ValueError: gmp_powm_sec(): Argument #2 ($exponent) must be greater than 0 +DivisionByZeroError: gmp_powm_sec(): Argument #3 ($modulus) Modulo by zero +ValueError: gmp_powm_sec(): Argument #3 ($modulus) must be odd +Done diff --git a/ext/gmp/tests/gmp_prevprime.phpt b/ext/gmp/tests/gmp_prevprime.phpt new file mode 100644 index 000000000000..42c08566c413 --- /dev/null +++ b/ext/gmp/tests/gmp_prevprime.phpt @@ -0,0 +1,34 @@ +--TEST-- +gmp_prevprime() +--EXTENSIONS-- +gmp +--SKIPIF-- + +--FILE-- +getMessage() . \PHP_EOL; + } +} + +var_dump(gmp_strval(gmp_prevprime(3))); +var_dump(gmp_strval(gmp_prevprime(4))); +var_dump(gmp_strval(gmp_prevprime(10000))); + +?> +--EXPECT-- +gmp_prevprime(): Argument #1 ($num) must be greater than 2 +gmp_prevprime(): Argument #1 ($num) must be greater than 2 +gmp_prevprime(): Argument #1 ($num) must be greater than 2 +gmp_prevprime(): Argument #1 ($num) must be greater than 2 +string(1) "2" +string(1) "3" +string(4) "9973" diff --git a/ext/pgsql/pgsql.c b/ext/pgsql/pgsql.c index 29ef4855a122..3a1b4a04cafb 100644 --- a/ext/pgsql/pgsql.c +++ b/ext/pgsql/pgsql.c @@ -4839,7 +4839,7 @@ static int php_pgsql_convert_match(const zend_string *str, zend_string *regex) */ static zend_string *php_pgsql_add_quotes(zend_string *src) { - return zend_string_concat3("E'", strlen("E'"), ZSTR_VAL(src), ZSTR_LEN(src), "'", strlen("'")); + return zend_string_concat3("'", strlen("'"), ZSTR_VAL(src), ZSTR_LEN(src), "'", strlen("'")); } /* }}} */ @@ -5110,7 +5110,6 @@ PHP_PGSQL_API zend_result php_pgsql_convert(PGconn *pg_link, const zend_string * zend_string *str; /* PostgreSQL ignores \0 */ str = zend_string_alloc(Z_STRLEN_P(val) * 2, 0); - /* better to use PGSQLescapeLiteral since PGescapeStringConn does not handle special \ */ ZSTR_LEN(str) = PQescapeStringConn(pg_link, ZSTR_VAL(str), Z_STRVAL_P(val), Z_STRLEN_P(val), &escape_err); if (escape_err) { diff --git a/ext/pgsql/tests/10pg_convert_9.phpt b/ext/pgsql/tests/10pg_convert_9.phpt index d733b888fe03..2ef325dbc970 100644 --- a/ext/pgsql/tests/10pg_convert_9.phpt +++ b/ext/pgsql/tests/10pg_convert_9.phpt @@ -24,6 +24,8 @@ $converted = pg_convert($db, $table_name, $fields); var_dump($converted); +var_dump(pg_convert($db, $table_name, ['str' => "\\' OR 1=1"])); + /* Invalid values */ try { $converted = pg_convert($db, $table_name, [5 => 'AAA']); @@ -51,6 +53,10 @@ try { } catch (\TypeError $e) { echo $e->getMessage(), \PHP_EOL; } + +/* standard_conforming_strings = 1 */ +pg_query($db, "SET standard_conforming_strings = 1"); +var_dump(pg_convert($db, $table_name, ['str' => "\\' OR 1=1"])); ?> --CLEAN-- string(4) "1234" [""str""]=> - string(6) "E'AAA'" + string(5) "'AAA'" [""bin""]=> - string(12) "E'\\x424242'" + string(11) "'\\x424242'" +} +array(1) { + [""str""]=> + string(13) "'\\'' OR 1=1'" } Array of values must be an associative array with string keys Array of values must be an associative array with string keys Values must be of type string|int|float|bool|null, array given Values must be of type string|int|float|bool|null, stdClass given Values must be of type string|int|float|bool|null, PgSql\Connection given +array(1) { + [""str""]=> + string(12) "'\'' OR 1=1'" +} diff --git a/ext/pgsql/tests/10pg_convert_json_array.phpt b/ext/pgsql/tests/10pg_convert_json_array.phpt index d1acc686d890..b8f3514b5ed3 100644 --- a/ext/pgsql/tests/10pg_convert_json_array.phpt +++ b/ext/pgsql/tests/10pg_convert_json_array.phpt @@ -42,8 +42,8 @@ pg_query($db, "DROP TABLE IF EXISTS {$table_name_92}"); --EXPECT-- array(2) { [""textary""]=> - string(51) "E'{"meeting", "lunch", "training", "presentation"}'" + string(50) "'{"meeting", "lunch", "training", "presentation"}'" [""jsn""]=> - string(22) "E'{"f1":1,"f2":"foo"}'" + string(21) "'{"f1":1,"f2":"foo"}'" } OK diff --git a/ext/pgsql/tests/12pg_insert_9.phpt b/ext/pgsql/tests/12pg_insert_9.phpt index b986d14e15dc..7782c93ef7aa 100644 --- a/ext/pgsql/tests/12pg_insert_9.phpt +++ b/ext/pgsql/tests/12pg_insert_9.phpt @@ -65,7 +65,7 @@ $db = pg_connect($conn_str); pg_query($db, "DROP TABLE IF EXISTS {$table_name}"); ?> --EXPECTF-- -INSERT INTO "table_12pg_insert_9" ("num","str","bin") VALUES (1234,E'AAA',E'\\x424242'); +INSERT INTO "table_12pg_insert_9" ("num","str","bin") VALUES (1234,'AAA','\\x424242'); INSERT INTO "table_12pg_insert_9" ("num","str","bin") VALUES ('1234','AAA','BBB'); object(PgSql\Result)#%d (0) { } diff --git a/ext/pgsql/tests/14pg_update_9.phpt b/ext/pgsql/tests/14pg_update_9.phpt index 602019c2fb62..6bcea5121501 100644 --- a/ext/pgsql/tests/14pg_update_9.phpt +++ b/ext/pgsql/tests/14pg_update_9.phpt @@ -39,6 +39,6 @@ $db = pg_connect($conn_str); pg_query($db, "DROP TABLE IF EXISTS {$table_name}"); ?> --EXPECT-- -UPDATE "table_14pg_update_9" SET "num"=1234,"str"=E'ABC',"bin"=E'\\x58595a' WHERE "num"=1234; +UPDATE "table_14pg_update_9" SET "num"=1234,"str"='ABC',"bin"='\\x58595a' WHERE "num"=1234; UPDATE "table_14pg_update_9" SET "num"='1234',"str"='ABC',"bin"='XYZ' WHERE "num"='1234'; Ok diff --git a/ext/pgsql/tests/GHSA-7qpv-r5mr-78m4.phpt b/ext/pgsql/tests/GHSA-7qpv-r5mr-78m4.phpt new file mode 100644 index 000000000000..93f6376bb1cf --- /dev/null +++ b/ext/pgsql/tests/GHSA-7qpv-r5mr-78m4.phpt @@ -0,0 +1,58 @@ +--TEST-- +GHSA-7qpv-r5mr-78m4: SQL injection via E'...' backslash breakout +--CREDITS-- +expatch.llc +--EXTENSIONS-- +pgsql +--SKIPIF-- + +--FILE-- + "zzz' OR 1=1 --"]; +echo pg_select($db, 'ghsa_7qpv_r5mr_78m4', $params, PGSQL_DML_STRING) . "\n"; +printf("returned: %d\n\n", count(pg_select($db, 'ghsa_7qpv_r5mr_78m4', $params))); + +$params = ['name' => "zzz\\' OR 1=1 --"]; +echo pg_select($db, 'ghsa_7qpv_r5mr_78m4', $params, PGSQL_DML_STRING) . "\n"; +printf("returned: %d\n\n", count(pg_select($db, 'ghsa_7qpv_r5mr_78m4', $params))); + +$params = ['name' => "john\\', true) --", 'admin' => 'false']; +echo pg_insert($db, 'ghsa_7qpv_r5mr_78m4', $params, PGSQL_DML_STRING) . "\n"; +pg_insert($db, 'ghsa_7qpv_r5mr_78m4', $params); +var_dump(pg_select($db, 'ghsa_7qpv_r5mr_78m4', ['id' => 3])[0]['admin']); +echo "\n"; + +$params = ['name' => "jake\\', true) --", 'admin' => 'f']; +echo pg_insert($db, 'ghsa_7qpv_r5mr_78m4', $params, PGSQL_DML_ESCAPE|PGSQL_DML_STRING) . "\n"; +pg_insert($db, 'ghsa_7qpv_r5mr_78m4', $params, PGSQL_DML_EXEC|PGSQL_DML_ESCAPE); +var_dump(pg_select($db, 'ghsa_7qpv_r5mr_78m4', ['id' => 4])[0]['admin']); + +?> +--EXPECT-- +SELECT * FROM "ghsa_7qpv_r5mr_78m4" WHERE "name"='zzz'' OR 1=1 --'; +returned: 0 + +SELECT * FROM "ghsa_7qpv_r5mr_78m4" WHERE "name"='zzz\'' OR 1=1 --'; +returned: 0 + +INSERT INTO "ghsa_7qpv_r5mr_78m4" ("name","admin") VALUES ('john\'', true) --','f'); +string(1) "f" + +INSERT INTO "ghsa_7qpv_r5mr_78m4" ("name","admin") VALUES ('jake\'', true) --','f'); +string(1) "f" +--CLEAN-- + diff --git a/ext/pgsql/tests/bug64609.phpt b/ext/pgsql/tests/bug64609.phpt index 67e10a3986cb..f6fbac26f616 100644 --- a/ext/pgsql/tests/bug64609.phpt +++ b/ext/pgsql/tests/bug64609.phpt @@ -30,5 +30,5 @@ var_dump($converted); --EXPECT-- array(1) { [""a""]=> - string(5) "E'ok'" + string(4) "'ok'" } diff --git a/ext/pgsql/tests/bug68638.phpt b/ext/pgsql/tests/bug68638.phpt index 957e9a33abf5..267423a22264 100644 --- a/ext/pgsql/tests/bug68638.phpt +++ b/ext/pgsql/tests/bug68638.phpt @@ -41,7 +41,7 @@ $table='test_68638'; pg_query($conn, "DROP TABLE IF EXISTS $table"); ?> --EXPECT-- -string(52) "UPDATE "test_68638" SET "value"=E'inf' WHERE "id"=1;" +string(51) "UPDATE "test_68638" SET "value"='inf' WHERE "id"=1;" array(2) { ["id"]=> string(1) "1" diff --git a/ext/phar/tests/tar/files/circular_symlinks.tar b/ext/phar/tests/tar/files/circular_symlinks.tar new file mode 100644 index 000000000000..2af7bb8c2384 Binary files /dev/null and b/ext/phar/tests/tar/files/circular_symlinks.tar differ diff --git a/ext/phar/tests/tar/files/circular_symlinks_long.tar b/ext/phar/tests/tar/files/circular_symlinks_long.tar new file mode 100644 index 000000000000..b2b4c1cb095c Binary files /dev/null and b/ext/phar/tests/tar/files/circular_symlinks_long.tar differ diff --git a/ext/phar/tests/tar/files/circular_symlinks_rho.tar b/ext/phar/tests/tar/files/circular_symlinks_rho.tar new file mode 100644 index 000000000000..2ccbf17c8c63 Binary files /dev/null and b/ext/phar/tests/tar/files/circular_symlinks_rho.tar differ diff --git a/ext/phar/tests/tar/ghsa-vc5h-9ppw-p5f3-symlink-circular.phpt b/ext/phar/tests/tar/ghsa-vc5h-9ppw-p5f3-symlink-circular.phpt new file mode 100644 index 000000000000..cf0048c0fcd9 --- /dev/null +++ b/ext/phar/tests/tar/ghsa-vc5h-9ppw-p5f3-symlink-circular.phpt @@ -0,0 +1,27 @@ +--TEST-- +GHSA-vc5h-9ppw-p5f3 (circular symlinks in tar should not cause stack overflow) +--CREDITS-- +Calvin Young - eWalker Consulting (HK) Limited +Enoch Chow - Isomorph Cyber +--EXTENSIONS-- +phar +--FILE-- +getContent() === ''); + +// rho-shaped cycle (tail leading into a loop) +$phar = new PharData($base . '/files/circular_symlinks_rho.tar'); +var_dump($phar['file_a']->getContent() === ''); + +// long cycle (400 entries) +$phar = new PharData($base . '/files/circular_symlinks_long.tar'); +var_dump($phar['link_0']->getContent() === ''); +?> +--EXPECT-- +bool(true) +bool(true) +bool(true) diff --git a/ext/phar/util.c b/ext/phar/util.c index c78ee50ece15..b93bf6940dea 100644 --- a/ext/phar/util.c +++ b/ext/phar/util.c @@ -63,35 +63,55 @@ static zend_string *phar_get_link_location(phar_entry_info *entry) /* {{{ */ } /* }}} */ -phar_entry_info *phar_get_link_source(phar_entry_info *entry) /* {{{ */ +static phar_entry_info *phar_follow_one_link(phar_entry_info *entry) { phar_entry_info *link_entry; - uint32_t depth = 0, max_depth; + zend_string *link; + + link = phar_get_link_location(entry); + if (NULL != (link_entry = zend_hash_find_ptr(&(entry->phar->manifest), entry->symlink)) || + NULL != (link_entry = zend_hash_find_ptr(&(entry->phar->manifest), link))) { + zend_string_release(link); + return link_entry; + } + + zend_string_release(link); + return NULL; +} + +phar_entry_info *phar_get_link_source(phar_entry_info *entry) +{ + phar_entry_info *slow, *fast; if (!entry->symlink) { return entry; } - max_depth = zend_hash_num_elements(&(entry->phar->manifest)); - - while (entry->symlink) { - if (UNEXPECTED(++depth > max_depth)) { - return NULL; + /* + * Use Floyd's cycle detection algorithm to follow the symlink chain without unbounded + * recursion. Each entry has at most one outgoing link, so if a cycle exists the fast pointer + * will eventually meet the slow one. Otherwise the fast pointer reaches the end first. + */ + slow = fast = entry; + while (1) { + fast = phar_follow_one_link(fast); + if (!fast || !fast->symlink) { + return fast; + } + fast = phar_follow_one_link(fast); + if (!fast || !fast->symlink) { + return fast; } - zend_string *link = phar_get_link_location(entry); - if (NULL != (link_entry = zend_hash_find_ptr(&(entry->phar->manifest), entry->symlink)) || - NULL != (link_entry = zend_hash_find_ptr(&(entry->phar->manifest), link))) { - zend_string_release(link); - entry = link_entry; - } else { - zend_string_release(link); + /* no need to check slow as it's always behind */ + slow = phar_follow_one_link(slow); + + if (slow == fast) { + /* circular symlink chain */ return NULL; } } - return entry; } -/* }}} */ static php_stream *phar_get_entrypufp(const phar_entry_info *entry) { diff --git a/main/streams/php_stream_errors.h b/main/streams/php_stream_errors.h index 878350f972ac..da7a4cc84e9d 100644 --- a/main/streams/php_stream_errors.h +++ b/main/streams/php_stream_errors.h @@ -93,8 +93,8 @@ typedef struct { /* Error operation management */ PHPAPI php_stream_error_operation *php_stream_error_operation_begin(void); -PHPAPI void php_stream_error_operation_end(php_stream_context *context); -PHPAPI void php_stream_error_operation_end_for_stream(php_stream *stream); +PHPAPI void php_stream_error_operation_end(const php_stream_context *context); +PHPAPI void php_stream_error_operation_end_for_stream(const php_stream *stream); PHPAPI void php_stream_error_operation_abort(void); /* State cleanup function */ @@ -108,35 +108,36 @@ PHPAPI void php_stream_error_clear_stored(void); /* Wrapper error reporting functions */ PHPAPI void php_stream_wrapper_error_with_name(const char *wrapper_name, - php_stream_context *context, const char *docref, int options, int severity, + const php_stream_context *context, const char *docref, int options, int severity, bool terminating, zend_enum_StreamErrorCode code, const char *fmt, ...) ZEND_ATTRIBUTE_FORMAT(printf, 8, 9); -PHPAPI void php_stream_wrapper_error(php_stream_wrapper *wrapper, php_stream_context *context, +PHPAPI void php_stream_wrapper_error( + const php_stream_wrapper *wrapper, const php_stream_context *context, const char *docref, int options, int severity, bool terminating, zend_enum_StreamErrorCode code, const char *fmt, ...) ZEND_ATTRIBUTE_FORMAT(printf, 8, 9); -PHPAPI void php_stream_error(php_stream *stream, const char *docref, int severity, +PHPAPI void php_stream_error(const php_stream *stream, const char *docref, int severity, bool terminating, zend_enum_StreamErrorCode code, const char *fmt, ...) ZEND_ATTRIBUTE_FORMAT(printf, 6, 7); /* Legacy wrapper error log functions */ PHPAPI void php_stream_wrapper_log_error(const php_stream_wrapper *wrapper, - php_stream_context *context, int options, int severity, bool terminating, + const php_stream_context *context, int options, int severity, bool terminating, zend_enum_StreamErrorCode code, const char *fmt, ...) ZEND_ATTRIBUTE_FORMAT(printf, 7, 8); PHPAPI void php_stream_display_wrapper_name_errors(const char *wrapper_name, - php_stream_context *context, zend_enum_StreamErrorCode code, + const php_stream_context *context, zend_enum_StreamErrorCode code, const char *caption); -PHPAPI void php_stream_display_wrapper_errors(php_stream_wrapper *wrapper, - php_stream_context *context, zend_enum_StreamErrorCode code, +PHPAPI void php_stream_display_wrapper_errors(const php_stream_wrapper *wrapper, + const php_stream_context *context, zend_enum_StreamErrorCode code, const char *caption); PHPAPI void php_stream_tidy_wrapper_name_error_log(const char *wrapper_name); -PHPAPI void php_stream_tidy_wrapper_error_log(php_stream_wrapper *wrapper); +PHPAPI void php_stream_tidy_wrapper_error_log(const php_stream_wrapper *wrapper); /* Convenience macros - code argument is the bare case name (e.g. RenameFailed) */ #define php_stream_wrapper_warn(wrapper, context, options, code, ...) \ diff --git a/main/streams/stream_errors.c b/main/streams/stream_errors.c index 40056f0856e7..4e59e275cf9a 100644 --- a/main/streams/stream_errors.c +++ b/main/streams/stream_errors.c @@ -33,7 +33,7 @@ static zend_class_entry *php_ce_stream_exception; static void php_stream_error_entry_free(php_stream_error_entry *entry); /* Helper to create a single StreamError object from an entry */ -static void php_stream_error_create_object(zval *zv, php_stream_error_entry *entry) +static void php_stream_error_create_object(zval *zv, const php_stream_error_entry *entry) { object_init_ex(zv, php_ce_stream_error); @@ -69,11 +69,11 @@ static void php_stream_error_create_object(zval *zv, php_stream_error_entry *ent } /* Create array of StreamError objects from error chain */ -static void php_stream_error_create_array(zval *zv, php_stream_error_entry *first) +static void php_stream_error_create_array(zval *zv, const php_stream_error_entry *first) { array_init(zv); - php_stream_error_entry *entry = first; + const php_stream_error_entry *entry = first; while (entry) { zval error_obj; php_stream_error_create_object(&error_obj, entry); @@ -113,7 +113,7 @@ static php_stream_error_store php_stream_auto_decide_error_store_mode(php_stream } } -static php_stream_error_mode php_stream_get_error_mode(php_stream_context *context) +static php_stream_error_mode php_stream_get_error_mode(const php_stream_context *context) { if (!context) { return PHP_STREAM_ERROR_MODE_ERROR; @@ -143,7 +143,7 @@ static php_stream_error_mode php_stream_get_error_mode(php_stream_context *conte } static php_stream_error_store php_stream_get_error_store_mode( - php_stream_context *context, php_stream_error_mode error_mode) + const php_stream_context *context, php_stream_error_mode error_mode) { if (!context) { return php_stream_auto_decide_error_store_mode(error_mode); @@ -178,9 +178,9 @@ static php_stream_error_store php_stream_get_error_store_mode( /* Helper functions */ -static bool php_stream_has_terminating_error(php_stream_error_operation *op) +static bool php_stream_has_terminating_error(const php_stream_error_operation *op) { - php_stream_error_entry *entry = op->first_error; + const php_stream_error_entry *entry = op->first_error; while (entry) { if (entry->terminating) { return true; @@ -205,7 +205,7 @@ static inline php_stream_error_operation *php_stream_get_operation_at_depth(uint static inline php_stream_error_operation *php_stream_get_parent_operation(void) { - php_stream_error_state *state = &FG(stream_error_state); + const php_stream_error_state *state = &FG(stream_error_state); if (state->operation_depth <= 1) { return NULL; @@ -265,7 +265,7 @@ PHPAPI void php_stream_error_state_cleanup(void) PHPAPI void php_stream_error_get_last(zval *return_value) { - php_stream_error_state *state = &FG(stream_error_state); + const php_stream_error_state *state = &FG(stream_error_state); if (!state->stored_errors) { ZVAL_EMPTY_ARRAY(return_value); @@ -359,7 +359,7 @@ static void php_stream_error_add(zend_enum_StreamErrorCode code, const char *wra /* Error reporting */ -static void php_stream_call_error_handler(zval *handler, zval *errors_array) +static void php_stream_call_error_handler(const zval *handler, zval *errors_array) { zend_fcall_info_cache fcc; char *is_callable_error = NULL; @@ -375,7 +375,7 @@ static void php_stream_call_error_handler(zval *handler, zval *errors_array) zend_call_known_fcc(&fcc, NULL, 1, errors_array, NULL); } -static void php_stream_throw_exception_with_errors(php_stream_error_operation *op) +static void php_stream_throw_exception_with_errors(const php_stream_error_operation *op) { if (!op->first_error) { return; @@ -401,7 +401,7 @@ static void php_stream_throw_exception_with_errors(php_stream_error_operation *o zend_throw_exception_object(&ex); } -static void php_stream_report_errors(php_stream_context *context, php_stream_error_operation *op, +static void php_stream_report_errors(const php_stream_context *context, const php_stream_error_operation *op, php_stream_error_mode error_mode, bool is_terminating) { switch (error_mode) { @@ -426,7 +426,7 @@ static void php_stream_report_errors(php_stream_context *context, php_stream_err } /* Call user error handler if set */ - zval *handler + const zval *handler = context ? php_stream_context_get_option(context, "stream", "error_handler") : NULL; if (handler) { @@ -441,7 +441,7 @@ static void php_stream_report_errors(php_stream_context *context, php_stream_err /* Error storage */ -PHPAPI void php_stream_error_operation_end(php_stream_context *context) +PHPAPI void php_stream_error_operation_end(const php_stream_context *context) { php_stream_error_state *state = &FG(stream_error_state); php_stream_error_operation *op = state->current_operation; @@ -533,7 +533,7 @@ PHPAPI void php_stream_error_operation_end(php_stream_context *context) op->error_count = 0; } -PHPAPI void php_stream_error_operation_end_for_stream(php_stream *stream) +PHPAPI void php_stream_error_operation_end_for_stream(const php_stream *stream) { php_stream_error_state *state = &FG(stream_error_state); php_stream_error_operation *op = state->current_operation; @@ -551,7 +551,7 @@ PHPAPI void php_stream_error_operation_end_for_stream(php_stream *stream) return; } - php_stream_context *context = PHP_STREAM_CONTEXT(stream); + const php_stream_context *context = PHP_STREAM_CONTEXT(stream); php_stream_error_operation_end(context); } @@ -575,7 +575,7 @@ PHPAPI void php_stream_error_operation_abort(void) /* Wrapper error reporting */ -static void php_stream_wrapper_error_internal(const char *wrapper_name, php_stream_context *context, +static void php_stream_wrapper_error_internal(const char *wrapper_name, const php_stream_context *context, const char *docref, int severity, bool terminating, zend_enum_StreamErrorCode code, zend_string *message) { @@ -592,7 +592,7 @@ static void php_stream_wrapper_error_internal(const char *wrapper_name, php_stre } PHPAPI void php_stream_wrapper_error_with_name(const char *wrapper_name, - php_stream_context *context, const char *docref, int options, int severity, + const php_stream_context *context, const char *docref, int options, int severity, bool terminating, zend_enum_StreamErrorCode code, const char *fmt, ...) { if (!(options & REPORT_ERRORS)) { @@ -608,7 +608,9 @@ PHPAPI void php_stream_wrapper_error_with_name(const char *wrapper_name, wrapper_name, context, docref, severity, terminating, code, message); } -PHPAPI void php_stream_wrapper_error(php_stream_wrapper *wrapper, php_stream_context *context, +PHPAPI void php_stream_wrapper_error( + const php_stream_wrapper *wrapper, + const php_stream_context *context, const char *docref, int options, int severity, bool terminating, zend_enum_StreamErrorCode code, const char *fmt, ...) { @@ -629,7 +631,7 @@ PHPAPI void php_stream_wrapper_error(php_stream_wrapper *wrapper, php_stream_con /* Stream error reporting */ -PHPAPI void php_stream_error(php_stream *stream, const char *docref, int severity, +PHPAPI void php_stream_error(const php_stream *stream, const char *docref, int severity, bool terminating, zend_enum_StreamErrorCode code, const char *fmt, ...) { va_list args; @@ -640,7 +642,7 @@ PHPAPI void php_stream_error(php_stream *stream, const char *docref, int severit const char *wrapper_name = stream->wrapper ? stream->wrapper->wops->label : "stream"; - php_stream_context *context = PHP_STREAM_CONTEXT(stream); + const php_stream_context *context = PHP_STREAM_CONTEXT(stream); php_stream_wrapper_error_internal(wrapper_name, context, docref, severity, terminating, code, message); @@ -694,7 +696,7 @@ static void php_stream_wrapper_log_store_error(zend_string *message, zend_enum_S } PHPAPI void php_stream_wrapper_log_error(const php_stream_wrapper *wrapper, - php_stream_context *context, int options, int severity, bool terminating, + const php_stream_context *context, int options, int severity, bool terminating, zend_enum_StreamErrorCode code, const char *fmt, ...) { va_list args; @@ -722,12 +724,12 @@ static zend_llist *php_stream_get_wrapper_errors_list(const char *wrapper_name) } PHPAPI void php_stream_display_wrapper_name_errors(const char *wrapper_name, - php_stream_context *context, zend_enum_StreamErrorCode code, + const php_stream_context *context, zend_enum_StreamErrorCode code, const char *caption) { char *msg; char errstr[256]; - int free_msg = 0; + bool free_msg = false; if (EG(exception)) { return; @@ -737,9 +739,7 @@ PHPAPI void php_stream_display_wrapper_name_errors(const char *wrapper_name, zend_llist *err_list = php_stream_get_wrapper_errors_list(wrapper_name); if (err_list) { size_t l = 0; - int brlen; - int i; - int count = (int) zend_llist_count(err_list); + size_t brlen; const char *br; php_stream_error_entry **err_entry_p; zend_llist_position pos; @@ -752,7 +752,9 @@ PHPAPI void php_stream_display_wrapper_name_errors(const char *wrapper_name, br = "\n"; } - for (err_entry_p = zend_llist_get_first_ex(err_list, &pos), i = 0; err_entry_p; + size_t i = 0; + const size_t count = zend_llist_count(err_list); + for (i = 0, err_entry_p = zend_llist_get_first_ex(err_list, &pos); err_entry_p; err_entry_p = zend_llist_get_next_ex(err_list, &pos), i++) { l += ZSTR_LEN((*err_entry_p)->message); if (i < count - 1) { @@ -769,7 +771,7 @@ PHPAPI void php_stream_display_wrapper_name_errors(const char *wrapper_name, } } - free_msg = 1; + free_msg = true; } else { if (!strcmp(wrapper_name, php_plain_files_wrapper.wops->label)) { msg = php_socket_strerror_s(errno, errstr, sizeof(errstr)); @@ -791,8 +793,8 @@ PHPAPI void php_stream_display_wrapper_name_errors(const char *wrapper_name, } } -PHPAPI void php_stream_display_wrapper_errors(php_stream_wrapper *wrapper, - php_stream_context *context, zend_enum_StreamErrorCode code, +PHPAPI void php_stream_display_wrapper_errors(const php_stream_wrapper *wrapper, + const php_stream_context *context, zend_enum_StreamErrorCode code, const char *caption) { if (wrapper) { @@ -808,7 +810,7 @@ PHPAPI void php_stream_tidy_wrapper_name_error_log(const char *wrapper_name) } } -PHPAPI void php_stream_tidy_wrapper_error_log(php_stream_wrapper *wrapper) +PHPAPI void php_stream_tidy_wrapper_error_log(const php_stream_wrapper *wrapper) { if (wrapper) { const char *wrapper_name = PHP_STREAM_ERROR_WRAPPER_NAME(wrapper); @@ -822,7 +824,7 @@ PHP_METHOD(StreamException, getErrors) { ZEND_PARSE_PARAMETERS_NONE(); - zval *errors = zend_read_property( + const zval *errors = zend_read_property( php_ce_stream_exception, Z_OBJ_P(ZEND_THIS), ZEND_STRL("errors"), 1, NULL); RETURN_COPY(errors); diff --git a/sapi/cli/cli.h b/sapi/cli/cli.h index 2f6ef95052ce..9502a6726fe4 100644 --- a/sapi/cli/cli.h +++ b/sapi/cli/cli.h @@ -54,4 +54,7 @@ typedef struct php_cli_server_context { php_cli_mode mode; } php_cli_server_context; +/* this performs full cli-SAPI boot, loads modules, sets up TSRM and co. */ +extern PHP_CLI_API int do_php_cli(int argc, char *argv[]); + #endif /* CLI_H */ diff --git a/sapi/cli/cli_win32.c b/sapi/cli/cli_win32.c index 4407fd088f68..de7d0a0282fd 100644 --- a/sapi/cli/cli_win32.c +++ b/sapi/cli/cli_win32.c @@ -1,2 +1,7 @@ #define PHP_CLI_WIN32_NO_CONSOLE 1 #include "php_cli.c" + +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) +{ + return do_php_cli(__argc, __argv); +} diff --git a/sapi/cli/config.m4 b/sapi/cli/config.m4 index 76c2d64e8c8a..6abaa88df419 100644 --- a/sapi/cli/config.m4 +++ b/sapi/cli/config.m4 @@ -5,6 +5,11 @@ PHP_ARG_ENABLE([cli], [yes], [no]) +dnl The embed SAPI requires the CLI sources for do_php_cli(). +if test "$PHP_EMBED" != "no" -a "$PHP_CLI" = "no"; then + AC_MSG_ERROR([--enable-embed requires the CLI SAPI, do not use --disable-cli with --enable-embed]) +fi + if test "$PHP_CLI" != "no"; then AC_CHECK_FUNCS([setproctitle]) @@ -32,9 +37,17 @@ if test "$PHP_CLI" != "no"; then dnl Select SAPI. PHP_SELECT_SAPI([cli], [program], - [php_cli.c php_http_parser.c php_cli_server.c ps_title.c php_cli_process_title.c], + [php_cli_main.c], [-DZEND_ENABLE_STATIC_TSRMLS_CACHE=1]) + dnl Everything except the main() entry point, so that the embed SAPI can link + dnl the same objects into libphp for do_php_cli(). + PHP_ADD_SOURCES_X([sapi/cli], + [php_cli.c php_http_parser.c php_cli_server.c ps_title.c php_cli_process_title.c], + [-DZEND_ENABLE_STATIC_TSRMLS_CACHE=1], + [PHP_CLI_SHARED_OBJS]) + PHP_CLI_OBJS="$PHP_CLI_OBJS $PHP_CLI_SHARED_OBJS" + AS_CASE([$host_alias], [*aix*], [ AS_VAR_IF([php_sapi_module], [shared], [ diff --git a/sapi/cli/config.w32 b/sapi/cli/config.w32 index 5dff4054b69d..695a5b46ec10 100644 --- a/sapi/cli/config.w32 +++ b/sapi/cli/config.w32 @@ -3,8 +3,13 @@ ARG_ENABLE('cli', 'Build CLI version of PHP', 'yes'); ARG_ENABLE('cli-win32', 'Build console-less CLI version of PHP', 'no'); +// The embed SAPI requires the CLI sources for do_php_cli(). +if (PHP_EMBED != "no" && PHP_CLI != "yes") { + ERROR("--enable-embed requires the CLI SAPI, do not use --disable-cli with --enable-embed"); +} + if (PHP_CLI == "yes") { - SAPI('cli', 'php_cli.c php_http_parser.c php_cli_server.c', 'php.exe', '/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1'); + SAPI('cli', 'php_cli.c php_cli_main.c php_http_parser.c php_cli_server.c', 'php.exe', '/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1'); ADD_SOURCES(configure_module_dirname, 'php_cli_process_title.c ps_title.c', 'cli'); ADD_FLAG("LIBS_CLI", "ws2_32.lib"); ADD_FLAG("LIBS_CLI", "shell32.lib"); diff --git a/sapi/cli/php_cli.c b/sapi/cli/php_cli.c index 9095fb10dd41..296b7cd521ff 100644 --- a/sapi/cli/php_cli.c +++ b/sapi/cli/php_cli.c @@ -1173,18 +1173,10 @@ static int do_cli(int argc, char **argv) /* {{{ */ } /* }}} */ -/* {{{ main */ -#ifdef PHP_CLI_WIN32_NO_CONSOLE -int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) -#else -int main(int argc, char *argv[]) -#endif +/* {{{ do_php_cli */ +PHP_CLI_API int do_php_cli(int argc, char *argv[]) { #if defined(PHP_WIN32) -# ifdef PHP_CLI_WIN32_NO_CONSOLE - int argc = __argc; - char **argv = __argv; -# endif int num_args; wchar_t **argv_wide; char **argv_save = argv; @@ -1387,6 +1379,6 @@ int main(int argc, char *argv[]) * exiting. */ cleanup_ps_args(argv); - exit(exit_status); + return exit_status; } /* }}} */ diff --git a/sapi/cli/php_cli_main.c b/sapi/cli/php_cli_main.c new file mode 100644 index 000000000000..1030b5feb923 --- /dev/null +++ b/sapi/cli/php_cli_main.c @@ -0,0 +1,19 @@ +/* + +----------------------------------------------------------------------+ + | Copyright © The PHP Group and Contributors. | + +----------------------------------------------------------------------+ + | This source file is subject to the Modified BSD License that is | + | bundled with this package in the file LICENSE, and is available | + | through the World Wide Web at . | + | | + | SPDX-License-Identifier: BSD-3-Clause | + +----------------------------------------------------------------------+ +*/ + +#include "php.h" +#include "cli.h" + +int main(int argc, char *argv[]) +{ + return do_php_cli(argc, argv); +} diff --git a/sapi/embed/config.m4 b/sapi/embed/config.m4 index 2bb5ed4df4da..e0051ecf66d1 100644 --- a/sapi/embed/config.m4 +++ b/sapi/embed/config.m4 @@ -1,10 +1,3 @@ -PHP_ARG_ENABLE([embed],, - [AS_HELP_STRING([[--enable-embed[=TYPE]]], - [Enable building of embedded SAPI library TYPE is either - 'shared' or 'static'. [TYPE=shared]])], - [no], - [no]) - AC_MSG_CHECKING([for embedded SAPI library support]) if test "$PHP_EMBED" != "no"; then @@ -33,6 +26,9 @@ if test "$PHP_EMBED" != "no"; then [php_embed.c], [-DZEND_ENABLE_STATIC_TSRMLS_CACHE=1]) PHP_INSTALL_HEADERS([sapi/embed], [php_embed.h]) + + dnl Link the CLI objects into libphp for do_php_cli(). + PHP_SAPI_OBJS="$PHP_SAPI_OBJS $PHP_CLI_SHARED_OBJS" ]) else AC_MSG_RESULT([no]) diff --git a/sapi/embed/config.w32 b/sapi/embed/config.w32 index 394982126cad..3ac4668bce8c 100644 --- a/sapi/embed/config.w32 +++ b/sapi/embed/config.w32 @@ -6,5 +6,8 @@ var PHP_EMBED_PGO = false; if (PHP_EMBED != "no") { SAPI('embed', 'php_embed.c', 'php' + PHP_VERSION + 'embed.lib', '/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1'); + ADD_SOURCES("sapi/cli", "php_cli.c php_http_parser.c php_cli_server.c ps_title.c php_cli_process_title.c", "embed", undefined, true); + ADD_FLAG("LIBS_EMBED", "ws2_32.lib"); + ADD_FLAG("LIBS_EMBED", "shell32.lib"); PHP_INSTALL_HEADERS("sapi/embed", "php_embed.h"); } diff --git a/sapi/embed/config0.m4 b/sapi/embed/config0.m4 new file mode 100644 index 000000000000..f1c05b8ea01a --- /dev/null +++ b/sapi/embed/config0.m4 @@ -0,0 +1,6 @@ +PHP_ARG_ENABLE([embed],, + [AS_HELP_STRING([[--enable-embed[=TYPE]]], + [Enable building of embedded SAPI library TYPE is either + 'shared' or 'static'. [TYPE=shared]])], + [no], + [no]) diff --git a/sapi/embed/php_embed.c b/sapi/embed/php_embed.c index 75249f97fc87..96534c18a698 100644 --- a/sapi/embed/php_embed.c +++ b/sapi/embed/php_embed.c @@ -28,10 +28,6 @@ static const char HARDCODED_INI[] = "max_execution_time=0\n" "max_input_time=-1\n\0"; -#if defined(PHP_WIN32) && defined(ZTS) -ZEND_TSRMLS_CACHE_DEFINE() -#endif - static char* php_embed_read_cookies(void) { return NULL;