diff --git a/ext/opcache/jit/zend_jit_ir.c b/ext/opcache/jit/zend_jit_ir.c index cf43d3ad840f..224f6f7237eb 100644 --- a/ext/opcache/jit/zend_jit_ir.c +++ b/ext/opcache/jit/zend_jit_ir.c @@ -4708,7 +4708,7 @@ static struct jit_observer_fcall_is_unobserved_data jit_observer_fcall_is_unobse ir_ref observer_handler_user = ir_ADD_OFFSET(run_time_cache, zend_observer_fcall_op_array_extension * sizeof(void *)); ir_MERGE_WITH(if_internal_func_end); - *observer_handler = ir_PHI_2(IR_ADDR, observer_handler_internal, observer_handler_user); + *observer_handler = ir_PHI_2(IR_ADDR, observer_handler_user, observer_handler_internal); } // JIT: if (*observer_handler == ZEND_OBSERVER_NONE_OBSERVED) { diff --git a/ext/opcache/tests/jit/gh22158.phpt b/ext/opcache/tests/jit/gh22158.phpt new file mode 100644 index 000000000000..ce7f9bc55938 --- /dev/null +++ b/ext/opcache/tests/jit/gh22158.phpt @@ -0,0 +1,33 @@ +--TEST-- +GH-22158 (Tracing JIT dispatches observer begin handler through the wrong run_time_cache slot on megamorphic calls) +--EXTENSIONS-- +opcache +zend_test +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.jit=tracing +opcache.jit_buffer_size=32M +opcache.jit_max_polymorphic_calls=0 +zend_test.observer.enabled=1 +zend_test.observer.observe_all=1 +zend_test.observer.show_output=0 +zend_test.observer.reserve_op_array_handle=1 +--FILE-- +f(); +} +echo $t, "\n"; +?> +--EXPECT-- +600000 diff --git a/ext/pdo_sqlite/pdo_sqlite.c b/ext/pdo_sqlite/pdo_sqlite.c index 0e7e02df46a4..2da9329e2a04 100644 --- a/ext/pdo_sqlite/pdo_sqlite.c +++ b/ext/pdo_sqlite/pdo_sqlite.c @@ -203,7 +203,7 @@ static int php_pdosqlite3_stream_seek(php_stream *stream, zend_off_t offset, int switch(whence) { case SEEK_CUR: if (offset < 0) { - if (sqlite3_stream->position < (size_t)(-offset)) { + if (sqlite3_stream->position < -(size_t)offset) { sqlite3_stream->position = 0; *newoffs = -1; return -1; @@ -241,7 +241,7 @@ static int php_pdosqlite3_stream_seek(php_stream *stream, zend_off_t offset, int sqlite3_stream->position = sqlite3_stream->size; *newoffs = -1; return -1; - } else if (sqlite3_stream->size < (size_t)(-offset)) { + } else if (sqlite3_stream->size < -(size_t)offset) { sqlite3_stream->position = 0; *newoffs = -1; return -1; diff --git a/ext/pdo_sqlite/tests/gh20964.phpt b/ext/pdo_sqlite/tests/gh20964.phpt new file mode 100644 index 000000000000..65070cb1838a --- /dev/null +++ b/ext/pdo_sqlite/tests/gh20964.phpt @@ -0,0 +1,23 @@ +--TEST-- +GH-20964 (fseek() on PDO SQLite blob stream with PHP_INT_MIN causes undefined behavior) +--EXTENSIONS-- +pdo_sqlite +--FILE-- +exec('CREATE TABLE test (id INTEGER PRIMARY KEY, data BLOB)'); +$db->exec("INSERT INTO test (id, data) VALUES (1, 'hello')"); + +$stream = $db->openBlob('test', 'data', 1); + +var_dump(fseek($stream, PHP_INT_MIN, SEEK_END)); + +rewind($stream); +var_dump(fseek($stream, PHP_INT_MIN, SEEK_CUR)); + +fclose($stream); +?> +--EXPECT-- +int(-1) +int(-1) diff --git a/ext/soap/php_http.c b/ext/soap/php_http.c index 1d030caf9d45..e8433e7c4f67 100644 --- a/ext/soap/php_http.c +++ b/ext/soap/php_http.c @@ -1158,12 +1158,12 @@ int make_http_soap_request( zend_string_release_ex(http_headers, 0); zend_string_release_ex(http_body, 0); if (new_uri->scheme == NULL && new_uri->path != NULL) { - new_uri->scheme = new_uri->scheme ? zend_string_copy(new_uri->scheme) : NULL; - new_uri->host = new_uri->host ? zend_string_copy(new_uri->host) : NULL; - new_uri->port = new_uri->port; + new_uri->scheme = uri->scheme ? zend_string_copy(uri->scheme) : NULL; + new_uri->host = uri->host ? zend_string_copy(uri->host) : NULL; + new_uri->port = uri->port; if (new_uri->path && ZSTR_VAL(new_uri->path)[0] != '/') { - if (new_uri->path) { - char *t = ZSTR_VAL(new_uri->path); + if (uri->path) { + char *t = ZSTR_VAL(uri->path); char *p = strrchr(t, '/'); if (p) { zend_string *s = zend_string_concat2(t, (p - t) + 1, ZSTR_VAL(new_uri->path), ZSTR_LEN(new_uri->path)); diff --git a/ext/soap/tests/bugs/relative_redirect.phpt b/ext/soap/tests/bugs/relative_redirect.phpt new file mode 100644 index 000000000000..774e7cbd98d7 --- /dev/null +++ b/ext/soap/tests/bugs/relative_redirect.phpt @@ -0,0 +1,49 @@ +--TEST-- +SOAP client follows a redirect with a scheme-less (relative) Location +--EXTENSIONS-- +soap +--SKIPIF-- + +--FILE-- +', + '', + 'ok', + ''; +} else { + http_response_code(302); + header("Location: /redirected"); +} +PHP; + +php_cli_server_start($code, null, $args); + +$client = new SoapClient(null, [ + 'location' => 'http://' . PHP_CLI_SERVER_ADDRESS . '/start', + 'uri' => 'test-uri', +]); + +try { + $client->__soapCall("foo", []); + echo "redirect followed\n"; +} catch (SoapFault $e) { + echo "SoapFault: " . $e->getMessage() . "\n"; +} +?> +--EXPECT-- +redirect followed diff --git a/ext/soap/tests/bugs/relative_redirect_path.phpt b/ext/soap/tests/bugs/relative_redirect_path.phpt new file mode 100644 index 000000000000..09d4c857cc92 --- /dev/null +++ b/ext/soap/tests/bugs/relative_redirect_path.phpt @@ -0,0 +1,49 @@ +--TEST-- +SOAP client follows a redirect with a relative Location resolved against the request path +--EXTENSIONS-- +soap +--SKIPIF-- + +--FILE-- +', + '', + 'ok', + ''; +} else { + http_response_code(302); + header("Location: redirected"); +} +PHP; + +php_cli_server_start($code, null, $args); + +$client = new SoapClient(null, [ + 'location' => 'http://' . PHP_CLI_SERVER_ADDRESS . '/svc/start', + 'uri' => 'test-uri', +]); + +try { + $client->__soapCall("foo", []); + echo "redirect followed\n"; +} catch (SoapFault $e) { + echo "SoapFault: " . $e->getMessage() . "\n"; +} +?> +--EXPECT-- +redirect followed diff --git a/ext/sqlite3/sqlite3.c b/ext/sqlite3/sqlite3.c index bef568a62dfd..67ff850cadd0 100644 --- a/ext/sqlite3/sqlite3.c +++ b/ext/sqlite3/sqlite3.c @@ -1158,7 +1158,7 @@ static int php_sqlite3_stream_seek(php_stream *stream, zend_off_t offset, int wh switch(whence) { case SEEK_CUR: if (offset < 0) { - if (sqlite3_stream->position < (size_t)(-offset)) { + if (sqlite3_stream->position < -(size_t)offset) { sqlite3_stream->position = 0; *newoffs = -1; return -1; @@ -1199,7 +1199,7 @@ static int php_sqlite3_stream_seek(php_stream *stream, zend_off_t offset, int wh sqlite3_stream->position = sqlite3_stream->size; *newoffs = -1; return -1; - } else if (sqlite3_stream->size < (size_t)(-offset)) { + } else if (sqlite3_stream->size < -(size_t)offset) { sqlite3_stream->position = 0; *newoffs = -1; return -1; diff --git a/ext/sqlite3/tests/gh20964.phpt b/ext/sqlite3/tests/gh20964.phpt new file mode 100644 index 000000000000..852940ba983e --- /dev/null +++ b/ext/sqlite3/tests/gh20964.phpt @@ -0,0 +1,24 @@ +--TEST-- +GH-20964 (fseek() on SQLite3 blob stream with PHP_INT_MIN causes undefined behavior) +--EXTENSIONS-- +sqlite3 +--FILE-- +exec('CREATE TABLE test (id INTEGER PRIMARY KEY, data BLOB)'); +$db->exec("INSERT INTO test (id, data) VALUES (1, 'hello')"); + +$stream = $db->openBlob('test', 'data', 1); + +var_dump(fseek($stream, PHP_INT_MIN, SEEK_END)); + +rewind($stream); +var_dump(fseek($stream, PHP_INT_MIN, SEEK_CUR)); + +fclose($stream); +$db->close(); +?> +--EXPECT-- +int(-1) +int(-1) diff --git a/ext/zend_test/observer.c b/ext/zend_test/observer.c index 8883a9d1dfb6..2fd4073b4af0 100644 --- a/ext/zend_test/observer.c +++ b/ext/zend_test/observer.c @@ -14,6 +14,7 @@ #include "php_test.h" #include "observer.h" #include "zend_observer.h" +#include "zend_extensions.h" #include "zend_smart_str.h" #include "ext/standard/php_var.h" #include "zend_generators.h" @@ -398,6 +399,7 @@ PHP_INI_BEGIN() STD_PHP_INI_BOOLEAN("zend_test.observer.fiber_switch", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_fiber_switch, zend_zend_test_globals, zend_test_globals) STD_PHP_INI_BOOLEAN("zend_test.observer.fiber_destroy", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_fiber_destroy, zend_zend_test_globals, zend_test_globals) STD_PHP_INI_BOOLEAN("zend_test.observer.execute_internal", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_execute_internal, zend_zend_test_globals, zend_test_globals) + STD_PHP_INI_BOOLEAN("zend_test.observer.reserve_op_array_handle", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_reserve_op_array_handle, zend_zend_test_globals, zend_test_globals) PHP_INI_END() void zend_test_observer_init(INIT_FUNC_ARGS) @@ -406,6 +408,9 @@ void zend_test_observer_init(INIT_FUNC_ARGS) if (type != MODULE_TEMPORARY) { REGISTER_INI_ENTRIES(); if (ZT_G(observer_enabled)) { + if (ZT_G(observer_reserve_op_array_handle)) { + zend_get_op_array_extension_handle("zend_test"); + } zend_observer_fcall_register(observer_fcall_init); } } else { diff --git a/ext/zend_test/php_test.h b/ext/zend_test/php_test.h index 65b04856eb31..eb6ef6181c48 100644 --- a/ext/zend_test/php_test.h +++ b/ext/zend_test/php_test.h @@ -47,6 +47,7 @@ ZEND_BEGIN_MODULE_GLOBALS(zend_test) int observer_fiber_switch; int observer_fiber_destroy; int observer_execute_internal; + int observer_reserve_op_array_handle; HashTable *global_weakmap; int replace_zend_execute_ex; int register_passes; diff --git a/main/streams/memory.c b/main/streams/memory.c index af54c46dd9ad..1cc1886e609d 100644 --- a/main/streams/memory.c +++ b/main/streams/memory.c @@ -126,7 +126,7 @@ static int php_stream_memory_seek(php_stream *stream, zend_off_t offset, int whe switch(whence) { case SEEK_CUR: if (offset < 0) { - if (ms->fpos < (size_t)(-offset)) { + if (ms->fpos < -(size_t)offset) { ms->fpos = 0; *newoffs = -1; return -1; @@ -163,7 +163,7 @@ static int php_stream_memory_seek(php_stream *stream, zend_off_t offset, int whe stream->eof = 0; stream->fatal_error = 0; return 0; - } else if (ZSTR_LEN(ms->data) < (size_t)(-offset)) { + } else if (ZSTR_LEN(ms->data) < -(size_t)offset) { ms->fpos = 0; *newoffs = -1; return -1; diff --git a/tests/basic/gh20964.phpt b/tests/basic/gh20964.phpt new file mode 100644 index 000000000000..2a97164c7924 --- /dev/null +++ b/tests/basic/gh20964.phpt @@ -0,0 +1,22 @@ +--TEST-- +GH-20964 (fseek() on php://memory with PHP_INT_MIN causes undefined behavior) +--FILE-- + +--EXPECT-- +int(-1) +bool(false) +int(-1) +bool(false)