mirror of
https://github.com/php/php-src.git
synced 2024-11-23 18:04:36 +08:00
Add runtime type inference verification
Co-authored-by: Dmitry Stogov <dmitry@zend.com> Closes GH-12930
This commit is contained in:
parent
bf4ec8bd9d
commit
ffc250d245
2
.github/nightly_matrix.php
vendored
2
.github/nightly_matrix.php
vendored
@ -63,7 +63,7 @@ function get_matrix_include(array $branches) {
|
||||
'branch' => $branch,
|
||||
'debug' => true,
|
||||
'zts' => true,
|
||||
'configuration_parameters' => "CFLAGS='-DZEND_RC_DEBUG=1 -DPROFITABILITY_CHECKS=0 -DZEND_VERIFY_FUNC_INFO=1'",
|
||||
'configuration_parameters' => "CFLAGS='-DZEND_RC_DEBUG=1 -DPROFITABILITY_CHECKS=0 -DZEND_VERIFY_FUNC_INFO=1 -DZEND_VERIFY_TYPE_INFERENCE'",
|
||||
'timeout_minutes' => 360,
|
||||
'test_function_jit' => true,
|
||||
'asan' => false,
|
||||
|
37
.github/workflows/nightly.yml
vendored
37
.github/workflows/nightly.yml
vendored
@ -349,9 +349,16 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
branch: ${{ fromJson(needs.GENERATE_MATRIX.outputs.branches) }}
|
||||
name: "${{ matrix.branch.name }}_COMMUNITY"
|
||||
type: ['asan', 'verify_type_inference']
|
||||
# These branches don't include type verification
|
||||
exclude:
|
||||
- { branch: { name: 'PHP-8.1', ref: 'PHP-8.1', major: 8, minor: 1 }, type: 'verify_type_inference' }
|
||||
- { branch: { name: 'PHP-8.2', ref: 'PHP-8.2', major: 8, minor: 2 }, type: 'verify_type_inference' }
|
||||
- { branch: { name: 'PHP-8.3', ref: 'PHP-8.3', major: 8, minor: 3 }, type: 'verify_type_inference' }
|
||||
name: "${{ matrix.branch.name }}_COMMUNITY_${{ matrix.type }}"
|
||||
runs-on: ubuntu-${{ matrix.branch.version.minor >= 3 && '22.04' || '20.04' }}
|
||||
env:
|
||||
ASAN_OPTIONS: exitcode=139
|
||||
UBSAN_OPTIONS: print_stacktrace=1
|
||||
USE_ZEND_ALLOC: 0
|
||||
USE_TRACKED_ALLOC: 1
|
||||
@ -365,11 +372,11 @@ jobs:
|
||||
- name: ./configure
|
||||
uses: ./.github/actions/configure-x64
|
||||
with:
|
||||
# CFLAGS removes O2, so we have to add it again...
|
||||
configurationParameters: >-
|
||||
--enable-debug
|
||||
--enable-zts
|
||||
CFLAGS='-fsanitize=undefined,address -fno-sanitize-recover -DZEND_TRACK_ARENA_ALLOC'
|
||||
LDFLAGS='-fsanitize=undefined,address'
|
||||
${{ matrix.type == 'asan' && '--enable-debug CFLAGS="-fsanitize=undefined,address -fno-sanitize-recover -DZEND_TRACK_ARENA_ALLOC" LDFLAGS="-fsanitize=undefined,address"' || '' }}
|
||||
${{ matrix.type == 'verify_type_inference' && 'CFLAGS="-DZEND_VERIFY_TYPE_INFERENCE -O2"' || '' }}
|
||||
- name: make
|
||||
run: make -j$(/usr/bin/nproc) >/dev/null
|
||||
- name: make install
|
||||
@ -379,12 +386,20 @@ jobs:
|
||||
sudo service mysql start
|
||||
mysql -uroot -proot -e "CREATE DATABASE IF NOT EXISTS test"
|
||||
mysql -uroot -proot -e "SET GLOBAL local_infile = true"
|
||||
- name: Enable Opcache and JIT
|
||||
- name: Enable Opcache
|
||||
run: |
|
||||
echo memory_limit=-1 >> /etc/php.d/opcache.ini
|
||||
echo zend_extension=opcache.so > /etc/php.d/opcache.ini
|
||||
echo opcache.enable_cli=1 >> /etc/php.d/opcache.ini
|
||||
echo opcache.enable=1 >> /etc/php.d/opcache.ini
|
||||
echo opcache.protect_memory=1 >> /etc/php.d/opcache.ini
|
||||
echo opcache.memory_consumption=256M >> /etc/php.d/opcache.ini
|
||||
echo opcache.file_update_protection=0 >> /etc/php.d/opcache.ini
|
||||
echo opcache.interned_strings_buffer=64 >> /etc/php.d/opcache.ini
|
||||
echo opcache.max_accelerated_files=100000 >> /etc/php.d/opcache.ini
|
||||
- name: Enable JIT
|
||||
if: matrix.type != 'verify_type_inference'
|
||||
run: |
|
||||
echo opcache.jit=tracing >> /etc/php.d/opcache.ini
|
||||
echo opcache.jit_buffer_size=1G >> /etc/php.d/opcache.ini
|
||||
echo opcache.jit_max_root_traces=100000 >> /etc/php.d/opcache.ini
|
||||
@ -394,11 +409,6 @@ jobs:
|
||||
echo opcache.jit_hot_func=1 >> /etc/php.d/opcache.ini
|
||||
echo opcache.jit_hot_return=1 >> /etc/php.d/opcache.ini
|
||||
echo opcache.jit_hot_side_exit=1 >> /etc/php.d/opcache.ini
|
||||
echo opcache.file_update_protection=0 >> /etc/php.d/opcache.ini
|
||||
echo opcache.memory_consumption=256M >> /etc/php.d/opcache.ini
|
||||
echo opcache.interned_strings_buffer=64 >> /etc/php.d/opcache.ini
|
||||
echo opcache.max_accelerated_files=100000 >> /etc/php.d/opcache.ini
|
||||
echo memory_limit=-1 >> /etc/php.d/opcache.ini
|
||||
php -v
|
||||
- name: Test AMPHP
|
||||
run: |
|
||||
@ -410,7 +420,6 @@ jobs:
|
||||
cd "amphp-$repository"
|
||||
git rev-parse HEAD
|
||||
php /usr/bin/composer install --no-progress --ignore-platform-reqs
|
||||
export ASAN_OPTIONS=exitcode=139
|
||||
vendor/bin/phpunit || EXIT_CODE=$?
|
||||
if [ ${EXIT_CODE:-0} -gt 128 ]; then
|
||||
X=1;
|
||||
@ -426,7 +435,6 @@ jobs:
|
||||
php /usr/bin/composer install --no-progress --ignore-platform-reqs
|
||||
# Hack to disable a test that hangs
|
||||
php -r '$c = file_get_contents("tests/Filesystem/FilesystemTest.php"); $c = str_replace("public function testSharedGet()", "#[\\PHPUnit\\Framework\\Attributes\\Group('"'"'skip'"'"')]\n public function testSharedGet()", $c); file_put_contents("tests/Filesystem/FilesystemTest.php", $c);'
|
||||
export ASAN_OPTIONS=exitcode=139
|
||||
php vendor/bin/phpunit --exclude-group skip || EXIT_CODE=$?
|
||||
if [ ${EXIT_CODE:-0} -gt 128 ]; then
|
||||
exit 1
|
||||
@ -441,7 +449,6 @@ jobs:
|
||||
cd "reactphp-$repository"
|
||||
git rev-parse HEAD
|
||||
php /usr/bin/composer install --no-progress --ignore-platform-reqs
|
||||
export ASAN_OPTIONS=exitcode=139
|
||||
vendor/bin/phpunit || EXIT_CODE=$?
|
||||
if [ $[EXIT_CODE:-0} -gt 128 ]; then
|
||||
X=1;
|
||||
@ -455,7 +462,6 @@ jobs:
|
||||
cd event-loop
|
||||
git rev-parse HEAD
|
||||
php /usr/bin/composer install --no-progress --ignore-platform-reqs
|
||||
export ASAN_OPTIONS=exitcode=139
|
||||
vendor/bin/phpunit || EXIT_CODE=$?
|
||||
if [ ${EXIT_CODE:-0} -gt 128 ]; then
|
||||
exit 1
|
||||
@ -471,7 +477,6 @@ jobs:
|
||||
php -r '$c = file_get_contents("src/Symfony/Component/HtmlSanitizer/Tests/HtmlSanitizerCustomTest.php"); $c = str_replace("public function testSanitizeDeepNestedString()", "/** @group skip */\n public function testSanitizeDeepNestedString()", $c); file_put_contents("src/Symfony/Component/HtmlSanitizer/Tests/HtmlSanitizerCustomTest.php", $c);'
|
||||
# Buggy FFI test in Symfony, see https://github.com/symfony/symfony/issues/47668
|
||||
php -r '$c = file_get_contents("src/Symfony/Component/VarDumper/Tests/Caster/FFICasterTest.php"); $c = str_replace("*/\n public function testCastNonTrailingCharPointer()", "* @group skip\n */\n public function testCastNonTrailingCharPointer()", $c); file_put_contents("src/Symfony/Component/VarDumper/Tests/Caster/FFICasterTest.php", $c);'
|
||||
export ASAN_OPTIONS=exitcode=139
|
||||
export SYMFONY_DEPRECATIONS_HELPER=max[total]=999
|
||||
X=0
|
||||
for component in $(find src/Symfony -mindepth 2 -type f -name phpunit.xml.dist -printf '%h\n'); do
|
||||
@ -487,7 +492,6 @@ jobs:
|
||||
git clone https://github.com/sebastianbergmann/phpunit.git --branch=main --depth=1
|
||||
cd phpunit
|
||||
git rev-parse HEAD
|
||||
export ASAN_OPTIONS=exitcode=139
|
||||
php /usr/bin/composer install --no-progress --ignore-platform-reqs
|
||||
php ./phpunit || EXIT_CODE=$?
|
||||
if [ ${EXIT_CODE:-0} -gt 128 ]; then
|
||||
@ -506,7 +510,6 @@ jobs:
|
||||
git clone https://github.com/WordPress/wordpress-develop.git wordpress --depth=1
|
||||
cd wordpress
|
||||
git rev-parse HEAD
|
||||
export ASAN_OPTIONS=exitcode=139
|
||||
php /usr/bin/composer install --no-progress --ignore-platform-reqs
|
||||
cp wp-tests-config-sample.php wp-tests-config.php
|
||||
sed -i 's/youremptytestdbnamehere/test/g' wp-tests-config.php
|
||||
|
@ -1332,6 +1332,26 @@ static void zend_redo_pass_two_ex(zend_op_array *op_array, zend_ssa *ssa)
|
||||
}
|
||||
break;
|
||||
}
|
||||
#ifdef ZEND_VERIFY_TYPE_INFERENCE
|
||||
if (ssa_op->op1_use >= 0) {
|
||||
opline->op1_use_type = ssa->var_info[ssa_op->op1_use].type;
|
||||
}
|
||||
if (ssa_op->op2_use >= 0) {
|
||||
opline->op2_use_type = ssa->var_info[ssa_op->op2_use].type;
|
||||
}
|
||||
if (ssa_op->result_use >= 0) {
|
||||
opline->result_use_type = ssa->var_info[ssa_op->result_use].type;
|
||||
}
|
||||
if (ssa_op->op1_def >= 0) {
|
||||
opline->op1_def_type = ssa->var_info[ssa_op->op1_def].type;
|
||||
}
|
||||
if (ssa_op->op2_def >= 0) {
|
||||
opline->op2_def_type = ssa->var_info[ssa_op->op2_def].type;
|
||||
}
|
||||
if (ssa_op->result_def >= 0) {
|
||||
opline->result_def_type = ssa->var_info[ssa_op->result_def].type;
|
||||
}
|
||||
#endif
|
||||
zend_vm_set_opcode_handler_ex(opline, op1_info, op2_info, res_info);
|
||||
opline++;
|
||||
}
|
||||
|
@ -1,5 +1,9 @@
|
||||
--TEST--
|
||||
GH-10168: Wrong assign to variable
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if (defined('ZEND_VERIFY_TYPE_INFERENCE')) die('skip Destructor side-effects violate type inference');
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
|
@ -124,6 +124,14 @@ static void init_op(zend_op *op)
|
||||
MAKE_NOP(op);
|
||||
op->extended_value = 0;
|
||||
op->lineno = CG(zend_lineno);
|
||||
#ifdef ZEND_VERIFY_TYPE_INFERENCE
|
||||
op->op1_use_type = 0;
|
||||
op->op2_use_type = 0;
|
||||
op->result_use_type = 0;
|
||||
op->op1_def_type = 0;
|
||||
op->op2_def_type = 0;
|
||||
op->result_def_type = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static zend_always_inline uint32_t get_next_op_number(void)
|
||||
|
@ -143,6 +143,14 @@ struct _zend_op {
|
||||
uint8_t op1_type; /* IS_UNUSED, IS_CONST, IS_TMP_VAR, IS_VAR, IS_CV */
|
||||
uint8_t op2_type; /* IS_UNUSED, IS_CONST, IS_TMP_VAR, IS_VAR, IS_CV */
|
||||
uint8_t result_type; /* IS_UNUSED, IS_CONST, IS_TMP_VAR, IS_VAR, IS_CV */
|
||||
#ifdef ZEND_VERIFY_TYPE_INFERENCE
|
||||
uint32_t op1_use_type;
|
||||
uint32_t op2_use_type;
|
||||
uint32_t result_use_type;
|
||||
uint32_t op1_def_type;
|
||||
uint32_t op2_def_type;
|
||||
uint32_t result_def_type;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
@ -4639,6 +4639,16 @@ static void zend_swap_operands(zend_op *op) /* {{{ */
|
||||
op->op1_type = op->op2_type;
|
||||
op->op2 = tmp;
|
||||
op->op2_type = tmp_type;
|
||||
|
||||
#ifdef ZEND_VERIFY_TYPE_INFERENCE
|
||||
uint32_t tmp_info;
|
||||
tmp_info = op->op1_use_type;
|
||||
op->op1_use_type = op->op2_use_type;
|
||||
op->op2_use_type = tmp_info;
|
||||
tmp_info = op->op1_def_type;
|
||||
op->op1_def_type = op->op2_def_type;
|
||||
op->op2_def_type = tmp_info;
|
||||
#endif
|
||||
}
|
||||
/* }}} */
|
||||
#endif
|
||||
@ -5301,6 +5311,8 @@ static zend_always_inline zend_execute_data *_zend_vm_stack_push_call_frame(uint
|
||||
# include "zend_vm_trace_lines.h"
|
||||
#elif defined(ZEND_VM_TRACE_MAP)
|
||||
# include "zend_vm_trace_map.h"
|
||||
#elif defined(ZEND_VERIFY_TYPE_INFERENCE)
|
||||
# include "zend_verify_type_inference.h"
|
||||
#endif
|
||||
|
||||
#define ZEND_VM_NEXT_OPCODE_EX(check_exception, skip) \
|
||||
|
203
Zend/zend_verify_type_inference.h
Normal file
203
Zend/zend_verify_type_inference.h
Normal file
@ -0,0 +1,203 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| Zend Engine |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) Zend Technologies Ltd. (http://www.zend.com) |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 2.00 of the Zend license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.zend.com/license/2_00.txt. |
|
||||
| If you did not receive a copy of the Zend license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@zend.com so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#include "zend_type_info.h"
|
||||
#include "zend_compile.h"
|
||||
|
||||
#define VM_TRACE_START()
|
||||
#define VM_TRACE_END()
|
||||
#define VM_TRACE(op) zend_verify_inference_use(execute_data, OPLINE); \
|
||||
{ \
|
||||
zend_execute_data *__current_ex = NULL; \
|
||||
const zend_op *__current_op = NULL; \
|
||||
if (OPLINE->opcode != ZEND_GENERATOR_RETURN) { \
|
||||
__current_ex = execute_data; __current_op = OPLINE; \
|
||||
}
|
||||
#define VM_TRACE_OP_END(op) \
|
||||
if (__current_ex && __current_op) { \
|
||||
zend_verify_inference_def(__current_ex, __current_op); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define ZEND_VERIFY_TYPE_INFERENCE_ERROR(msg, ...) \
|
||||
do { \
|
||||
fprintf(stderr, "Inference verification failed at %04d %s (" msg ")\n", (int)(opline - EX(func)->op_array.opcodes), operand, __VA_ARGS__); \
|
||||
exit(139); \
|
||||
} while (0)
|
||||
|
||||
static void zend_verify_type_inference(zval *value, uint32_t type_mask, uint8_t op_type, zend_execute_data *execute_data, const zend_op *opline, const char *operand)
|
||||
{
|
||||
if (type_mask == MAY_BE_CLASS) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Z_TYPE_P(value) == IS_INDIRECT) {
|
||||
if (!(type_mask & MAY_BE_INDIRECT)) {
|
||||
ZEND_VERIFY_TYPE_INFERENCE_ERROR("mask 0x%x mising MAY_BE_INDIRECT", type_mask);
|
||||
}
|
||||
value = Z_INDIRECT_P(value);
|
||||
}
|
||||
|
||||
/* Verifying RC inference is currently not possible because type information is based on the SSA
|
||||
* built without ZEND_SSA_RC_INFERENCE, which is missing various definitions for RC-modifying
|
||||
* operations. Support could be added by repeating SSA-construction and type inference with the
|
||||
* given flag. */
|
||||
// if (Z_REFCOUNTED_P(value)) {
|
||||
// if (Z_REFCOUNT_P(value) == 1 && !(type_mask & MAY_BE_RC1)) {
|
||||
// ZEND_VERIFY_TYPE_INFERENCE_ERROR("mask 0x%x missing MAY_BE_RC1", type_mask);
|
||||
// }
|
||||
// if (Z_REFCOUNT_P(value) > 1 && !(type_mask & MAY_BE_RCN)) {
|
||||
// ZEND_VERIFY_TYPE_INFERENCE_ERROR("mask 0x%x missing MAY_BE_RCN", type_mask);
|
||||
// }
|
||||
// }
|
||||
|
||||
if (Z_TYPE_P(value) == IS_REFERENCE) {
|
||||
if (!(type_mask & MAY_BE_REF)) {
|
||||
ZEND_VERIFY_TYPE_INFERENCE_ERROR("mask 0x%x missing MAY_BE_REF", type_mask);
|
||||
}
|
||||
value = Z_REFVAL_P(value);
|
||||
}
|
||||
|
||||
if (!(type_mask & (1u << Z_TYPE_P(value)))) {
|
||||
if (Z_TYPE_P(value) == IS_UNUSED && op_type == IS_VAR && (type_mask & MAY_BE_NULL)) {
|
||||
/* FETCH_OBJ_* for typed property may return IS_UNDEF. This is an exception. */
|
||||
} else {
|
||||
ZEND_VERIFY_TYPE_INFERENCE_ERROR("mask 0x%x missing type %d", type_mask, Z_TYPE_P(value));
|
||||
}
|
||||
}
|
||||
|
||||
if (Z_TYPE_P(value) == IS_ARRAY) {
|
||||
HashTable *ht = Z_ARRVAL_P(value);
|
||||
uint32_t num_checked = 0;
|
||||
zend_string *str;
|
||||
zval *val;
|
||||
if (HT_IS_INITIALIZED(ht)) {
|
||||
if (HT_IS_PACKED(ht) && !MAY_BE_PACKED(type_mask)) {
|
||||
ZEND_VERIFY_TYPE_INFERENCE_ERROR("mask 0x%x missing MAY_BE_ARRAY_PACKED", type_mask);
|
||||
}
|
||||
if (!HT_IS_PACKED(ht) && !MAY_BE_HASH(type_mask)) {
|
||||
ZEND_VERIFY_TYPE_INFERENCE_ERROR("mask 0x%x missing MAY_BE_ARRAY_HASH", type_mask);
|
||||
}
|
||||
} else {
|
||||
if (!(type_mask & MAY_BE_ARRAY_EMPTY)) {
|
||||
ZEND_VERIFY_TYPE_INFERENCE_ERROR("mask 0x%x missing MAY_BE_ARRAY_EMPTY", type_mask);
|
||||
}
|
||||
}
|
||||
ZEND_HASH_FOREACH_STR_KEY_VAL(ht, str, val) {
|
||||
if (str) {
|
||||
if (!(type_mask & MAY_BE_ARRAY_KEY_STRING)) {
|
||||
ZEND_VERIFY_TYPE_INFERENCE_ERROR("mask 0x%x missing MAY_BE_ARRAY_KEY_STRING", type_mask);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (!(type_mask & MAY_BE_ARRAY_KEY_LONG)) {
|
||||
ZEND_VERIFY_TYPE_INFERENCE_ERROR("mask 0x%x missing MAY_BE_ARRAY_KEY_LONG", type_mask);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t array_type = 1u << (Z_TYPE_P(val) + MAY_BE_ARRAY_SHIFT);
|
||||
if (!(type_mask & array_type)) {
|
||||
ZEND_VERIFY_TYPE_INFERENCE_ERROR("mask 0x%x missing array type %d", type_mask, Z_TYPE_P(val));
|
||||
break;
|
||||
}
|
||||
|
||||
/* Don't check all elements of large arrays. */
|
||||
if (++num_checked > 16) {
|
||||
break;
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
}
|
||||
}
|
||||
|
||||
/* Clang reports false positive unused warnings. */
|
||||
#ifdef __clang__
|
||||
__attribute__((unused))
|
||||
#endif
|
||||
static void zend_verify_inference_use(zend_execute_data *execute_data, const zend_op *opline)
|
||||
{
|
||||
if (opline->op1_use_type
|
||||
&& (opline->op1_type & (IS_TMP_VAR|IS_VAR|IS_CV))
|
||||
&& opline->opcode != ZEND_ROPE_ADD
|
||||
&& opline->opcode != ZEND_ROPE_END) {
|
||||
zend_verify_type_inference(EX_VAR(opline->op1.var), opline->op1_use_type, opline->op1_type, execute_data, opline, "op1_use");
|
||||
}
|
||||
if (opline->op2_use_type
|
||||
&& (opline->op2_type & (IS_TMP_VAR|IS_VAR|IS_CV))) {
|
||||
zend_verify_type_inference(EX_VAR(opline->op2.var), opline->op2_use_type, opline->op2_type, execute_data, opline, "op2_use");
|
||||
}
|
||||
if (opline->result_use_type
|
||||
&& (opline->result_type & (IS_TMP_VAR|IS_VAR|IS_CV))) {
|
||||
zend_verify_type_inference(EX_VAR(opline->result.var), opline->result_use_type, opline->result_type, execute_data, opline, "result_use");
|
||||
}
|
||||
}
|
||||
|
||||
/* Clang reports false positive unused warnings. */
|
||||
#ifdef __clang__
|
||||
__attribute__((unused))
|
||||
#endif
|
||||
static void zend_verify_inference_def(zend_execute_data *execute_data, const zend_op *opline)
|
||||
{
|
||||
if (EG(exception)) {
|
||||
return;
|
||||
}
|
||||
if (opline->op1_def_type
|
||||
&& (opline->op1_type & (IS_TMP_VAR|IS_VAR|IS_CV))
|
||||
// array is actually changed by the the following instruction(s)
|
||||
&& opline->opcode != ZEND_FETCH_DIM_W
|
||||
&& opline->opcode != ZEND_FETCH_DIM_RW
|
||||
&& opline->opcode != ZEND_FETCH_DIM_FUNC_ARG
|
||||
&& opline->opcode != ZEND_FETCH_LIST_W) {
|
||||
zend_verify_type_inference(EX_VAR(opline->op1.var), opline->op1_def_type, opline->op1_type, execute_data, opline, "op1_def");
|
||||
}
|
||||
if (opline->op2_def_type
|
||||
&& (opline->op2_type & (IS_TMP_VAR|IS_VAR|IS_CV))
|
||||
/* ZEND_FE_FETCH_R[W] does not define a result in the last iteration. */
|
||||
&& opline->opcode != ZEND_FE_FETCH_R
|
||||
&& opline->opcode != ZEND_FE_FETCH_RW) {
|
||||
zend_verify_type_inference(EX_VAR(opline->op2.var), opline->op2_def_type, opline->op2_type, execute_data, opline, "op2_def");
|
||||
}
|
||||
if (opline->result_def_type
|
||||
&& (opline->result_type & (IS_TMP_VAR|IS_VAR|IS_CV))
|
||||
&& opline->opcode != ZEND_ROPE_INIT
|
||||
&& opline->opcode != ZEND_ROPE_ADD
|
||||
/* Some jump opcode handlers don't set result when it's never read. */
|
||||
&& opline->opcode != ZEND_JMP_SET
|
||||
&& opline->opcode != ZEND_JMP_NULL
|
||||
&& opline->opcode != ZEND_COALESCE
|
||||
&& opline->opcode != ZEND_ASSERT_CHECK
|
||||
/* Smart branches may not declare result. */
|
||||
&& !zend_is_smart_branch(opline)
|
||||
/* User calls only initialize result when returning from the called function. */
|
||||
&& opline->opcode != ZEND_DO_FCALL
|
||||
&& opline->opcode != ZEND_DO_UCALL
|
||||
&& opline->opcode != ZEND_DO_FCALL_BY_NAME
|
||||
/* ZEND_FE_FETCH_R[W] does not define a result in the last iteration. */
|
||||
&& opline->opcode != ZEND_FE_FETCH_R
|
||||
&& opline->opcode != ZEND_FE_FETCH_RW) {
|
||||
zend_verify_type_inference(EX_VAR(opline->result.var), opline->result_def_type, opline->result_type, execute_data, opline, "result_def");
|
||||
|
||||
/* Verify return value in the context of caller. */
|
||||
if ((opline->opcode == ZEND_RETURN || opline->opcode == ZEND_RETURN_BY_REF)
|
||||
&& execute_data->prev_execute_data
|
||||
&& execute_data->prev_execute_data->func
|
||||
&& ZEND_USER_CODE(execute_data->prev_execute_data->func->type)) {
|
||||
zend_execute_data *prev_execute_data = execute_data->prev_execute_data;
|
||||
const zend_op *opline = execute_data->prev_execute_data->opline;
|
||||
zend_verify_type_inference(ZEND_CALL_VAR(prev_execute_data, opline->result.var), opline->result_def_type, opline->result_type, prev_execute_data, opline, "result_def");
|
||||
}
|
||||
}
|
||||
}
|
1008
Zend/zend_vm_execute.h
generated
1008
Zend/zend_vm_execute.h
generated
File diff suppressed because it is too large
Load Diff
@ -1057,7 +1057,8 @@ function gen_handler($f, $spec, $kind, $name, $op1, $op2, $use, $code, $lineno,
|
||||
$code =
|
||||
"\t\t\tHYBRID_CASE({$spec_name}):\n"
|
||||
. "\t\t\t\tVM_TRACE($spec_name)\n"
|
||||
. stream_get_contents($out);
|
||||
. stream_get_contents($out)
|
||||
. "\t\t\t\tVM_TRACE_OP_END($spec_name)\n";
|
||||
fclose($out);
|
||||
} else {
|
||||
$inline =
|
||||
@ -1068,6 +1069,7 @@ function gen_handler($f, $spec, $kind, $name, $op1, $op2, $use, $code, $lineno,
|
||||
"\t\t\tHYBRID_CASE({$spec_name}):\n"
|
||||
. "\t\t\t\tVM_TRACE($spec_name)\n"
|
||||
. "\t\t\t\t{$spec_name}{$inline}_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n"
|
||||
. "\t\t\t\tVM_TRACE_OP_END($spec_name)\n"
|
||||
. "\t\t\t\tHYBRID_BREAK();\n";
|
||||
}
|
||||
if (is_array($gen_order)) {
|
||||
@ -1768,6 +1770,7 @@ function gen_executor_code($f, $spec, $kind, $prolog, &$switch_labels = array())
|
||||
out($f,"\t\t\tHYBRID_DEFAULT:\n");
|
||||
out($f,"\t\t\t\tVM_TRACE(ZEND_NULL)\n");
|
||||
out($f,"\t\t\t\tZEND_NULL_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n");
|
||||
out($f,"\t\t\t\tVM_TRACE_OP_END(ZEND_NULL)\n");
|
||||
out($f,"\t\t\t\tHYBRID_BREAK(); /* Never reached */\n");
|
||||
break;
|
||||
}
|
||||
@ -1835,6 +1838,9 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name)
|
||||
out($f,"# define VM_TRACE(op)\n");
|
||||
}
|
||||
out($f,"#endif\n");
|
||||
out($f,"#ifndef VM_TRACE_OP_END\n");
|
||||
out($f,"# define VM_TRACE_OP_END(op)\n");
|
||||
out($f,"#endif\n");
|
||||
out($f,"#ifndef VM_TRACE_START\n");
|
||||
out($f,"# define VM_TRACE_START()\n");
|
||||
out($f,"#endif\n");
|
||||
|
@ -347,3 +347,10 @@ const UPLOAD_ERR_CANT_WRITE = UNKNOWN;
|
||||
* @cvalue PHP_UPLOAD_ERROR_X
|
||||
*/
|
||||
const UPLOAD_ERR_EXTENSION = UNKNOWN;
|
||||
#ifdef ZEND_VERIFY_TYPE_INFERENCE
|
||||
/**
|
||||
* @var bool
|
||||
* @cvalue ZEND_VERIFY_TYPE_INFERENCE
|
||||
*/
|
||||
const ZEND_VERIFY_TYPE_INFERENCE = UNKNOWN;
|
||||
#endif
|
||||
|
5
main/main_arginfo.h
generated
5
main/main_arginfo.h
generated
@ -1,5 +1,5 @@
|
||||
/* This is a generated file, edit the .stub.php file instead.
|
||||
* Stub hash: 9447c185f3098fd2c7806e2f8adf4bf395bb18af */
|
||||
* Stub hash: 2542736c885829255e4226783b60db1453342b65 */
|
||||
|
||||
|
||||
|
||||
@ -96,4 +96,7 @@ static void register_main_symbols(int module_number)
|
||||
REGISTER_LONG_CONSTANT("UPLOAD_ERR_NO_TMP_DIR", PHP_UPLOAD_ERROR_E, CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("UPLOAD_ERR_CANT_WRITE", PHP_UPLOAD_ERROR_F, CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("UPLOAD_ERR_EXTENSION", PHP_UPLOAD_ERROR_X, CONST_PERSISTENT);
|
||||
#if defined(ZEND_VERIFY_TYPE_INFERENCE)
|
||||
REGISTER_BOOL_CONSTANT("ZEND_VERIFY_TYPE_INFERENCE", ZEND_VERIFY_TYPE_INFERENCE, CONST_PERSISTENT);
|
||||
#endif
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user