Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ PHP NEWS
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
?? ??? ????, PHP 8.6.0beta1

- GMP:
. Added optional $definitely_prime output parameter to gmp_prevprime().
(Weilin Du)
. Added gmp_powm_sec(). (Weilin Du)

30 Jul 2026, PHP 8.6.0alpha3

Expand All @@ -23,7 +27,6 @@ PHP NEWS
. 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)
Expand Down
8 changes: 5 additions & 3 deletions UPGRADING
Original file line number Diff line number Diff line change
Expand Up @@ -275,9 +275,11 @@ PHP 8.6 UPGRADE NOTES
. 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.
number. The optional $definitely_prime output parameter indicates whether
the returned number is definitely prime, as opposed to probably prime.
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(),
Expand Down
2 changes: 1 addition & 1 deletion Zend/Optimizer/dfa_pass.c
Original file line number Diff line number Diff line change
Expand Up @@ -471,7 +471,7 @@ static uint32_t zend_dfa_optimize_calls(zend_op_array *op_array, zend_ssa *ssa)
}

if (call_info->caller_call_opline && call_info->caller_call_opline->opcode == ZEND_CALLABLE_CONVERT_PARTIAL) {
/* Build a bitset of constant pre-bound PFA args: These are args whose value is alway the same for all
/* Build a bitset of constant pre-bound PFA args: These are args whose value is always the same for all
* instances of a PFA. */
uint32_t const_args = 0;
for (uint32_t i = 0, l = MIN(sizeof(const_args)*CHAR_BIT, call_info->num_args); i < l; i++) {
Expand Down
12 changes: 6 additions & 6 deletions Zend/tests/partial_application/const_arg_opt.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,12 @@ $f(2);
echo "# Constant pre-bound argument:\n";
$f = f(2, ?);
print_lexical_vars($f);
$f(2);
$f(1);

echo "# Constant pre-bound argument (inverted):\n";
$f = f(?, 2);
$f = f(?, 3);
print_lexical_vars($f);
$f(1);
$f(4);

echo "# Inlined pre-bound argument:\n";
$f = f(g(), ?);
Expand Down Expand Up @@ -100,15 +100,15 @@ array(2) {
[0]=>
int(2)
[1]=>
int(2)
int(1)
}
# Constant pre-bound argument (inverted):
no lexical vars
array(2) {
[0]=>
int(1)
int(4)
[1]=>
int(2)
int(3)
}
# Inlined pre-bound argument:
no lexical vars
Expand Down
23 changes: 18 additions & 5 deletions Zend/zend_API.h
Original file line number Diff line number Diff line change
Expand Up @@ -854,12 +854,19 @@ static zend_always_inline zend_result zend_call_function_with_return_value(
* If retval_ptr is NULL, the return value is discarded.
* If object is NULL, this must be a free function or static call.
* called_scope must be provided for instance and static method calls. */
ZEND_API void zend_call_known_function(
ZEND_API void zend_call_known_function_ex(
zend_function *fn, zend_object *object, zend_class_entry *called_scope, zval *retval_ptr,
uint32_t param_count, zval *params, HashTable *named_params);
uint32_t param_count, zval *params, HashTable *named_params, uint32_t consumed_args);

static zend_always_inline void zend_call_known_fcc(
const zend_fcall_info_cache *fcc, zval *retval_ptr, uint32_t param_count, zval *params, HashTable *named_params)
static zend_always_inline void zend_call_known_function(
zend_function *fn, zend_object *object, zend_class_entry *called_scope, zval *retval_ptr,
uint32_t param_count, zval *params, HashTable *named_params) {
zend_call_known_function_ex(fn, object, called_scope, retval_ptr, param_count, params, named_params, 0);
}

static zend_always_inline void zend_call_known_fcc_ex(
const zend_fcall_info_cache *fcc, zval *retval_ptr,
uint32_t param_count, zval *params, HashTable *named_params, uint32_t consumed_args)
{
zend_function *func = fcc->function_handler;
/* Need to copy trampolines as they get released after they are called */
Expand All @@ -868,7 +875,13 @@ static zend_always_inline void zend_call_known_fcc(
memcpy(func, fcc->function_handler, sizeof(zend_function));
zend_string_addref(func->op_array.function_name);
}
zend_call_known_function(func, fcc->object, fcc->called_scope, retval_ptr, param_count, params, named_params);
zend_call_known_function_ex(func, fcc->object, fcc->called_scope, retval_ptr, param_count, params, named_params, consumed_args);
}

static zend_always_inline void zend_call_known_fcc(
const zend_fcall_info_cache *fcc, zval *retval_ptr, uint32_t param_count, zval *params, HashTable *named_params)
{
zend_call_known_fcc_ex(fcc, retval_ptr, param_count, params, named_params, 0);
}

/* Call the provided zend_function instance method on an object. */
Expand Down
2 changes: 1 addition & 1 deletion Zend/zend_ast.c
Original file line number Diff line number Diff line change
Expand Up @@ -1352,7 +1352,7 @@ static zend_result ZEND_FASTCALL zend_ast_evaluate_inner(
ZEND_CALL_NUM_ARGS(frame), ZEND_CALL_ARG(frame, 1),
extra_named_params, named_positions,
fcc_ast->filename, &ast->lineno,
(void**)cache_slot, fcc_ast->name, flags, 0);
(void**)cache_slot, fcc_ast->name, flags, /* const_args */ 0);

if (named_positions) {
zend_array_release(named_positions);
Expand Down
6 changes: 3 additions & 3 deletions Zend/zend_execute_API.c
Original file line number Diff line number Diff line change
Expand Up @@ -1100,9 +1100,9 @@ zend_result zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_
}
/* }}} */

ZEND_API void zend_call_known_function(
ZEND_API void zend_call_known_function_ex(
zend_function *fn, zend_object *object, zend_class_entry *called_scope, zval *retval_ptr,
uint32_t param_count, zval *params, HashTable *named_params)
uint32_t param_count, zval *params, HashTable *named_params, uint32_t consumed_args)
{
zval retval;
zend_fcall_info fci;
Expand All @@ -1116,7 +1116,7 @@ ZEND_API void zend_call_known_function(
fci.param_count = param_count;
fci.params = params;
fci.named_params = named_params;
fci.consumed_args = 0;
fci.consumed_args = consumed_args;
ZVAL_UNDEF(&fci.function_name); /* Unused */

fcic.function_handler = fn;
Expand Down
8 changes: 7 additions & 1 deletion ext/gmp/gmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -1087,10 +1087,13 @@ GMP_UNARY_OP_FUNCTION(nextprime);
ZEND_FUNCTION(gmp_prevprime)
{
mpz_ptr gmpnum_a, gmpnum_result;
zval *definitely_prime = NULL;
int res;

ZEND_PARSE_PARAMETERS_START(1, 1)
ZEND_PARSE_PARAMETERS_START(1, 2)
GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_a)
Z_PARAM_OPTIONAL
Z_PARAM_ZVAL(definitely_prime)
ZEND_PARSE_PARAMETERS_END();

if (mpz_cmp_ui(gmpnum_a, 2) <= 0) {
Expand All @@ -1106,6 +1109,9 @@ ZEND_FUNCTION(gmp_prevprime)
INIT_GMP_RETVAL(gmpnum_result);
res = mpz_prevprime(gmpnum_result, gmpnum_a);
ZEND_ASSERT(res);
if (definitely_prime) {
ZEND_TRY_ASSIGN_REF_BOOL(definitely_prime, res == 2);
}
}
/* }}} */
#endif
Expand Down
3 changes: 2 additions & 1 deletion ext/gmp/gmp.stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,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 {}
/** @param bool $definitely_prime */
function gmp_prevprime(GMP|int|string $num, &$definitely_prime = null): GMP {}
#endif

function gmp_binomial(GMP|int|string $n, int $k): GMP {}
3 changes: 2 additions & 1 deletion ext/gmp/gmp_arginfo.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

26 changes: 26 additions & 0 deletions ext/gmp/tests/gmp_prevprime.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,42 @@ foreach ([-1, 0, 1, 2] as $value) {
}
}

$definitelyPrime = null;
try {
var_dump(gmp_prevprime(2, $definitelyPrime));
} catch (\ValueError $e) {
echo $e->getMessage() . \PHP_EOL;
}
var_dump($definitelyPrime);

var_dump(gmp_strval(gmp_prevprime(3)));
var_dump(gmp_strval(gmp_prevprime(4)));
var_dump(gmp_strval(gmp_prevprime(10000)));

$definitelyPrime = null;
var_dump(gmp_strval(gmp_prevprime(3, $definitelyPrime)));
var_dump($definitelyPrime);

$probablePrime = gmp_nextprime(gmp_pow(10, 80));
$definitelyPrime = null;
$previousPrime = gmp_prevprime(gmp_add($probablePrime, 1), $definitelyPrime);
var_dump(gmp_cmp($previousPrime, $probablePrime) === 0);
var_dump(is_bool($definitelyPrime));
var_dump($definitelyPrime === (gmp_prob_prime($previousPrime) === 2));

?>
--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
gmp_prevprime(): Argument #1 ($num) must be greater than 2
NULL
string(1) "2"
string(1) "3"
string(4) "9973"
string(1) "2"
bool(true)
bool(true)
bool(true)
bool(true)
58 changes: 30 additions & 28 deletions ext/zip/php_zip.c
Original file line number Diff line number Diff line change
Expand Up @@ -353,10 +353,8 @@ static zend_result php_zip_add_file(ze_zip_object *obj, const char *filename, si

typedef struct {
zend_long remove_all_path;
char *remove_path;
size_t remove_path_len;
char *add_path;
size_t add_path_len;
const zend_string *remove_path;
const zend_string *add_path;
zip_flags_t flags;
zip_int32_t comp_method;
zip_uint32_t comp_flags;
Expand Down Expand Up @@ -450,8 +448,8 @@ static zend_result php_zip_parse_options(HashTable *options, zip_options *opts)
zend_value_error("Option \"remove_path\" must be less than %d bytes", MAXPATHLEN - 1);
return FAILURE;
}
opts->remove_path_len = Z_STRLEN_P(option);
opts->remove_path = Z_STRVAL_P(option);
/* No need to copy the string as it's only ever used to check the paths after parsing the options */
opts->remove_path = Z_STR_P(option);
}

if ((option = zend_hash_str_find(options, "add_path", sizeof("add_path") - 1)) != NULL) {
Expand All @@ -470,8 +468,7 @@ static zend_result php_zip_parse_options(HashTable *options, zip_options *opts)
zend_value_error("Option \"add_path\" must be less than %d bytes", MAXPATHLEN - 1);
return FAILURE;
}
opts->add_path_len = Z_STRLEN_P(option);
opts->add_path = Z_STRVAL_P(option);
opts->add_path = Z_STR_P(option);
}

if ((option = zend_hash_str_find(options, "flags", sizeof("flags") - 1)) != NULL) {
Expand Down Expand Up @@ -654,7 +651,7 @@ static bool php_zipobj_close(ze_zip_object *obj, zend_string **out_str) /* {{{ *
}
/* }}} */

int php_zip_glob(zend_string *spattern, zend_long flags, zval *return_value) /* {{{ */
static int php_zip_glob(zend_string *spattern, zend_long flags, zval *return_value) /* {{{ */
{
int cwd_skip = 0;
#ifdef ZTS
Expand Down Expand Up @@ -758,7 +755,7 @@ int php_zip_glob(zend_string *spattern, zend_long flags, zval *return_value) /*
}
/* }}} */

int php_zip_pcre(zend_string *regexp, char *path, int path_len, zval *return_value) /* {{{ */
static int php_zip_pcre(zend_string *regexp, char *path, int path_len, zval *return_value) /* {{{ */
{
#ifdef ZTS
char cwd[MAXPATHLEN];
Expand Down Expand Up @@ -1826,53 +1823,58 @@ static void php_zip_add_from_pattern(INTERNAL_FUNCTION_PARAMETERS, int type) /*
ze_zip_object *ze_obj = Z_ZIP_P(self);

for (int i = 0; i < found; i++) {
char *file_stripped, *entry_name;
size_t entry_name_len, file_stripped_len;
char entry_name_buf[MAXPATHLEN];
zend_string *basename = NULL;

if ((zval_file = zend_hash_index_find(Z_ARRVAL_P(return_value), i)) != NULL) {
const char *file_stripped;
size_t file_stripped_len;
if (opts.remove_all_path) {
basename = php_basename(Z_STRVAL_P(zval_file), Z_STRLEN_P(zval_file), NULL, 0);
file_stripped = ZSTR_VAL(basename);
file_stripped_len = ZSTR_LEN(basename);
} else if (opts.remove_path && Z_STRLEN_P(zval_file) > opts.remove_path_len && !memcmp(Z_STRVAL_P(zval_file), opts.remove_path, opts.remove_path_len)) {
if (IS_SLASH(Z_STRVAL_P(zval_file)[opts.remove_path_len])) {
file_stripped = Z_STRVAL_P(zval_file) + opts.remove_path_len + 1;
file_stripped_len = Z_STRLEN_P(zval_file) - opts.remove_path_len - 1;
} else if (opts.remove_path && zend_string_starts_with(Z_STR_P(zval_file), opts.remove_path)) {
if (IS_SLASH(Z_STRVAL_P(zval_file)[ZSTR_LEN(opts.remove_path)])) {
file_stripped = Z_STRVAL_P(zval_file) + ZSTR_LEN(opts.remove_path) + 1;
file_stripped_len = Z_STRLEN_P(zval_file) - ZSTR_LEN(opts.remove_path) - 1;
} else {
file_stripped = Z_STRVAL_P(zval_file) + opts.remove_path_len;
file_stripped_len = Z_STRLEN_P(zval_file) - opts.remove_path_len;
file_stripped = Z_STRVAL_P(zval_file) + ZSTR_LEN(opts.remove_path);
file_stripped_len = Z_STRLEN_P(zval_file) - ZSTR_LEN(opts.remove_path);
}
} else {
file_stripped = Z_STRVAL_P(zval_file);
file_stripped_len = Z_STRLEN_P(zval_file);
}

zend_string *entry_name;
if (opts.add_path) {
if ((opts.add_path_len + file_stripped_len) > MAXPATHLEN) {
if ((ZSTR_LEN(opts.add_path) + file_stripped_len) > MAXPATHLEN) {
if (basename) {
zend_string_release_ex(basename, false);
}
php_error_docref(NULL, E_WARNING, "Entry name too long (max: %d, %zd given)",
MAXPATHLEN - 1, (opts.add_path_len + file_stripped_len));
php_error_docref(NULL, E_WARNING, "Entry name too long (max: %d, %zu given)",
MAXPATHLEN - 1, (ZSTR_LEN(opts.add_path) + file_stripped_len));
zend_array_destroy(Z_ARR_P(return_value));
RETURN_FALSE;
}
snprintf(entry_name_buf, MAXPATHLEN, "%s%s", opts.add_path, file_stripped);
entry_name = zend_string_concat2(
ZSTR_VAL(opts.add_path), ZSTR_LEN(opts.add_path),
file_stripped, file_stripped_len
);
} else {
snprintf(entry_name_buf, MAXPATHLEN, "%s", file_stripped);
entry_name = zend_string_init(file_stripped, file_stripped_len, false);
}
ZEND_ASSERT(ZSTR_LEN(entry_name) <= MAXPATHLEN);

entry_name = entry_name_buf;
entry_name_len = strlen(entry_name);
if (basename) {
zend_string_release_ex(basename, false);
basename = NULL;
}

if (php_zip_add_file(ze_obj, Z_STRVAL_P(zval_file), Z_STRLEN_P(zval_file),
entry_name, entry_name_len, 0, 0, -1, opts.flags) == FAILURE) {
const zend_result status = php_zip_add_file(ze_obj, Z_STRVAL_P(zval_file), Z_STRLEN_P(zval_file),
ZSTR_VAL(entry_name), ZSTR_LEN(entry_name), 0, 0, -1, opts.flags);

zend_string_release_ex(entry_name, false);
if (status == FAILURE) {
zend_array_destroy(Z_ARR_P(return_value));
RETURN_FALSE;
}
Expand Down