Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
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
4 changes: 4 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,8 @@ PHP NEWS
. Fixed bug GH-19926 (reset internal pointer earlier while splicing array
while COW violation flag is still set). (alexandre-daubois)

- Zip:
. Fixed ZipArchive callback being called after executor has shut down.
(ilutov)

<<< NOTE: Insert NEWS from last stable release here prior to actual release! >>>
46 changes: 46 additions & 0 deletions Zend/tests/gh19844.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
--TEST--
GH-19844: Bail from stream_close() in zend_shutdown_executor_values()
--SKIPIF--
<?php
if (substr(PHP_OS, 0, 3) == 'WIN') die('skip Aborts with STATUS_BAD_FUNCTION_TABLE on Windows');
?>
--FILE--
<?php

class Test {
public $context;
private static $nested = false;

function stream_open() {
return true;
}

function stream_read() {
return '.';
}
function stream_set_option() {}
function stream_stat() {}

function stream_eof() {
if (!Test::$nested) {
Test::$nested = true;
include 'Test://';
}
@trigger_error('Bail', E_USER_ERROR);
}

function stream_close() {
@trigger_error('Bail', E_USER_ERROR);
}
}

stream_wrapper_register('Test', Test::class);
include 'Test://';

?>
--EXPECTF--
Fatal error: Bail in %s on line %d

Fatal error: Bail in %s on line %d

Fatal error: Bail in %s on line %d
4 changes: 1 addition & 3 deletions Zend/zend_execute_API.c
Original file line number Diff line number Diff line change
Expand Up @@ -273,9 +273,7 @@ void shutdown_destructors(void) /* {{{ */
ZEND_API void zend_shutdown_executor_values(bool fast_shutdown)
{
EG(flags) |= EG_FLAGS_IN_RESOURCE_SHUTDOWN;
zend_try {
zend_close_rsrc_list(&EG(regular_list));
} zend_end_try();
zend_close_rsrc_list(&EG(regular_list));

/* No PHP callback functions should be called after this point. */
EG(active) = 0;
Expand Down
24 changes: 17 additions & 7 deletions Zend/zend_list.c
Original file line number Diff line number Diff line change
Expand Up @@ -217,15 +217,25 @@ void zend_close_rsrc_list(HashTable *ht)
/* Reload ht->arData on each iteration, as it may be reallocated. */
uint32_t i = ht->nNumUsed;

while (i-- > 0) {
zval *p = ZEND_HASH_ELEMENT(ht, i);
if (Z_TYPE_P(p) != IS_UNDEF) {
zend_resource *res = Z_PTR_P(p);
if (res->type >= 0) {
zend_resource_dtor(res);
retry:
zend_try {
while (i-- > 0) {
zval *p = ZEND_HASH_ELEMENT(ht, i);
if (Z_TYPE_P(p) != IS_UNDEF) {
zend_resource *res = Z_PTR_P(p);
if (res->type >= 0) {
zend_resource_dtor(res);
}
}
}
}
} zend_catch {
/* If we have bailed, we probably executed user code (e.g. user stream
* API). Keep closing resources so they don't leak. User handlers must be
* called now so they aren't called in zend_deactivate() on
* zend_destroy_rsrc_list(&EG(regular_list)). At that point, the executor
* has already shut down and the process would crash. */
goto retry;
} zend_end_try();
}


Expand Down
10 changes: 10 additions & 0 deletions ext/libxml/libxml.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
#ifdef LIBXML_SCHEMAS_ENABLED
#include <libxml/relaxng.h>
#include <libxml/xmlschemas.h>
#include <libxml/xmlschemastypes.h>
#endif

#include "php_libxml.h"
Expand Down Expand Up @@ -928,7 +929,16 @@ PHP_LIBXML_API void php_libxml_initialize(void)
if (!php_libxml_initialized) {
/* we should be the only one's to ever init!! */
ZEND_IGNORE_LEAKS_BEGIN();

xmlInitParser();
#ifdef ZTS
# ifdef LIBXML_SCHEMAS_ENABLED
xmlSchemaInitTypes();
# endif
# ifdef LIBXML_RELAXNG_ENABLED
xmlRelaxNGInitTypes();
# endif
#endif
ZEND_IGNORE_LEAKS_END();

php_libxml_default_entity_loader = xmlGetExternalEntityLoader();
Expand Down
2 changes: 2 additions & 0 deletions ext/opcache/jit/ir/ir.h
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,8 @@ typedef enum _ir_type {
_(UGE, d2, def, def, ___) /* unsigned greater or equal */ \
_(ULE, d2, def, def, ___) /* unsigned less or equal */ \
_(UGT, d2, def, def, ___) /* unsigned greater */ \
_(ORDERED, d2, def, def, ___) /* both operands are not NAN */ \
_(UNORDERED, d2, def, def, ___) /* one of operands is NAN */ \
\
/* arithmetic ops */ \
_(ADD, d2C, def, def, ___) /* addition */ \
Expand Down
64 changes: 44 additions & 20 deletions ext/opcache/jit/ir/ir_aarch64.dasc
Original file line number Diff line number Diff line change
Expand Up @@ -747,6 +747,9 @@ static uint32_t ir_match_insn(ir_ctx *ctx, ir_ref ref)
return IR_CMP_FP;
}
break;
case IR_ORDERED:
case IR_UNORDERED:
return IR_CMP_FP;
case IR_ADD:
case IR_SUB:
if (IR_IS_TYPE_INT(insn->type)) {
Expand Down Expand Up @@ -1043,7 +1046,7 @@ binop_fp:
case IR_IF:
if (!IR_IS_CONST_REF(insn->op2) && ctx->use_lists[insn->op2].count == 1) {
op2_insn = &ctx->ir_base[insn->op2];
if (op2_insn->op >= IR_EQ && op2_insn->op <= IR_UGT) {
if (op2_insn->op >= IR_EQ && op2_insn->op <= IR_UNORDERED) {
if (IR_IS_TYPE_INT(ctx->ir_base[op2_insn->op1].type)) {
ctx->rules[insn->op2] = IR_FUSED | IR_CMP_INT;
return IR_CMP_AND_BRANCH_INT;
Expand All @@ -1066,7 +1069,7 @@ binop_fp:
case IR_GUARD_NOT:
if (!IR_IS_CONST_REF(insn->op2) && ctx->use_lists[insn->op2].count == 1) {
op2_insn = &ctx->ir_base[insn->op2];
if (op2_insn->op >= IR_EQ && op2_insn->op <= IR_UGT
if (op2_insn->op >= IR_EQ && op2_insn->op <= IR_UNORDERED
// TODO: register allocator may clobber operands of CMP before they are used in the GUARD_CMP
&& (insn->op2 == ref - 1 ||
(insn->op2 == ctx->prev_ref[ref] - 1
Expand Down Expand Up @@ -1110,6 +1113,9 @@ binop_fp:
ctx->flags2 |= IR_HAS_VA_ARG_GP|IR_HAS_VA_ARG_FP;
}
}
} else {
/* va_list may escape */
ctx->flags2 |= IR_HAS_VA_ARG_GP|IR_HAS_VA_ARG_FP;
}
return IR_VA_START;
case IR_VA_END:
Expand Down Expand Up @@ -2991,6 +2997,12 @@ static void ir_emit_cmp_fp(ir_ctx *ctx, ir_ref def, ir_insn *insn)
case IR_UGT:
| cset Rw(def_reg), hi
break;
case IR_ORDERED:
| cset Rw(def_reg), vc
break;
case IR_UNORDERED:
| cset Rw(def_reg), vs
break;
}
if (IR_REG_SPILLED(ctx->regs[def][0])) {
ir_emit_store(ctx, insn->type, def, def_reg);
Expand Down Expand Up @@ -3065,7 +3077,7 @@ static void ir_emit_jcc(ir_ctx *ctx, uint32_t b, ir_ref def, ir_insn *insn, uint
ir_get_true_false_blocks(ctx, b, &true_block, &false_block);
if (true_block == next_block) {
/* swap to avoid unconditional JMP */
if (int_cmp || op == IR_EQ || op == IR_NE) {
if (int_cmp || op == IR_EQ || op == IR_NE || op == IR_ORDERED || op == IR_UNORDERED) {
op ^= 1; // reverse
} else {
op ^= 5; // reverse
Expand Down Expand Up @@ -3145,6 +3157,11 @@ static void ir_emit_jcc(ir_ctx *ctx, uint32_t b, ir_ref def, ir_insn *insn, uint
case IR_UGT:
| bhi =>true_block
break;
case IR_ORDERED:
| bvc =>true_block
break;
case IR_UNORDERED:
| bvs =>true_block
// case IR_ULT: fprintf(stderr, "\tjb .LL%d\n", true_block); break;
// case IR_UGE: fprintf(stderr, "\tjae .LL%d\n", true_block); break;
// case IR_ULE: fprintf(stderr, "\tjbe .LL%d\n", true_block); break;
Expand Down Expand Up @@ -4462,11 +4479,7 @@ static void ir_emit_va_arg(ir_ctx *ctx, ir_ref def, ir_insn *insn)
ir_reg tmp_reg = ctx->regs[def][3];
int32_t offset;

if (ctx->use_lists[def].count == 1) {
/* dead load */
return;
}
IR_ASSERT(def_reg != IR_REG_NONE && tmp_reg != IR_REG_NONE);
IR_ASSERT((def_reg != IR_REG_NONE || ctx->use_lists[def].count == 1) && tmp_reg != IR_REG_NONE);
if (op2_reg != IR_REG_NONE) {
if (IR_REG_SPILLED(op2_reg)) {
op2_reg = IR_REG_NUM(op2_reg);
Expand All @@ -4479,10 +4492,12 @@ static void ir_emit_va_arg(ir_ctx *ctx, ir_ref def, ir_insn *insn)
offset = ir_local_offset(ctx, &ctx->ir_base[insn->op2]);
}
| ldr Rx(tmp_reg), [Rx(op2_reg), #offset]
ir_emit_load_mem(ctx, type, def_reg, IR_MEM_BO(tmp_reg, 0));
if (def_reg != IR_REG_NONE) {
ir_emit_load_mem(ctx, type, def_reg, IR_MEM_BO(tmp_reg, 0));
}
| add Rx(tmp_reg), Rx(tmp_reg), #IR_MAX(ir_type_size[type], sizeof(void*))
| str Rx(tmp_reg), [Rx(op2_reg), #offset]
if (IR_REG_SPILLED(ctx->regs[def][0])) {
if (def_reg != IR_REG_NONE && IR_REG_SPILLED(ctx->regs[def][0])) {
ir_emit_store(ctx, type, def, def_reg);
}
#else
Expand All @@ -4494,11 +4509,7 @@ static void ir_emit_va_arg(ir_ctx *ctx, ir_ref def, ir_insn *insn)
ir_reg tmp_reg = ctx->regs[def][3];
int32_t offset;

if (ctx->use_lists[def].count == 1) {
/* dead load */
return;
}
IR_ASSERT(def_reg != IR_REG_NONE && tmp_reg != IR_REG_NONE);
IR_ASSERT((def_reg != IR_REG_NONE || ctx->use_lists[def].count == 1) && tmp_reg != IR_REG_NONE);
if (op2_reg != IR_REG_NONE) {
if (IR_REG_SPILLED(op2_reg)) {
op2_reg = IR_REG_NUM(op2_reg);
Expand All @@ -4517,13 +4528,17 @@ static void ir_emit_va_arg(ir_ctx *ctx, ir_ref def, ir_insn *insn)
| ldr Rx(IR_REG_INT_TMP), [Rx(op2_reg), #(offset+offsetof(ir_va_list, gr_top))]
| sxtw Rx(tmp_reg), Rw(tmp_reg)
| add Rx(IR_REG_INT_TMP), Rx(tmp_reg), Rx(IR_REG_INT_TMP)
| ldr Rx(def_reg), [Rx(IR_REG_INT_TMP)]
if (def_reg != IR_REG_NONE) {
| ldr Rx(def_reg), [Rx(IR_REG_INT_TMP)]
}
| add Rw(tmp_reg), Rw(tmp_reg), #sizeof(void*)
| str Rw(tmp_reg), [Rx(op2_reg), #(offset+offsetof(ir_va_list, gr_offset))]
| b >2
|1:
| ldr Rx(tmp_reg), [Rx(op2_reg), #(offset+offsetof(ir_va_list, stack))]
| ldr Rx(def_reg), [Rx(tmp_reg)]
if (def_reg != IR_REG_NONE) {
| ldr Rx(def_reg), [Rx(tmp_reg)]
}
| add Rx(tmp_reg), Rx(tmp_reg), #sizeof(void*)
| str Rx(tmp_reg), [Rx(op2_reg), #(offset+offsetof(ir_va_list, stack))]
|2:
Expand All @@ -4534,18 +4549,22 @@ static void ir_emit_va_arg(ir_ctx *ctx, ir_ref def, ir_insn *insn)
| ldr Rx(IR_REG_INT_TMP), [Rx(op2_reg), #(offset+offsetof(ir_va_list, vr_top))]
| sxtw Rx(tmp_reg), Rw(tmp_reg)
| add Rx(IR_REG_INT_TMP), Rx(tmp_reg), Rx(IR_REG_INT_TMP)
| ldr Rd(def_reg-IR_REG_FP_FIRST), [Rx(IR_REG_INT_TMP)]
if (def_reg != IR_REG_NONE) {
| ldr Rd(def_reg-IR_REG_FP_FIRST), [Rx(IR_REG_INT_TMP)]
}
| add Rw(tmp_reg), Rw(tmp_reg), #16
| str Rw(tmp_reg), [Rx(op2_reg), #(offset+offsetof(ir_va_list, vr_offset))]
| b >2
|1:
| ldr Rx(tmp_reg), [Rx(op2_reg), #(offset+offsetof(ir_va_list, stack))]
| ldr Rd(def_reg-IR_REG_FP_FIRST), [Rx(tmp_reg)]
if (def_reg != IR_REG_NONE) {
| ldr Rd(def_reg-IR_REG_FP_FIRST), [Rx(tmp_reg)]
}
| add Rx(tmp_reg), Rx(tmp_reg), #sizeof(void*)
| str Rx(tmp_reg), [Rx(op2_reg), #(offset+offsetof(ir_va_list, stack))]
|2:
}
if (IR_REG_SPILLED(ctx->regs[def][0])) {
if (def_reg != IR_REG_NONE && IR_REG_SPILLED(ctx->regs[def][0])) {
ir_emit_store(ctx, type, def, def_reg);
}
#endif
Expand Down Expand Up @@ -5378,6 +5397,11 @@ static void ir_emit_guard_jcc(ir_ctx *ctx, uint8_t op, void *addr, bool int_cmp)
case IR_GT:
| bgt &addr
break;
case IR_ORDERED:
| bvc &addr
break;
case IR_UNORDERED:
| bvs &addr
// case IR_ULT: fprintf(stderr, "\tjb .LL%d\n", true_block); break;
// case IR_UGE: fprintf(stderr, "\tjae .LL%d\n", true_block); break;
// case IR_ULE: fprintf(stderr, "\tjbe .LL%d\n", true_block); break;
Expand Down
1 change: 1 addition & 0 deletions ext/opcache/jit/ir/ir_check.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ void ir_consistency_check(void)
IR_ASSERT((IR_UGT ^ 3) == IR_ULT);
IR_ASSERT((IR_ULE ^ 3) == IR_UGE);
IR_ASSERT((IR_UGE ^ 3) == IR_ULE);
IR_ASSERT((IR_ORDERED ^ 1) == IR_UNORDERED);

IR_ASSERT(IR_ADD + 1 == IR_SUB);
}
Expand Down
Loading