Compare commits

...
73 Commits
Author SHA1 Message Date
Derick Rethans 52e517a4b6 Update versions for PHP 7.4.19 2021-05-04 11:06:31 +00:00
Derick Rethans 4c0231ebc3 Update NEWS for PHP 7.4.19 2021-05-04 11:06:31 +00:00
Derick Rethans d5cb73e7df Prepare for a potential 7.4.19 from this branch 2021-05-04 11:56:43 +01:00
Matteo Beccati 8ab932d774 Revert "Fix #80892: PDO::PARAM_INT is treated the same as PDO::PARAM_STR"
This reverts commit 340a06778c.
2021-05-04 11:55:47 +01:00
Derick Rethans 13389613fa Update NEWS for PHP 7.4.18 2021-04-27 14:35:40 +00:00
Derick Rethans f98f4875df Prepare for 7.4.18 2021-04-27 15:33:01 +01:00
Christoph M. Becker b1680c5fe3 Fix #80710: imap_mail_compose() header injection
Like `mail()` and `mb_send_mail()`, `imap_mail_compose()` must prevent
header injection.  For maximum backward compatibility, we still allow
header folding for general headers, and still accept trailing line
breaks for address lists.
2021-04-27 15:29:59 +01:00
Derick Rethans 8cb114413f Put back inadvertedly removed NEWS entries 2021-04-13 11:49:36 +01:00
Derick Rethans 1e0f53278d Update NEWS for PHP 7.4.18RC1 2021-04-13 10:24:25 +00:00
Derick Rethans d4f7e8cedc Prepare NEWS for 7.4.18RC1 2021-04-13 10:00:45 +01:00
Nikita Popov a1fdfa700b Fixed bug #80950
Function info for curl_exec() incorrect specified that the
function cannot return true. This is already fixed in PHP 8,
as the func info entry was removed there.
2021-04-12 16:05:37 +02:00
Christoph M. Becker 0a36d417e8 Fix #79812: Potential integer overflow in pcntl_exec()
We use the proper type, and make sure that no overflow can occur by
using `safe_emalloc()` (we can assume that neither string length is
`SIZE_MAX`).

Closes GH-6845.
2021-04-12 12:12:40 +02:00
David Carlier a04fac84e7 Disable ifunc support on openbsd
Enabling it leads to segfault when resolvers are used e.g.
php_stripslashes.

Closes GH-6851.
2021-04-12 11:27:50 +02:00
fishmore 600402d986 Update zend_alloc.c
Don't free main thunk.  It will crash.
2021-04-12 09:28:24 +03:00
Matteo Beccati 340a06778c Fix #80892: PDO::PARAM_INT is treated the same as PDO::PARAM_STR 2021-04-12 08:03:07 +02:00
Matteo Beccati da3a807f22 Increased test compatibility
The test expects no masked signals at the beginning, but when run as part
of a Bamboo build, SIGQUIT is already masked and the test fails.
2021-04-11 17:19:58 +02:00
Nikita Popov 454d297564 Fix gidlist allocation leak on error 2021-04-11 10:37:40 +02:00
Dmitry Stogov 7a8ffcec7d Fixed type inference for OP_DATA 2021-04-09 14:52:55 +03:00
Nikita Popov 29fa4d203a Don't mark non-refcounted phi as live
If the value is not refcounted, then it doesn't matter if the
FREE gets dropped.
2021-04-08 18:20:09 +02:00
Nikita Popov 0826a54836 Fix DCE of FREE of COALESCE
When encountering the following SSA graph:

    BB1:
    #2.T1 [string] = COALESCE #1.CV0($str) [null, string] BB2

    BB2:
    #5.T1 [string] = QM_ASSIGN string("")

    BB3:
    #7.X1 [string] = Phi(#2.X1 [string], #5.X1 [string])
    FREE #7.T1 [string]

We would currently determine that #7, #5 are dead, and eliminate
the FREE and QM_ASSIGN. However, we cannot eliminate #2, as
COALESCE is also responsible for control flow.

Fix this my marking all non-CV phis as live to start with. This
can be relaxed to check the kind of the source instruction, but
I couldn't immediately come up with a case where it would be
useful.
2021-04-08 17:01:13 +02:00
Remi Collet 25f5a1b2e1 Improve fix for #80783 2021-04-08 15:28:03 +02:00
Nikita Popov eebcfeb68e Support more than NGROUPS_MAX groups on macos
I suspect this is the cause for our recent CI failures. Apparently,
on macos it is possible for getgroups() to return more than
NGROUPS_MAX groups. We avoid an EINVAL in that case by fetching
the exact number of groups in advance. This should work on both
macos and posix systems.
2021-04-08 12:23:39 +02:00
Christoph M. Becker 0a181ca27a Update version in main/php_version.h as well
Otherwise the file is modified by each new build, what is confusing.
2021-04-07 12:45:21 +02:00
Christoph M. Becker 9688071679 Fix #80880: SSL_read on shutdown, ftp/proc_open
When `SSL_read()` after `SSL_shutdown()` fails with `SSL_ERROR_SYSCALL`,
we should not warn about this, because it is likely caused by the peer
having closed the connection without having sent a close_notify
shutdown alert.

Signed-off-by: Christoph M. Becker <cmbecker69@gmx.de>

Closes GH-6803.
2021-04-06 14:03:19 +02:00
Dylan K. Taylor 50f476591f .gdbinit: make zbacktrace show the correct stack when switching threads
I found this mainly to be a problem when working with threading
extensions. zbacktrace doesn't show the correct stack when switching
threads.

Closes GH-6814.
2021-04-05 21:10:52 +02:00
Dmitry Stogov 39d8fc1edc Changed PowerPC CPU registers used by Zend VM to work around GCC bug.
Old registers (r28/r29) might be clobbered by _restgpr routine used for return from C function compiled with -Os.
2021-03-31 13:10:21 +03:00
Rowan Tommins 206fd35a98 Handle reference zvals when outputting superglobals in phpinfo()
Fixes <https://bugs.php.net/80915>.

Closes GH-80915.

Signed-off-by: Christoph M. Becker <cmbecker69@gmx.de>
2021-03-30 13:49:22 +02:00
Christoph M. Becker 75cb678206 Fix #69668: SOAP special XML characters in namespace URIs not encoded
`xmlNewNs()` does not XML encode the passed `href`, so we need to do
that manually.

Closes GH-6804.

Signed-off-by: Christoph M. Becker <cmbecker69@gmx.de>
2021-03-29 14:17:55 +02:00
Christoph M. Becker 498eb8e052 Fix #73533: Invalid memory access in php_libxml_xmlCheckUTF8
A string passed to `php_libxml_xmlCheckUTF8()` may be longer than
1<<31-1 bytes, so we're better using a `size_t`.

Closes GH-6802.
2021-03-24 11:50:50 +01:00
Christoph M. Becker 688e56d0ac Properly initialize PS(mod) on RINIT
We need to do that in case a user handler has been set.  However, we
can't do that in `php_rinit_session_globals()` since that function is
called by PHP function `session_destroy()` too, but in that case we
don't want to reset PS(mod).

Closes GH-6795.
2021-03-23 13:12:19 +01:00
Christoph M. Becker 838951c2d6 Fix #80889: amendment
`session_set_save_handler()` may be called with callables instead of an
object; we need to cater to that as well.

We also extract a set_user_save_handler_ini() function to avoid code
duplication.

Closes GH-6796.
2021-03-22 22:17:35 +01:00
Jakub Zelenka bc7ea73da5 Use ServerClientTestCase in a test for default_socket_timeout=-1 2021-03-21 21:19:40 +00:00
Jakub Zelenka 538f95b1b7 Fix NEWS entry position for the latest FPM fix 2021-03-21 18:58:57 +00:00
Jakub Zelenka c483b59124 Fix bug #80024: Duplication of info about inherited socket after pool removing 2021-03-21 18:52:07 +00:00
Christoph M. Becker 06bfada99b Fix #80889: Cannot set save handler when save_handler is invalid
There is no need to require a (valid) save_handler to be set, when a
user handler is supposed to be set.  We just have to make sure, that
no user handler is already set in this case.

Closes GH-6788.
2021-03-19 16:59:54 +01:00
Christoph M. Becker bccca0b53a Fix #80783: PDO ODBC truncates BLOB records at every 256th byte
It is not guaranteed, that the driver inserts only a single NUL byte at
the end of the buffer.  Apparently, there is no way to find out the
actual data length in the buffer after calling `SQLGetData()`, so we
adjust after the next `SQLGetData()` call.

We also prevent PDO::ODBC_ATTR_ASSUME_UTF8 from fetching garbage, by
fetching all chunks with the same C type.

Closes GH-6716.
2021-03-18 15:13:27 +01:00
Nikita Popov 4be867e910 Fix locale switch back to C in pcre
The compile context is shared between patterns, so we need to set
the character tables unconditionally in case we switched from
a non-C locale to the C locale.
2021-03-18 10:48:43 +01:00
Christoph M. Becker a08847ab39 Fix #66783: UAF when appending DOMDocument to element
According to the DOM standard, elements may only contain element, text,
processing instruction and comment nodes[1].  It is also specified that
a HierarchyRequestError should be thrown if a document is to be
inserted[2].  We follow that standard, and prevent the use-after-free
this way.

[1] <https://dom.spec.whatwg.org/#node-trees>
[2] <https://dom.spec.whatwg.org/#mutation-algorithms>

Closes GH-6765.
2021-03-17 12:37:18 +01:00
Derick Rethans 4adc08a403 Fix build version too 2021-03-16 09:41:21 +00:00
Derick Rethans 5e4ee3d0bd NEWS for 7.4.18 2021-03-16 09:40:05 +00:00
Derick Rethans eb1d1fe373 Prepare for 7.4.17RC1 2021-03-16 09:33:33 +00:00
Christoph M. Becker f448b0e6dd Fix #80817: dba_popen() may cause segfault during RSHUTDOWN
We need to close persistent streams with the proper flag.
2021-03-15 18:37:44 +01:00
Dharman 282355efd5 Fix bug #80866
Closes GH-6774.
2021-03-15 14:47:45 +01:00
Dharman c93b461ad7 Fix bug #80837
The error needs to be reported on the statement, not the connection.
2021-03-15 14:38:09 +01:00
Nikita Popov fc4cd598a2 Update ubuntu on i386 job
There is a failure with apt on PHP-7.4 that's not present on
PHP-8.0/master. Switching to a newer ubuntu version on PHP-7.4
avoids the issue.
2021-03-15 14:11:19 +01:00
Nikita Popov 703bbf5210 Downgrade security level in tests using TLS < 1.2
A few additional tests have been added on master that require
lower security level.

(cherry picked from commit c2a6395dcb)
2021-03-15 14:11:12 +01:00
Christoph M. BeckerandMichael Wallner f901bec494 Fix #51903: simplexml_load_file() doesn't use HTTP headers
The `encoding` attribute of the XML declaration is optional; it is good
practice to use external encoding information where available if it is
missing.  Thus, we check for `charset` info of `Content-Type` headers,
and see whether the encoding is supported.

We cater to trailing parameters and quoted-strings, but not to escaped
backslashes and quotes in quoted-strings, since no known character
encoding contains these anyway.

Co-authored-by: Michael Wallner <mike@php.net>

Closes GH-6747.
2021-03-08 15:07:01 +01:00
manuel 5787f91c55 Fix #80838: HTTP wrapper waits for HTTP 1 response after HTTP 101
Don't wait for further responses after a HTTP 101 (Switching Protocols) response

Closes GH-6730.
2021-03-08 14:36:31 +01:00
George Wang 8fc0bdfb0a Merge branch 'PHP-7.4' of git.php.net:php-src into PHP-7.4 2021-03-05 10:57:46 -05:00
George Wang 797edd6211 LiteSpeed SAPI v7.9: Process manager keeps forked child process alive for longer time based on load. Reduces PM overhead for busy setup. 2021-03-05 10:46:12 -05:00
Christoph M. Becker e0e167e581 Print error code if CreateMutex() fails
This issue came up recently in a bug report[1]; without the error code,
users can barely guess why the function failed.

[1] <https://bugs.php.net/80812>

Closes GH-6745.
2021-03-05 15:06:18 +01:00
Christoph M. Becker 51e2015af3 Fix #78719: http wrapper silently ignores long Location headers
When opening HTTP streams, and reading the headers, we currently
discard header lines longer than `HTTP_HEADER_BLOCK_SIZE` (1024 bytes).
While this is not generally forbidden by RFC 7230, section 3.2.5, it
is not generally allowed either, since that may change the "message
framing or response semantics".

We thus fix this by allowing arbitrarily long header lines.

Closes GH-6720.
2021-03-03 10:45:25 +01:00
Christoph M. BeckerandNikita Popov 71297a254b Fix #80751: Comma in recipient name breaks email delivery
So far, `SendText()` simply separates potential email address lists at
any comma, disregarding that commas inside a quoted-string do not
delimit addresses.  We fix that by introducing an own variant of
`strtok_r()` which caters to quoted-strings.

We also make `FormatEmailAddress()` aware of quoted strings.

We do not cater to email address comments, and potentially other quirks
of RFC 5322 email addresses, but catering to quoted-strings is supposed
to solve almost all practical use cases.

Co-authored-by: Nikita Popov <nikita.ppv@gmail.com>

Closes GH-6735.
2021-03-01 18:46:21 +01:00
Nikita Popov 2c508c4d40 Always remove HT iterators, even for uninit HT
Fixes oss-fuzz #31423.
2021-03-01 16:22:11 +01:00
Nikita Popov e857936518 Fixed bug #80805
Handle missing result_var in binary_op_result_type.

(cherry picked from commit 8446e28275)
2021-03-01 15:13:15 +01:00
Felipe Pena 988c3f9659 Fix memleak on ReflectionFunction and ReflectionGenerator classes when calling __construct after instantiation 2021-02-25 20:53:14 +00:00
Remi Collet ae0585c98e skip test with openssl < 1.1.0
The test fails, but without any crash
(this test is designed to catch a crash)
2021-02-25 13:52:35 +01:00
Dylan K. Taylor a480bf8093 Capture Microsoft-defined HRESULT exit codes exit codes
The lack of such a check leads to false-passes of tests on Windows
which expect no output, but produce a segfault or similar issue. I
discovered this a while ago due to bad tests in an extension I maintain.

Closes GH-6722.
2021-02-25 12:01:04 +01:00
Daniel Black 8309c04464 mysqlnd pam fix test error message
Closes GH-6727.
2021-02-25 09:51:51 +01:00
Nikita Popov 766f827e26 Fix potential file collision in dom tests 2021-02-24 21:30:20 +01:00
Felipe Pena 3ec37a74a2 Fix bug #80757 (Exit code is 0 when could not open file) 2021-02-24 18:50:27 +00:00
Felipe Pena 78b0a85de6 Update NEWS 2021-02-24 18:40:32 +00:00
Christoph M. Becker 67bb06cc9b Merge branch 'PHP-7.3' into PHP-7.4
* PHP-7.3:
  run-tests: fixed exit code not being set on BORKED tests
2021-02-23 13:15:30 +01:00
Dylan K. Taylor 729cd8bacd run-tests: fixed exit code not being set on BORKED tests
When no test paths are specified this shows up when 'make test' is used on a PECL extension without specifying tests to run (or in php-src too, I guess...)

Closes GH-6717.
2021-02-23 12:50:03 +01:00
Christoph M. Becker 81396ea890 Update php_version.h to proper version number 2021-02-23 12:09:06 +01:00
Christoph M. Becker 963e50c8c4 Fix #75776: Flushing streams with compression filter is broken
First, the `bzip2.compress` filter has the same issue as `zlib.deflate`
so we port the respective fix[1] to ext/bz2.

Second, there is still an issue, if a stream with an attached
compression filter is flushed before it is closed, without any writes
in between.  In that case, the compression is never finalized.  We fix
this by enforcing a `_php_stream_flush()` with the `closing` flag set
in `_php_stream_free()`, whenever a write filter is attached.  This
call is superfluous for most write filters, but does not hurt, even
when it is unnecessary.

[1] <http://git.php.net/?p=php-src.git;a=commit;h=20e75329f2adb11dd231852c061926d0e4080929>

Closes GH-6703.
2021-02-22 15:28:46 +01:00
Christoph M. Becker 073b6ea818 Fix #80771: phpinfo(INFO_CREDITS) displays nothing in CLI
There is no good reason not to show the credits in text based SAPIs,
except for brevity.  Thus, we suppress the credits from `php -i`.

Closes GH-6710.
2021-02-22 14:31:51 +01:00
Christoph M. Becker d7c98ca1ac Fix #80774: session_name() problem with backslash
Since we do no longer URL decode cookie names[1], we must not URL
encode the session name.  We need to prevent broken Set-Cookie headers,
by rejecting names which contain invalid characters.

[1] <http://git.php.net/?p=php-src.git;a=commit;h=6559fe912661ca5ce5f0eeeb591d928451428ed0>

Closes GH-6711.
2021-02-22 12:32:56 +01:00
Nikita Popov 6dd85f83f7 Fixed bug #80781
zend_find_array_dim_slow() may throw, make sure to handle this.
This backports the code we already use for this on PHP-8.0,
and also backports an exception check that makes this easier to
catch.
2021-02-22 09:36:43 +01:00
Christoph M. Becker 84b6152842 Fix #80763: msgfmt_format() does not accept DateTime references
`intl_zval_to_millis()` needs to cater to references.

Closes GH-6707.
2021-02-17 17:26:48 +01:00
Nikita Popov 9552cf6b84 Handle incomplete result set metadata more gracefully
Rather than segfaulting because sname is missing lateron, report
a FAIL here. As this indicates a server bug, the errors is reported
as an out of band warning, rather than a client error.

This fixes the PHP side of bug #80713.
2021-02-16 15:34:14 +01:00
Derick Rethans 2d858fbfb1 Fixed dates 2021-02-16 11:31:34 +00:00
Derick Rethans 6d3d9104e6 PHP-7.4 is now 7.4.17-dev 2021-02-16 11:26:47 +00:00
82 changed files with 1603 additions and 205 deletions

No files matched your search

+1 -3
View File
@@ -11,9 +11,7 @@ end
define ____executor_globals
if basic_functions_module.zts
if !$tsrm_ls
set $tsrm_ls = ts_resource_ex(0, 0)
end
set $tsrm_ls = _tsrm_ls_cache
set $eg = ((zend_executor_globals*) (*((void ***) $tsrm_ls))[executor_globals_id-1])
set $cg = ((zend_compiler_globals*) (*((void ***) $tsrm_ls))[compiler_globals_id-1])
set $eg_ptr = $eg
+86 -2
View File
@@ -1,6 +1,90 @@
PHP NEWS
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
?? ??? 2021, PHP 7.4.16
06 May 2021, PHP 7.4.19
- PDO_pgsql:
. Reverted bug fix for #80892 (PDO::PARAM_INT is treated the same as
PDO::PARAM_STR). (Matteo)
29 Apr 2021, PHP 7.4.18
- Core:
. Fixed bug #80781 (Error handler that throws ErrorException infinite loop).
(Nikita)
. Fixed bug #75776 (Flushing streams with compression filter is broken). (cmb)
- Dba:
. Fixed bug #80817 (dba_popen() may cause segfault during RSHUTDOWN). (cmb)
- DOM:
. Fixed bug #66783 (UAF when appending DOMDocument to element). (cmb)
- FPM:
. Fixed bug #80024 (Duplication of info about inherited socket after pool
removing). (Jakub Zelenka)
- FTP:
. Fixed bug #80880 (SSL_read on shutdown, ftp/proc_open). (cmb, Jakub
Zelenka)
- Imap:
. Fixed bug #80710 (imap_mail_compose() header injection). (cmb, Stas)
- Intl:
. Fixed bug #80763 (msgfmt_format() does not accept DateTime references).
(cmb)
- LibXML:
. Fixed bug #51903 (simplexml_load_file() doesn't use HTTP headers). (cmb)
. Fixed bug #73533 (Invalid memory access in php_libxml_xmlCheckUTF8). (cmb)
- MySQLnd:
. Fixed bug #80713 (SegFault when disabling ATTR_EMULATE_PREPARES and
MySQL 8.0). (Nikita)
. Fixed bug #80837 (Calling stmt_store_result after fetch doesn't throw an
error). (Kamil Tekiela)
- Opcache:
. Fixed bug #80805 (create simple class and get error in opcache.so). (Nikita)
. Fixed bug #80950 (Variables become null in if statements). (Nikita)
- Pcntl:
. Fixed bug #79812 (Potential integer overflow in pcntl_exec()). (cmb)
- PCRE:
. Fixed bug #80866 (preg_split ignores limit flag when pattern with \K has
0-width fullstring match). (Kamil Tekiela)
- PDO_ODBC:
. Fixed bug #80783 (PDO ODBC truncates BLOB records at every 256th byte).
(cmb)
- PDO_pgsql:
. Fixed bug #80892 (PDO::PARAM_INT is treated the same as PDO::PARAM_STR).
(Matteo)
- phpdbg:
. Fixed bug #80757 (Exit code is 0 when could not open file). (Felipe)
- Session:
. Fixed bug #80774 (session_name() problem with backslash). (cmb)
. Fixed bug #80889 (Cannot set save handler when save_handler is invalid).
(cmb)
- SOAP:
. Fixed bug #69668 (SOAP special XML characters in namespace URIs not
encoded). (cmb)
- Standard:
. Fixed bug #78719 (http wrapper silently ignores long Location headers).
(cmb)
. Fixed bug #80771 (phpinfo(INFO_CREDITS) displays nothing in CLI). (cmb)
. Fixed bug #80838 (HTTP wrapper waits for HTTP 1 response after HTTP 101).
(manuelm)
. Fixed bug #80915 (Taking a reference to $_SERVER hides its values from
phpinfo()). (Rowan Tommins)
04 Mar 2021, php 7.4.16
- Core:
. Fixed #80706 (mail(): Headers after Bcc headers may be ignored). (cmb)
@@ -37,7 +121,7 @@ PHP NEWS
. Fixed bug #80648 (Fix for bug 79296 should be based on runtime version).
(cmb, Remi)
21 Jan 2021, PHP 7.4.15
04 Feb 2021, PHP 7.4.15
- Core:
. Fixed bug #80523 (bogus parse error on >4GB source code). (Nikita)
@@ -0,0 +1,15 @@
--TEST--
HT iterator should be destroyed if array becomes empty during array_splice
--FILE--
<?php
$a=[4];
$i = 0;
foreach ($a as &$r) {
var_dump($r);
$a = array_splice($a, 0);
if (++$i == 2) break;
}
?>
--EXPECT--
int(4)
int(4)
+32
View File
@@ -0,0 +1,32 @@
--TEST--
Bug #80781: Error handler that throws ErrorException infinite loop
--FILE--
<?php
function handle(int $severity, string $message, string $file, int $line): bool {
if((error_reporting() & $severity) !== 0) {
throw new \ErrorException($message, 0, $severity, $file, $line);
}
return true; // stfu operator
}
set_error_handler('handle');
function getPlugin(string $plugin) : bool{
return false;
}
$data = [];
$array = [];
if (isset($array[$data]) or getPlugin($data)) {
}
?>
--EXPECTF--
Fatal error: Uncaught ErrorException: Illegal offset type in isset or empty in %s:%d
Stack trace:
#0 %s(%d): handle(2, 'Illegal offset ...', %s, %d, Array)
#1 {main}
thrown in %s on line %d
+1 -1
View File
@@ -1099,7 +1099,7 @@ static zend_always_inline void zend_mm_free_pages_ex(zend_mm_heap *heap, zend_mm
/* this setting may be not accurate */
chunk->free_tail = page_num;
}
if (free_chunk && chunk->free_pages == ZEND_MM_PAGES - ZEND_MM_FIRST_PAGE) {
if (free_chunk && chunk != heap->main_chunk && chunk->free_pages == ZEND_MM_PAGES - ZEND_MM_FIRST_PAGE) {
zend_mm_delete_chunk(heap, chunk);
}
}
+5 -4
View File
@@ -51,11 +51,11 @@
# define ZEND_VM_FP_GLOBAL_REG "%r14"
# define ZEND_VM_IP_GLOBAL_REG "%r15"
# elif defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(__powerpc64__)
# define ZEND_VM_FP_GLOBAL_REG "r28"
# define ZEND_VM_IP_GLOBAL_REG "r29"
# define ZEND_VM_FP_GLOBAL_REG "r14"
# define ZEND_VM_IP_GLOBAL_REG "r15"
# elif defined(__IBMC__) && ZEND_GCC_VERSION >= 4002 && defined(__powerpc64__)
# define ZEND_VM_FP_GLOBAL_REG "r28"
# define ZEND_VM_IP_GLOBAL_REG "r29"
# define ZEND_VM_FP_GLOBAL_REG "r14"
# define ZEND_VM_IP_GLOBAL_REG "r15"
# elif defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(__aarch64__)
# define ZEND_VM_FP_GLOBAL_REG "x27"
# define ZEND_VM_IP_GLOBAL_REG "x28"
@@ -4555,6 +4555,7 @@ static zend_always_inline zend_execute_data *_zend_vm_stack_push_call_frame(uint
if (check_exception) { \
OPLINE = EX(opline) + (skip); \
} else { \
ZEND_ASSERT(!EG(exception)); \
OPLINE = opline + (skip); \
} \
ZEND_VM_CONTINUE()
+1 -1
View File
@@ -1630,10 +1630,10 @@ ZEND_API void ZEND_FASTCALL zend_array_destroy(HashTable *ht)
} else if (EXPECTED(HT_FLAGS(ht) & HASH_FLAG_UNINITIALIZED)) {
goto free_ht;
}
zend_hash_iterators_remove(ht);
SET_INCONSISTENT(HT_DESTROYED);
efree(HT_GET_DATA_ADDR(ht));
free_ht:
zend_hash_iterators_remove(ht);
FREE_HASHTABLE(ht);
}
+4
View File
@@ -6937,6 +6937,10 @@ ZEND_VM_C_LABEL(num_index_prop):
ZEND_VM_C_GOTO(isset_again);
} else {
value = zend_find_array_dim_slow(ht, offset EXECUTE_DATA_CC);
if (UNEXPECTED(EG(exception))) {
result = 0;
ZEND_VM_C_GOTO(isset_dim_obj_exit);
}
}
if (!(opline->extended_value & ZEND_ISEMPTY)) {
+36
View File
@@ -6302,6 +6302,10 @@ num_index_prop:
goto isset_again;
} else {
value = zend_find_array_dim_slow(ht, offset EXECUTE_DATA_CC);
if (UNEXPECTED(EG(exception))) {
result = 0;
goto isset_dim_obj_exit;
}
}
if (!(opline->extended_value & ZEND_ISEMPTY)) {
@@ -8496,6 +8500,10 @@ num_index_prop:
goto isset_again;
} else {
value = zend_find_array_dim_slow(ht, offset EXECUTE_DATA_CC);
if (UNEXPECTED(EG(exception))) {
result = 0;
goto isset_dim_obj_exit;
}
}
if (!(opline->extended_value & ZEND_ISEMPTY)) {
@@ -10949,6 +10957,10 @@ num_index_prop:
goto isset_again;
} else {
value = zend_find_array_dim_slow(ht, offset EXECUTE_DATA_CC);
if (UNEXPECTED(EG(exception))) {
result = 0;
goto isset_dim_obj_exit;
}
}
if (!(opline->extended_value & ZEND_ISEMPTY)) {
@@ -14985,6 +14997,10 @@ num_index_prop:
goto isset_again;
} else {
value = zend_find_array_dim_slow(ht, offset EXECUTE_DATA_CC);
if (UNEXPECTED(EG(exception))) {
result = 0;
goto isset_dim_obj_exit;
}
}
if (!(opline->extended_value & ZEND_ISEMPTY)) {
@@ -16402,6 +16418,10 @@ num_index_prop:
goto isset_again;
} else {
value = zend_find_array_dim_slow(ht, offset EXECUTE_DATA_CC);
if (UNEXPECTED(EG(exception))) {
result = 0;
goto isset_dim_obj_exit;
}
}
if (!(opline->extended_value & ZEND_ISEMPTY)) {
@@ -17689,6 +17709,10 @@ num_index_prop:
goto isset_again;
} else {
value = zend_find_array_dim_slow(ht, offset EXECUTE_DATA_CC);
if (UNEXPECTED(EG(exception))) {
result = 0;
goto isset_dim_obj_exit;
}
}
if (!(opline->extended_value & ZEND_ISEMPTY)) {
@@ -41505,6 +41529,10 @@ num_index_prop:
goto isset_again;
} else {
value = zend_find_array_dim_slow(ht, offset EXECUTE_DATA_CC);
if (UNEXPECTED(EG(exception))) {
result = 0;
goto isset_dim_obj_exit;
}
}
if (!(opline->extended_value & ZEND_ISEMPTY)) {
@@ -44950,6 +44978,10 @@ num_index_prop:
goto isset_again;
} else {
value = zend_find_array_dim_slow(ht, offset EXECUTE_DATA_CC);
if (UNEXPECTED(EG(exception))) {
result = 0;
goto isset_dim_obj_exit;
}
}
if (!(opline->extended_value & ZEND_ISEMPTY)) {
@@ -50123,6 +50155,10 @@ num_index_prop:
goto isset_again;
} else {
value = zend_find_array_dim_slow(ht, offset EXECUTE_DATA_CC);
if (UNEXPECTED(EG(exception))) {
result = 0;
goto isset_dim_obj_exit;
}
}
if (!(opline->extended_value & ZEND_ISEMPTY)) {
+1 -1
View File
@@ -5,7 +5,7 @@ parameters:
jobs:
- job: ${{ parameters.configurationName }}
pool:
vmImage: 'ubuntu-18.04'
vmImage: 'ubuntu-20.04'
steps:
- template: apt.yml
- script: |
+2 -2
View File
@@ -17,7 +17,7 @@ dnl Basic autoconf initialization, generation of config.nice.
dnl ----------------------------------------------------------------------------
AC_PREREQ([2.68])
AC_INIT([PHP],[7.4.16-dev],[https://bugs.php.net],[php],[https://www.php.net])
AC_INIT([PHP],[7.4.19],[https://bugs.php.net],[php],[https://www.php.net])
AC_CONFIG_SRCDIR([main/php_version.h])
AC_CONFIG_AUX_DIR([build])
AC_PRESERVE_HELP_ORDER
@@ -568,7 +568,7 @@ dnl Fix for these systems is already included in GCC 7, but not on GCC 6.
dnl
dnl At least some versions of FreeBSD seem to have buggy ifunc support, see
dnl bug #77284. Conservatively don't use ifuncs on FreeBSD.
AS_CASE([$host_alias], [*-*-*android*|*-*-*uclibc*|*-*-*musl*|*freebsd*], [true], [
AS_CASE([$host_alias], [*-*-*android*|*-*-*uclibc*|*-*-*musl*|*freebsd*|*openbsd*], [true], [
AX_GCC_FUNC_ATTRIBUTE([ifunc])
AX_GCC_FUNC_ATTRIBUTE([target])
])
+10 -3
View File
@@ -41,6 +41,7 @@ typedef struct _php_bz2_filter_data {
enum strm_status status; /* Decompress option */
unsigned int small_footprint : 1; /* Decompress option */
unsigned int expect_concatenated : 1; /* Decompress option */
unsigned int is_flushed : 1; /* only for compression */
int persistent;
} php_bz2_filter_data;
@@ -228,6 +229,8 @@ static php_stream_filter_status_t php_bz2_compress_filter(
bucket = php_stream_bucket_make_writeable(buckets_in->head);
while (bin < bucket->buflen) {
int flush_mode;
desired = bucket->buflen - bin;
if (desired > data->inbuf_len) {
desired = data->inbuf_len;
@@ -235,7 +238,9 @@ static php_stream_filter_status_t php_bz2_compress_filter(
memcpy(data->strm.next_in, bucket->buf + bin, desired);
data->strm.avail_in = desired;
status = BZ2_bzCompress(&(data->strm), flags & PSFS_FLAG_FLUSH_CLOSE ? BZ_FINISH : (flags & PSFS_FLAG_FLUSH_INC ? BZ_FLUSH : BZ_RUN));
flush_mode = flags & PSFS_FLAG_FLUSH_CLOSE ? BZ_FINISH : (flags & PSFS_FLAG_FLUSH_INC ? BZ_FLUSH : BZ_RUN);
data->is_flushed = flush_mode != BZ_RUN;
status = BZ2_bzCompress(&(data->strm), flush_mode);
if (status != BZ_RUN_OK && status != BZ_FLUSH_OK && status != BZ_FINISH_OK) {
/* Something bad happened */
php_stream_bucket_delref(bucket);
@@ -261,11 +266,12 @@ static php_stream_filter_status_t php_bz2_compress_filter(
php_stream_bucket_delref(bucket);
}
if (flags & PSFS_FLAG_FLUSH_CLOSE) {
if (flags & PSFS_FLAG_FLUSH_CLOSE || ((flags & PSFS_FLAG_FLUSH_INC) && !data->is_flushed)) {
/* Spit it out! */
status = BZ_FINISH_OK;
while (status == BZ_FINISH_OK) {
status = BZ2_bzCompress(&(data->strm), BZ_FINISH);
status = BZ2_bzCompress(&(data->strm), (flags & PSFS_FLAG_FLUSH_CLOSE ? BZ_FINISH : BZ_FLUSH));
data->is_flushed = 1;
if (data->strm.avail_out < data->outbuf_len) {
size_t bucketlen = data->outbuf_len - data->strm.avail_out;
@@ -381,6 +387,7 @@ static php_stream_filter *php_bz2_filter_create(const char *filtername, zval *fi
}
status = BZ2_bzCompressInit(&(data->strm), blockSize100k, 0, workFactor);
data->is_flushed = 1;
fops = &php_bz2_compress_ops;
} else {
status = BZ_DATA_ERROR;
+24
View File
@@ -0,0 +1,24 @@
--TEST--
Bug #75776 (Flushing streams with compression filter is broken)
--SKIPIF--
<?php
if (!extension_loaded('bz2')) die('skip bz2 extension not available');
?>
--FILE--
<?php
$text = str_repeat('0123456789abcdef', 1000);
$temp = fopen('php://temp', 'r+');
stream_filter_append($temp, 'bzip2.compress', STREAM_FILTER_WRITE);
fwrite($temp, $text);
rewind($temp);
var_dump(bin2hex(stream_get_contents($temp)));
var_dump(ftell($temp));
fclose($temp);
?>
--EXPECT--
string(144) "425a68343141592653599fe7bbbf0001f389007fe03f002000902980026826aa80003ea9061520c6a41954833a9069520d6a41b54837a9071520e6a41d5483ba9079520f6a41f548"
int(72)
+2 -2
View File
@@ -972,9 +972,9 @@ restart:
zend_bool close_both;
close_both = (info->fp != info->lock.fp);
php_stream_close(info->lock.fp);
php_stream_free(info->lock.fp, persistent ? PHP_STREAM_FREE_CLOSE_PERSISTENT : PHP_STREAM_FREE_CLOSE);
if (close_both) {
php_stream_close(info->fp);
php_stream_free(info->fp, persistent ? PHP_STREAM_FREE_CLOSE_PERSISTENT : PHP_STREAM_FREE_CLOSE);
}
info->fp = NULL;
info->lock.fp = NULL;
+7 -3
View File
@@ -1302,9 +1302,13 @@ int dom_hierarchy(xmlNodePtr parent, xmlNodePtr child)
{
xmlNodePtr nodep;
if (parent == NULL || child == NULL || child->doc != parent->doc) {
return SUCCESS;
}
if (parent == NULL || child == NULL || child->doc != parent->doc) {
return SUCCESS;
}
if (child->type == XML_DOCUMENT_NODE) {
return FAILURE;
}
nodep = parent;
@@ -9,7 +9,7 @@ require_once __DIR__ .'/skipif.inc';
?>
--FILE--
<?php
$filename = __DIR__."/tmp_savehtmlfile".time().".html";
$filename = __DIR__."/DOMDocument_saveHTMLFile_basic.html";
$doc = new DOMDocument('1.0');
$root = $doc->createElement('html');
$root = $doc->appendChild($root);
@@ -9,7 +9,7 @@ require_once __DIR__ .'/skipif.inc';
?>
--FILE--
<?php
$filename = __DIR__."/tmp_savehtmlfile".time().".html";
$filename = __DIR__."/DOMDocument_saveHTMLFile_formatOutput.html";
$doc = new DOMDocument('1.0');
$doc->formatOutput = true;
$root = $doc->createElement('html');
+19
View File
@@ -0,0 +1,19 @@
--TEST--
Bug #66783 (UAF when appending DOMDocument to element)
--SKIPIF--
<?php
if (!extension_loaded('dom')) die('skip dom extension not available');
?>
--FILE--
<?php
$doc = new DomDocument;
$doc->loadXML('<root></root>');
$e = $doc->createElement('e');
try {
$e->appendChild($doc);
} catch (DOMException $ex) {
echo $ex->getMessage(), PHP_EOL;
}
?>
--EXPECTF--
Hierarchy Request Error
+6
View File
@@ -1931,6 +1931,12 @@ static void ftp_ssl_shutdown(ftpbuf_t *ftp, php_socket_t fd, SSL *ssl_handle) {
/* SSL wants a write. Really odd. Let's bail out. */
done = 1;
break;
case SSL_ERROR_SYSCALL:
/* most likely the peer closed the connection without
sending a close_notify shutdown alert;
bail out to avoid raising a spurious warning */
done = 1;
break;
default:
if ((sslerror = ERR_get_error())) {
ERR_error_string_n(sslerror, buf, sizeof(buf));
+56
View File
@@ -3551,6 +3551,23 @@ PHP_FUNCTION(imap_fetch_overview)
}
/* }}} */
static zend_bool header_injection(zend_string *str, zend_bool adrlist)
{
char *p = ZSTR_VAL(str);
while ((p = strpbrk(p, "\r\n")) != NULL) {
if (!(p[0] == '\r' && p[1] == '\n')
/* adrlists do not support folding, but swallow trailing line breaks */
&& !((adrlist && p[1] == '\0')
/* other headers support folding */
|| !adrlist && (p[1] == ' ' || p[1] == '\t'))) {
return 1;
}
p++;
}
return 0;
}
/* {{{ proto string imap_mail_compose(array envelope, array body)
Create a MIME message based on given envelope and body sections */
PHP_FUNCTION(imap_mail_compose)
@@ -3571,6 +3588,13 @@ PHP_FUNCTION(imap_mail_compose)
return;
}
#define CHECK_HEADER_INJECTION(zstr, adrlist, header) \
if (header_injection(zstr, adrlist)) { \
php_error_docref(NULL, E_WARNING, "header injection attempt in " header); \
RETVAL_FALSE; \
goto done; \
}
#define PHP_RFC822_PARSE_ADRLIST(target, value) \
str_copy = estrndup(Z_STRVAL_P(value), Z_STRLEN_P(value)); \
rfc822_parse_adrlist(target, str_copy, "NO HOST"); \
@@ -3579,46 +3603,57 @@ PHP_FUNCTION(imap_mail_compose)
env = mail_newenvelope();
if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "remail", sizeof("remail") - 1)) != NULL) {
convert_to_string_ex(pvalue);
CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "remail");
env->remail = cpystr(Z_STRVAL_P(pvalue));
}
if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "return_path", sizeof("return_path") - 1)) != NULL) {
convert_to_string_ex(pvalue);
CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 1, "return_path");
PHP_RFC822_PARSE_ADRLIST(&env->return_path, pvalue);
}
if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "date", sizeof("date") - 1)) != NULL) {
convert_to_string_ex(pvalue);
CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "date");
env->date = (unsigned char*)cpystr(Z_STRVAL_P(pvalue));
}
if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "from", sizeof("from") - 1)) != NULL) {
convert_to_string_ex(pvalue);
CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 1, "from");
PHP_RFC822_PARSE_ADRLIST(&env->from, pvalue);
}
if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "reply_to", sizeof("reply_to") - 1)) != NULL) {
convert_to_string_ex(pvalue);
CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 1, "reply_to");
PHP_RFC822_PARSE_ADRLIST(&env->reply_to, pvalue);
}
if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "in_reply_to", sizeof("in_reply_to") - 1)) != NULL) {
convert_to_string_ex(pvalue);
CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "in_reply_to");
env->in_reply_to = cpystr(Z_STRVAL_P(pvalue));
}
if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "subject", sizeof("subject") - 1)) != NULL) {
convert_to_string_ex(pvalue);
CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "subject");
env->subject = cpystr(Z_STRVAL_P(pvalue));
}
if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "to", sizeof("to") - 1)) != NULL) {
convert_to_string_ex(pvalue);
CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 1, "to");
PHP_RFC822_PARSE_ADRLIST(&env->to, pvalue);
}
if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "cc", sizeof("cc") - 1)) != NULL) {
convert_to_string_ex(pvalue);
CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 1, "cc");
PHP_RFC822_PARSE_ADRLIST(&env->cc, pvalue);
}
if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "bcc", sizeof("bcc") - 1)) != NULL) {
convert_to_string_ex(pvalue);
CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 1, "bcc");
PHP_RFC822_PARSE_ADRLIST(&env->bcc, pvalue);
}
if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "message_id", sizeof("message_id") - 1)) != NULL) {
convert_to_string_ex(pvalue);
CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "message_id");
env->message_id=cpystr(Z_STRVAL_P(pvalue));
}
@@ -3629,6 +3664,7 @@ PHP_FUNCTION(imap_mail_compose)
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(pvalue), env_data) {
custom_headers_param = mail_newbody_parameter();
convert_to_string_ex(env_data);
CHECK_HEADER_INJECTION(Z_STR_P(env_data), 0, "custom_headers");
custom_headers_param->value = (char *) fs_get(Z_STRLEN_P(env_data) + 1);
custom_headers_param->attribute = NULL;
memcpy(custom_headers_param->value, Z_STRVAL_P(env_data), Z_STRLEN_P(env_data) + 1);
@@ -3667,6 +3703,7 @@ PHP_FUNCTION(imap_mail_compose)
}
if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "charset", sizeof("charset") - 1)) != NULL) {
convert_to_string_ex(pvalue);
CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body charset");
tmp_param = mail_newbody_parameter();
tmp_param->value = cpystr(Z_STRVAL_P(pvalue));
tmp_param->attribute = cpystr("CHARSET");
@@ -3679,9 +3716,11 @@ PHP_FUNCTION(imap_mail_compose)
SEPARATE_ARRAY(pvalue);
ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(pvalue), key, disp_data) {
if (key == NULL) continue;
CHECK_HEADER_INJECTION(key, 0, "body disposition key");
disp_param = mail_newbody_parameter();
disp_param->attribute = cpystr(ZSTR_VAL(key));
convert_to_string_ex(disp_data);
CHECK_HEADER_INJECTION(Z_STR_P(disp_data), 0, "body disposition value");
disp_param->value = (char *) fs_get(Z_STRLEN_P(disp_data) + 1);
memcpy(disp_param->value, Z_STRVAL_P(disp_data), Z_STRLEN_P(disp_data) + 1);
disp_param->next = tmp_param;
@@ -3692,18 +3731,22 @@ PHP_FUNCTION(imap_mail_compose)
}
if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "subtype", sizeof("subtype") - 1)) != NULL) {
convert_to_string_ex(pvalue);
CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body subtype");
bod->subtype = cpystr(Z_STRVAL_P(pvalue));
}
if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "id", sizeof("id") - 1)) != NULL) {
convert_to_string_ex(pvalue);
CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body id");
bod->id = cpystr(Z_STRVAL_P(pvalue));
}
if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "description", sizeof("description") - 1)) != NULL) {
convert_to_string_ex(pvalue);
CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body description");
bod->description = cpystr(Z_STRVAL_P(pvalue));
}
if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "disposition.type", sizeof("disposition.type") - 1)) != NULL) {
convert_to_string_ex(pvalue);
CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body disposition.type");
bod->disposition.type = (char *) fs_get(Z_STRLEN_P(pvalue) + 1);
memcpy(bod->disposition.type, Z_STRVAL_P(pvalue), Z_STRLEN_P(pvalue)+1);
}
@@ -3713,9 +3756,11 @@ PHP_FUNCTION(imap_mail_compose)
SEPARATE_ARRAY(pvalue);
ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(pvalue), key, disp_data) {
if (key == NULL) continue;
CHECK_HEADER_INJECTION(key, 0, "body type.parameters key");
disp_param = mail_newbody_parameter();
disp_param->attribute = cpystr(ZSTR_VAL(key));
convert_to_string_ex(disp_data);
CHECK_HEADER_INJECTION(Z_STR_P(disp_data), 0, "body type.parameters value");
disp_param->value = (char *) fs_get(Z_STRLEN_P(disp_data) + 1);
memcpy(disp_param->value, Z_STRVAL_P(disp_data), Z_STRLEN_P(disp_data) + 1);
disp_param->next = tmp_param;
@@ -3746,6 +3791,7 @@ PHP_FUNCTION(imap_mail_compose)
}
if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "md5", sizeof("md5") - 1)) != NULL) {
convert_to_string_ex(pvalue);
CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body md5");
bod->md5 = cpystr(Z_STRVAL_P(pvalue));
}
} else if (Z_TYPE_P(data) == IS_ARRAY && topbod->type == TYPEMULTIPART) {
@@ -3778,6 +3824,7 @@ PHP_FUNCTION(imap_mail_compose)
}
if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "charset", sizeof("charset") - 1)) != NULL) {
convert_to_string_ex(pvalue);
CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body charset");
tmp_param = mail_newbody_parameter();
tmp_param->value = (char *) fs_get(Z_STRLEN_P(pvalue) + 1);
memcpy(tmp_param->value, Z_STRVAL_P(pvalue), Z_STRLEN_P(pvalue) + 1);
@@ -3791,9 +3838,11 @@ PHP_FUNCTION(imap_mail_compose)
SEPARATE_ARRAY(pvalue);
ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(pvalue), key, disp_data) {
if (key == NULL) continue;
CHECK_HEADER_INJECTION(key, 0, "body type.parameters key");
disp_param = mail_newbody_parameter();
disp_param->attribute = cpystr(ZSTR_VAL(key));
convert_to_string_ex(disp_data);
CHECK_HEADER_INJECTION(Z_STR_P(disp_data), 0, "body type.parameters value");
disp_param->value = (char *)fs_get(Z_STRLEN_P(disp_data) + 1);
memcpy(disp_param->value, Z_STRVAL_P(disp_data), Z_STRLEN_P(disp_data) + 1);
disp_param->next = tmp_param;
@@ -3804,18 +3853,22 @@ PHP_FUNCTION(imap_mail_compose)
}
if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "subtype", sizeof("subtype") - 1)) != NULL) {
convert_to_string_ex(pvalue);
CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body subtype");
bod->subtype = cpystr(Z_STRVAL_P(pvalue));
}
if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "id", sizeof("id") - 1)) != NULL) {
convert_to_string_ex(pvalue);
CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body id");
bod->id = cpystr(Z_STRVAL_P(pvalue));
}
if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "description", sizeof("description") - 1)) != NULL) {
convert_to_string_ex(pvalue);
CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body description");
bod->description = cpystr(Z_STRVAL_P(pvalue));
}
if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "disposition.type", sizeof("disposition.type") - 1)) != NULL) {
convert_to_string_ex(pvalue);
CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body disposition.type");
bod->disposition.type = (char *) fs_get(Z_STRLEN_P(pvalue) + 1);
memcpy(bod->disposition.type, Z_STRVAL_P(pvalue), Z_STRLEN_P(pvalue)+1);
}
@@ -3825,9 +3878,11 @@ PHP_FUNCTION(imap_mail_compose)
SEPARATE_ARRAY(pvalue);
ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(pvalue), key, disp_data) {
if (key == NULL) continue;
CHECK_HEADER_INJECTION(key, 0, "body disposition key");
disp_param = mail_newbody_parameter();
disp_param->attribute = cpystr(ZSTR_VAL(key));
convert_to_string_ex(disp_data);
CHECK_HEADER_INJECTION(Z_STR_P(disp_data), 0, "body disposition value");
disp_param->value = (char *) fs_get(Z_STRLEN_P(disp_data) + 1);
memcpy(disp_param->value, Z_STRVAL_P(disp_data), Z_STRLEN_P(disp_data) + 1);
disp_param->next = tmp_param;
@@ -3858,6 +3913,7 @@ PHP_FUNCTION(imap_mail_compose)
}
if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "md5", sizeof("md5") - 1)) != NULL) {
convert_to_string_ex(pvalue);
CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body md5");
bod->md5 = cpystr(Z_STRVAL_P(pvalue));
}
}
+37
View File
@@ -0,0 +1,37 @@
--TEST--
Bug #80710 (imap_mail_compose() header injection) - MIME Splitting Attack
--SKIPIF--
<?php
if (!extension_loaded("imap")) die("skip imap extension not available");
?>
--FILE--
<?php
$envelope["from"]= "joe@example.com\n From : X-INJECTED";
$envelope["to"] = "foo@example.com\nFrom: X-INJECTED";
$envelope["cc"] = "bar@example.com\nFrom: X-INJECTED";
$envelope["subject"] = "bar@example.com\n\n From : X-INJECTED";
$envelope["x-remail"] = "bar@example.com\nFrom: X-INJECTED";
$envelope["something"] = "bar@example.com\nFrom: X-INJECTED";
$part1["type"] = TYPEMULTIPART;
$part1["subtype"] = "mixed";
$part2["type"] = TYPEAPPLICATION;
$part2["encoding"] = ENCBINARY;
$part2["subtype"] = "octet-stream\nContent-Type: X-INJECTED";
$part2["description"] = "some file\nContent-Type: X-INJECTED";
$part2["contents.data"] = "ABC\nContent-Type: X-INJECTED";
$part3["type"] = TYPETEXT;
$part3["subtype"] = "plain";
$part3["description"] = "description3";
$part3["contents.data"] = "contents.data3\n\n\n\t";
$body[1] = $part1;
$body[2] = $part2;
$body[3] = $part3;
echo imap_mail_compose($envelope, $body);
?>
--EXPECTF--
Warning: imap_mail_compose(): header injection attempt in from in %s on line %d
+37
View File
@@ -0,0 +1,37 @@
--TEST--
Bug #80710 (imap_mail_compose() header injection) - Remail
--SKIPIF--
<?php
if (!extension_loaded("imap")) die("skip imap extension not available");
?>
--FILE--
<?php
$envelope["from"]= "joe@example.com\n From : X-INJECTED";
$envelope["to"] = "foo@example.com\nFrom: X-INJECTED";
$envelope["cc"] = "bar@example.com\nFrom: X-INJECTED";
$envelope["subject"] = "bar@example.com\n\n From : X-INJECTED";
$envelope["remail"] = "X-INJECTED-REMAIL: X-INJECTED\nFrom: X-INJECTED-REMAIL-FROM"; //<--- Injected as first hdr
$envelope["something"] = "bar@example.com\nFrom: X-INJECTED";
$part1["type"] = TYPEMULTIPART;
$part1["subtype"] = "mixed";
$part2["type"] = TYPEAPPLICATION;
$part2["encoding"] = ENCBINARY;
$part2["subtype"] = "octet-stream\nContent-Type: X-INJECTED";
$part2["description"] = "some file\nContent-Type: X-INJECTED";
$part2["contents.data"] = "ABC\nContent-Type: X-INJECTED";
$part3["type"] = TYPETEXT;
$part3["subtype"] = "plain";
$part3["description"] = "description3";
$part3["contents.data"] = "contents.data3\n\n\n\t";
$body[1] = $part1;
$body[2] = $part2;
$body[3] = $part3;
echo imap_mail_compose($envelope, $body);
?>
--EXPECTF--
Warning: imap_mail_compose(): header injection attempt in remail in %s on line %d
+4
View File
@@ -175,6 +175,7 @@ U_CFUNC double intl_zval_to_millis(zval *z, intl_error *err, const char *func)
return ZEND_NAN;
}
try_again:
switch (Z_TYPE_P(z)) {
case IS_STRING:
type = is_numeric_string(Z_STRVAL_P(z), Z_STRLEN_P(z), &lv, &rv, 0);
@@ -227,6 +228,9 @@ U_CFUNC double intl_zval_to_millis(zval *z, intl_error *err, const char *func)
efree(message);
}
break;
case IS_REFERENCE:
z = Z_REFVAL_P(z);
goto try_again;
default:
spprintf(&message, 0, "%s: invalid PHP type for date", func);
intl_errors_set(err, U_ILLEGAL_ARGUMENT_ERROR,
+16
View File
@@ -0,0 +1,16 @@
--TEST--
Bug #80763 (msgfmt_format() does not accept DateTime references)
--SKIPIF--
<?php
if (!extension_loaded('intl')) die('skip intl extension not available');
?>
--FILE--
<?php
$today = new DateTime('2021-02-17 12:00:00');
$formatter = new \MessageFormatter('en_US', 'Today is {today, date, full}.');
$params = ['today' => $today];
array_walk($params, fn() => 1);
var_dump($formatter->format($params));
?>
--EXPECT--
string(38) "Today is Wednesday, February 17, 2021."
+49 -1
View File
@@ -409,6 +409,54 @@ php_libxml_input_buffer_create_filename(const char *URI, xmlCharEncoding enc)
return(NULL);
}
/* Check if there's been an external transport protocol with an encoding information */
if (enc == XML_CHAR_ENCODING_NONE) {
php_stream *s = (php_stream *) context;
if (Z_TYPE(s->wrapperdata) == IS_ARRAY) {
zval *header;
ZEND_HASH_FOREACH_VAL_IND(Z_ARRVAL(s->wrapperdata), header) {
const char buf[] = "Content-Type:";
if (Z_TYPE_P(header) == IS_STRING &&
!zend_binary_strncasecmp(Z_STRVAL_P(header), Z_STRLEN_P(header), buf, sizeof(buf)-1, sizeof(buf)-1)) {
char *needle = estrdup("charset=");
char *haystack = estrndup(Z_STRVAL_P(header), Z_STRLEN_P(header));
char *encoding = php_stristr(haystack, needle, Z_STRLEN_P(header), sizeof("charset=")-1);
if (encoding) {
char *end;
encoding += sizeof("charset=")-1;
if (*encoding == '"') {
encoding++;
}
end = strchr(encoding, ';');
if (end == NULL) {
end = encoding + strlen(encoding);
}
end--; /* end == encoding-1 isn't a buffer underrun */
while (*end == ' ' || *end == '\t') {
end--;
}
if (*end == '"') {
end--;
}
if (encoding >= end) continue;
*(end+1) = '\0';
enc = xmlParseCharEncoding(encoding);
if (enc <= XML_CHAR_ENCODING_NONE) {
enc = XML_CHAR_ENCODING_NONE;
}
}
efree(haystack);
efree(needle);
break; /* found content-type */
}
} ZEND_HASH_FOREACH_END();
}
}
/* Allocate the Input buffer front-end. */
ret = xmlAllocParserInputBuffer(enc);
if (ret != NULL) {
@@ -1134,7 +1182,7 @@ static PHP_FUNCTION(libxml_set_external_entity_loader)
/* {{{ Common functions shared by extensions */
int php_libxml_xmlCheckUTF8(const unsigned char *s)
{
int i;
size_t i;
unsigned char c;
for (i = 0; (c = s[i++]);) {
+38
View File
@@ -0,0 +1,38 @@
--TEST--
Bug #51903 (simplexml_load_file() doesn't use HTTP headers)
--SKIPIF--
<?php
if (!extension_loaded('simplexml')) die('skip simplexml extension not available');
if (@!include "./ext/standard/tests/http/server.inc") die('skip server.inc not available');
http_server_skipif('tcp://127.0.0.1:12342');
?>
--FILE--
<?php
require "./ext/standard/tests/http/server.inc";
$responses = [
"data://text/plain,HTTP/1.1 200 OK\r\n"
. "Content-Type: text/xml; charset=ISO-8859-1\r\n\r\n"
. "<?xml version=\"1.0\"?>\n"
. "<root>\xE4\xF6\xFC</root>\n",
"data://text/plain,HTTP/1.1 200 OK\r\n"
. "Content-Type: text/xml; charset=ISO-8859-1; foo=bar\r\n\r\n"
. "<?xml version=\"1.0\"?>\n"
. "<root>\xE4\xF6\xFC</root>\n",
"data://text/plain,HTTP/1.1 200 OK\r\n"
. "Content-Type: text/xml; charset=\"ISO-8859-1\" ; foo=bar\r\n\r\n"
. "<?xml version=\"1.0\"?>\n"
. "<root>\xE4\xF6\xFC</root>\n",
];
$pid = http_server('tcp://127.0.0.1:12342', $responses);
for ($i = 0; $i < count($responses); $i++) {
$sxe = simplexml_load_file('http://127.0.0.1:12342/');
echo "$sxe\n";
}
http_server_kill($pid);
?>
--EXPECT--
äöü
äöü
äöü
+38
View File
@@ -0,0 +1,38 @@
--TEST--
Bug #80837 Calling stmt_store_result after fetch doesn't throw an error
--SKIPIF--
<?php
require_once 'skipif.inc';
require_once 'skipifconnectfailure.inc';
if (!defined('MYSQLI_STORE_RESULT_COPY_DATA')) die('skip requires mysqlnd');
?>
--FILE--
<?php
require_once "connect.inc";
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new my_mysqli($host, $user, $passwd, $db, $port, $socket);
$mysqli->query('DROP TABLE IF EXISTS test');
$mysqli->query('CREATE TABLE test (b int)');
$mysqli->query('INSERT INTO test VALUES (1),(2),(3)');
$statement = $mysqli->prepare("SELECT b FROM test");
$statement->execute();
$statement->bind_result($name);
$statement->fetch();
try {
$statement->store_result();
} catch (mysqli_sql_exception $e) {
echo $e->getMessage();
}
$mysqli->close();
?>
--CLEAN--
<?php
require_once "clean_table.inc";
?>
--EXPECTF--
Commands out of sync; you can't run this command now
+2 -2
View File
@@ -102,8 +102,8 @@ max_execution_time=240
require_once('table.inc');
if (!$link = my_mysqli_connect($host, 'pamtest', 'pamtest', $db, $port, $socket)) {
printf("[001] Cannot connect to the server using host=%s, user=%s, passwd=***, dbname=%s, port=%s, socket=%s\n",
$host, $user, $db, $port, $socket);
printf("[001] Cannot connect to the server using host=%s, user=pamtest, passwd=pamtest dbname=%s, port=%s, socket=%s\n",
$host, $db, $port, $socket);
} else {
if (!$res = $link->query("SELECT id FROM test WHERE id = 1"))
+1 -1
View File
@@ -92,7 +92,7 @@ MYSQLND_METHOD(mysqlnd_stmt, store_result)(MYSQLND_STMT * const s)
/* Nothing to store for UPSERT/LOAD DATA*/
if (!mysqlnd_stmt_check_state(stmt)) {
SET_CLIENT_ERROR(conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
SET_CLIENT_ERROR(stmt->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
DBG_RETURN(NULL);
}
+3 -2
View File
@@ -1216,8 +1216,9 @@ php_mysqlnd_rset_field_read(MYSQLND_CONN_DATA * conn, void * _packet)
DBG_RETURN(PASS);
} else if (EODATA_MARKER == *p && packet->header.size < 8) {
/* Premature EOF. That should be COM_FIELD_LIST. But we don't support COM_FIELD_LIST anymore, thus this should not happen */
DBG_INF("Premature EOF. That should be COM_FIELD_LIST");
DBG_RETURN(PASS);
DBG_ERR("Premature EOF. That should be COM_FIELD_LIST");
php_error_docref(NULL, E_WARNING, "Premature EOF in result field metadata");
DBG_RETURN(FAIL);
}
meta = packet->metadata;
+19 -5
View File
@@ -368,6 +368,10 @@ static zend_bool try_remove_var_def(context *ctx, int free_var, int use_chain, z
return 0;
}
static zend_always_inline zend_bool may_be_refcounted(uint32_t type) {
return (type & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) != 0;
}
/* Returns whether the instruction has been DCEd */
static zend_bool dce_instr(context *ctx, zend_op *opline, zend_ssa_op *ssa_op) {
zend_ssa *ssa = ctx->ssa;
@@ -379,16 +383,15 @@ static zend_bool dce_instr(context *ctx, zend_op *opline, zend_ssa_op *ssa_op) {
}
/* We mark FREEs as dead, but they're only really dead if the destroyed var is dead */
if (opline->opcode == ZEND_FREE
&& (ssa->var_info[ssa_op->op1_use].type & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))
if (opline->opcode == ZEND_FREE && may_be_refcounted(ssa->var_info[ssa_op->op1_use].type)
&& !is_var_dead(ctx, ssa_op->op1_use)) {
return 0;
}
if ((opline->op1_type & (IS_VAR|IS_TMP_VAR))&& !is_var_dead(ctx, ssa_op->op1_use)) {
if (!try_remove_var_def(ctx, ssa_op->op1_use, ssa_op->op1_use_chain, opline)) {
if (ssa->var_info[ssa_op->op1_use].type & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)
&& opline->opcode != ZEND_CASE) {
if (may_be_refcounted(ssa->var_info[ssa_op->op1_use].type)
&& opline->opcode != ZEND_CASE) {
free_var = ssa_op->op1_use;
free_var_type = opline->op1_type;
}
@@ -396,7 +399,7 @@ static zend_bool dce_instr(context *ctx, zend_op *opline, zend_ssa_op *ssa_op) {
}
if ((opline->op2_type & (IS_VAR|IS_TMP_VAR)) && !is_var_dead(ctx, ssa_op->op2_use)) {
if (!try_remove_var_def(ctx, ssa_op->op2_use, ssa_op->op2_use_chain, opline)) {
if (ssa->var_info[ssa_op->op2_use].type & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
if (may_be_refcounted(ssa->var_info[ssa_op->op2_use].type)) {
if (free_var >= 0) {
// TODO: We can't free two vars. Keep instruction alive.
zend_bitset_excl(ctx->instr_dead, opline - ctx->op_array->opcodes);
@@ -503,6 +506,17 @@ int dce_optimize_op_array(zend_op_array *op_array, zend_ssa *ssa, zend_bool reor
ctx.phi_dead = alloca(sizeof(zend_ulong) * ctx.phi_worklist_len);
memset(ctx.phi_dead, 0xff, sizeof(zend_ulong) * ctx.phi_worklist_len);
/* Mark non-CV phis as live. Even if the result is unused, we generally cannot remove one
* of the producing instructions, as it combines producing the result with control flow.
* This can be made more precise if there are any cases where this is not the case. */
FOREACH_PHI(phi) {
if (phi->var >= op_array->last_var
&& may_be_refcounted(ssa->var_info[phi->ssa_var].type)) {
zend_bitset_excl(ctx.phi_dead, phi->ssa_var);
add_phi_sources_to_worklists(&ctx, phi, 0);
}
} FOREACH_PHI_END();
/* Mark reacable instruction without side effects as dead */
int b = ssa->cfg.blocks_count;
while (b > 0) {
+1 -1
View File
@@ -1040,7 +1040,7 @@ static const func_info_t func_infos[] = {
F1("curl_version", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY),
F0("curl_setopt", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
F0("curl_setopt_array", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
FN("curl_exec", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
FN("curl_exec", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_STRING),
F1("curl_getinfo", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING | MAY_BE_LONG | MAY_BE_DOUBLE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY),
F1("curl_error", MAY_BE_NULL | MAY_BE_STRING),
F0("curl_errno", MAY_BE_NULL | MAY_BE_LONG),
+19 -4
View File
@@ -1947,6 +1947,18 @@ static void add_usages(const zend_op_array *op_array, zend_ssa *ssa, zend_bitset
if (op->op2_def >= 0) {
zend_bitset_incl(worklist, op->op2_def);
}
} else if (use + 1 < op_array->last
&& op_array->opcodes[use + 1].opcode == ZEND_OP_DATA) {
op++;
if (op->result_def >= 0) {
zend_bitset_incl(worklist, op->result_def);
}
if (op->op1_def >= 0) {
zend_bitset_incl(worklist, op->op1_def);
}
if (op->op2_def >= 0) {
zend_bitset_incl(worklist, op->op2_def);
}
}
use = zend_ssa_next_use(ssa->ops, var, use);
} while (use >= 0);
@@ -2141,7 +2153,7 @@ static uint32_t assign_dim_result_type(
/* For binary ops that have compound assignment operators */
static uint32_t binary_op_result_type(
zend_ssa *ssa, zend_uchar opcode, uint32_t t1, uint32_t t2, uint32_t result_var,
zend_ssa *ssa, zend_uchar opcode, uint32_t t1, uint32_t t2, int result_var,
zend_long optimization_level) {
uint32_t tmp = 0;
uint32_t t1_type = (t1 & MAY_BE_ANY) | (t1 & MAY_BE_UNDEF ? MAY_BE_NULL : 0);
@@ -2159,7 +2171,8 @@ static uint32_t binary_op_result_type(
switch (opcode) {
case ZEND_ADD:
if (t1_type == MAY_BE_LONG && t2_type == MAY_BE_LONG) {
if (!ssa->var_info[result_var].has_range ||
if (result_var < 0 ||
!ssa->var_info[result_var].has_range ||
ssa->var_info[result_var].range.underflow ||
ssa->var_info[result_var].range.overflow) {
/* may overflow */
@@ -2185,7 +2198,8 @@ static uint32_t binary_op_result_type(
case ZEND_SUB:
case ZEND_MUL:
if (t1_type == MAY_BE_LONG && t2_type == MAY_BE_LONG) {
if (!ssa->var_info[result_var].has_range ||
if (result_var < 0 ||
!ssa->var_info[result_var].has_range ||
ssa->var_info[result_var].range.underflow ||
ssa->var_info[result_var].range.overflow) {
/* may overflow */
@@ -2627,7 +2641,8 @@ static int zend_update_type_info(const zend_op_array *op_array,
}
tmp |= binary_op_result_type(
ssa, opline->extended_value, t1, t2, ssa_ops[i].op1_def, optimization_level);
ssa, opline->extended_value, t1, t2,
opline->opcode == ZEND_ASSIGN_OP ? ssa_ops[i].op1_def : -1, optimization_level);
if (tmp & (MAY_BE_STRING|MAY_BE_ARRAY)) {
tmp |= MAY_BE_RC1;
}
+1 -1
View File
@@ -80,7 +80,7 @@ void zend_shared_alloc_create_lock(void)
{
memory_mutex = CreateMutex(NULL, FALSE, create_name_with_username(ACCEL_MUTEX_NAME));
if (!memory_mutex) {
zend_accel_error(ACCEL_LOG_FATAL, "Cannot create mutex");
zend_accel_error(ACCEL_LOG_FATAL, "Cannot create mutex (error %u)", GetLastError());
return;
}
ReleaseMutex(memory_mutex);
+26
View File
@@ -0,0 +1,26 @@
--TEST--
Bug #80805: create simple class and get error in opcache.so
--FILE--
<?php
class Test {
public int $foo;
public function __construct()
{
$this->foo = 2;
}
public function inc(): int
{
return $this->foo += 2;
}
}
$test = new Test();
var_dump($test->foo);
$test->inc();
var_dump($test->foo);
?>
--EXPECT--
int(2)
int(4)
+17
View File
@@ -0,0 +1,17 @@
--TEST--
Incorrect DCE of FREE of COALESCE
--FILE--
<?php
function test(?string $str) {
$str ?? $str = '';
return strlen($str);
}
$foo = 'foo';
$foo .= 'bar';
var_dump(test($foo));
?>
--EXPECT--
int(6)
+42 -5
View File
@@ -3,14 +3,51 @@ Bug #62890 (default_socket_timeout=-1 causes connection to timeout)
--SKIPIF--
<?php
if (!extension_loaded('openssl')) die('skip openssl extension not available');
if (getenv('SKIP_ONLINE_TESTS')) die('skip online test');
if (!function_exists("proc_open")) die("skip no proc_open");
?>
--INI--
default_socket_timeout=-1
--FILE--
<?php
$clientCtx = stream_context_create(['ssl' => ['verify_peer' => false]]);
var_dump((bool) file_get_contents('https://www.php.net', false, $clientCtx));
$certFile = __DIR__ . DIRECTORY_SEPARATOR . 'bug62890.pem.tmp';
$serverCode = <<<'CODE'
$flags = STREAM_SERVER_BIND|STREAM_SERVER_LISTEN;
$ctx = stream_context_create(['ssl' => [
'local_cert' => '%s',
'security_level' => 1,
]]);
$server = stream_socket_server('tls://127.0.0.1:64321', $errno, $errstr, $flags, $ctx);
phpt_notify();
@stream_socket_accept($server, 3);
CODE;
$serverCode = sprintf($serverCode, $certFile);
$clientCode = <<<'CODE'
$flags = STREAM_CLIENT_CONNECT;
$ctx = stream_context_create(['ssl' => [
'verify_peer' => false,
'verify_peer_name' => false,
'security_level' => 1,
]]);
phpt_wait();
$client = stream_socket_client("tls://127.0.0.1:64321", $errno, $errstr, 3, $flags, $ctx);
var_dump($client);
CODE;
include 'CertificateGenerator.inc';
$certificateGenerator = new CertificateGenerator();
$certificateGenerator->saveNewCertAsFileWithKey('bug62890', $certFile);
include 'ServerClientTestCase.inc';
ServerClientTestCase::getInstance()->run($clientCode, $serverCode);
?>
--EXPECT--
bool(true)
--CLEAN--
<?php
@unlink(__DIR__ . DIRECTORY_SEPARATOR . 'bug62890.pem.tmp');
?>
--EXPECTF--
resource(%d) of type (stream)
+2 -1
View File
@@ -3,7 +3,8 @@ Bug #80747: Providing RSA key size < 512 generates key that crash PHP
--FILE--
--SKIPIF--
<?php
if (!extension_loaded("openssl")) die("skip");
if (!extension_loaded("openssl")) die("skip openssl not loaded");
if (OPENSSL_VERSION_NUMBER < 0x10100000) die("skip OpenSSL >= v1.1.0 required");
?>
--FILE--
<?php
+3 -1
View File
@@ -14,7 +14,8 @@ $serverCode = <<<'CODE'
$serverUri = "ssl://127.0.0.1:64321";
$serverFlags = STREAM_SERVER_BIND | STREAM_SERVER_LISTEN;
$serverCtx = stream_context_create(['ssl' => [
'local_cert' => '%s'
'local_cert' => '%s',
'security_level' => 1,
]]);
$server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx);
@@ -36,6 +37,7 @@ $clientCode = <<<'CODE'
'cafile' => '%s',
'peer_name' => '%s',
'capture_session_meta' => true,
'security_level' => 1,
]]);
phpt_wait();
@@ -14,7 +14,8 @@ $serverCode = <<<'CODE'
$serverUri = "ssl://127.0.0.1:64321";
$serverFlags = STREAM_SERVER_BIND | STREAM_SERVER_LISTEN;
$serverCtx = stream_context_create(['ssl' => [
'local_cert' => '%s'
'local_cert' => '%s',
'security_level' => 1,
]]);
$server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx);
@@ -34,6 +35,7 @@ $clientCode = <<<'CODE'
'verify_peer' => true,
'cafile' => '%s',
'peer_name' => '%s',
'security_level' => 1,
]]);
phpt_wait();
@@ -14,7 +14,8 @@ $serverCode = <<<'CODE'
$serverUri = "ssl://127.0.0.1:64321";
$serverFlags = STREAM_SERVER_BIND | STREAM_SERVER_LISTEN;
$serverCtx = stream_context_create(['ssl' => [
'local_cert' => '%s'
'local_cert' => '%s',
'security_level' => 1,
]]);
$server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx);
@@ -35,6 +36,7 @@ $clientCode = <<<'CODE'
'verify_peer' => true,
'cafile' => '%s',
'peer_name' => '%s',
'security_level' => 1,
]]);
phpt_wait();
@@ -17,8 +17,9 @@ $serverCode = <<<'CODE'
$serverCtx = stream_context_create(['ssl' => [
'local_cert' => '%s',
// Only accept TLSv1.2 connections
// Only accept TLSv1.0 and TLSv1.2 connections
'crypto_method' => STREAM_CRYPTO_METHOD_TLSv1_0_SERVER | STREAM_CRYPTO_METHOD_TLSv1_2_SERVER,
'security_level' => 1,
]]);
$server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx);
@@ -39,6 +40,7 @@ $clientCode = <<<'CODE'
'verify_peer' => true,
'cafile' => '%s',
'peer_name' => '%s',
'security_level' => 1,
]]);
phpt_wait();
@@ -16,6 +16,7 @@ $serverCode = <<<'CODE'
$serverCtx = stream_context_create(['ssl' => [
'local_cert' => '%s',
'crypto_method' => STREAM_CRYPTO_METHOD_TLSv1_0_SERVER,
'security_level' => 1,
]]);
$server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx);
@@ -36,6 +37,7 @@ $clientCode = <<<'CODE'
'verify_peer' => true,
'cafile' => '%s',
'peer_name' => '%s',
'security_level' => 1,
]]);
phpt_wait();
+3 -2
View File
@@ -955,7 +955,7 @@ PHP_FUNCTION(pcntl_exec)
int envc = 0, envi = 0;
char **argv = NULL, **envp = NULL;
char **current_arg, **pair;
int pair_length;
size_t pair_length;
zend_string *key;
char *path;
size_t path_len;
@@ -1015,8 +1015,9 @@ PHP_FUNCTION(pcntl_exec)
}
/* Length of element + equal sign + length of key + null */
ZEND_ASSERT(Z_STRLEN_P(element) < SIZE_MAX && ZSTR_LEN(key) < SIZE_MAX);
*pair = safe_emalloc(Z_STRLEN_P(element) + 1, sizeof(char), ZSTR_LEN(key) + 1);
pair_length = Z_STRLEN_P(element) + ZSTR_LEN(key) + 2;
*pair = emalloc(pair_length);
strlcpy(*pair, ZSTR_VAL(key), ZSTR_LEN(key) + 1);
strlcat(*pair, "=", pair_length);
strlcat(*pair, Z_STRVAL_P(element), pair_length);
+6 -1
View File
@@ -9,6 +9,9 @@ pcntl: SIG_BLOCK, SIG_UNBLOCK, SIG_SETMASK
--FILE--
<?php
// Clear mask
pcntl_sigprocmask(SIG_SETMASK, array(), $prev);
pcntl_sigprocmask(SIG_BLOCK, array(SIGCHLD,SIGTERM), $old);
var_dump(count($old));
pcntl_sigprocmask(SIG_BLOCK, array(SIGINT), $old);
@@ -19,7 +22,9 @@ pcntl_sigprocmask(SIG_SETMASK, array(SIGINT), $old);
var_dump(count($old));
pcntl_sigprocmask(SIG_SETMASK, array(), $old);
var_dump(count($old));
pcntl_sigprocmask(SIG_SETMASK, array(), $old);
// Restore previous mask
pcntl_sigprocmask(SIG_SETMASK, $prev, $old);
var_dump(count($old));
?>
+5 -1
View File
@@ -767,8 +767,8 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache_ex(zend_string *regex, in
zend_hash_add_ptr(&char_tables, _k, (void *)tables);
zend_string_release(_k);
}
pcre2_set_character_tables(cctx, tables);
}
pcre2_set_character_tables(cctx, tables);
/* Set extra options for the compile context. */
if (PHP_PCRE_DEFAULT_EXTRA_COPTIONS != extra_coptions) {
@@ -2644,6 +2644,10 @@ matched:
the match again at the same point. If this fails (picked up above) we
advance to the next character. */
if (start_offset == offsets[0]) {
/* Get next piece if no limit or limit not yet reached and something matched*/
if (limit_val != -1 && limit_val <= 1) {
break;
}
count = pcre2_match(pce->re, (PCRE2_SPTR)subject, ZSTR_LEN(subject_str), start_offset,
PCRE2_NO_UTF_CHECK | PCRE2_NOTEMPTY_ATSTART | PCRE2_ANCHORED, match_data, mctx);
if (count >= 0) {
+12
View File
@@ -0,0 +1,12 @@
--TEST--
Bug #80866 preg_split ignores limit flag when pattern with \K has 0-width fullstring match
--FILE--
<?php
var_export(preg_split('~.{3}\K~', 'abcdefghijklm', 3));
?>
--EXPECT--
array (
0 => 'abc',
1 => 'def',
2 => 'ghijklm',
)
+18
View File
@@ -0,0 +1,18 @@
--TEST--
Changing LC_CTYPE back to C
--SKIPIF--
<?php
if (!setlocale(LC_CTYPE, "de_DE", "de-DE")) die("skip requires de_DE locale");
?>
--FILE--
<?php
var_dump(setlocale(LC_CTYPE, "de_DE", "de-DE") !== false);
var_dump(preg_match('/\w/', "\xe4"));
var_dump(setlocale(LC_CTYPE, "C") !== false);
var_dump(preg_match('/\w/', "\xe4"));
?>
--EXPECT--
bool(true)
int(1)
bool(true)
int(0)
+15 -5
View File
@@ -652,6 +652,7 @@ static int odbc_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, zend_ulong
/* if it is a column containing "long" data, perform late binding now */
if (C->is_long) {
SQLLEN orig_fetched_len = SQL_NULL_DATA;
zend_ulong used = 0;
char *buf;
RETCODE rc;
@@ -662,18 +663,20 @@ static int odbc_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, zend_ulong
rc = SQLGetData(S->stmt, colno+1, C->is_unicode ? SQL_C_BINARY : SQL_C_CHAR, C->data,
256, &C->fetched_len);
orig_fetched_len = C->fetched_len;
if (rc == SQL_SUCCESS) {
if (rc == SQL_SUCCESS && C->fetched_len < 256) {
/* all the data fit into our little buffer;
* jump down to the generic bound data case */
goto in_data;
}
if (rc == SQL_SUCCESS_WITH_INFO) {
if (rc == SQL_SUCCESS_WITH_INFO || rc == SQL_SUCCESS) {
/* this is a 'long column'
read the column in 255 byte blocks until the end of the column is reached, reassembling those blocks
in order into the output buffer
in order into the output buffer; 255 bytes are an optimistic assumption, since the driver may assert
more or less NUL bytes at the end; we cater to that later, if actual length information is available
this loop has to work whether or not SQLGetData() provides the total column length.
calling SQLDescribeCol() or other, specifically to get the column length, then doing a single read
@@ -687,10 +690,17 @@ static int odbc_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, zend_ulong
do {
C->fetched_len = 0;
/* read block. 256 bytes => 255 bytes are actually read, the last 1 is NULL */
rc = SQLGetData(S->stmt, colno+1, SQL_C_CHAR, buf2, 256, &C->fetched_len);
rc = SQLGetData(S->stmt, colno+1, C->is_unicode ? SQL_C_BINARY : SQL_C_CHAR, buf2, 256, &C->fetched_len);
/* adjust `used` in case we have length info from the driver */
if (orig_fetched_len >= 0 && C->fetched_len >= 0) {
SQLLEN fixed_used = orig_fetched_len - C->fetched_len;
ZEND_ASSERT(fixed_used <= used + 1);
used = fixed_used;
}
/* resize output buffer and reassemble block */
if (rc==SQL_SUCCESS_WITH_INFO) {
if (rc==SQL_SUCCESS_WITH_INFO || (rc==SQL_SUCCESS && C->fetched_len > 255)) {
/* point 5, in section "Retrieving Data with SQLGetData" in http://msdn.microsoft.com/en-us/library/windows/desktop/ms715441(v=vs.85).aspx
states that if SQL_SUCCESS_WITH_INFO, fetched_len will be > 255 (greater than buf2's size)
(if a driver fails to follow that and wrote less than 255 bytes to buf2, this will AV or read garbage into buf) */
+32
View File
@@ -0,0 +1,32 @@
--TEST--
Bug #80783 (PDO ODBC truncates BLOB records at every 256th byte)
--SKIPIF--
<?php
if (!extension_loaded('pdo_odbc')) die('skip pdo_odbc extension not available');
require 'ext/pdo/tests/pdo_test.inc';
PDOTest::skip();
?>
--FILE--
<?php
require 'ext/pdo/tests/pdo_test.inc';
$db = PDOTest::test_factory(dirname(__FILE__) . '/common.phpt');
$db->exec("CREATE TABLE bug80783 (name IMAGE)");
$string = str_repeat("0123456789", 50);
$db->exec("INSERT INTO bug80783 VALUES('$string')");
$stmt = $db->prepare("SELECT name FROM bug80783");
$stmt->bindColumn(1, $data, PDO::PARAM_LOB);
$stmt->execute();
$stmt->fetch(PDO::FETCH_BOUND);
var_dump($data === bin2hex($string));
?>
--CLEAN--
<?php
require 'ext/pdo/tests/pdo_test.inc';
$db = PDOTest::test_factory(dirname(__FILE__) . '/common.phpt');
$db->exec("DROP TABLE bug80783");
?>
--EXPECT--
bool(true)
+33
View File
@@ -0,0 +1,33 @@
--TEST--
Bug #80783 (PDO ODBC truncates BLOB records at every 256th byte)
--SKIPIF--
<?php
if (!extension_loaded('pdo_odbc')) die('skip pdo_odbc extension not available');
require 'ext/pdo/tests/pdo_test.inc';
PDOTest::skip();
?>
--FILE--
<?php
require 'ext/pdo/tests/pdo_test.inc';
$db = PDOTest::test_factory(dirname(__FILE__) . '/common.phpt');
$db->exec("CREATE TABLE bug80783a (name NVARCHAR(MAX))");
$string = str_repeat("0123456789", 50);
$db->exec("INSERT INTO bug80783a VALUES('$string')");
$stmt = $db->prepare("SELECT name FROM bug80783a");
$stmt->setAttribute(PDO::ODBC_ATTR_ASSUME_UTF8, true);
$stmt->bindColumn(1, $data, PDO::PARAM_STR);
$stmt->execute();
$stmt->fetch(PDO::FETCH_BOUND);
var_dump($data === $string);
?>
--CLEAN--
<?php
require 'ext/pdo/tests/pdo_test.inc';
$db = PDOTest::test_factory(dirname(__FILE__) . '/common.phpt');
$db->exec("DROP TABLE bug80783a");
?>
--EXPECT--
bool(true)
+12 -2
View File
@@ -563,22 +563,32 @@ PHP_FUNCTION(posix_setegid)
#ifdef HAVE_GETGROUPS
PHP_FUNCTION(posix_getgroups)
{
gid_t gidlist[NGROUPS_MAX];
gid_t *gidlist;
int result;
int i;
PHP_POSIX_NO_ARGS;
if ((result = getgroups(NGROUPS_MAX, gidlist)) < 0) {
/* MacOS may return more than NGROUPS_MAX groups.
* Fetch the actual number of groups and create an appropriate allocation. */
if ((result = getgroups(0, NULL)) < 0) {
POSIX_G(last_error) = errno;
RETURN_FALSE;
}
gidlist = emalloc(sizeof(gid_t) * result);
if ((result = getgroups(result, gidlist)) < 0) {
POSIX_G(last_error) = errno;
efree(gidlist);
RETURN_FALSE;
}
array_init(return_value);
for (i=0; i<result; i++) {
add_next_index_long(return_value, gidlist[i]);
}
efree(gidlist);
}
#endif
/* }}} */
+9
View File
@@ -1534,6 +1534,11 @@ ZEND_METHOD(reflection_function, __construct)
}
}
if (intern->ptr) {
zval_ptr_dtor(&intern->obj);
zval_ptr_dtor(reflection_prop_name(object));
}
ZVAL_STR_COPY(reflection_prop_name(object), fptr->common.function_name);
intern->ptr = fptr;
intern->ref_type = REF_TYPE_FUNCTION;
@@ -2073,6 +2078,10 @@ ZEND_METHOD(reflection_generator, __construct)
return;
}
if (intern->ce) {
zval_ptr_dtor(&intern->obj);
}
intern->ref_type = REF_TYPE_GENERATOR;
Z_ADDREF_P(generator);
ZVAL_OBJ(&intern->obj, Z_OBJ_P(generator));
+29 -27
View File
@@ -1261,13 +1261,11 @@ static void php_session_remove_cookie(void) {
zend_llist_element *next;
zend_llist_element *current;
char *session_cookie;
zend_string *e_session_name;
size_t session_cookie_len;
size_t len = sizeof("Set-Cookie")-1;
e_session_name = php_url_encode(PS(session_name), strlen(PS(session_name)));
spprintf(&session_cookie, 0, "Set-Cookie: %s=", ZSTR_VAL(e_session_name));
zend_string_free(e_session_name);
ZEND_ASSERT(strpbrk(PS(session_name), "=,; \t\r\n\013\014") == NULL);
spprintf(&session_cookie, 0, "Set-Cookie: %s=", PS(session_name));
session_cookie_len = strlen(session_cookie);
current = l->head;
@@ -1299,7 +1297,7 @@ static int php_session_send_cookie(void) /* {{{ */
{
smart_str ncookie = {0};
zend_string *date_fmt = NULL;
zend_string *e_session_name, *e_id;
zend_string *e_id;
if (SG(headers_sent)) {
const char *output_start_filename = php_output_get_start_filename();
@@ -1313,16 +1311,20 @@ static int php_session_send_cookie(void) /* {{{ */
return FAILURE;
}
/* URL encode session_name and id because they might be user supplied */
e_session_name = php_url_encode(PS(session_name), strlen(PS(session_name)));
/* Prevent broken Set-Cookie header, because the session_name might be user supplied */
if (strpbrk(PS(session_name), "=,; \t\r\n\013\014") != NULL) { /* man isspace for \013 and \014 */
php_error_docref(NULL, E_WARNING, "session.name cannot contain any of the following '=,; \\t\\r\\n\\013\\014'");
return FAILURE;
}
/* URL encode id because it might be user supplied */
e_id = php_url_encode(ZSTR_VAL(PS(id)), ZSTR_LEN(PS(id)));
smart_str_appendl(&ncookie, "Set-Cookie: ", sizeof("Set-Cookie: ")-1);
smart_str_appendl(&ncookie, ZSTR_VAL(e_session_name), ZSTR_LEN(e_session_name));
smart_str_appendl(&ncookie, PS(session_name), strlen(PS(session_name)));
smart_str_appendc(&ncookie, '=');
smart_str_appendl(&ncookie, ZSTR_VAL(e_id), ZSTR_LEN(e_id));
zend_string_release_ex(e_session_name, 0);
zend_string_release_ex(e_id, 0);
if (PS(cookie_lifetime) > 0) {
@@ -1921,13 +1923,24 @@ static PHP_FUNCTION(session_module_name)
}
/* }}} */
static inline void set_user_save_handler_ini(void) {
zend_string *ini_name, *ini_val;
ini_name = zend_string_init("session.save_handler", sizeof("session.save_handler") - 1, 0);
ini_val = zend_string_init("user", sizeof("user") - 1, 0);
PS(set_handler) = 1;
zend_alter_ini_entry(ini_name, ini_val, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
PS(set_handler) = 0;
zend_string_release_ex(ini_val, 0);
zend_string_release_ex(ini_name, 0);
}
/* {{{ proto bool session_set_save_handler(string open, string close, string read, string write, string destroy, string gc, string create_sid)
Sets user-level functions */
static PHP_FUNCTION(session_set_save_handler)
{
zval *args = NULL;
int i, num_args, argc = ZEND_NUM_ARGS();
zend_string *ini_name, *ini_val;
if (PS(session_status) == php_session_active) {
php_error_docref(NULL, E_WARNING, "Cannot change save handler when session is active");
@@ -2029,14 +2042,8 @@ static PHP_FUNCTION(session_set_save_handler)
remove_user_shutdown_function("session_shutdown", sizeof("session_shutdown") - 1);
}
if (PS(mod) && PS(session_status) != php_session_active && PS(mod) != &ps_mod_user) {
ini_name = zend_string_init("session.save_handler", sizeof("session.save_handler") - 1, 0);
ini_val = zend_string_init("user", sizeof("user") - 1, 0);
PS(set_handler) = 1;
zend_alter_ini_entry(ini_name, ini_val, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
PS(set_handler) = 0;
zend_string_release_ex(ini_val, 0);
zend_string_release_ex(ini_name, 0);
if (PS(session_status) != php_session_active && (!PS(mod) || PS(mod) != &ps_mod_user)) {
set_user_save_handler_ini();
}
RETURN_TRUE;
@@ -2064,14 +2071,8 @@ static PHP_FUNCTION(session_set_save_handler)
}
}
if (PS(mod) && PS(mod) != &ps_mod_user) {
ini_name = zend_string_init("session.save_handler", sizeof("session.save_handler") - 1, 0);
ini_val = zend_string_init("user", sizeof("user") - 1, 0);
PS(set_handler) = 1;
zend_alter_ini_entry(ini_name, ini_val, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
PS(set_handler) = 0;
zend_string_release_ex(ini_val, 0);
zend_string_release_ex(ini_name, 0);
if (!PS(mod) || PS(mod) != &ps_mod_user) {
set_user_save_handler_ini();
}
for (i = 0; i < argc; i++) {
@@ -2854,7 +2855,8 @@ static int php_rinit_session(zend_bool auto_start) /* {{{ */
{
php_rinit_session_globals();
if (PS(mod) == NULL) {
PS(mod) = NULL;
{
char *value;
value = zend_ini_string("session.save_handler", sizeof("session.save_handler") - 1, 0);
+15
View File
@@ -0,0 +1,15 @@
--TEST--
Bug #80774 (session_name() problem with backslash)
--SKIPIF--
<?php
if (!extension_loaded('session')) die("skip session extension not available");
?>
--FILE--
<?php
session_name("foo\\bar");
session_id('12345');
session_start();
?>
--EXPECTHEADERS--
Set-Cookie: foo\bar=12345; path=/
--EXPECT--
+37
View File
@@ -0,0 +1,37 @@
--TEST--
Bug #80889 (Cannot set save handler when save_handler is invalid)
--SKIPIF--
<?php include('skipif.inc'); ?>
--INI--
session.save_handler=whatever
--FILE--
<?php
class DummyHandler implements SessionHandlerInterface {
public function open($savePath, $sessionName) {
return true;
}
public function close() {
return true;
}
public function read($id) {
return '';
}
public function write($id, $data) {
return true;
}
public function destroy($id) {
return true;
}
public function gc($maxlifetime) {
return true;
}
}
$initHandler = ini_get('session.save_handler');
session_set_save_handler(new DummyHandler());
$setHandler = ini_get('session.save_handler');
var_dump($initHandler, $setHandler);
?>
--EXPECT--
string(8) "whatever"
string(4) "user"
+35
View File
@@ -0,0 +1,35 @@
--TEST--
Bug #80889 (Cannot set save handler when save_handler is invalid)
--SKIPIF--
<?php include('skipif.inc'); ?>
--INI--
session.save_handler=whatever
--FILE--
<?php
$initHandler = ini_get('session.save_handler');
session_set_save_handler(
function ($savePath, $sessionName) {
return true;
},
function () {
return true;
},
function ($id) {
return '';
},
function ($id, $data) {
return true;
},
function ($id) {
return true;
},
function ($maxlifetime) {
return true;
}
);
$setHandler = ini_get('session.save_handler');
var_dump($initHandler, $setHandler);
?>
--EXPECT--
string(8) "whatever"
string(4) "user"
@@ -48,6 +48,8 @@ string(9) "PHPSESSID"
bool(true)
string(9) "PHPSESSID"
string(9) "PHPSESSID"
Warning: session_start(): session.name cannot contain any of the following '=,; \t\r\n\013\014' in %s on line %d
bool(true)
string(1) " "
bool(true)
@@ -55,6 +57,8 @@ string(1) " "
Warning: session_name(): session.name cannot be a numeric or empty '' in %s on line %d
string(1) " "
Warning: session_start(): session.name cannot contain any of the following '=,; \t\r\n\013\014' in %s on line %d
bool(true)
string(1) " "
bool(true)
+4 -1
View File
@@ -3381,6 +3381,7 @@ xmlNsPtr encode_add_ns(xmlNodePtr node, const char* ns)
} else {
smart_str prefix = {0};
int num = ++SOAP_GLOBAL(cur_uniq_ns);
xmlChar *enc_ns;
while (1) {
smart_str_appendl(&prefix, "ns", 2);
@@ -3394,7 +3395,9 @@ xmlNsPtr encode_add_ns(xmlNodePtr node, const char* ns)
num = ++SOAP_GLOBAL(cur_uniq_ns);
}
xmlns = xmlNewNs(node->doc->children, BAD_CAST(ns), BAD_CAST(prefix.s ? ZSTR_VAL(prefix.s) : ""));
enc_ns = xmlEncodeSpecialChars(node->doc, BAD_CAST(ns));
xmlns = xmlNewNs(node->doc->children, enc_ns, BAD_CAST(prefix.s ? ZSTR_VAL(prefix.s) : ""));
xmlFree(enc_ns);
smart_str_free(&prefix);
}
}
+26
View File
@@ -0,0 +1,26 @@
--TEST--
Bug #69668 (SOAP: special XML characters in namespace URIs not encoded)
--SKIPIF--
<?php
require_once('skipif.inc');
?>
--FILE--
<?php
class MySoapClient extends SoapClient {
public function __doRequest($request, $location, $action, $version, $one_way = 0) {
echo $request, PHP_EOL;
return '';
}
}
$client = new MySoapClient(__DIR__ . '/bug69668.wsdl', [
'trace' => true,
'exceptions' => true,
'cache_wsdl' => WSDL_CACHE_NONE,
]);
$client->test();
?>
--EXPECT--
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://localhost/69668.php?a=a&amp;b=b" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body><ns1:test/></SOAP-ENV:Body></SOAP-ENV:Envelope>
+35
View File
@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:tns="http://localhost/69668.php?a=a&amp;b=b" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap-enc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" name="TestService" targetNamespace="http://localhost/69668.php?a=a&amp;b=b">
<types>
<xsd:schema targetNamespace="http://localhost/69668.php?a=a&amp;b=b" />
</types>
<portType name="TestServicePort">
<operation name="test">
<documentation>test</documentation>
<input message="tns:testIn" />
<output message="tns:testOut" />
</operation>
</portType>
<binding name="TestServiceBinding" type="tns:TestServicePort">
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http" />
<operation name="test">
<soap:operation soapAction="http://localhost/69668.php?a=a&amp;b=b#test" />
<input>
<soap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://localhost/69668.php?a=a&amp;b=b" />
</input>
<output>
<soap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://localhost/69668.php?a=a&amp;b=b" />
</output>
</operation>
</binding>
<service name="TestServiceService">
<port name="TestServicePort" binding="tns:TestServiceBinding">
<soap:address location="http://localhost/69668.php?a=a&amp;b=b" />
</port>
</service>
<message name="testIn" />
<message name="testOut">
<part name="return" type="xsd:string" />
</message>
</definitions>
+6 -14
View File
@@ -680,7 +680,7 @@ finish:
/* status codes of 1xx are "informational", and will be followed by a real response
* e.g "100 Continue". RFC 7231 states that unexpected 1xx status MUST be parsed,
* and MAY be ignored. As such, we need to skip ahead to the "real" status*/
if (response_code >= 100 && response_code < 200) {
if (response_code >= 100 && response_code < 200 && response_code != 101) {
/* consume lines until we find a line starting 'HTTP/1' */
while (
!php_stream_eof(stream)
@@ -732,24 +732,16 @@ finish:
/* read past HTTP headers */
http_header_line = emalloc(HTTP_HEADER_BLOCK_SIZE);
while (!php_stream_eof(stream)) {
size_t http_header_line_length;
if (php_stream_get_line(stream, http_header_line, HTTP_HEADER_BLOCK_SIZE, &http_header_line_length) && *http_header_line != '\n' && *http_header_line != '\r') {
if (http_header_line != NULL) {
efree(http_header_line);
}
if ((http_header_line = php_stream_get_line(stream, NULL, 0, &http_header_line_length)) && *http_header_line != '\n' && *http_header_line != '\r') {
char *e = http_header_line + http_header_line_length - 1;
char *http_header_value;
if (*e != '\n') {
do { /* partial header */
if (php_stream_get_line(stream, http_header_line, HTTP_HEADER_BLOCK_SIZE, &http_header_line_length) == NULL) {
php_stream_wrapper_log_error(wrapper, options, "Failed to read HTTP headers");
goto out;
}
e = http_header_line + http_header_line_length - 1;
} while (*e != '\n');
continue;
}
while (e >= http_header_line && (*e == '\n' || *e == '\r')) {
e--;
}
+2 -2
View File
@@ -176,7 +176,7 @@ static ZEND_COLD void php_print_gpcse_array(char *name, uint32_t name_length)
key = zend_string_init(name, name_length, 0);
zend_is_auto_global(key);
if ((data = zend_hash_find(&EG(symbol_table), key)) != NULL && (Z_TYPE_P(data) == IS_ARRAY)) {
if ((data = zend_hash_find_deref(&EG(symbol_table), key)) != NULL && (Z_TYPE_P(data) == IS_ARRAY)) {
ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(data), num_key, string_key, tmp) {
if (!sapi_module.phpinfo_as_text) {
php_info_print("<tr>");
@@ -1000,7 +1000,7 @@ PHPAPI ZEND_COLD void php_print_info(int flag)
}
if ((flag & PHP_INFO_CREDITS) && !sapi_module.phpinfo_as_text) {
if (flag & PHP_INFO_CREDITS) {
php_info_print_hr();
php_print_credits(PHP_CREDITS_ALL & ~PHP_CREDITS_FULLPAGE);
}
+20
View File
@@ -0,0 +1,20 @@
--TEST--
Bug #80915: Taking a reference to $_SERVER hides its values from phpinfo()
--FILE--
<?php
$_ENV = [];
$_SERVER = [ 'test' => 'test' ];
$reference =& $_SERVER;
phpinfo(INFO_VARIABLES);
?>
--EXPECT--
phpinfo()
PHP Variables
Variable => Value
$_SERVER['test'] => test
@@ -0,0 +1,16 @@
--TEST--
Bug #80771 (phpinfo(INFO_CREDITS) displays nothing in CLI)
--FILE--
<?php
ob_start();
phpinfo(INFO_CREDITS);
$info = ob_get_clean();
ob_start();
phpcredits();
$credits = ob_get_clean();
var_dump(strpos($info, $credits) !== false);
?>
--EXPECT--
bool(true)
+26
View File
@@ -0,0 +1,26 @@
--TEST--
Bug #78719 (http wrapper silently ignores long Location headers)
--SKIPIF--
<?php require 'server.inc'; http_server_skipif('tcp://127.0.0.1:12342'); ?>
--INI--
allow_url_fopen=1
--FILE--
<?php
require 'server.inc';
$url = str_repeat('*', 2000);
$responses = array(
"data://text/plain,HTTP/1.0 302 Ok\r\nLocation: $url\r\n\r\nBody",
);
$pid = http_server("tcp://127.0.0.1:12342", $responses, $output);
$context = stream_context_create(['http' => ['follow_location' => 0]]);
$stream = fopen('http://127.0.0.1:12342/', 'r', false, $context);
var_dump(stream_get_contents($stream));
var_dump(stream_get_meta_data($stream)['wrapper_data'][1] === "Location: $url");
http_server_kill($pid);
?>
--EXPECTF--
string(4) "Body"
bool(true)
+41
View File
@@ -0,0 +1,41 @@
--TEST--
Bug #80838 (HTTP wrapper waits for HTTP 1 response after HTTP 101)
--INI--
allow_url_fopen=1
--SKIPIF--
<?php require 'server.inc'; http_server_skipif('tcp://127.0.0.1:12342'); ?>
--FILE--
<?php
require 'server.inc';
$responses = [
"data://text/plain,HTTP/1.1 101 Switching Protocols\r\nHeader1: Value1\r\nHeader2: Value2\r\n\r\n"
. "Hello from another protocol"
];
$pid = http_server('tcp://127.0.0.1:12342', $responses);
$options = [
'http' => [
'ignore_errors' => true
],
];
$ctx = stream_context_create($options);
$fd = fopen('http://127.0.0.1:12342/', 'rb', false, $ctx);
fclose($fd);
var_dump($http_response_header);
http_server_kill($pid);
?>
--EXPECT--
array(3) {
[0]=>
string(32) "HTTP/1.1 101 Switching Protocols"
[1]=>
string(15) "Header1: Value1"
[2]=>
string(15) "Header2: Value2"
}
+93
View File
@@ -0,0 +1,93 @@
--TEST--
Bug #80751 (Comma in recipient name breaks email delivery)
--SKIPIF--
<?php
if (PHP_OS_FAMILY !== 'Windows') die('skip Windows only test');
if (getenv("SKIP_SLOW_TESTS")) die('skip slow test');
require_once __DIR__ . '/mail_skipif.inc';
?>
--INI--
SMTP=localhost
smtp_port=25
--FILE--
<?php
require_once __DIR__ . '/mail_include.inc';
function find_and_delete_message($username, $subject) {
global $default_mailbox, $password;
$imap_stream = imap_open($default_mailbox, $username, $password);
if ($imap_stream === false) {
die("Cannot connect to IMAP server $server: " . imap_last_error() . "\n");
}
$found = false;
$repeat_count = 20; // we will repeat a max of 20 times
while (!$found && $repeat_count > 0) {
// sleep for a while to allow msg to be delivered
sleep(1);
$num_messages = imap_check($imap_stream)->Nmsgs;
for ($i = $num_messages; $i > 0; $i--) {
$info = imap_headerinfo($imap_stream, $i);
if ($info->subject === $subject) {
$header = imap_fetchheader($imap_stream, $i);
echo "Return-Path header found: ";
var_dump(strpos($header, 'Return-Path: joe@example.com') !== false);
echo "To header found: ";
var_dump(strpos($header, 'To: "<bob@example.com>" <info@mail.local>') !== false);
echo "From header found: ";
var_dump(strpos($header, 'From: "<bob@example.com>" <joe@example.com>') !== false);
echo "Cc header found: ";
var_dump(strpos($header, 'Cc: "Lastname, Firstname\\\\" <admin@mail.local>') !== false);
imap_delete($imap_stream, $i);
$found = true;
break;
}
}
$repeat_count--;
}
imap_close($imap_stream, CL_EXPUNGE);
return $found;
}
$to = "\"<bob@example.com>\" <{$users[1]}@$domain>";
$subject = bin2hex(random_bytes(16));
$message = 'hello';
$headers = "From: \"<bob@example.com>\" <joe@example.com>\r\n"
. "Cc: \"Lastname, Firstname\\\\\" <{$users[2]}@$domain>\r\n"
. "Bcc: \"Firstname \\\"Ni,ck\\\" Lastname\" <{$users[3]}@$domain>\r\n";
$res = mail($to, $subject, $message, $headers);
if ($res !== true) {
die("TEST FAILED : Unable to send test email\n");
} else {
echo "Message sent OK\n";
}
foreach ([$users[1], $users[2], $users[3]] as $user) {
if (!find_and_delete_message("$user@$domain", $subject)) {
echo "TEST FAILED: email not delivered\n";
} else {
echo "TEST PASSED: Message sent and deleted OK\n";
}
}
?>
--EXPECT--
Message sent OK
Return-Path header found: bool(true)
To header found: bool(true)
From header found: bool(true)
Cc header found: bool(true)
TEST PASSED: Message sent and deleted OK
Return-Path header found: bool(true)
To header found: bool(true)
From header found: bool(true)
Cc header found: bool(true)
TEST PASSED: Message sent and deleted OK
Return-Path header found: bool(true)
To header found: bool(true)
From header found: bool(true)
Cc header found: bool(true)
TEST PASSED: Message sent and deleted OK
+32
View File
@@ -0,0 +1,32 @@
--TEST--
Bug #75776 (Flushing streams with compression filter is broken)
--SKIPIF--
<?php
if (!extension_loaded('zlib')) die('skip zlib extension not available');
if (!extension_loaded('bz2')) die('skip bz2 extension not available');
?>
--FILE--
<?php
$compression = [
'gz' => ['zlib.deflate', 'gzinflate'],
'bz2' => ['bzip2.compress', 'bzdecompress']
];
foreach ($compression as $ext => [$filter, $function]) {
$stream = fopen(__DIR__ . "/75776.$ext", 'w');
stream_filter_append($stream, $filter);
fwrite($stream,"sdfgdfg");
fflush($stream);
fclose($stream);
$compressed = file_get_contents(__DIR__ . "/75776.$ext");
var_dump($function($compressed));
}
?>
--EXPECT--
string(7) "sdfgdfg"
string(7) "sdfgdfg"
--CLEAN--
<?php
@unlink(__DIR__ . "/75776.gz");
@unlink(__DIR__ . "/75776.bz2");
?>
+4 -4
View File
@@ -2,7 +2,7 @@
/* edit configure.ac to change version number */
#define PHP_MAJOR_VERSION 7
#define PHP_MINOR_VERSION 4
#define PHP_RELEASE_VERSION 16
#define PHP_EXTRA_VERSION "-dev"
#define PHP_VERSION "7.4.16-dev"
#define PHP_VERSION_ID 70416
#define PHP_RELEASE_VERSION 19
#define PHP_EXTRA_VERSION ""
#define PHP_VERSION "7.4.19"
#define PHP_VERSION_ID 70419
+1 -1
View File
@@ -445,7 +445,7 @@ fprintf(stderr, "stream_free: %s:%p[%s] preserve_handle=%d release_cast=%d remov
(close_options & PHP_STREAM_FREE_RSRC_DTOR) == 0);
#endif
if (stream->flags & PHP_STREAM_FLAG_WAS_WRITTEN) {
if (stream->flags & PHP_STREAM_FLAG_WAS_WRITTEN || stream->writefilters.head) {
/* make sure everything is saved */
_php_stream_flush(stream, 1);
}
+4 -1
View File
@@ -797,7 +797,7 @@ HELP;
junit_save_xml();
if (getenv('REPORT_EXIT_STATUS') !== '0' &&
getenv('REPORT_EXIT_STATUS') !== 'no' && ($sum_results['FAILED'] || $sum_results['LEAKED'])) {
getenv('REPORT_EXIT_STATUS') !== 'no' && ($sum_results['FAILED'] || $sum_results['BORKED'] || $sum_results['LEAKED'])) {
exit(1);
}
exit(0);
@@ -1273,6 +1273,9 @@ function system_with_timeout($commandline, $env = null, $stdin = null, $captureS
}
if ($stat["exitcode"] > 128 && $stat["exitcode"] < 160) {
$data .= "\nTermsig=" . ($stat["exitcode"] - 128) . "\n";
} else if (defined('PHP_WINDOWS_VERSION_MAJOR') && (($stat["exitcode"] >> 28) & 0b1111) === 0b1100) {
// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/87fba13e-bf06-450e-83b1-9241dc81e781
$data .= "\nTermsig=" . $stat["exitcode"] . "\n";
}
proc_close($proc);
+1 -1
View File
@@ -642,7 +642,7 @@ static int do_cli(int argc, char **argv) /* {{{ */
goto err;
}
request_started = 1;
php_print_info(0xFFFFFFFF);
php_print_info(PHP_INFO_ALL & ~PHP_INFO_CREDITS);
php_output_end_all();
exit_status = (c == '?' && argc > 1 && !strchr(argv[1], c));
goto out;
+16 -12
View File
@@ -39,6 +39,16 @@ static struct fpm_array_s sockets_list;
enum { FPM_GET_USE_SOCKET = 1, FPM_STORE_SOCKET = 2, FPM_STORE_USE_SOCKET = 3 };
static inline void fpm_sockets_get_env_name(char *envname, unsigned idx) /* {{{ */
{
if (!idx) {
strcpy(envname, "FPM_SOCKETS");
} else {
sprintf(envname, "FPM_SOCKETS_%d", idx);
}
}
/* }}} */
static void fpm_sockets_cleanup(int which, void *arg) /* {{{ */
{
unsigned i;
@@ -82,13 +92,11 @@ static void fpm_sockets_cleanup(int which, void *arg) /* {{{ */
if (env_value) {
for (i = 0; i < socket_set_count; i++) {
if (!i) {
strcpy(envname, "FPM_SOCKETS");
} else {
sprintf(envname, "FPM_SOCKETS_%d", i);
}
fpm_sockets_get_env_name(envname, i);
setenv(envname, env_value + socket_set[i], 1);
}
fpm_sockets_get_env_name(envname, socket_set_count);
unsetenv(envname);
free(env_value);
}
@@ -373,7 +381,7 @@ int fpm_sockets_init_main() /* {{{ */
{
unsigned i, lq_len;
struct fpm_worker_pool_s *wp;
char sockname[32];
char envname[32];
char sockpath[256];
char *inherited;
struct listening_socket_s *ls;
@@ -384,12 +392,8 @@ int fpm_sockets_init_main() /* {{{ */
/* import inherited sockets */
for (i = 0; i < FPM_ENV_SOCKET_SET_MAX; i++) {
if (!i) {
strcpy(sockname, "FPM_SOCKETS");
} else {
sprintf(sockname, "FPM_SOCKETS_%d", i);
}
inherited = getenv(sockname);
fpm_sockets_get_env_name(envname, i);
inherited = getenv(envname);
if (!inherited) {
break;
}
@@ -17,7 +17,7 @@ log_level = notice
include = {{INCLUDE:CONF}}
EOT;
$cfgPoolTemplate = <<<EOT
$cfg['poolTemplate'] = <<<EOT
[%name%]
listen = {{ADDR[%name%]}}
user = foo
@@ -25,10 +25,7 @@ pm = ondemand
pm.max_children = 5
EOT;
$names = ['cccc', 'aaaa', 'eeee', 'dddd', 'bbbb'];
foreach($names as $name) {
$cfg[$name] = str_replace('%name%', $name, $cfgPoolTemplate);
}
$cfg['names'] = ['cccc', 'aaaa', 'eeee', 'dddd', 'bbbb'];
$tester = new FPM\Tester($cfg);
$tester->start();
@@ -0,0 +1,49 @@
--TEST--
FPM: bug80024 - Duplication of info about inherited socket after pool removing
--SKIPIF--
<?php include "skipif.inc"; ?>
--FILE--
<?php
require_once "tester.inc";
$cfg['main'] = <<<EOT
[global]
error_log = {{FILE:LOG}}
pid = {{FILE:PID}}
include = {{INCLUDE:CONF}}
EOT;
$cfg['poolTemplate'] = <<<EOT
[pool_%index%]
listen = {{ADDR:UDS[pool_%index%]}}
pm = ondemand
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
pm.max_children = 5
EOT;
$cfg['count'] = 129;
$tester = new FPM\Tester($cfg);
$tester->start();
$tester->expectLogStartNotices();
$cfg['count'] = 128;
$tester->reload($cfg);
$tester->expectLogReloadingNotices(129);
$tester->reload();
$tester->expectLogReloadingNotices(128);
$tester->terminate();
$tester->expectLogTerminatingNotices();
$tester->close();
?>
Done
--EXPECT--
Done
--CLEAN--
<?php
require_once "tester.inc";
FPM\Tester::clean();
?>
+33 -6
View File
@@ -9,6 +9,12 @@ class LogTool
const P_PREFIX_STDOUT = '\[pool unconfined\] child \d+ said into stdout: ';
const FINAL_SUFFIX = ', pipe is closed';
const DEBUG = 'DEBUG';
const NOTICE = 'NOTICE';
const WARNING = 'WARNING';
const ERROR = 'ERROR';
const ALERT = 'ALERT';
/**
* @var string
*/
@@ -278,6 +284,28 @@ class LogTool
return true;
}
/**
* @param array $lines
* @return bool
*/
public function expectReloadingLines(array $lines)
{
if (
!$this->expectNotice($lines[0], 'Reloading in progress ...') ||
!$this->expectNotice($lines[1], 'reloading: .*')
) {
return false;
}
for ($i = 2; $i < count($lines) - 2; $i++) {
if (!$this->expectNotice($lines[$i], 'using inherited socket fd=\d+, "[^"]+"')) {
return false;
}
}
return $this->expectStartingLines(array_splice($lines, $i));
}
/**
* @param array $lines
* @return bool
@@ -359,7 +387,7 @@ class LogTool
*/
public function expectDebug(string $line, string $expectedMessage, $pool = null)
{
return $this->expectEntry('DEBUG', $line, $expectedMessage, $pool);
return $this->expectEntry(self::DEBUG, $line, $expectedMessage, $pool);
}
/**
@@ -370,7 +398,7 @@ class LogTool
*/
public function expectNotice(string $line, string $expectedMessage, $pool = null)
{
return $this->expectEntry('NOTICE', $line, $expectedMessage, $pool);
return $this->expectEntry(self::NOTICE, $line, $expectedMessage, $pool);
}
/**
@@ -381,7 +409,7 @@ class LogTool
*/
public function expectWarning(string $line, string $expectedMessage, $pool = null)
{
return $this->expectEntry('WARNING', $line, $expectedMessage, $pool);
return $this->expectEntry(self::WARNING, $line, $expectedMessage, $pool);
}
/**
@@ -392,7 +420,7 @@ class LogTool
*/
public function expectError(string $line, string $expectedMessage, $pool = null)
{
return $this->expectEntry('ERROR', $line, $expectedMessage, $pool);
return $this->expectEntry(self::ERROR, $line, $expectedMessage, $pool);
}
/**
@@ -403,10 +431,9 @@ class LogTool
*/
public function expectAlert(string $line, string $expectedMessage, $pool = null)
{
return $this->expectEntry('ALERT', $line, $expectedMessage, $pool);
return $this->expectEntry(self::ALERT, $line, $expectedMessage, $pool);
}
/**
* @param string $msg
* @return bool
+109 -15
View File
@@ -72,7 +72,7 @@ class Tester
/**
* Configuration template
*
* @var string
* @var string|array
*/
private $configTemplate;
@@ -152,7 +152,14 @@ class Tester
unlink($filePath);
}
}
// clean config files
self::cleanConfigFiles();
}
/**
* Clean config files
*/
static public function cleanConfigFiles() {
if (is_dir(self::CONF_DIR)) {
foreach(glob(self::CONF_DIR . '/*.conf') as $name) {
unlink($name);
@@ -686,6 +693,12 @@ class Tester
}
}
if ($this->debug) {
foreach ($lines as $line) {
echo "LOG LINE: " . $line;
}
}
return $lines;
}
@@ -731,6 +744,24 @@ class Tester
return getmygid();
}
/**
* Reload FPM by sending USR2 signal and optionally change config before that.
*
* @param string|array $configTemplate
* @return string
* @throws \Exception
*/
public function reload($configTemplate = null)
{
if (!is_null($configTemplate)) {
self::cleanConfigFiles();
$this->configTemplate = $configTemplate;
$this->createConfig();
}
return $this->signal('USR2');
}
/**
* Send signal to the supplied PID or the server PID.
*
@@ -784,14 +815,13 @@ class Tester
throw new \Exception('The config template array has to have main config');
}
$mainTemplate = $configTemplates['main'];
unset($configTemplates['main']);
if (!is_dir(self::CONF_DIR)) {
mkdir(self::CONF_DIR);
}
foreach ($configTemplates as $name => $configTemplate) {
foreach ($this->createPoolConfigs($configTemplates) as $name => $poolConfig) {
$this->makeFile(
'conf',
$this->processTemplate($configTemplate),
$this->processTemplate($poolConfig),
self::CONF_DIR,
$name
);
@@ -803,6 +833,36 @@ class Tester
return $this->makeFile($extension, $this->processTemplate($mainTemplate));
}
/**
* Create pool config templates.
*
* @param array $configTemplates
* @return array
* @throws \Exception
*/
private function createPoolConfigs(array $configTemplates)
{
if (!isset($configTemplates['poolTemplate'])) {
unset($configTemplates['main']);
return $configTemplates;
}
$poolTemplate = $configTemplates['poolTemplate'];
$configs = [];
if (isset($configTemplates['count'])) {
$start = $configTemplates['start'] ?? 1;
for ($i = $start; $i < $start + $configTemplates['count']; $i++) {
$configs[$i] = str_replace('%index%', $i, $poolTemplate);
}
} elseif (isset($configTemplates['names'])) {
foreach($configTemplates['names'] as $name) {
$configs[$name] = str_replace('%name%', $name, $poolTemplate);
}
} else {
throw new \Exception('The config template requires count or names if poolTemplate set');
}
return $configs;
}
/**
* Process template string.
*
@@ -1110,6 +1170,16 @@ class Tester
$this->logTool->checkTruncatedMessage($this->response->getErrorData());
}
/**
* Expect reloading lines to be logged.
*
* @param int $socketCount
*/
public function expectLogReloadingNotices($socketCount = 1)
{
$this->logTool->expectReloadingLines($this->getLogLines($socketCount + 4));
}
/**
* Expect starting lines to be logged.
*/
@@ -1176,16 +1246,36 @@ class Tester
return $this->logTool->checkWrappedMessage($logLines, false, true, $is_stderr);
}
/**
* Expect log entry.
*
* @param string $type The log type
* @param string $message The expected message
* @param string|null $pool The pool for pool prefixed log entry
* @param int $count The number of items
* @return bool
*/
private function expectLogEntry(string $type, string $message, $pool = null, $count = 1)
{
for ($i = 0; $i < $count; $i++) {
if (!$this->logTool->expectEntry($type, $this->getLastLogLine(), $message, $pool)) {
return false;
}
}
return true;
}
/**
* Expect a log debug message.
*
* @param string $message
* @param string|null $pool
* @param int $count
* @return bool
*/
public function expectLogDebug(string $message, $pool = null)
public function expectLogDebug(string $message, $pool = null, $count = 1)
{
return $this->logTool->expectDebug($this->getLastLogLine(), $message, $pool);
return $this->expectLogEntry(LogTool::DEBUG, $message, $pool, $count);
}
/**
@@ -1193,11 +1283,12 @@ class Tester
*
* @param string $message
* @param string|null $pool
* @param int $count
* @return bool
*/
public function expectLogNotice(string $message, $pool = null)
public function expectLogNotice(string $message, $pool = null, $count = 1)
{
return $this->logTool->expectNotice($this->getLastLogLine(), $message, $pool);
return $this->expectLogEntry(LogTool::NOTICE, $message, $pool, $count);
}
/**
@@ -1205,11 +1296,12 @@ class Tester
*
* @param string $message
* @param string|null $pool
* @param int $count
* @return bool
*/
public function expectLogWarning(string $message, $pool = null)
public function expectLogWarning(string $message, $pool = null, $count = 1)
{
return $this->logTool->expectWarning($this->getLastLogLine(), $message, $pool);
return $this->expectLogEntry(LogTool::WARNING, $message, $pool, $count);
}
/**
@@ -1217,11 +1309,12 @@ class Tester
*
* @param string $message
* @param string|null $pool
* @param int $count
* @return bool
*/
public function expectLogError(string $message, $pool = null)
public function expectLogError(string $message, $pool = null, $count = 1)
{
return $this->logTool->expectError($this->getLastLogLine(), $message, $pool);
return $this->expectLogEntry(LogTool::ERROR, $message, $pool, $count);
}
/**
@@ -1229,11 +1322,12 @@ class Tester
*
* @param string $message
* @param string|null $pool
* @param int $count
* @return bool
*/
public function expectLogAlert(string $message, $pool = null)
public function expectLogAlert(string $message, $pool = null, $count = 1)
{
return $this->logTool->expectAlert($this->getLastLogLine(), $message, $pool);
return $this->expectLogEntry(LogTool::ALERT, $message, $pool, $count);
}
/**
+2 -2
View File
@@ -603,7 +603,7 @@ static int sapi_lsapi_activate()
static sapi_module_struct lsapi_sapi_module =
{
"litespeed",
"LiteSpeed V7.7",
"LiteSpeed V7.9",
php_lsapi_startup, /* startup */
php_module_shutdown_wrapper, /* shutdown */
@@ -806,7 +806,7 @@ static int alter_ini( const char * pKey, int keyLen, const char * pValue, int va
Use ACTIVATE stage in legacy mode only.
RUNTIME stage should be used here,
as with ACTIVATE it's impossible to change the option from script with ini_set
as with ACTIVATE it's impossible to change the option from script with ini_set
*/
if(!mod_lsapi_mode)
{
+53 -36
View File
@@ -152,7 +152,7 @@ static int s_ppid;
static int s_restored_ppid = 0;
static int s_pid = 0;
static int s_slow_req_msecs = 0;
static int s_keepListener = 0;
static int s_keep_listener = 1;
static int s_dump_debug_info = 0;
static int s_pid_dump_debug_info = 0;
static int s_req_processed = 0;
@@ -244,8 +244,8 @@ void LSAPI_Log(int flag, const char * fmt, ...)
{
char buf[1024];
char *p = buf;
if ((flag & LSAPI_LOG_TIMESTAMP_BITS) &&
!((flag & LSAPI_LOG_TIMESTAMP_STDERR) && s_stderr_is_pipe))
if ((flag & LSAPI_LOG_TIMESTAMP_BITS)
&& !(s_stderr_is_pipe))
{
struct timeval tv;
struct tm tm;
@@ -272,7 +272,7 @@ void LSAPI_Log(int flag, const char * fmt, ...)
if (flag & LSAPI_LOG_PID)
{
p += snprintf(p, 100, "[%d] ", s_pid);
p += snprintf(p, 100, "[UID:%d][%d] ", getuid(), s_pid);
}
if (p > buf)
@@ -294,7 +294,13 @@ void LSAPI_Log(int flag, const char * fmt, ...)
#endif
#define lsapi_log(...) LSAPI_Log(LSAPI_LOG_TIMESTAMP_FULL|LSAPI_LOG_TIMESTAMP_STDERR|LSAPI_LOG_PID, __VA_ARGS__)
#define lsapi_log(...) LSAPI_Log(LSAPI_LOG_TIMESTAMP_FULL|LSAPI_LOG_PID, __VA_ARGS__)
void lsapi_perror(const char * pMessage, int err_no)
{
lsapi_log("%s, errno: %d (%s)\n", pMessage, err_no, strerror(err_no));
}
static int lsapi_parent_dead()
@@ -893,7 +899,8 @@ int LSAPI_is_suEXEC_Daemon(void)
static int LSAPI_perror_r( LSAPI_Request * pReq, const char * pErr1, const char *pErr2 )
{
char achError[4096];
int n = snprintf(achError, sizeof(achError), "[%d] %s:%s: %s\n", getpid(),
int n = snprintf(achError, sizeof(achError), "[UID:%d][%d] %s:%s: %s\n",
getuid(), getpid(),
pErr1, (pErr2)?pErr2:"", strerror(errno));
if (n > (int)sizeof(achError))
n = sizeof(achError);
@@ -939,7 +946,7 @@ static int lsapi_enterLVE( LSAPI_Request * pReq, uid_t uid )
ret = (*fp_lve_enter)(s_lve, uid, -1, -1, &cookie);
if ( ret < 0 )
{
lsapi_log("enter LVE (%d) : ressult: %d !\n", uid, ret );
//lsapi_log("enter LVE (%d) : ressult: %d !\n", uid, ret );
LSAPI_perror_r(pReq, "LSAPI: lve_enter() failure, reached resource limit.", NULL );
lsapi_lve_error( pReq );
return -1;
@@ -2938,6 +2945,7 @@ static void lsapi_sigchild( int signal )
static int lsapi_init_children_status(void)
{
char * pBuf;
int size = 4096;
int max_children;
if (g_prefork_server->m_pChildrenStatus)
@@ -2945,7 +2953,6 @@ static int lsapi_init_children_status(void)
max_children = g_prefork_server->m_iMaxChildren
+ g_prefork_server->m_iExtraChildren;
char * pBuf;
size = max_children * sizeof( lsapi_child_status ) * 2 + 3 * sizeof(int);
size = (size + 4095) / 4096 * 4096;
pBuf =( char*) mmap( NULL, size, PROT_READ | PROT_WRITE,
@@ -2978,9 +2985,9 @@ static void dump_debug_info( lsapi_child_status * pStatus, long tmCur )
return;
}
lsapi_log("Possible runaway process, PPID: %d, PID: %d, "
lsapi_log("Possible runaway process, UID: %d, PPID: %d, PID: %d, "
"reqCount: %d, process time: %ld, checkpoint time: %ld, start "
"time: %ld\n", getpid(), pStatus->m_pid,
"time: %ld\n", getuid(), getppid(), pStatus->m_pid,
pStatus->m_iReqCounter, tmCur - pStatus->m_tmReqBegin,
tmCur - pStatus->m_tmLastCheckPoint, tmCur - pStatus->m_tmStart );
@@ -3008,12 +3015,11 @@ static void lsapi_check_child_status( long tmCur )
while( pStatus < pEnd )
{
tobekilled = 0;
if ( pStatus->m_pid != 0 )
if ( pStatus->m_pid != 0 && pStatus->m_pid != -1)
{
++count;
if ( !pStatus->m_inProcess )
{
if (g_prefork_server->m_iCurChildren - dying
> g_prefork_server->m_iMaxChildren
|| idle > g_prefork_server->m_iMaxIdleChildren)
@@ -3030,7 +3036,7 @@ static void lsapi_check_child_status( long tmCur )
//tobekilled = SIGUSR1;
}
}
if ( !tobekilled )
if (!pStatus->m_iKillSent)
++idle;
}
else
@@ -3184,6 +3190,9 @@ static int lsapi_prefork_server_accept( lsapi_prefork_server * pServer,
#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__)
*s_avail_pages = sysconf(_SC_AVPHYS_PAGES);
// lsapi_log("Memory total: %zd, free: %zd, free %%%zd\n",
// s_total_pages, *s_avail_pages, *s_avail_pages * 100 / s_total_pages);
#endif
FD_ZERO( &readfds );
FD_SET( pServer->m_fd, &readfds );
@@ -3196,7 +3205,8 @@ static int lsapi_prefork_server_accept( lsapi_prefork_server * pServer,
if (s_accepting_workers)
accepting = __sync_add_and_fetch(s_accepting_workers, 0);
if (pServer->m_iCurChildren > 0 && accepting > 0)
if (pServer->m_iCurChildren > 0
&& accepting > 0)
{
usleep(400);
while(accepting-- > 0)
@@ -3265,10 +3275,10 @@ static int lsapi_prefork_server_accept( lsapi_prefork_server * pServer,
__sync_add_and_fetch(s_busy_workers, 1);
lsapi_set_nblock( pReq->m_fd, 0 );
//keep it open if busy_count is used.
if (s_busy_workers
if (!s_keep_listener && s_busy_workers
&& *s_busy_workers > (pServer->m_iMaxChildren >> 1))
s_keepListener = 1;
if ((s_uid == 0 || !s_keepListener || !is_enough_free_mem())
s_keep_listener = 1;
if ((s_uid == 0 || !s_keep_listener || !is_enough_free_mem())
&& pReq->m_fdListen != -1 )
{
close( pReq->m_fdListen );
@@ -3289,7 +3299,9 @@ static int lsapi_prefork_server_accept( lsapi_prefork_server * pServer,
}
else if ( pid == -1 )
{
perror( "fork() failed, please increase process limit" );
lsapi_perror("fork() failed, please increase process limit", errno);
if (child_status)
child_status->m_pid = 0;
}
else
{
@@ -3312,7 +3324,7 @@ static int lsapi_prefork_server_accept( lsapi_prefork_server * pServer,
{
if (( errno == EINTR )||( errno == EAGAIN))
continue;
perror( "accept() failed" );
lsapi_perror("accept() failed", errno);
return -1;
}
}
@@ -3350,10 +3362,10 @@ int LSAPI_Postfork_Child(LSAPI_Request * pReq)
__sync_add_and_fetch(s_busy_workers, 1);
lsapi_set_nblock( pReq->m_fd, 0 );
//keep it open if busy_count is used.
if (s_busy_workers
if (!s_keep_listener && s_busy_workers
&& *s_busy_workers > (max_children >> 1))
s_keepListener = 1;
if ((s_uid == 0 || !s_keepListener || !is_enough_free_mem())
s_keep_listener = 1;
if ((s_uid == 0 || !s_keep_listener || !is_enough_free_mem())
&& pReq->m_fdListen != -1 )
{
close(pReq->m_fdListen);
@@ -3512,7 +3524,7 @@ int LSAPI_Accept_Before_Fork(LSAPI_Request * pReq)
{
if ((errno == EINTR) || (errno == EAGAIN))
continue;
perror( "accept() failed" );
lsapi_perror("accept() failed", errno);
ret = -1;
break;
}
@@ -3528,13 +3540,6 @@ int LSAPI_Accept_Before_Fork(LSAPI_Request * pReq)
}
void lsapi_perror( const char * pMessage, int err_no )
{
lsapi_log("%s, errno: %d (%s)\n", pMessage, err_no,
strerror( err_no ) );
}
int LSAPI_Prefork_Accept_r( LSAPI_Request * pReq )
{
int fd;
@@ -3620,9 +3625,21 @@ int LSAPI_Prefork_Accept_r( LSAPI_Request * pReq )
if ( s_worker_status )
{
s_worker_status->m_inProcess = 0;
if (fd == pReq->m_fdListen
&& (s_keepListener != 2 || !is_enough_free_mem()))
return -1;
if (fd == pReq->m_fdListen)
{
if (s_keep_listener == 0 || !is_enough_free_mem())
return -1;
if (s_keep_listener == 1)
{
int wait_time = 10;
if (s_busy_workers)
wait_time += *s_busy_workers * 10;
if (s_accepting_workers)
wait_time >>= (*s_accepting_workers);
if (wait_secs >= wait_time)
return -1;
}
}
}
++wait_secs;
if (( s_max_idle_secs > 0 )&&(wait_secs >= s_max_idle_secs ))
@@ -3657,7 +3674,7 @@ int LSAPI_Prefork_Accept_r( LSAPI_Request * pReq )
lsapi_set_nblock( fd, 0 );
//init_conn_key( pReq->m_fd );
if (!s_keepListener)
if (!s_keep_listener)
{
close( pReq->m_fdListen );
pReq->m_fdListen = -1;
@@ -3949,7 +3966,7 @@ int LSAPI_Init_Env_Parameters( fn_select_t fp )
if ( p )
{
n = atoi( p );
s_keepListener = n;
s_keep_listener = n;
}
p = getenv( "LSAPI_AVOID_FORK" );
@@ -3958,7 +3975,7 @@ int LSAPI_Init_Env_Parameters( fn_select_t fp )
avoidFork = atoi( p );
if (avoidFork)
{
s_keepListener = 2;
s_keep_listener = 2;
ch = *(p + strlen(p) - 1);
if ( ch == 'G' || ch == 'g' )
avoidFork *= 1024 * 1024 * 1024;
+1
View File
@@ -773,6 +773,7 @@ PHPDBG_COMMAND(run) /* {{{ */
if (!PHPDBG_G(ops)) {
if (phpdbg_compile() == FAILURE) {
phpdbg_error("compile", "type=\"compilefailure\" context=\"%s\"", "Failed to compile %s, cannot run", PHPDBG_G(exec));
EG(exit_status) = FAILURE;
goto out;
}
}
+86 -16
View File
@@ -333,6 +333,37 @@ PHPAPI char *GetSMErrorText(int index)
}
}
/* strtok_r like, but recognizes quoted-strings */
static char *find_address(char *list, char **state)
{
zend_bool in_quotes = 0;
char *p = list;
if (list == NULL) {
if (*state == NULL) {
return NULL;
}
p = list = *state;
}
*state = NULL;
while ((p = strpbrk(p, ",\"\\")) != NULL) {
if (*p == '\\' && in_quotes) {
if (p[1] == '\0') {
/* invalid address; let SMTP server deal with it */
break;
}
p++;
} else if (*p == '"') {
in_quotes = !in_quotes;
} else if (*p == ',' && !in_quotes) {
*p = '\0';
*state = p + 1;
break;
}
p++;
}
return list;
}
/*********************************************************************
// Name: SendText
@@ -357,7 +388,7 @@ static int SendText(char *RPath, char *Subject, char *mailTo, char *mailCc, char
{
int res;
char *p;
char *tempMailTo, *token, *pos1, *pos2;
char *tempMailTo, *token, *token_state, *pos1, *pos2;
char *server_response = NULL;
char *stripped_header = NULL;
zend_string *data_cln;
@@ -410,7 +441,7 @@ static int SendText(char *RPath, char *Subject, char *mailTo, char *mailCc, char
tempMailTo = estrdup(mailTo);
/* Send mail to all rcpt's */
token = strtok(tempMailTo, ",");
token = find_address(tempMailTo, &token_state);
while (token != NULL)
{
SMTP_SKIP_SPACE(token);
@@ -424,14 +455,14 @@ static int SendText(char *RPath, char *Subject, char *mailTo, char *mailCc, char
efree(tempMailTo);
return (res);
}
token = strtok(NULL, ",");
token = find_address(NULL, &token_state);
}
efree(tempMailTo);
if (mailCc && *mailCc) {
tempMailTo = estrdup(mailCc);
/* Send mail to all rcpt's */
token = strtok(tempMailTo, ",");
token = find_address(tempMailTo, &token_state);
while (token != NULL)
{
SMTP_SKIP_SPACE(token);
@@ -445,7 +476,7 @@ static int SendText(char *RPath, char *Subject, char *mailTo, char *mailCc, char
efree(tempMailTo);
return (res);
}
token = strtok(NULL, ",");
token = find_address(NULL, &token_state);
}
efree(tempMailTo);
}
@@ -471,7 +502,7 @@ static int SendText(char *RPath, char *Subject, char *mailTo, char *mailCc, char
tempMailTo = estrndup(pos1, pos2 - pos1);
}
token = strtok(tempMailTo, ",");
token = find_address(tempMailTo, &token_state);
while (token != NULL)
{
SMTP_SKIP_SPACE(token);
@@ -485,7 +516,7 @@ static int SendText(char *RPath, char *Subject, char *mailTo, char *mailCc, char
efree(tempMailTo);
return (res);
}
token = strtok(NULL, ",");
token = find_address(NULL,&token_state);
}
efree(tempMailTo);
}
@@ -496,7 +527,7 @@ static int SendText(char *RPath, char *Subject, char *mailTo, char *mailCc, char
if (mailBcc && *mailBcc) {
tempMailTo = estrdup(mailBcc);
/* Send mail to all rcpt's */
token = strtok(tempMailTo, ",");
token = find_address(tempMailTo, &token_state);
while (token != NULL)
{
SMTP_SKIP_SPACE(token);
@@ -510,7 +541,7 @@ static int SendText(char *RPath, char *Subject, char *mailTo, char *mailCc, char
efree(tempMailTo);
return (res);
}
token = strtok(NULL, ",");
token = find_address(NULL, &token_state);
}
efree(tempMailTo);
}
@@ -544,7 +575,7 @@ static int SendText(char *RPath, char *Subject, char *mailTo, char *mailCc, char
}
}
token = strtok(tempMailTo, ",");
token = find_address(tempMailTo, &token_state);
while (token != NULL)
{
SMTP_SKIP_SPACE(token);
@@ -558,7 +589,7 @@ static int SendText(char *RPath, char *Subject, char *mailTo, char *mailCc, char
efree(tempMailTo);
return (res);
}
token = strtok(NULL, ",");
token = find_address(NULL, &token_state);
}
efree(tempMailTo);
@@ -978,6 +1009,46 @@ static unsigned long GetAddr(LPSTR szHost)
return (lAddr);
} /* end GetAddr() */
/* returns the contents of an angle-addr (caller needs to efree) or NULL */
static char *get_angle_addr(char *address)
{
zend_bool in_quotes = 0;
char *p1 = address, *p2;
while ((p1 = strpbrk(p1, "<\"\\")) != NULL) {
if (*p1 == '\\' && in_quotes) {
if (p1[1] == '\0') {
/* invalid address; let SMTP server deal with it */
return NULL;
}
p1++;
} else if (*p1 == '"') {
in_quotes = !in_quotes;
} else if (*p1 == '<' && !in_quotes) {
break;
}
p1++;
}
if (p1 == NULL) return NULL;
p2 = ++p1;
while ((p2 = strpbrk(p2, ">\"\\")) != NULL) {
if (*p2 == '\\' && in_quotes) {
if (p2[1] == '\0') {
/* invalid address; let SMTP server deal with it */
return NULL;
}
p2++;
} else if (*p2 == '"') {
in_quotes = !in_quotes;
} else if (*p2 == '>' && !in_quotes) {
break;
}
p2++;
}
if (p2 == NULL) return NULL;
return estrndup(p1, p2 - p1);
}
/*********************************************************************
// Name: int FormatEmailAddress
@@ -993,13 +1064,12 @@ static unsigned long GetAddr(LPSTR szHost)
// History:
//********************************************************************/
static int FormatEmailAddress(char* Buf, char* EmailAddress, char* FormatString) {
char *tmpAddress1, *tmpAddress2;
char *tmpAddress;
int result;
if( (tmpAddress1 = strchr(EmailAddress, '<')) && (tmpAddress2 = strchr(tmpAddress1, '>')) ) {
*tmpAddress2 = 0; // terminate the string temporarily.
result = snprintf(Buf, MAIL_BUFFER_SIZE, FormatString , tmpAddress1+1);
*tmpAddress2 = '>'; // put it back the way it was.
if ((tmpAddress = get_angle_addr(EmailAddress)) != NULL) {
result = snprintf(Buf, MAIL_BUFFER_SIZE, FormatString, tmpAddress);
efree(tmpAddress);
return result;
}
return snprintf(Buf, MAIL_BUFFER_SIZE , FormatString , EmailAddress );