Add runtime type inference verification

Co-authored-by: Dmitry Stogov <dmitry@zend.com>

Closes GH-12930
This commit is contained in:
Ilija Tovilo 2024-01-09 16:17:24 +01:00
parent bf4ec8bd9d
commit ffc250d245
No known key found for this signature in database
GPG Key ID: A4F5D403F118200A
12 changed files with 1302 additions and 20 deletions

View File

@ -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,

View File

@ -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

View File

@ -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++;
}

View File

@ -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

View File

@ -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)

View File

@ -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
};

View File

@ -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) \

View 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

File diff suppressed because it is too large Load Diff

View File

@ -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");

View File

@ -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
View File

@ -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
}