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
1 change: 1 addition & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ PHP NEWS

- OPcache:
. Fixed ZTS OPcache build on Cygwin. (cmb)
. Added opcache.file_cache_read_only. (Samuel Melrose)

- Output:
. Fixed calculation of aligned buffer size. (cmb)
Expand Down
11 changes: 11 additions & 0 deletions UPGRADING
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,17 @@ PHP 8.5 UPGRADE NOTES
11. Changes to INI File Handling
========================================

- Opcache:
. Added opcache.file_cache_read_only to support a read-only
opcache.file_cache directory, for use with read-only file systems
(e.g. read-only Docker containers).
Best used with opcache.validate_timestamps=0,
opcache.enable_file_override=1,
and opcache.file_cache_consistency_checks=0.
Note: A cache generated with a different build of PHP, a different file
path, or different settings (including which extensions are loaded), may be
ignored.

========================================
12. Windows Support
========================================
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ function test(string $name, object $obj) {
$reflector->initializeLazyObject($obj);
$reflector->getProperty('a')->setRawValueWithoutLazyInitialization($obj, 'test');

var_dump($obj->a);
var_dump($obj);
}

Expand All @@ -33,22 +34,50 @@ $obj = $reflector->newLazyProxy(function () {

test('Proxy', $obj);

$real = new C('foo');
$obj = $reflector->newLazyProxy(function () use ($real) {
return $real;
});
$reflector->initializeLazyObject($obj);
$reflector->resetAsLazyProxy($real, function () {
return new C('bar');
});
$reflector->initializeLazyObject($real);

test('Nested Proxy', $obj);

?>
--EXPECTF--
# Ghost
string(4) "test"
object(C)#%d (2) {
["a"]=>
string(4) "test"
["b"]=>
NULL
}
# Proxy
string(4) "test"
lazy proxy object(C)#%d (1) {
["instance"]=>
object(C)#%d (2) {
["a"]=>
NULL
string(4) "test"
["b"]=>
NULL
}
}
# Nested Proxy
string(4) "test"
lazy proxy object(C)#%d (1) {
["instance"]=>
lazy proxy object(C)#%d (1) {
["instance"]=>
object(C)#%d (2) {
["a"]=>
string(4) "test"
["b"]=>
NULL
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,19 @@ $obj = $reflector->newLazyProxy(function () {

test('Proxy', $obj);

$real = new C('foo');
$obj = $reflector->newLazyProxy(function () use ($real) {
return $real;
});
$reflector->initializeLazyObject($obj);
$reflector->resetAsLazyProxy($real, function () {
var_dump("initializer");
return new C('bar');
});
$reflector->initializeLazyObject($real);

test('Nested Proxy', $obj);

?>
--EXPECTF--
# Ghost
Expand All @@ -48,7 +61,7 @@ object(C)#%d (2) {
NULL
}
# Proxy
int(1)
int(2)
bool(true)
lazy proxy object(C)#%d (1) {
["instance"]=>
Expand All @@ -59,3 +72,19 @@ lazy proxy object(C)#%d (1) {
NULL
}
}
string(11) "initializer"
# Nested Proxy
int(2)
bool(true)
lazy proxy object(C)#%d (1) {
["instance"]=>
lazy proxy object(C)#%d (1) {
["instance"]=>
object(C)#%d (2) {
["a"]=>
int(2)
["b"]=>
NULL
}
}
}
14 changes: 14 additions & 0 deletions build/gen_stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -2086,6 +2086,13 @@ public function getMethodSynopsisElement(array $funcMap, array $aliasMap, DOMDoc

$methodSynopsis->appendChild(new DOMText("\n "));

foreach ($this->attributes as $attribute) {
$modifier = $doc->createElement("modifier", "#[\\" . $attribute->class . "]");
$modifier->setAttribute("role", "attribute");
$methodSynopsis->appendChild($modifier);
$methodSynopsis->appendChild(new DOMText("\n "));
}

foreach ($this->getModifierNames() as $modifierString) {
$modifierElement = $doc->createElement('modifier', $modifierString);
$methodSynopsis->appendChild($modifierElement);
Expand Down Expand Up @@ -3870,6 +3877,13 @@ private static function createOoElement(
$ooElement->appendChild($doc->createElement('modifier', $modifierOverride));
$ooElement->appendChild(new DOMText("\n$indentation "));
} elseif ($withModifiers) {
foreach ($classInfo->attributes as $attribute) {
$modifier = $doc->createElement("modifier", "#[\\" . $attribute->class . "]");
$modifier->setAttribute("role", "attribute");
$ooElement->appendChild($modifier);
$ooElement->appendChild(new DOMText("\n$indentation "));
}

if ($classInfo->flags & Modifiers::FINAL) {
$ooElement->appendChild($doc->createElement('modifier', 'final'));
$ooElement->appendChild(new DOMText("\n$indentation "));
Expand Down
8 changes: 4 additions & 4 deletions docs/source/miscellaneous/stubs.rst
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ Additional meta information can be attached to functions, with the following PHP
- ``@deprecated``: Triggers the usual deprecation notice when the function/method is called.

- ``@alias``: If a function/method is an alias of another function/method, then the aliased
function/method name has to be provided as value. E.g. the function ``sizeof()` has the ``@alias
function/method name has to be provided as value. E.g. the function ``sizeof()`` has the ``@alias
count`` annotation.

- ``@implementation-alias``: This is very similar to ``@alias`` with some semantic differences.
Expand Down Expand Up @@ -255,7 +255,7 @@ Additional meta information can be attached to functions, with the following PHP
In order to generate code which is necessary for registering constants, classes, properties, enums,
and traits, use the ``@generate-class-entries`` file-level PHPDoc block.

``@generate-class-entries`` implies ``@generate-function-entries```, so the latter is then
``@generate-class-entries`` implies ``@generate-function-entries``, so the latter is then
superfluous.

Given the following stub:
Expand Down Expand Up @@ -573,8 +573,8 @@ Then notice the ``#if (PHP_VERSION_ID >= ...)`` conditions in the generated argi
return class_entry;
}

The preprocessor conditions are necessary because ``enum``s, ``readonly`` properties, and the
``not-serializable`` flag, are PHP 8.1 features and don't exist in PHP 8.0.
The preprocessor conditions are necessary because enumerations (``enum``), ``readonly`` properties,
and the ``not-serializable`` flag, are PHP 8.1 features and don't exist in PHP 8.0.

The registration of ``Number`` is therefore completely omitted, while the ``readonly`` flag is not
added for``Elephpant::$name`` for PHP versions before 8.1.
Expand Down
45 changes: 23 additions & 22 deletions ext/filter/logical_filters.c
Original file line number Diff line number Diff line change
Expand Up @@ -925,13 +925,13 @@ void php_filter_validate_ip(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */

if (flags & FILTER_FLAG_GLOBAL_RANGE) {
if (
(ip[0] == 100 && ip[1] >= 64 && ip[1] <= 127 ) ||
(ip[0] == 192 && ip[1] == 0 && ip[2] == 0 ) ||
(ip[0] == 192 && ip[1] == 0 && ip[2] == 2 ) ||
(ip[0] == 198 && ip[1] >= 18 && ip[1] <= 19 ) ||
(ip[0] == 198 && ip[1] == 51 && ip[2] == 100 ) ||
(ip[0] == 203 && ip[1] == 0 && ip[2] == 113 )
) {
(ip[0] == 100 && ip[1] >= 64 && ip[1] <= 127 ) ||
(ip[0] == 192 && ip[1] == 0 && ip[2] == 0 ) ||
(ip[0] == 192 && ip[1] == 0 && ip[2] == 2 ) ||
(ip[0] == 198 && ip[1] >= 18 && ip[1] <= 19 ) ||
(ip[0] == 198 && ip[1] == 51 && ip[2] == 100 ) ||
(ip[0] == 203 && ip[1] == 0 && ip[2] == 113 )
) {
RETURN_VALIDATION_FAILED
}
}
Expand All @@ -952,23 +952,24 @@ void php_filter_validate_ip(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
}
}
if (flags & FILTER_FLAG_NO_RES_RANGE || flags & FILTER_FLAG_GLOBAL_RANGE) {
if ((ip[0] == 0 && ip[1] == 0 && ip[2] == 0 && ip[3] == 0
&& ip[4] == 0 && ip[5] == 0 && ip[6] == 0 && (ip[7] == 0 || ip[7] == 1))
|| (ip[0] == 0x5f)
|| (ip[0] >= 0xfe80 && ip[0] <= 0xfebf)
|| (ip[0] == 0x2001 && (ip[1] == 0x0db8 || (ip[1] >= 0x0010 && ip[1] <= 0x001f)))
|| (ip[0] == 0x3ff3)
) {
RETURN_VALIDATION_FAILED
}
if (
(ip[0] == 0 && ip[1] == 0 && ip[2] == 0 && ip[3] == 0 && ip[4] == 0 && ip[5] == 0 && ip[6] == 0 && (ip[7] == 0 || ip[7] == 1)) ||
(ip[0] == 0x5f) ||
(ip[0] >= 0xfe80 && ip[0] <= 0xfebf) ||
(ip[0] == 0x2001 && (ip[1] == 0x0db8 || (ip[1] >= 0x0010 && ip[1] <= 0x001f))) ||
(ip[0] == 0x3ff3)
) {
RETURN_VALIDATION_FAILED
}
}
if (flags & FILTER_FLAG_GLOBAL_RANGE) {
if ((ip[0] == 0 && ip[1] == 0 && ip[2] == 0 && ip[3] == 0 && ip[4] == 0 && ip[5] == 0xffff) ||
(ip[0] == 0x0100 && ip[1] == 0 && ip[2] == 0 && ip[3] == 0) ||
(ip[0] == 0x2001 && ip[1] <= 0x01ff) ||
(ip[0] == 0x2001 && ip[1] == 0x0002 && ip[2] == 0) ||
(ip[0] >= 0xfc00 && ip[0] <= 0xfdff)
) {
if (
(ip[0] == 0 && ip[1] == 0 && ip[2] == 0 && ip[3] == 0 && ip[4] == 0 && ip[5] == 0xffff) ||
(ip[0] == 0x0100 && ip[1] == 0 && ip[2] == 0 && ip[3] == 0) ||
(ip[0] == 0x2001 && ip[1] <= 0x01ff) ||
(ip[0] == 0x2001 && ip[1] == 0x0002 && ip[2] == 0) ||
(ip[0] >= 0xfc00 && ip[0] <= 0xfdff)
) {
RETURN_VALIDATION_FAILED
}
}
Expand Down
49 changes: 49 additions & 0 deletions ext/opcache/ZendAccelerator.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
#include "zend_accelerator_util_funcs.h"
#include "zend_accelerator_hash.h"
#include "zend_file_cache.h"
#include "zend_system_id.h"
#include "ext/pcre/php_pcre.h"
#include "ext/standard/basic_functions.h"

Expand Down Expand Up @@ -3301,6 +3302,54 @@ static zend_result accel_post_startup(void)
#endif
accel_shared_globals = calloc(1, sizeof(zend_accel_shared_globals));
}

/* opcache.file_cache_read_only should only be enabled when all script files are read-only */
int file_cache_access_mode = 0;

if (ZCG(accel_directives).file_cache_read_only) {
zend_accel_error(ACCEL_LOG_INFO, "opcache.file_cache is in read-only mode");

if (!ZCG(accel_directives).file_cache) {
accel_startup_ok = false;
zend_accel_error_noreturn(ACCEL_LOG_FATAL, "opcache.file_cache_read_only is set without a proper setting of opcache.file_cache");
return SUCCESS;
}

/* opcache.file_cache is read only, so ensure the directory is readable */
#ifndef ZEND_WIN32
file_cache_access_mode = R_OK | X_OK;
#else
file_cache_access_mode = 04; // Read access
#endif
} else {
/* opcache.file_cache isn't read only, so ensure the directory is writable */
#ifndef ZEND_WIN32
file_cache_access_mode = R_OK | W_OK | X_OK;
#else
file_cache_access_mode = 06; // Read and write access
#endif
}

if ( ZCG(accel_directives).file_cache ) {
zend_accel_error(ACCEL_LOG_INFO, "opcache.file_cache running with PHP build ID: %s", zend_system_id);

zend_stat_t buf = {0};

if (!IS_ABSOLUTE_PATH(ZCG(accel_directives).file_cache, strlen(ZCG(accel_directives).file_cache)) ||
zend_stat(ZCG(accel_directives).file_cache, &buf) != 0 ||
!S_ISDIR(buf.st_mode) ||
#ifndef ZEND_WIN32
access(ZCG(accel_directives).file_cache, file_cache_access_mode) != 0
#else
_access(ZCG(accel_directives).file_cache, file_cache_access_mode) != 0
#endif
) {
accel_startup_ok = false;
zend_accel_error_noreturn(ACCEL_LOG_FATAL, "opcache.file_cache must be a full path of an accessible directory");
return SUCCESS;
}
}

#if ENABLE_FILE_CACHE_FALLBACK
file_cache_fallback:
#endif
Expand Down
1 change: 1 addition & 0 deletions ext/opcache/ZendAccelerator.h
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ typedef struct _zend_accel_directives {
char *lockfile_path;
#endif
char *file_cache;
bool file_cache_read_only;
bool file_cache_only;
bool file_cache_consistency_checks;
#if ENABLE_FILE_CACHE_FALLBACK
Expand Down
37 changes: 35 additions & 2 deletions ext/opcache/jit/zend_jit_ir.c
Original file line number Diff line number Diff line change
Expand Up @@ -11720,6 +11720,32 @@ static int zend_jit_rope(zend_jit_ctx *jit, const zend_op *opline, uint32_t op2_
return 1;
}

static int zend_jit_zval_copy_deref_reg(zend_jit_ctx *jit, zend_jit_addr res_addr, uint32_t res_info, zend_jit_addr val_addr, ir_ref type, ir_ref *values)
{
ir_ref if_type, val;

if (res_info == MAY_BE_LONG) {
if_type = ir_IF(ir_EQ(type, ir_CONST_U32(IS_LONG)));
ir_IF_TRUE(if_type);
val = jit_ZVAL_ADDR(jit, val_addr);
ir_END_PHI_list(*values, val);
ir_IF_FALSE(if_type);
val = ir_ADD_OFFSET(jit_Z_PTR(jit, val_addr), offsetof(zend_reference, val));
ir_END_PHI_list(*values, val);
} else if (res_info == MAY_BE_DOUBLE) {
if_type = ir_IF(ir_EQ(type, ir_CONST_U32(IS_DOUBLE)));
ir_IF_TRUE(if_type);
val = jit_ZVAL_ADDR(jit, val_addr);
ir_END_PHI_list(*values, val);
ir_IF_FALSE(if_type);
val = ir_ADD_OFFSET(jit_Z_PTR(jit, val_addr), offsetof(zend_reference, val));
ir_END_PHI_list(*values, val);
} else {
ZEND_UNREACHABLE();
}
return 1;
}

static int zend_jit_zval_copy_deref(zend_jit_ctx *jit, zend_jit_addr res_addr, zend_jit_addr val_addr, ir_ref type)
{
ir_ref if_refcounted, if_reference, if_refcounted2, ptr, val2, ptr2, type2;
Expand Down Expand Up @@ -14463,9 +14489,16 @@ static int zend_jit_fetch_obj(zend_jit_ctx *jit,
}
ir_END_list(end_inputs);
} else {
if (((res_info & MAY_BE_GUARD) && JIT_G(current_frame) && prop_info)
|| Z_MODE(res_addr) == IS_REG) {
if ((res_info & MAY_BE_GUARD) && JIT_G(current_frame) && prop_info) {
ir_END_PHI_list(end_values, jit_ZVAL_ADDR(jit, prop_addr));
} else if ((res_info & MAY_BE_GUARD) && Z_MODE(res_addr) == IS_REG) {
ir_END_PHI_list(end_values, jit_ZVAL_ADDR(jit, prop_addr));
} else if (Z_MODE(res_addr) == IS_REG) {
prop_type_ref = jit_Z_TYPE_INFO(jit, prop_addr);

if (!zend_jit_zval_copy_deref_reg(jit, res_addr, res_info & ~MAY_BE_GUARD, prop_addr, prop_type_ref, &end_values)) {
return 0;
}
} else {
prop_type_ref = jit_Z_TYPE_INFO(jit, prop_addr);

Expand Down
1 change: 1 addition & 0 deletions ext/opcache/tests/zzz_basic_logging.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ outputs the correct logging at the highest log_verbosity_level
--INI--
opcache.enable=1
opcache.enable_cli=1
opcache.file_cache=
opcache.file_cache_only=0
opcache.error_log=
opcache.log_verbosity_level=4
Expand Down
Loading