Compare commits

...
141 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
Nikita Popov 7566742754 Suppress OpenSSL error on missing optional config
openssl_pkey_new() fetches various options from the config file --
most of these are optional, and not specifying them is not an error
condition from the perspective of the user. Unfortunately, the
CONF_get_string() API pushes an error when accessing a key that
doesn't exist (_CONF_get_string does not, but that is presumably a
private API). This commit adds a helper php_openssl_conf_get_string()
that automatically clears the error in this case. I've found that
OpenSSL occasionally does the same thing internally:
https://github.com/openssl/openssl/blob/22040fb790c854cefb04bed98ed38ea6357daf83/apps/req.c#L515-L517

Closes GH-6699.
2021-02-16 10:11:00 +01:00
Nikita Popov 64b1085464 Fixed bug #80747
If RSA key generation fails, actually report that failure.
2021-02-15 15:34:01 +01:00
Nikita Popov 7b7d99839c Fix symtable cache being used while cleaning symtable
We need to first clean the symtable and then check whether a cache
slot is available for it. Otherwise, it may happen that a destructor
runs while cleaning the table and uses up all the remaining slots
in the cache.

This is particularly insidious because once we overflow the cache,
the first pointer we modify is symtable_cache_ptr, making it hard
to understand what happened after the fact.

Fixes oss-fuzz #30815.
2021-02-15 14:58:38 +01:00
Daniel Black 3646604203 Fix #78680: mysqlnd pam plugin missing terminating null
The PAM service requires the terminating null to be part
of the communication.

Tested with MariaDB-10.4(pam) and Percona Server 5.7.32(auth_pam_compat).

Also changed MySQL Enterprise test to the server side plugin, authentication_pam
as opposed to the client plugin mysql_clear_password.

Add additional check for pamtest user and pam service file as
all are required for the test.

More importantly, test result should actually succeed.

Thanks Geoff Montee for bug report.

Closes GH-78680.
2021-02-15 11:32:07 +01:00
Nikita Popov 44a80b64b9 Fix leak when breaking out of FilesystemIterator
We need to always destroy current, not just when iter.data is not
set.

Take this opportunity to clean up the iterator destructor code a
bit, to remove redundant checks and incorrect comments.
2021-02-15 10:37:59 +01:00
Nikita Popov c34c523467 Fixed bug #80719 2021-02-11 16:12:06 +01:00
Christoph M. Becker 4f508003a9 Avoid C4090 level 1 warning
This breaks the build for PHP 8 by default.
2021-02-08 23:11:37 +01:00
Christoph M. Becker 03713ace23 Fix locale dependent parsing of PostgreSQL version number
Version numbers are not supposed to be localized, so we must not apply
locale dependent parsing with `atof()`.

Using `php_version_compare()` might even be better.

Closes GH-6668.
2021-02-08 18:57:08 +01:00
Christoph M. Becker ca7547c9e2 Fix #80706: mail(): Headers after Bcc headers may be ignored
We need to handle the case where a CRLF after a Bcc header is not the
beginning of a folding marker, because in that case the Bcc header was
not the last "thing".

Closes GH-6666.
2021-02-08 18:42:31 +01:00
Christoph M. Becker 4ff2665509 Use ST_Y() instead of the deprecated/removed Y() in test 2021-02-05 14:53:19 +01:00
Christoph M. Becker 3f8d21b922 Fix #74779: x() and y() truncating floats to integers
We must not use the locale dependent `atof()`, but instead use the
(hopefully) locale independent `zend_strtod()`, when converting string
representations of floating point numbers which are sent by the server.

Closes GH-6665.
2021-02-05 13:09:59 +01:00
Nikita Popov 8b7aaad7d6 Try SIGTERM before SIGKILL in opcache restart
SIGTERM is subject to HANDLE_BLOCK_INTERRUPTIONS(), which will
allow code to exit critical sections before it gets terminated.

Closes GH-6493.
2021-02-04 17:07:18 +01:00
Christoph M. Becker 958e3b93c3 [ci skip] Merge branch 'PHP-7.3' into PHP-7.4
* PHP-7.3:
  Fix newly introduced compiler warning
2021-02-03 12:43:40 +01:00
Nikita Popov 06c9633b43 Fix newly introduced compiler warning
(cherry picked from commit ab8177de2c)
2021-02-03 12:42:28 +01:00
Christoph M. Becker 1bb2a4f91c Fix #53467: Phar cannot compress large archives
When Phars are flushed, a new temporary file is created for each entry
which should be compressed, and the `compressed_filesize` is retrieved.
Afterwards, the Phar manifest is written, and only after that the files
are copied to the actual Phar.  So for each such entry there is an open
temp file, what easily exceeds the limit.

Therefore, we use a single temporary file for all entries, and store
the start offset in the otherwise unused `header_offset` member.  We
ensure that the `cfp` members are properly set to NULL even if flushing
fails, to avoid use after free scenarios.

This solution is based on a suggestion by @lserni[1].

Closes GH-6643.

[1] <https://github.com/box-project/box2/issues/80#issuecomment-77147371>
2021-02-03 11:22:37 +01:00
Christoph M. Becker 3d09626f0d [ci skip] Merge branch 'PHP-7.3' into PHP-7.4
* PHP-7.3:
  7.3.28 is next
2021-02-02 17:07:16 +01:00
Christoph M. Becker 039ca4e219 7.3.28 is next 2021-02-02 17:01:55 +01:00
Peter Kokot 8c04944b66 Update year to 2021
Closes GH-6636.
2021-02-02 16:46:16 +01:00
Nikita Popov 54fa0a69f8 Add missing derefs in CurlFile
As pointed out on GH-6456.
2021-02-02 10:31:16 +01:00
Nikita Popov 51d76c346e Fix persistent leak on load_wsdl_ex failure
Move the load_wsdl_ex call into the zend_try that destroys the
docs hash table. The wsdl will be inserted into docs early on,
and will thus be released on subsequent bailout.
2021-02-02 10:05:35 +01:00
Christoph M. Becker 675a9b2831 Merge branch 'PHP-7.3' into PHP-7.4
* PHP-7.3:
  Revert "Updated to version 2021.1 (2021a)"
2021-02-01 13:42:43 +01:00
Christoph M. Becker 57257a4335 Revert "Updated to version 2021.1 (2021a)"
This reverts commit 491488d217, since
PHP-7.3 is in security mode, and this does not look security related.
2021-02-01 13:41:32 +01:00
Christoph M. Becker 7e9479083d Fix #80654: file_get_contents() maxlen fails above (2**31)-1 bytes
We remove the arbitrary restriction to `INT_MAX`; it is superfluous on
32bit systems where `ZEND_LONG_MAX == INT_MAX` anyway, and not useful
on 64bit systems, where larger files should be readable, if the
`memory_limit` is large enough.

Closes GH-6648.
2021-02-01 12:57:40 +01:00
Nikita Popov 217b9e7b41 Fix Laravel build on community job
Now requires PHP 7.4, so use php7.4 to run composer everywhere.
2021-02-01 09:48:14 +01:00
Nikita Popov ab8177de2c Fix build 2021-02-01 09:46:17 +01:00
Stanislav Malyshev 86de4d7af6 Merge branch 'PHP-7.3' into PHP-7.4
* PHP-7.3:
  Fix bug #80672 - Null Dereference in SoapClient
2021-01-31 21:42:41 -08:00
Stanislav Malyshev 3c939e3f69 Fix bug #80672 - Null Dereference in SoapClient 2021-01-31 21:15:23 -08:00
Remi Collet aeb4f21549 NEWS 2021-01-28 16:25:35 +01:00
Remi Collet 067f7e4150 Fix #80682 opcache doesn't honour pcre.jit option 2021-01-28 16:24:39 +01:00
Stanislav Malyshev 21f861225a Merge branch 'PHP-7.3' into PHP-7.4
* PHP-7.3:
  Rm unneeded function
2021-01-27 00:15:13 -08:00
Stanislav Malyshev 9c673083cd Rm unneeded function 2021-01-27 00:13:43 -08:00
Stanislav Malyshev fbf8c758fe Merge branch 'PHP-7.3' into PHP-7.4
* PHP-7.3:
  Alternative fix for bug 77423
2021-01-26 22:55:10 -08:00
Christoph M. Becker 4a89e726bd Alternative fix for bug 77423
That bug report originally was about `parse_url()` misbehaving, but the
security aspect was actually only regarding `FILTER_VALIDATE_URL`.
Since the changes to `parse_url_ex()` apparently affect userland code
which is relying on the sloppy URL parsing[1], this alternative
restores the old parsing behavior, but ensures that the userinfo is
checked for correctness for `FILTER_VALIDATE_URL`.

[1] <https://github.com/php/php-src/commit/5174de7cd33c3d4fa591c9c93859ff9989b07e8c#commitcomment-45967652>
2021-01-26 22:54:58 -08:00
Christoph M. Becker 6a0b889f57 Fix #70091: Phar does not mark UTF-8 filenames in ZIP archives
The default encoding of filenames in a ZIP archive is IBM Code Page
437.  Phar, however, only supports UTF-8 filenames.  Therefore we have
to mark filenames as being stored in UTF-8 by setting the general
purpose bit 11 (the language encoding flag).

The effect of not setting this bit for non ASCII filenames can be seen
in popular tools like 7-Zip and UnZip, but not when extracting the
archives via ext/phar (which is agnostic to the filename encoding), or
via ext/zip (which guesses the encoding).  Thus we add a somewhat
brittle low-level test case.

Closes GH-6630.
2021-01-26 19:14:25 +01:00
Christoph M. Becker 94af11d5e1 Update version
That appears to have been forgotten for a while.
2021-01-26 19:08:23 +01:00
Christoph M. Becker 61ed904cec Fix #75850: Unclear error message wrt. __halt_compiler() w/o semicolon
We add the failure reason to the error message.

Closes GH-6638.
2021-01-25 18:47:15 +01:00
Derick Rethans 3f183bbcf8 Updated to version 2021.1 (2021a) 2021-01-25 10:44:05 +00:00
Derick Rethans 072cfef1d5 Empty merge 2021-01-25 10:44:05 +00:00
Derick Rethans 491488d217 Updated to version 2021.1 (2021a) 2021-01-25 10:44:04 +00:00
Christoph M. Becker edb389730d Add missing SKIPIF clause for recently introduced test case 2021-01-21 17:27:09 +01:00
Christoph M. Becker 6adfb8c962 Fix #80648: Fix for bug 79296 should be based on runtime version
Instead of checking for actually affected libzip versions, we now always
`ZIP_TRUNCATE` empty files unless `ZIP_RDONLY` is set.

Closes GH-6625.
2021-01-20 16:20:13 +01:00
Christoph M. Becker 4c1b3e3036 Add missing SKIPIF clauses to new test cases 2021-01-20 11:02:52 +01:00
Derick Rethans a33d0c3aae Update NEWS and version 2021-01-19 14:58:38 +00:00
Derick Rethans e8a89c49db Update NEWS for PHP 7.4.15RC1 2021-01-19 14:44:32 +00:00
sj-i 5d31ee302d Fixed bug #42560
Check open_basedir after the fallback to the system's temporary
directory in tempnam().

In order to preserve the current behavior of upload_tmp_dir
(do not check explicitly specified dir, but check fallback),
new flags are added to check open_basedir for explicit dir
and for fallback.

Closes GH-6526.
2021-01-19 11:41:58 +01:00
Christoph M. BeckerandAnna Filina 68f5289e9e Fix #69279: Compressed ZIP Phar extractTo() creates garbage files
When extracting compressed files from an uncompressed Phar, we must not
use the direct file pointer, but rather get an uncompressed file
pointer.

We also add a test to show that deflated and stored entries are
properly extracted.

This also fixes #79912, which appears to be a duplicate of #69279.

Co-authored-by: Anna Filina <afilina@gmail.com>

Closes GH-6599.
2021-01-19 10:28:54 +01:00
Christoph M. Becker 38ad37ad43 Fix #80595: Resetting POSTFIELDS to empty array breaks request
This is mainly to work around https://github.com/curl/curl/issues/6455,
but not building the mime structure for empty hashtables is a general
performance optimization, so we do not restrict it to affected cURL
versions (7.56.0 to 7.75.0).

The minor change to bug79033.phpt is unexpected, but should not matter
in practice.

Closes GH-6606.
2021-01-18 10:57:56 +01:00
Christoph M. Becker 25103c37aa Revert "Fix #76813: Access violation near NULL on source operand"
This reverts commit 5e15c9c41f, since
re2c default rules are only available as of re2c 0.13.7.
2021-01-11 13:21:12 +01:00
Christoph M. Becker 9450893dc6 Avoid modifying the return value of readline_completion_function()
The internal function `_readline_command_generator()` modifies the
internal array pointer of `readline_completion_function()`'s return
value.  We therefore separate the array, what also avoids failing
assertions regarding the array refcount.

Closes GH-6582.
2021-01-07 13:46:09 +01:00
Christoph M. Becker d1b1c04398 Fix #77565: Incorrect locator detection in ZIP-based phars
We must not assume that the first end of central dir signature in a ZIP
archive actually designates the end of central directory record, since
the data in the archive may contain arbitrary byte patterns.  Thus, we
better search from the end of the data, what is also slightly more
efficient.

There is, however, no way to detect the end of central directory
signature by searching from the end of the ZIP archive with absolute
certainty, since the signature could be part of the trailing comment.
To mitigate, we check that the comment length fits to the found
position, but that might still not be the correct position in rare
cases.

Closes GH-6507.
2021-01-05 23:40:24 +01:00
Christoph M. Becker 5c963731e2 Fix memory leak in Phar::webPhar() on Windows
Closes GH-6574.
2021-01-05 14:21:35 +01:00
Dylan K. Taylor 6b631f073d gdbinit: use ____print_str to print htable keys
I noticed this problem while dumping the contents of EG(function_table),
where keys for closures start with a null byte. printf interprets this
as a zero-length string and emits nothing. This allows the key to be
rendered properly in readable form.

Closes GH-6577.
2021-01-05 10:11:56 +01:00
Nikita Popov 46d6daea7a Disable non-cron travis jobs
This was already done for PHP-8.0 and master, do it for PHP-7.4
as well.
2021-01-04 10:52:37 +01:00
Stanislav Malyshev e65932060a [ci skip] Update NEWS 2021-01-04 01:46:32 -08:00
Stanislav Malyshev ec589a27da Merge branch 'PHP-7.3' into PHP-7.4
* PHP-7.3:
  [ci skip] Fix order
2021-01-04 01:46:11 -08:00
Stanislav Malyshev 65d7ade684 [ci skip] Fix order 2021-01-04 01:45:15 -08:00
Stanislav Malyshev 2498385dd9 Merge branch 'PHP-7.3' into PHP-7.4
* PHP-7.3:
  [ci skip] Unpdate NEWS
2021-01-04 01:44:18 -08:00
Stanislav Malyshev 8967e66559 [ci skip] Unpdate NEWS 2021-01-04 01:43:45 -08:00
Stanislav Malyshev 434c2b1bdb Merge branch 'PHP-7.3' into PHP-7.4
* PHP-7.3:
  Fix #77423: parse_url() will deliver a wrong host to user
2021-01-01 21:29:08 -08:00
Stanislav Malyshev 128fca4037 Merge branch 'PHP-7.2' into PHP-7.3
* PHP-7.2:
  Fix #77423: parse_url() will deliver a wrong host to user
2021-01-01 21:06:07 -08:00
Christoph M. Becker 2d3d72412a Fix #77423: parse_url() will deliver a wrong host to user
To avoid that `parse_url()` returns an erroneous host, which would be
valid for `FILTER_VALIDATE_URL`, we make sure that only userinfo which
is valid according to RFC 3986 is treated as such.

For consistency with the existing url parsing code, we use ctype
functions, although that is not necessarily correct.
2021-01-01 20:08:01 -08:00
haszi 0db6f5267c Replace sort() function calls with ksort() in basic ksort test
Closes GH-6541.
2020-12-27 18:30:58 +01:00
Adam SeitzandChristoph M. Becker 70dfbe0068 Fix #80384: limit read buffer size
In the case of a stream with no filters, php_stream_fill_read_buffer
only reads stream->chunk_size into the read buffer. If the stream has
filters attached, it could unnecessarily buffer a large amount of data.

With this change, php_stream_fill_read_buffer only proceeds until either
the requested size or stream->chunk_size is available in the read buffer.

Co-authored-by: Christoph M. Becker <cmbecker69@gmx.de>

Closes GH-6444.
2020-12-23 13:49:56 +01:00
Derick Rethans b043759cb4 Fixed bug #80376 (last day of the month causes runway cpu usage) 2020-12-21 10:30:40 +00:00
Nikita Popov bc166844e3 MySQLnd: Support cursors in store/get result
This fixes two related issues:

1. When a PS with cursor is used in store_result/get_result,
   perform a COM_FETCH with maximum number of rows rather than
   silently switching to an unbuffered result set (in the case of
   store_result) or erroring (in the case of get_result).
   In the future, we might want to make get_result unbuffered for
   PS with cursors, as using cursors with buffered result sets
   doesn't really make sense. Unlike store_result, get_result
   isn't very explicit about what kind of result set is desired.
2. If the client did not request a cursor, but the server reports
   that a cursor exists, ignore this and treat the PS as if it
   has no cursor (i.e. to not use COM_FETCH). It appears to be a
   server side bug that a cursor used inside an SP will be reported
   to the client, even though the client cannot use the cursor.

Fixes bug #64638, bug #72862, bug #77935.

Closes GH-6518.
2020-12-18 10:19:13 +01:00
Nikita Popov 315f3f8dc9 Fixed bug #67983
We need to check the BIT case first, otherwise it will get skipped
in INT_AND_FLOAT_NATIVE mode.
2020-12-16 10:52:27 +01:00
Nikita Popov 118ff03335 Fix bug #80523
Don't truncate the file length to unsigned int...

I have no idea whether that fully fixes the problem because the
process gets OOM killed before finishing, but at least the
immediate parse error is gone now.
2020-12-16 10:20:20 +01:00
Derick Rethans 078cdd8f76 Prepare for 7.4.15 2020-12-15 14:13:29 +00:00
152 changed files with 28715 additions and 23552 deletions

No files matched your search

+3 -4
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
@@ -352,7 +350,8 @@ define ____print_ht
end
printf "[%d] ", $i
if $p->key
printf "%s => ", $p->key->val
____print_str $p->key->val $p->key->len
printf " => "
else
printf "%d => ", $p->h
end
+3
View File
@@ -70,10 +70,13 @@ jobs:
include:
- env: ENABLE_MAINTAINER_ZTS=0 ENABLE_DEBUG=0
arch: amd64
if: type = cron
- env: ENABLE_MAINTAINER_ZTS=1 ENABLE_DEBUG=1
arch: amd64
if: type = cron
- env: ENABLE_MAINTAINER_ZTS=1 ENABLE_DEBUG=1 SKIP_IO_CAPTURE_TESTS=1 ARM64=1
arch: arm64
if: type = cron
before_script:
- ccache --version
+1 -1
View File
@@ -1,6 +1,6 @@
--------------------------------------------------------------------
The PHP License, version 3.01
Copyright (c) 1999 - 2019 The PHP Group. All rights reserved.
Copyright (c) 1999 - 2021 The PHP Group. All rights reserved.
--------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
+152 -4
View File
@@ -1,6 +1,155 @@
PHP NEWS
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
?? ??? ????, PHP 7.4.14
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)
- MySQLnd:
. Fixed bug #78680 (mysqlnd's mysql_clear_password does not transmit
null-terminated password). (Daniel Black)
- MySQLi:
. Fixed bug #74779 (x() and y() truncating floats to integers). (cmb)
- OPcache:
. Fixed bug #80682 (opcache doesn't honour pcre.jit option). (Remi)
- OpenSSL:
. Fixed bug #80747 (Providing RSA key size < 512 generates key that crash
PHP). (Nikita)
- Phar:
. Fixed bug #75850 (Unclear error message wrt. __halt_compiler() w/o
semicolon) (cmb)
. Fixed bug #70091 (Phar does not mark UTF-8 filenames in ZIP archives). (cmb)
. Fixed bug #53467 (Phar cannot compress large archives). (cmb, lserni)
- SPL:
. Fixed bug#80719 (Iterating after failed ArrayObject::setIteratorClass()
causes Segmentation fault). (Nikita)
- Standard:
. Fixed bug #80654 (file_get_contents() maxlen fails above (2**31)-1 bytes).
(cmb)
- Zip:
. Fixed bug #80648 (Fix for bug 79296 should be based on runtime version).
(cmb, Remi)
04 Feb 2021, PHP 7.4.15
- Core:
. Fixed bug #80523 (bogus parse error on >4GB source code). (Nikita)
. Fixed bug #80384 (filter buffers entire read until file closed). (Adam
Seitz, cmb)
- Curl:
. Fixed bug #80595 (Resetting POSTFIELDS to empty array breaks request). (cmb)
- Date:
. Fixed bug #80376 (last day of the month causes runway cpu usage. (Derick)
- MySQLi:
. Fixed bug #67983 (mysqlnd with MYSQLI_OPT_INT_AND_FLOAT_NATIVE fails to
interpret bit columns). (Nikita)
. Fixed bug #64638 (Fetching resultsets from stored procedure with cursor
fails). (Nikita)
. Fixed bug #72862 (segfault using prepared statements on stored procedures
that use a cursor). (Nikita)
. Fixed bug #77935 (Crash in mysqlnd_fetch_stmt_row_cursor when calling an SP
with a cursor). (Nikita)
- Phar:
. Fixed bug #77565 (Incorrect locator detection in ZIP-based phars). (cmb)
. Fixed bug #69279 (Compressed ZIP Phar extractTo() creates garbage files).
(cmb)
07 Jan 2021, PHP 7.4.14
- Core:
. Fixed bug #74558 (Can't rebind closure returned by Closure::fromCallable()).
@@ -49,10 +198,9 @@ PHP NEWS
. Fixed bug #76815 (PDOStatement cannot be GCed/closeCursor-ed when a
PROCEDURE resultset SIGNAL). (Nikita)
- Phpdbg:
. Fixed bug #76813 (Access violation near NULL on source operand). (cmb)
- Standard:
. Fixed bug #77423 (FILTER_VALIDATE_URL accepts URLs with invalid userinfo).
(CVE-2020-7071) (cmb)
. Fixed bug #80366 (Return Value of zend_fstat() not Checked). (sagpant, cmb)
. Fixed bug #80411 (References to null-serialized object break serialize()).
(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
@@ -0,0 +1,19 @@
--TEST--
Symtable cache slots may be acquired while cleaning symtable
--FILE--
<?php
class A {
// Must be larger than the symtable cache.
static $max = 40;
function __destruct() {
if (self::$max-- < 0) return;
$x = 'y';
$$x = new a;
}
}
new A;
?>
===DONE===
--EXPECT--
===DONE===
+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);
}
}
+9 -7
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"
@@ -3437,12 +3437,13 @@ ZEND_API void execute_internal(zend_execute_data *execute_data, zval *return_val
ZEND_API void zend_clean_and_cache_symbol_table(zend_array *symbol_table) /* {{{ */
{
/* Clean before putting into the cache, since clean could call dtors,
* which could use the cached hash. Also do this before the check for
* available cache slots, as those may be used by a dtor as well. */
zend_symtable_clean(symbol_table);
if (EG(symtable_cache_ptr) >= EG(symtable_cache_limit)) {
zend_array_destroy(symbol_table);
} else {
/* clean before putting into the cache, since clean
could call dtors, which could use cached hash */
zend_symtable_clean(symbol_table);
*(EG(symtable_cache_ptr)++) = symbol_table;
}
}
@@ -4554,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);
}
+3 -3
View File
@@ -177,7 +177,7 @@ static void yy_pop_state(void)
zend_stack_del_top(&SCNG(state_stack));
}
static void yy_scan_buffer(char *str, unsigned int len)
static void yy_scan_buffer(char *str, size_t len)
{
YYCURSOR = (YYCTYPE*)str;
YYLIMIT = YYCURSOR + len;
@@ -554,7 +554,7 @@ ZEND_API int open_file_for_scanning(zend_file_handle *file_handle)
}
}
SCNG(yy_start) = (unsigned char *)buf;
yy_scan_buffer(buf, (unsigned int)size);
yy_scan_buffer(buf, size);
} else {
zend_error_noreturn(E_COMPILE_ERROR, "zend_stream_mmap() failed");
}
@@ -722,7 +722,7 @@ ZEND_API int zend_prepare_string_for_scanning(zval *str, char *filename)
}
}
yy_scan_buffer(buf, (unsigned int)size);
yy_scan_buffer(buf, size);
new_compiled_filename = zend_string_init(filename, strlen(filename), 0);
zend_set_compiled_filename(new_compiled_filename);
+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)) {
+4 -4
View File
@@ -50,7 +50,7 @@ jobs:
- script: |
git clone https://github.com/laravel/framework.git --branch=master --depth=1
cd framework
php7.3 /usr/bin/composer install --no-progress
php7.4 /usr/bin/composer install --no-progress
export USE_ZEND_ALLOC=0
sed -i 's/$exit = true/$exit = false/g' vendor/phpunit/phpunit/src/TextUI/Command.php
# Avoid test using exit(), which thus leaks.
@@ -61,8 +61,8 @@ jobs:
- script: |
git clone https://github.com/symfony/symfony.git --depth=1
cd symfony
php7.3 /usr/bin/composer install --no-progress
php7.3 ./phpunit install
php7.4 /usr/bin/composer install --no-progress
php7.4 ./phpunit install
export USE_ZEND_ALLOC=0
export USE_TRACKED_ALLOC=1
export ASAN_OPTIONS=exitcode=139
@@ -82,7 +82,7 @@ jobs:
displayName: 'Test Amphp'
condition: or(succeeded(), failed())
- script: |
php7.3 /usr/bin/composer create-project symfony/symfony-demo symfony_demo --no-progress
php7.4 /usr/bin/composer create-project symfony/symfony-demo symfony_demo --no-progress
cd symfony_demo
export USE_ZEND_ALLOC=0
export USE_TRACKED_ALLOC=1
+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.13-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)
+11 -1
View File
@@ -2207,6 +2207,7 @@ static inline int build_mime_structure_from_hash(php_curl *ch, zval *zpostfields
#endif
prop = zend_read_property(curl_CURLFile_class, current, "name", sizeof("name")-1, 0, &rv);
ZVAL_DEREF(prop);
if (Z_TYPE_P(prop) != IS_STRING) {
php_error_docref(NULL, E_WARNING, "Invalid filename for key %s", ZSTR_VAL(string_key));
} else {
@@ -2217,10 +2218,12 @@ static inline int build_mime_structure_from_hash(php_curl *ch, zval *zpostfields
}
prop = zend_read_property(curl_CURLFile_class, current, "mime", sizeof("mime")-1, 0, &rv);
ZVAL_DEREF(prop);
if (Z_TYPE_P(prop) == IS_STRING && Z_STRLEN_P(prop) > 0) {
type = Z_STRVAL_P(prop);
}
prop = zend_read_property(curl_CURLFile_class, current, "postname", sizeof("postname")-1, 0, &rv);
ZVAL_DEREF(prop);
if (Z_TYPE_P(prop) == IS_STRING && Z_STRLEN_P(prop) > 0) {
filename = Z_STRVAL_P(prop);
}
@@ -2969,7 +2972,14 @@ static int _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue) /* {{{
case CURLOPT_POSTFIELDS:
if (Z_TYPE_P(zvalue) == IS_ARRAY || Z_TYPE_P(zvalue) == IS_OBJECT) {
return build_mime_structure_from_hash(ch, zvalue);
if (zend_hash_num_elements(HASH_OF(zvalue)) == 0) {
/* no need to build the mime structure for empty hashtables;
also works around https://github.com/curl/curl/issues/6455 */
curl_easy_setopt(ch->cp, CURLOPT_POSTFIELDS, "");
error = curl_easy_setopt(ch->cp, CURLOPT_POSTFIELDSIZE, 0);
} else {
return build_mime_structure_from_hash(ch, zvalue);
}
} else {
#if LIBCURL_VERSION_NUM >= 0x071101
zend_string *tmp_str;
+2 -1
View File
@@ -21,9 +21,10 @@ var_dump(curl_getinfo($ch)["request_header"]);
string(%d) "array(0) {
}
"
string(90) "POST /get.inc?test=post HTTP/1.1
string(%d) "POST /get.inc?test=post HTTP/1.1
Host: localhost:%d
Accept: */*
Content-Length: 0
Content-Type: application/x-www-form-urlencoded
"
+30
View File
@@ -0,0 +1,30 @@
--TEST--
Bug #80595 (Resetting POSTFIELDS to empty array breaks request)
--SKIPIF--
<?php include 'skipif.inc'; ?>
--FILE--
<?php
include 'server.inc';
$host = curl_cli_server_start();
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_URL => "{$host}/get.inc?test=post",
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, ['foo' => 'bar']);
var_dump(curl_exec($ch));
curl_setopt($ch, CURLOPT_POSTFIELDS, []);
var_dump(curl_exec($ch));
?>
--EXPECT--
string(43) "array(1) {
["foo"]=>
string(3) "bar"
}
"
string(13) "array(0) {
}
"
+22837 -20045
View File
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+2681 -2482
View File
File diff suppressed because it is too large. Load diff
+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
+23
View File
@@ -555,6 +555,22 @@ void php_filter_validate_domain(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
}
/* }}} */
static int is_userinfo_valid(zend_string *str)
{
const char *valid = "-._~!$&'()*+,;=:";
const char *p = ZSTR_VAL(str);
while (p - ZSTR_VAL(str) < ZSTR_LEN(str)) {
if (isalpha(*p) || isdigit(*p) || strchr(valid, *p)) {
p++;
} else if (*p == '%' && p - ZSTR_VAL(str) <= ZSTR_LEN(str) - 3 && isdigit(*(p+1)) && isxdigit(*(p+2))) {
p += 3;
} else {
return 0;
}
}
return 1;
}
void php_filter_validate_url(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
{
php_url *url;
@@ -615,6 +631,13 @@ bad_url:
php_url_free(url);
RETURN_VALIDATION_FAILED
}
if (url->user != NULL && !is_userinfo_valid(url->user)) {
php_url_free(url);
RETURN_VALIDATION_FAILED
}
php_url_free(url);
}
/* }}} */
+15
View File
@@ -0,0 +1,15 @@
--TEST--
Bug #77423 (parse_url() will deliver a wrong host to user)
--FILE--
<?php
$urls = array(
"http://php.net\@aliyun.com/aaa.do",
"https://example.com\uFF03@bing.com",
);
foreach ($urls as $url) {
var_dump(filter_var($url, FILTER_VALIDATE_URL));
}
?>
--EXPECT--
bool(false)
bool(false)
+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--
äöü
äöü
äöü
+35
View File
@@ -0,0 +1,35 @@
--TEST--
Bug #67983: mysqlnd with MYSQLI_OPT_INT_AND_FLOAT_NATIVE fails to interpret bit columns
--SKIPIF--
<?php
require_once('skipif.inc');
require_once('skipifconnectfailure.inc');
if (!$IS_MYSQLND) {
die("skip mysqlnd only test");
}
?>
--FILE--
<?php
require_once("connect.inc");
$connection = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket);
mysqli_options($connection, MYSQLI_OPT_INT_AND_FLOAT_NATIVE, true);
mysqli_set_charset($connection, 'utf8');
mysqli_query($connection, 'DROP TABLE IF EXISTS test');
mysqli_query($connection, 'CREATE TABLE test (id BIT(8))');
mysqli_query($connection, 'INSERT INTO test VALUES (0), (1), (42)');
$res = mysqli_query($connection, 'SELECT * FROM test');
while ($result = mysqli_fetch_assoc($res)) {
var_dump($result['id']);
}
?>
--EXPECT--
int(0)
int(1)
int(42)
+42
View File
@@ -0,0 +1,42 @@
--TEST--
Bug #74779 (x() and y() truncating floats to integers)
--SKIPIF--
<?php
require_once('skipif.inc');
require_once('skipifconnectfailure.inc');
if (!setlocale(LC_NUMERIC, "de_DE", "de_DE.UTF-8", "de-DE")) die('skip locale not available');
?>
--FILE--
<?php
require_once("connect.inc");
if (!$link = my_mysqli_connect($host, $user, $passwd, $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);
}
if (!setlocale(LC_NUMERIC, "de_DE", "de_DE.UTF-8", "de-DE")) {
echo "[002] Cannot set locale\n";
}
if (!$link->options(MYSQLI_OPT_INT_AND_FLOAT_NATIVE, true)) {
printf("[003] [%d] %s\n", $link->errno, $link->error);
}
if (!$result = $link->query("SELECT ST_Y(Point(56.7, 53.34))")) {
printf("[004] [%d] %s\n", $link->errno, $link->error);
}
if (!$array = $result->fetch_array(MYSQLI_ASSOC)) {
printf("[005] [%d] %s\n", $link->errno, $link->error);
}
var_dump($array);
mysqli_close($link);
?>
--EXPECT--
array(1) {
["ST_Y(Point(56.7, 53.34))"]=>
float(53,34)
}
+38
View File
@@ -0,0 +1,38 @@
--TEST--
Bug #77935: Crash in mysqlnd_fetch_stmt_row_cursor when calling an SP with a cursor
--SKIPIF--
<?php
require_once('skipif.inc');
require_once('skipifconnectfailure.inc');
?>
--FILE--
<?php
require_once(__DIR__ . '/connect.inc');
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$db = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket);
$db->query('DROP PROCEDURE IF EXISTS testSp');
$db->query(<<<'SQL'
CREATE
PROCEDURE `testSp`()
BEGIN
DECLARE `cur` CURSOR FOR SELECT 1;
OPEN `cur`;
CLOSE `cur`;
SELECT 1;
END;
SQL);
$stmt = $db->prepare("CALL testSp()");
$stmt->execute();
$result = $stmt->get_result();
while ($row = $result->fetch_assoc()) {
var_dump($row);
}
?>
--EXPECT--
array(1) {
[1]=>
int(1)
}
+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
+48 -8
View File
@@ -19,8 +19,8 @@ if (!$res = $link->query("SHOW PLUGINS"))
$have_pam = false;
while ($row = $res->fetch_assoc()) {
if (isset($row['Name']) && ('mysql_clear_password' == $row['Name'])) {
$have_pam = true;
if (isset($row['Name']) && in_array($row['Name'], array('pam', 'authentication_pam', 'auth_pam_compat'))) {
$have_pam = $row['Name'];
break;
}
}
@@ -29,12 +29,54 @@ $res->close();
if (!$have_pam)
die("SKIP Server PAM plugin not installed");
if ($have_pam == 'pam') {
/* MariaDB - needs system variable pam_use_cleartext_plugin=ON to be set */
if (!$res = mysqli_query($link, 'SHOW GLOBAL VARIABLES LIKE "pam_use_cleartext_plugin"'))
die(sprintf("SKIP MariaDB probe of GLOBAL VARIABLES failed [%d] %s\n",
mysqli_errno($link), mysqli_error($link)));
$pam_use_cleartext_plugin = mysqli_fetch_row($res);
mysqli_free_result($res);
if (!$pam_use_cleartext_plugin or $pam_use_cleartext_plugin[1]!='ON')
die("SKIP Server setting pam_use_cleartext_plugin!=ON");
$pam_service = file_get_contents('/etc/pam.d/mysql');
} elseif ($have_pam == 'authentication_pam') {
/*
required MySQL syntax:
https://dev.mysql.com/doc/refman/8.0/en/pam-pluggable-authentication.html#pam-pluggable-authentication-usage
*/
$have_pam .= " AS 'mysql-unix'";
$pam_service = file_get_contents('/etc/pam.d/mysql-unix');
} else {
$pam_service = file_get_contents('/etc/pam.d/mysql');
}
$auth = 0;
$account = 0;
foreach (explode("\n", $pam_service) as $line)
{
if (preg_match('/^auth/', $line)) {
$auth = 1;
} elseif (preg_match('/^account/', $line)) {
$account = 1;
}
}
if (!$auth) {
die("SKIP pam service file missing 'auth' directive");
}
if (!$account) {
die("SKIP pam service file missing 'account' directive");
}
if (!posix_getpwnam('pamtest')) {
die("SKIP no pamtest user");
}
/* Password of user 'pamtest' should be set to 'pamtest' */
mysqli_query($link, 'DROP USER pamtest');
mysqli_query($link, 'DROP USER pamtest@localhost');
if (!mysqli_query($link, 'CREATE USER pamtest@"%" IDENTIFIED WITH mysql_clear_password') ||
!mysqli_query($link, 'CREATE USER pamtest@"localhost" IDENTIFIED WITH mysql_clear_password')) {
if (!mysqli_query($link, "CREATE USER pamtest@'%' IDENTIFIED WITH $have_pam") ||
!mysqli_query($link, "CREATE USER pamtest@'localhost' IDENTIFIED WITH $have_pam")) {
printf("skip Cannot create second DB user [%d] %s", mysqli_errno($link), mysqli_error($link));
mysqli_close($link);
die("skip CREATE USER failed");
@@ -60,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"))
@@ -88,6 +130,4 @@ max_execution_time=240
mysqli_query($link, 'DROP USER pamtest@localhost');
?>
--EXPECTF--
Warning: mysqli_real_connect(): (28000/1045): Access denied for user %s
[001] Cannot connect to the server using host=%s
done!
+16 -33
View File
@@ -110,21 +110,7 @@ if (!function_exists('mysqli_stmt_get_result'))
mysqli_stmt_close($stmt);
if (!$stmt = mysqli_stmt_init($link))
printf("[032] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
if (!mysqli_stmt_prepare($stmt, "SELECT id, label FROM test ORDER BY id LIMIT 2"))
printf("[033] [%d] %s\n", mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
if (!mysqli_stmt_execute($stmt))
printf("[034] [%d] %s\n", mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
$id = NULL;
$label = NULL;
if (true !== ($tmp = mysqli_stmt_bind_result($stmt, $id, $label)))
printf("[035] Expecting boolean/true, got %s/%s\n", gettype($tmp), var_export($tmp, 1));
// get_result cannot be used in PS cursor mode
// get_result can be used in PS cursor mode
if (!$stmt = mysqli_stmt_init($link))
printf("[030] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
@@ -137,24 +123,11 @@ if (!function_exists('mysqli_stmt_get_result'))
if (!mysqli_stmt_execute($stmt))
printf("[033] [%d] %s\n", mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
try {
$res = mysqli_stmt_get_result($stmt);
// we expect no segfault if we try to fetch a row because get_result should throw an error or return false
mysqli_fetch_assoc($res);
} catch (\mysqli_sql_exception $e) {
echo $e->getMessage() . "\n";
$result = mysqli_stmt_get_result($stmt);
while ($row = mysqli_fetch_assoc($result)) {
var_dump($row);
}
try {
$res = $stmt->get_result();
// we expect no segfault if we try to fetch a row because get_result should throw an error or return false
$res->fetch_assoc();
} catch (\mysqli_sql_exception $e) {
echo $e->getMessage() . "\n";
}
mysqli_report(MYSQLI_REPORT_OFF);
if (!$stmt = mysqli_stmt_init($link))
printf("[034] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
@@ -213,8 +186,18 @@ Warning: mysqli_stmt_fetch(): invalid object or resource mysqli_stmt
Warning: mysqli_stmt_get_result(): invalid object or resource mysqli_stmt
in %s on line %d
mysqli_stmt_get_result() cannot be used with cursors
get_result() cannot be used with cursors
array(2) {
["id"]=>
int(1)
["label"]=>
string(1) "a"
}
array(2) {
["id"]=>
int(2)
["label"]=>
string(1) "b"
}
[040] [2014] [Commands out of sync; you can't run this command now]
[041] [0] []
array(2) {
@@ -0,0 +1,99 @@
--TEST--
PS using cursor and returning multiple result sets
--SKIPIF--
<?php
require_once('skipif.inc');
require_once('skipifconnectfailure.inc');
?>
--FILE--
<?php
require_once(__DIR__ . '/connect.inc');
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$db = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket);
$db->query('DROP PROCEDURE IF EXISTS testPs');
$db->query(<<<'SQL'
CREATE PROCEDURE testPs() BEGIN
DECLARE testCursor CURSOR FOR SELECT 'stuff';
OPEN testCursor;
CLOSE testCursor;
SELECT 1 as a, 2 as b;
SELECT 3 as a, 4 as b;
END
SQL
);
echo "use_result:\n";
$stmt = $db->prepare("call testPs()");
$stmt->execute();
$stmt->bind_result($v1, $v2);
while ($stmt->fetch()) {
var_dump($v1, $v2);
}
$stmt->next_result();
$stmt->bind_result($v1, $v2);
while ($stmt->fetch()) {
var_dump($v1, $v2);
}
$stmt->next_result();
echo "\nstore_result:\n";
$stmt = $db->prepare("call testPs()");
$stmt->execute();
$stmt->store_result();
$stmt->bind_result($v1, $v2);
while ($stmt->fetch()) {
var_dump($v1, $v2);
}
$stmt->next_result();
$stmt->store_result();
$stmt->bind_result($v1, $v2);
while ($stmt->fetch()) {
var_dump($v1, $v2);
}
$stmt->next_result();
echo "\nget_result:\n";
$stmt = $db->prepare("call testPs()");
$stmt->execute();
$result = $stmt->get_result();
while ($row = $result->fetch_assoc()) {
var_dump($row);
}
$stmt->next_result();
$result = $stmt->get_result();
while ($row = $result->fetch_assoc()) {
var_dump($row);
}
$stmt->next_result();
?>
--EXPECT--
use_result:
int(1)
int(2)
int(3)
int(4)
store_result:
int(1)
int(2)
int(3)
int(4)
get_result:
array(2) {
["a"]=>
int(1)
["b"]=>
int(2)
}
array(2) {
["a"]=>
int(3)
["b"]=>
int(4)
}
+5 -1
View File
@@ -652,7 +652,11 @@ mysqlnd_pam_auth_get_auth_data(struct st_mysqlnd_authentication_plugin * self,
if (passwd && passwd_len) {
ret = (zend_uchar*) zend_strndup(passwd, passwd_len);
}
*auth_data_len = passwd_len;
/*
Trailing null required. bug#78680
https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_connection_phase_authentication_methods_clear_text_password.html
*/
*auth_data_len = passwd_len + 1;
return ret;
}
+72 -59
View File
@@ -40,6 +40,36 @@ enum_func_status mysqlnd_stmt_execute_batch_generate_request(MYSQLND_STMT * cons
static void mysqlnd_stmt_separate_result_bind(MYSQLND_STMT * const stmt);
static void mysqlnd_stmt_separate_one_result_bind(MYSQLND_STMT * const stmt, const unsigned int param_no);
static enum_func_status mysqlnd_stmt_send_cursor_fetch_command(
const MYSQLND_STMT_DATA *stmt, unsigned max_rows)
{
MYSQLND_CONN_DATA *conn = stmt->conn;
zend_uchar buf[MYSQLND_STMT_ID_LENGTH /* statement id */ + 4 /* number of rows to fetch */];
const MYSQLND_CSTRING payload = {(const char*) buf, sizeof(buf)};
int4store(buf, stmt->stmt_id);
int4store(buf + MYSQLND_STMT_ID_LENGTH, max_rows);
if (conn->command->stmt_fetch(conn, payload) == FAIL) {
COPY_CLIENT_ERROR(stmt->error_info, *conn->error_info);
return FAIL;
}
return PASS;
}
static zend_bool mysqlnd_stmt_check_state(const MYSQLND_STMT_DATA *stmt)
{
const MYSQLND_CONN_DATA *conn = stmt->conn;
if (stmt->state != MYSQLND_STMT_WAITING_USE_OR_STORE) {
return 0;
}
if (stmt->cursor_exists) {
return GET_CONNECTION_STATE(&conn->state) == CONN_READY;
} else {
return GET_CONNECTION_STATE(&conn->state) == CONN_FETCHING_DATA;
}
}
/* {{{ mysqlnd_stmt::store_result */
static MYSQLND_RES *
MYSQLND_METHOD(mysqlnd_stmt, store_result)(MYSQLND_STMT * const s)
@@ -60,15 +90,9 @@ MYSQLND_METHOD(mysqlnd_stmt, store_result)(MYSQLND_STMT * const s)
DBG_RETURN(NULL);
}
if (stmt->cursor_exists) {
/* Silently convert buffered to unbuffered, for now */
DBG_RETURN(s->m->use_result(s));
}
/* Nothing to store for UPSERT/LOAD DATA*/
if (GET_CONNECTION_STATE(&conn->state) != CONN_FETCHING_DATA || stmt->state != MYSQLND_STMT_WAITING_USE_OR_STORE)
{
SET_CLIENT_ERROR(conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
if (!mysqlnd_stmt_check_state(stmt)) {
SET_CLIENT_ERROR(stmt->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
DBG_RETURN(NULL);
}
@@ -78,6 +102,12 @@ MYSQLND_METHOD(mysqlnd_stmt, store_result)(MYSQLND_STMT * const s)
SET_EMPTY_ERROR(conn->error_info);
MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_PS_BUFFERED_SETS);
if (stmt->cursor_exists) {
if (mysqlnd_stmt_send_cursor_fetch_command(stmt, -1) == FAIL) {
DBG_RETURN(NULL);
}
}
result = stmt->result;
result->type = MYSQLND_RES_PS_BUF;
/* result->m.row_decoder = php_mysqlnd_rowp_read_binary_protocol; */
@@ -152,19 +182,8 @@ MYSQLND_METHOD(mysqlnd_stmt, get_result)(MYSQLND_STMT * const s)
DBG_RETURN(NULL);
}
if (stmt->cursor_exists) {
/* Prepared statement cursors are not supported as of yet */
char * msg;
mnd_sprintf(&msg, 0, "%s() cannot be used with cursors", get_active_function_name());
SET_CLIENT_ERROR(stmt->error_info, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE, msg);
if (msg) {
mnd_sprintf_free(msg);
}
DBG_RETURN(NULL);
}
/* Nothing to store for UPSERT/LOAD DATA*/
if (GET_CONNECTION_STATE(&conn->state) != CONN_FETCHING_DATA || stmt->state != MYSQLND_STMT_WAITING_USE_OR_STORE) {
if (!mysqlnd_stmt_check_state(stmt)) {
SET_CLIENT_ERROR(stmt->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
DBG_RETURN(NULL);
}
@@ -173,6 +192,12 @@ MYSQLND_METHOD(mysqlnd_stmt, get_result)(MYSQLND_STMT * const s)
SET_EMPTY_ERROR(conn->error_info);
MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_BUFFERED_SETS);
if (stmt->cursor_exists) {
if (mysqlnd_stmt_send_cursor_fetch_command(stmt, -1) == FAIL) {
DBG_RETURN(NULL);
}
}
do {
result = conn->m->result_init(stmt->result->field_count);
if (!result) {
@@ -561,28 +586,30 @@ mysqlnd_stmt_execute_parse_response(MYSQLND_STMT * const s, enum_mysqlnd_parse_e
DBG_INF_FMT("server_status=%u cursor=%u", UPSERT_STATUS_GET_SERVER_STATUS(stmt->upsert_status),
UPSERT_STATUS_GET_SERVER_STATUS(stmt->upsert_status) & SERVER_STATUS_CURSOR_EXISTS);
if (UPSERT_STATUS_GET_SERVER_STATUS(stmt->upsert_status) & SERVER_STATUS_CURSOR_EXISTS) {
DBG_INF("cursor exists");
stmt->cursor_exists = TRUE;
SET_CONNECTION_STATE(&conn->state, CONN_READY);
/* Only cursor read */
stmt->default_rset_handler = s->m->use_result;
DBG_INF("use_result");
} else if (stmt->flags & CURSOR_TYPE_READ_ONLY) {
DBG_INF("asked for cursor but got none");
/*
We have asked for CURSOR but got no cursor, because the condition
above is not fulfilled. Then...
if (stmt->flags & CURSOR_TYPE_READ_ONLY) {
if (UPSERT_STATUS_GET_SERVER_STATUS(stmt->upsert_status) & SERVER_STATUS_CURSOR_EXISTS) {
DBG_INF("cursor exists");
stmt->cursor_exists = TRUE;
SET_CONNECTION_STATE(&conn->state, CONN_READY);
/* Only cursor read */
stmt->default_rset_handler = s->m->use_result;
DBG_INF("use_result");
} else {
DBG_INF("asked for cursor but got none");
/*
We have asked for CURSOR but got no cursor, because the condition
above is not fulfilled. Then...
This is a single-row result set, a result set with no rows, EXPLAIN,
SHOW VARIABLES, or some other command which either a) bypasses the
cursors framework in the server and writes rows directly to the
network or b) is more efficient if all (few) result set rows are
precached on client and server's resources are freed.
*/
/* preferred is buffered read */
stmt->default_rset_handler = s->m->store_result;
DBG_INF("store_result");
This is a single-row result set, a result set with no rows, EXPLAIN,
SHOW VARIABLES, or some other command which either a) bypasses the
cursors framework in the server and writes rows directly to the
network or b) is more efficient if all (few) result set rows are
precached on client and server's resources are freed.
*/
/* preferred is buffered read */
stmt->default_rset_handler = s->m->store_result;
DBG_INF("store_result");
}
} else {
DBG_INF("no cursor");
/* preferred is unbuffered read */
@@ -940,11 +967,7 @@ MYSQLND_METHOD(mysqlnd_stmt, use_result)(MYSQLND_STMT * s)
}
DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
if (!stmt->field_count ||
(!stmt->cursor_exists && GET_CONNECTION_STATE(&conn->state) != CONN_FETCHING_DATA) ||
(stmt->cursor_exists && GET_CONNECTION_STATE(&conn->state) != CONN_READY) ||
(stmt->state != MYSQLND_STMT_WAITING_USE_OR_STORE))
{
if (!stmt->field_count || !mysqlnd_stmt_check_state(stmt)) {
SET_CLIENT_ERROR(conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
DBG_ERR("command out of sync");
DBG_RETURN(NULL);
@@ -974,7 +997,6 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES * result, void * param, const unsigned
MYSQLND_STMT * s = (MYSQLND_STMT *) param;
MYSQLND_STMT_DATA * stmt = s? s->data : NULL;
MYSQLND_CONN_DATA * conn = stmt? stmt->conn : NULL;
zend_uchar buf[MYSQLND_STMT_ID_LENGTH /* statement id */ + 4 /* number of rows to fetch */];
MYSQLND_PACKET_ROW * row_packet;
DBG_ENTER("mysqlnd_fetch_stmt_row_cursor");
@@ -998,18 +1020,9 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES * result, void * param, const unsigned
SET_EMPTY_ERROR(stmt->error_info);
SET_EMPTY_ERROR(conn->error_info);
int4store(buf, stmt->stmt_id);
int4store(buf + MYSQLND_STMT_ID_LENGTH, 1); /* for now fetch only one row */
{
const MYSQLND_CSTRING payload = {(const char*) buf, sizeof(buf)};
ret = conn->command->stmt_fetch(conn, payload);
if (ret == FAIL) {
COPY_CLIENT_ERROR(stmt->error_info, *conn->error_info);
DBG_RETURN(FAIL);
}
/* for now fetch only one row */
if (mysqlnd_stmt_send_cursor_fetch_command(stmt, 1) == FAIL) {
DBG_RETURN(FAIL);
}
row_packet->skip_extraction = stmt->result_bind? FALSE:TRUE;
+27 -25
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;
@@ -1616,8 +1617,28 @@ php_mysqlnd_rowp_read_text_protocol_aux(MYSQLND_ROW_BUFFER * row_buffer, zval *
}
MYSQLND_INC_CONN_STATISTIC_W_VALUE2(stats, statistic, 1, STAT_BYTES_RECEIVED_PURE_DATA_TEXT, len);
}
if (fields_metadata[i].type == MYSQL_TYPE_BIT) {
/*
BIT fields are specially handled. As they come as bit mask, they have
to be converted to human-readable representation.
*/
ps_fetch_from_1_to_8_bytes(current_field, &(fields_metadata[i]), 0, (const zend_uchar **) &p, len);
/*
We have advanced in ps_fetch_from_1_to_8_bytes. We should go back because
later in this function there will be an advancement.
*/
p -= len;
if (Z_TYPE_P(current_field) == IS_LONG && !as_int_or_float) {
/* we are using the text protocol, so convert to string */
char tmp[22];
const size_t tmp_len = sprintf((char *)&tmp, ZEND_ULONG_FMT, Z_LVAL_P(current_field));
ZVAL_STRINGL(current_field, tmp, tmp_len);
} else if (Z_TYPE_P(current_field) == IS_STRING) {
/* nothing to do here, as we want a string and ps_fetch_from_1_to_8_bytes() has given us one */
}
}
#ifdef MYSQLND_STRING_TO_INT_CONVERSION
if (as_int_or_float && perm_bind.php_type == IS_LONG) {
else if (as_int_or_float && perm_bind.php_type == IS_LONG) {
zend_uchar save = *(p + len);
/* We have to make it ASCIIZ temporarily */
*(p + len) = '\0';
@@ -1659,30 +1680,11 @@ php_mysqlnd_rowp_read_text_protocol_aux(MYSQLND_ROW_BUFFER * row_buffer, zval *
zend_uchar save = *(p + len);
/* We have to make it ASCIIZ temporarily */
*(p + len) = '\0';
ZVAL_DOUBLE(current_field, atof((char *) p));
ZVAL_DOUBLE(current_field, zend_strtod((char *) p, NULL));
*(p + len) = save;
} else
}
#endif /* MYSQLND_STRING_TO_INT_CONVERSION */
if (fields_metadata[i].type == MYSQL_TYPE_BIT) {
/*
BIT fields are specially handled. As they come as bit mask, they have
to be converted to human-readable representation.
*/
ps_fetch_from_1_to_8_bytes(current_field, &(fields_metadata[i]), 0, (const zend_uchar **) &p, len);
/*
We have advanced in ps_fetch_from_1_to_8_bytes. We should go back because
later in this function there will be an advancement.
*/
p -= len;
if (Z_TYPE_P(current_field) == IS_LONG && !as_int_or_float) {
/* we are using the text protocol, so convert to string */
char tmp[22];
const size_t tmp_len = sprintf((char *)&tmp, ZEND_ULONG_FMT, Z_LVAL_P(current_field));
ZVAL_STRINGL(current_field, tmp, tmp_len);
} else if (Z_TYPE_P(current_field) == IS_STRING) {
/* nothing to do here, as we want a string and ps_fetch_from_1_to_8_bytes() has given us one */
}
} else if (len == 0) {
else if (len == 0) {
ZVAL_EMPTY_STRING(current_field);
} else if (len == 1) {
ZVAL_INTERNED_STR(current_field, ZSTR_CHAR((zend_uchar)*(char *)p));
+1 -1
View File
@@ -1,6 +1,6 @@
--------------------------------------------------------------------
The PHP License, version 3.01
Copyright (c) 1999 - 2019 The PHP Group. All rights reserved.
Copyright (c) 1999 - 2021 The PHP Group. All rights reserved.
--------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
+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;
}
+5 -2
View File
@@ -774,14 +774,15 @@ static inline void kill_all_lockers(struct flock *mem_usage_check)
/* so that other process won't try to force while we are busy cleaning up */
ZCSG(force_restart_time) = 0;
while (mem_usage_check->l_pid > 0) {
/* Clear previous errno, reset success and tries */
/* Try SIGTERM first, switch to SIGKILL if not successful. */
int signal = SIGTERM;
errno = 0;
success = 0;
tries = 10;
while (tries--) {
zend_accel_error(ACCEL_LOG_WARNING, "Attempting to kill locker %d", mem_usage_check->l_pid);
if (kill(mem_usage_check->l_pid, SIGKILL)) {
if (kill(mem_usage_check->l_pid, signal)) {
if (errno == ESRCH) {
/* Process died before the signal was sent */
success = 1;
@@ -800,6 +801,8 @@ static inline void kill_all_lockers(struct flock *mem_usage_check)
break;
}
usleep(10000);
/* If SIGTERM was not sufficient, use SIGKILL. */
signal = SIGKILL;
}
if (!success) {
/* errno is not ESRCH or we ran out of tries to kill the locker */
+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)
+6 -4
View File
@@ -185,10 +185,12 @@ static void zend_accel_blacklist_update_regexp(zend_blacklist *blacklist)
return;
}
#ifdef HAVE_PCRE_JIT_SUPPORT
if (0 > pcre2_jit_compile(it->re, PCRE2_JIT_COMPLETE)) {
/* Don't return here, even JIT could fail to compile, the pattern is still usable. */
pcre2_get_error_message(errnumber, pcre_error, sizeof(pcre_error));
zend_accel_error(ACCEL_LOG_WARNING, "Blacklist JIT compilation failed, %s\n", pcre_error);
if (PCRE_G(jit)) {
if (0 > pcre2_jit_compile(it->re, PCRE2_JIT_COMPLETE)) {
/* Don't return here, even JIT could fail to compile, the pattern is still usable. */
pcre2_get_error_message(errnumber, pcre_error, sizeof(pcre_error));
zend_accel_error(ACCEL_LOG_WARNING, "Blacklist JIT compilation failed, %s\n", pcre_error);
}
}
#endif
/* prepare for the next iteration */
+26 -26
View File
@@ -1064,6 +1064,17 @@ static inline int php_openssl_config_check_syntax(const char * section_label, co
}
/* }}} */
static char *php_openssl_conf_get_string(
LHASH_OF(CONF_VALUE) *conf, const char *group, const char *name) {
char *str = CONF_get_string(conf, group, name);
if (str == NULL) {
/* OpenSSL reports an error if a configuration value is not found.
* However, we don't want to generate errors for optional configuration. */
ERR_clear_error();
}
return str;
}
static int php_openssl_add_oid_section(struct php_x509_request * req) /* {{{ */
{
char * str;
@@ -1071,9 +1082,8 @@ static int php_openssl_add_oid_section(struct php_x509_request * req) /* {{{ */
CONF_VALUE * cnf;
int i;
str = CONF_get_string(req->req_config, NULL, "oid_section");
str = php_openssl_conf_get_string(req->req_config, NULL, "oid_section");
if (str == NULL) {
php_openssl_store_errors();
return SUCCESS;
}
sktmp = CONF_get_section(req->req_config, str);
@@ -1158,10 +1168,8 @@ static int php_openssl_parse_config(struct php_x509_request * req, zval * option
}
/* read in the oids */
str = CONF_get_string(req->req_config, NULL, "oid_file");
if (str == NULL) {
php_openssl_store_errors();
} else if (!php_openssl_open_base_dir_chk(str)) {
str = php_openssl_conf_get_string(req->req_config, NULL, "oid_file");
if (str != NULL && !php_openssl_open_base_dir_chk(str)) {
BIO *oid_bio = BIO_new_file(str, PHP_OPENSSL_BIO_MODE_R(PKCS7_BINARY));
if (oid_bio) {
OBJ_create_objects(oid_bio);
@@ -1173,11 +1181,11 @@ static int php_openssl_parse_config(struct php_x509_request * req, zval * option
return FAILURE;
}
SET_OPTIONAL_STRING_ARG("digest_alg", req->digest_name,
CONF_get_string(req->req_config, req->section_name, "default_md"));
php_openssl_conf_get_string(req->req_config, req->section_name, "default_md"));
SET_OPTIONAL_STRING_ARG("x509_extensions", req->extensions_section,
CONF_get_string(req->req_config, req->section_name, "x509_extensions"));
php_openssl_conf_get_string(req->req_config, req->section_name, "x509_extensions"));
SET_OPTIONAL_STRING_ARG("req_extensions", req->request_extensions_section,
CONF_get_string(req->req_config, req->section_name, "req_extensions"));
php_openssl_conf_get_string(req->req_config, req->section_name, "req_extensions"));
SET_OPTIONAL_LONG_ARG("private_key_bits", req->priv_key_bits,
CONF_get_number(req->req_config, req->section_name, "default_bits"));
@@ -1186,11 +1194,9 @@ static int php_openssl_parse_config(struct php_x509_request * req, zval * option
if (optional_args && (item = zend_hash_str_find(Z_ARRVAL_P(optional_args), "encrypt_key", sizeof("encrypt_key")-1)) != NULL) {
req->priv_key_encrypt = Z_TYPE_P(item) == IS_TRUE ? 1 : 0;
} else {
str = CONF_get_string(req->req_config, req->section_name, "encrypt_rsa_key");
str = php_openssl_conf_get_string(req->req_config, req->section_name, "encrypt_rsa_key");
if (str == NULL) {
str = CONF_get_string(req->req_config, req->section_name, "encrypt_key");
/* it is sure that there are some errrors as str was NULL for encrypt_rsa_key */
php_openssl_store_errors();
str = php_openssl_conf_get_string(req->req_config, req->section_name, "encrypt_key");
}
if (str != NULL && strcmp(str, "no") == 0) {
req->priv_key_encrypt = 0;
@@ -1218,12 +1224,10 @@ static int php_openssl_parse_config(struct php_x509_request * req, zval * option
/* digest alg */
if (req->digest_name == NULL) {
req->digest_name = CONF_get_string(req->req_config, req->section_name, "default_md");
req->digest_name = php_openssl_conf_get_string(req->req_config, req->section_name, "default_md");
}
if (req->digest_name != NULL) {
req->digest = req->md_alg = EVP_get_digestbyname(req->digest_name);
} else {
php_openssl_store_errors();
}
if (req->md_alg == NULL) {
req->md_alg = req->digest = EVP_sha1();
@@ -1245,10 +1249,8 @@ static int php_openssl_parse_config(struct php_x509_request * req, zval * option
#endif
/* set the string mask */
str = CONF_get_string(req->req_config, req->section_name, "string_mask");
if (str == NULL) {
php_openssl_store_errors();
} else if (!ASN1_STRING_set_default_mask_asc(str)) {
str = php_openssl_conf_get_string(req->req_config, req->section_name, "string_mask");
if (str != NULL && !ASN1_STRING_set_default_mask_asc(str)) {
php_error_docref(NULL, E_WARNING, "Invalid global string mask setting %s", str);
return FAILURE;
}
@@ -3138,9 +3140,8 @@ static int php_openssl_make_REQ(struct php_x509_request * req, X509_REQ * csr, z
php_openssl_store_errors();
return FAILURE;
}
attr_sect = CONF_get_string(req->req_config, req->section_name, "attributes");
attr_sect = php_openssl_conf_get_string(req->req_config, req->section_name, "attributes");
if (attr_sect == NULL) {
php_openssl_store_errors();
attr_sk = NULL;
} else {
attr_sk = CONF_get_section(req->req_config, attr_sect);
@@ -3994,10 +3995,7 @@ static EVP_PKEY * php_openssl_generate_private_key(struct php_x509_request * req
return NULL;
}
randfile = CONF_get_string(req->req_config, req->section_name, "RANDFILE");
if (randfile == NULL) {
php_openssl_store_errors();
}
randfile = php_openssl_conf_get_string(req->req_config, req->section_name, "RANDFILE");
php_openssl_load_rand_file(randfile, &egdsocket, &seeded);
if ((req->priv_key = EVP_PKEY_new()) != NULL) {
@@ -4021,6 +4019,8 @@ static EVP_PKEY * php_openssl_generate_private_key(struct php_x509_request * req
PHP_OPENSSL_RAND_ADD_TIME();
if (rsaparam == NULL || !RSA_generate_key_ex(rsaparam, req->priv_key_bits, bne, NULL)) {
php_openssl_store_errors();
RSA_free(rsaparam);
rsaparam = NULL;
}
BN_free(bne);
}
+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)
+24
View File
@@ -0,0 +1,24 @@
--TEST--
Bug #80747: Providing RSA key size < 512 generates key that crash PHP
--FILE--
--SKIPIF--
<?php
if (!extension_loaded("openssl")) die("skip openssl not loaded");
if (OPENSSL_VERSION_NUMBER < 0x10100000) die("skip OpenSSL >= v1.1.0 required");
?>
--FILE--
<?php
$conf = array(
'config' => __DIR__ . DIRECTORY_SEPARATOR . 'openssl.cnf',
'private_key_bits' => 511,
);
var_dump(openssl_pkey_new($conf));
while ($e = openssl_error_string()) {
echo $e, "\n";
}
?>
--EXPECTF--
bool(false)
error:%s:key size too small
+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)
+9 -6
View File
@@ -1424,9 +1424,10 @@ static void php_pgsql_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent)
}
pgsql = (PGconn *) le->ptr;
#if HAVE_PQPROTOCOLVERSION && HAVE_PQPARAMETERSTATUS
if (PQprotocolVersion(pgsql) >= 3 && atof(PQparameterStatus(pgsql, "server_version")) >= 7.2) {
/* consider to use php_version_compare() here */
if (PQprotocolVersion(pgsql) >= 3 && zend_strtod(PQparameterStatus(pgsql, "server_version"), NULL) >= 7.2) {
#else
if (atof(PG_VERSION) >= 7.2) {
if (zend_strtod(PG_VERSION, NULL) >= 7.2) {
#endif
pg_result = PQexec(pgsql, "RESET ALL;");
PQclear(pg_result);
@@ -5326,9 +5327,10 @@ PHP_FUNCTION(pg_get_notify)
add_index_string(return_value, 0, pgsql_notify->relname);
add_index_long(return_value, 1, pgsql_notify->be_pid);
#if HAVE_PQPROTOCOLVERSION && HAVE_PQPARAMETERSTATUS
if (PQprotocolVersion(pgsql) >= 3 && atof(PQparameterStatus(pgsql, "server_version")) >= 9.0) {
/* consider to use php_version_compare() here */
if (PQprotocolVersion(pgsql) >= 3 && zend_strtod(PQparameterStatus(pgsql, "server_version"), NULL) >= 9.0) {
#else
if (atof(PG_VERSION) >= 9.0) {
if (zend_strtod(PG_VERSION) >= 9.0, NULL) {
#endif
#if HAVE_PQPARAMETERSTATUS
add_index_string(return_value, 2, pgsql_notify->extra);
@@ -5339,9 +5341,10 @@ PHP_FUNCTION(pg_get_notify)
add_assoc_string(return_value, "message", pgsql_notify->relname);
add_assoc_long(return_value, "pid", pgsql_notify->be_pid);
#if HAVE_PQPROTOCOLVERSION && HAVE_PQPARAMETERSTATUS
if (PQprotocolVersion(pgsql) >= 3 && atof(PQparameterStatus(pgsql, "server_version")) >= 9.0) {
/* consider to use php_version_compare() here */
if (PQprotocolVersion(pgsql) >= 3 && zend_strtod(PQparameterStatus(pgsql, "server_version"), NULL) >= 9.0) {
#else
if (atof(PG_VERSION) >= 9.0) {
if (zend_strtod(PG_VERSION, NULL) >= 9.0) {
#endif
#if HAVE_PQPARAMETERSTATUS
add_assoc_string(return_value, "payload", pgsql_notify->extra);
+1 -1
View File
@@ -1,4 +1,4 @@
.TH PHAR 1 "2019" "The PHP Group" "User Commands"
.TH PHAR 1 "2021" "The PHP Group" "User Commands"
.SH NAME
phar, phar.phar \- PHAR (PHP archive) command line tool
.SH SYNOPSIS
+42 -18
View File
@@ -2508,6 +2508,7 @@ int phar_flush(phar_archive_data *phar, char *user_stub, zend_long len, int conv
smart_str main_metadata_str = {0};
int free_user_stub, free_fp = 1, free_ufp = 1;
int manifest_hack = 0;
php_stream *shared_cfp = NULL;
if (phar->is_persistent) {
if (error) {
@@ -2602,7 +2603,7 @@ int phar_flush(phar_archive_data *phar, char *user_stub, zend_long len, int conv
}
php_stream_close(newfile);
if (error) {
spprintf(error, 0, "illegal stub for phar \"%s\"", phar->fname);
spprintf(error, 0, "illegal stub for phar \"%s\" (__HALT_COMPILER(); is missing)", phar->fname);
}
if (free_user_stub) {
zend_string_free(suser_stub);
@@ -2788,10 +2789,13 @@ int phar_flush(phar_archive_data *phar, char *user_stub, zend_long len, int conv
return EOF;
}
/* create new file that holds the compressed version */
/* create new file that holds the compressed versions */
/* work around inability to specify freedom in write and strictness
in read count */
entry->cfp = php_stream_fopen_tmpfile();
if (shared_cfp == NULL) {
shared_cfp = php_stream_fopen_tmpfile();
}
entry->cfp = shared_cfp;
if (!entry->cfp) {
if (error) {
spprintf(error, 0, "unable to create temporary file");
@@ -2800,8 +2804,11 @@ int phar_flush(phar_archive_data *phar, char *user_stub, zend_long len, int conv
php_stream_close(oldfile);
}
php_stream_close(newfile);
return EOF;
goto cleanup;
}
/* for real phars, header_offset is unused; we misuse it here to store the offset in the temp file */
ZEND_ASSERT(entry->header_offset == 0);
entry->header_offset = php_stream_tell(entry->cfp);
php_stream_flush(file);
if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 0)) {
if (closeoldfile) {
@@ -2811,7 +2818,7 @@ int phar_flush(phar_archive_data *phar, char *user_stub, zend_long len, int conv
if (error) {
spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname);
}
return EOF;
goto cleanup;
}
php_stream_filter_append((&entry->cfp->writefilters), filter);
if (SUCCESS != php_stream_copy_to_stream_ex(file, entry->cfp, entry->uncompressed_filesize, NULL)) {
@@ -2822,15 +2829,14 @@ int phar_flush(phar_archive_data *phar, char *user_stub, zend_long len, int conv
if (error) {
spprintf(error, 0, "unable to copy compressed file contents of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname);
}
return EOF;
goto cleanup;
}
php_stream_filter_flush(filter, 1);
php_stream_flush(entry->cfp);
php_stream_filter_remove(filter, 1);
php_stream_seek(entry->cfp, 0, SEEK_END);
entry->compressed_filesize = (uint32_t) php_stream_tell(entry->cfp);
entry->compressed_filesize = ((uint32_t) php_stream_tell(entry->cfp)) - entry->header_offset;
/* generate crc on compressed file */
php_stream_rewind(entry->cfp);
entry->old_flags = entry->flags;
entry->is_modified = 1;
global_flags |= (entry->flags & PHAR_ENT_COMPRESSION_MASK);
@@ -2886,7 +2892,7 @@ int phar_flush(phar_archive_data *phar, char *user_stub, zend_long len, int conv
spprintf(error, 0, "unable to write manifest header of new phar \"%s\"", phar->fname);
}
return EOF;
goto cleanup;
}
phar->alias_len = restore_alias_len;
@@ -2907,7 +2913,7 @@ int phar_flush(phar_archive_data *phar, char *user_stub, zend_long len, int conv
spprintf(error, 0, "unable to write manifest meta-data of new phar \"%s\"", phar->fname);
}
return EOF;
goto cleanup;
}
smart_str_free(&main_metadata_str);
@@ -2942,7 +2948,7 @@ int phar_flush(phar_archive_data *phar, char *user_stub, zend_long len, int conv
spprintf(error, 0, "unable to write filename of file \"%s\" to manifest of new phar \"%s\"", entry->filename, phar->fname);
}
}
return EOF;
goto cleanup;
}
/* set the manifest meta-data:
@@ -2975,7 +2981,7 @@ int phar_flush(phar_archive_data *phar, char *user_stub, zend_long len, int conv
spprintf(error, 0, "unable to write temporary manifest of file \"%s\" to manifest of new phar \"%s\"", entry->filename, phar->fname);
}
return EOF;
goto cleanup;
}
} ZEND_HASH_FOREACH_END();
/* Hack - see bug #65028, add padding byte to the end of the manifest */
@@ -2991,7 +2997,7 @@ int phar_flush(phar_archive_data *phar, char *user_stub, zend_long len, int conv
spprintf(error, 0, "unable to write manifest padding byte");
}
return EOF;
goto cleanup;
}
}
@@ -3004,7 +3010,7 @@ int phar_flush(phar_archive_data *phar, char *user_stub, zend_long len, int conv
if (entry->cfp) {
file = entry->cfp;
php_stream_rewind(file);
php_stream_seek(file, entry->header_offset, SEEK_SET);
} else {
file = phar_get_efp(entry, 0);
if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 0)) {
@@ -3015,7 +3021,7 @@ int phar_flush(phar_archive_data *phar, char *user_stub, zend_long len, int conv
if (error) {
spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname);
}
return EOF;
goto cleanup;
}
}
@@ -3027,7 +3033,7 @@ int phar_flush(phar_archive_data *phar, char *user_stub, zend_long len, int conv
if (error) {
spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname);
}
return EOF;
goto cleanup;
}
/* this will have changed for all files that have either changed compression or been modified */
@@ -3044,14 +3050,14 @@ int phar_flush(phar_archive_data *phar, char *user_stub, zend_long len, int conv
spprintf(error, 0, "unable to write contents of file \"%s\" to new phar \"%s\"", entry->filename, phar->fname);
}
return EOF;
goto cleanup;
}
entry->is_modified = 0;
if (entry->cfp) {
php_stream_close(entry->cfp);
entry->cfp = NULL;
entry->header_offset = 0;
}
if (entry->fp_type == PHAR_MOD) {
@@ -3067,6 +3073,11 @@ int phar_flush(phar_archive_data *phar, char *user_stub, zend_long len, int conv
}
} ZEND_HASH_FOREACH_END();
if (shared_cfp != NULL) {
php_stream_close(shared_cfp);
shared_cfp = NULL;
}
/* append signature */
if (global_flags & PHAR_HDR_SIGNATURE) {
char sig_buf[4];
@@ -3196,6 +3207,19 @@ int phar_flush(phar_archive_data *phar, char *user_stub, zend_long len, int conv
return EOF;
}
return EOF;
cleanup:
if (shared_cfp != NULL) {
php_stream_close(shared_cfp);
}
ZEND_HASH_FOREACH_PTR(&phar->manifest, entry) {
if (entry->cfp) {
entry->cfp = NULL;
entry->header_offset = 0;
}
} ZEND_HASH_FOREACH_END();
return EOF;
}
/* }}} */
+18 -20
View File
@@ -609,7 +609,7 @@ PHP_METHOD(Phar, webPhar)
if (NULL == (z_script_name = zend_hash_str_find(_server, "SCRIPT_NAME", sizeof("SCRIPT_NAME")-1)) ||
IS_STRING != Z_TYPE_P(z_script_name) ||
!strstr(Z_STRVAL_P(z_script_name), basename)) {
return;
goto finish;
}
if (NULL != (z_path_info = zend_hash_str_find(_server, "PATH_INFO", sizeof("PATH_INFO")-1)) &&
@@ -634,7 +634,7 @@ PHP_METHOD(Phar, webPhar)
testit = sapi_getenv("SCRIPT_NAME", sizeof("SCRIPT_NAME")-1);
if (!(pt = strstr(testit, basename))) {
efree(testit);
return;
goto finish;
}
path_info = sapi_getenv("PATH_INFO", sizeof("PATH_INFO")-1);
@@ -659,7 +659,7 @@ PHP_METHOD(Phar, webPhar)
if (!(pt = strstr(path_info, basename))) {
/* this can happen with rewrite rules - and we have no idea what to do then, so return */
return;
goto finish;
}
entry_len = strlen(path_info);
@@ -685,7 +685,7 @@ PHP_METHOD(Phar, webPhar)
}
efree(pt);
return;
goto finish;
}
fci.param_count = 1;
@@ -703,7 +703,7 @@ PHP_METHOD(Phar, webPhar)
}
efree(pt);
return;
goto finish;
}
if (Z_TYPE_P(fci.retval) == IS_UNDEF || Z_TYPE(retval) == IS_UNDEF) {
@@ -712,7 +712,7 @@ PHP_METHOD(Phar, webPhar)
}
zend_throw_exception_ex(phar_ce_PharException, 0, "phar error: rewrite callback must return a string or false");
efree(pt);
return;
goto finish;
}
switch (Z_TYPE(retval)) {
@@ -731,7 +731,7 @@ PHP_METHOD(Phar, webPhar)
efree(pt);
zend_bailout();
return;
goto finish;
default:
if (free_pathinfo) {
efree(path_info);
@@ -739,7 +739,7 @@ PHP_METHOD(Phar, webPhar)
efree(pt);
zend_throw_exception_ex(phar_ce_PharException, 0, "phar error: rewrite callback must return a string or false");
return;
goto finish;
}
}
@@ -812,9 +812,6 @@ PHP_METHOD(Phar, webPhar)
if (FAILURE == phar_get_archive(&phar, fname, fname_len, NULL, 0, NULL) ||
(info = phar_get_entry_info(phar, entry, entry_len, NULL, 0)) == NULL) {
phar_do_404(phar, fname, fname_len, f404, f404_len, entry, entry_len);
#ifdef PHP_WIN32
efree(fname);
#endif
zend_bailout();
}
@@ -838,10 +835,8 @@ PHP_METHOD(Phar, webPhar)
}
efree(pt);
efree(entry);
#ifdef PHP_WIN32
efree(fname);
#endif
RETURN_FALSE;
RETVAL_FALSE;
goto finish;
}
break;
case IS_STRING:
@@ -855,10 +850,8 @@ PHP_METHOD(Phar, webPhar)
}
efree(pt);
efree(entry);
#ifdef PHP_WIN32
efree(fname);
#endif
RETURN_FALSE;
RETVAL_FALSE;
goto finish;
}
}
}
@@ -868,6 +861,11 @@ PHP_METHOD(Phar, webPhar)
code = phar_file_type(&PHAR_G(mime_types), entry, &mime_type);
}
phar_file_action(phar, info, mime_type, code, entry, entry_len, fname, pt, ru, ru_len);
finish: ;
#ifdef PHP_WIN32
efree(fname);
#endif
}
/* }}} */
@@ -4277,7 +4275,7 @@ static int phar_extract_file(zend_bool overwrite, phar_entry_info *entry, char *
return FAILURE;
}
if (!phar_get_efp(entry, 0)) {
if ((phar_get_fp_type(entry) == PHAR_FP && (entry->flags & PHAR_ENT_COMPRESSION_MASK)) || !phar_get_efp(entry, 0)) {
if (FAILURE == phar_open_entry_fp(entry, error, 1)) {
if (error) {
spprintf(error, 4096, "Cannot extract \"%s\" to \"%s\", unable to open internal file pointer: %s", entry->filename, fullpath, *error);
+30
View File
@@ -0,0 +1,30 @@
--TEST--
Bug #69279 (Compressed ZIP Phar extractTo() creates garbage files)
--SKIPIF--
<?php
if (!extension_loaded('phar')) die('skip phar extension not available');
if (!extension_loaded('zlib')) die('skip zlib extension not available');
?>
--INI--
phar.readonly=0
--FILE--
<?php
$w = new Phar(__DIR__ . "/bug69279.phar.zip");
$w["bug69279.txt"] = "Sample content.";
$w->compressFiles(Phar::GZ);
unset($w);
$r = new Phar(__DIR__ . "/bug69279.phar.zip");
var_dump($r["bug69279.txt"]->isCompressed());
$r->extractTo(__DIR__, NULL, TRUE);
var_dump(file_get_contents(__DIR__ . "/bug69279.txt"));
?>
--EXPECT--
bool(true)
string(15) "Sample content."
--CLEAN--
<?php
@unlink(__DIR__ . "/bug69279.txt");
@unlink(__DIR__ . "/bug69279.phar.zip");
?>
+27
View File
@@ -0,0 +1,27 @@
--TEST--
Bug #69279 (Compressed ZIP Phar extractTo() creates garbage files)
--SKIPIF--
<?php
if (!extension_loaded('phar')) die('skip phar extension not available');
if (!extension_loaded('zlib')) die('skip zlib extension not available');
?>
--FILE--
<?php
$phar = new PharData(__DIR__ . '/bug69279a.zip');
mkdir(__DIR__ . '/bug69279a');
var_dump($phar->extractTo(__DIR__ . '/bug69279a', null, true));
var_dump(strncmp(file_get_contents(__DIR__ . '/bug69279a/1.txt'), 'Lorem ipsum', 11));
var_dump(strncmp(file_get_contents(__DIR__ . '/bug69279a/2.txt'), 'foo', 3));
var_dump(strncmp(file_get_contents(__DIR__ . '/bug69279a/3.txt'), 'Lorem ipsum', 11));
?>
--EXPECT--
bool(true)
int(0)
int(0)
int(0)
--CLEAN--
<?php
@unlink(__DIR__ . '/bug69279a/1.txt');
@unlink(__DIR__ . '/bug69279a/2.txt');
@unlink(__DIR__ . '/bug69279a/3.txt');
@rmdir(__DIR__ . '/bug69279a');
Binary file not shown.
+1 -1
View File
@@ -14,7 +14,7 @@ $r = new Phar($fname, 0);
==DONE==
--EXPECTF--
UnexpectedValueException: phar error: corrupted central directory entry, no magic signature in zip-based phar "%sbug69441.phar" in %sbug69441.php:%d
UnexpectedValueException: phar error: end of central directory not found in zip-based phar "%sbug69441.phar" in %sbug69441.php:%d
Stack trace:
#0 %s%ebug69441.php(%d): Phar->__construct('%s', 0)
#1 {main}
+60
View File
@@ -0,0 +1,60 @@
--TEST--
Bug #70091 (Phar does not mark UTF-8 filenames in ZIP archives)
--SKIPIF--
<?php
if (!extension_loaded('phar')) die('skip phar extension not available');
if (!extension_loaded('zlib')) die('skip zlib extension not available');
?>
--FILE--
<?php
$phar = new PharData(__DIR__ . '/bug70091.zip');
$phar->addFromString('föö', '');
$phar->addFromString('foo', '');
unset($phar);
$stream = fopen(__DIR__ . '/bug70091.zip', 'r');
$data = fread($stream, 8);
var_dump(unpack('H8sig/@6/nflags', $data));
fseek($stream, 53);
$data = fread($stream, 8);
var_dump(unpack('H8sig/@6/nflags', $data));
fseek($stream, 104);
$data = fread($stream, 10);
var_dump(unpack('H8sig/@8/nflags', $data));
fseek($stream, 173);
$data = fread($stream, 10);
var_dump(unpack('H8sig/@8/nflags', $data));
?>
--EXPECT--
array(2) {
["sig"]=>
string(8) "504b0304"
["flags"]=>
int(8)
}
array(2) {
["sig"]=>
string(8) "504b0304"
["flags"]=>
int(8)
}
array(2) {
["sig"]=>
string(8) "504b0102"
["flags"]=>
int(8)
}
array(2) {
["sig"]=>
string(8) "504b0102"
["flags"]=>
int(8)
}
--CLEAN--
<?php
@unlink(__DIR__ . '/bug70091.zip');
?>
+13
View File
@@ -0,0 +1,13 @@
--TEST--
Bug #77565 (Incorrect locator detection in ZIP-based phars)
--SKIPIF--
<?php
if (!extension_loaded('phar')) die('skip phar extension not available');
?>
--FILE--
<?php
$phar = new PharData(__DIR__ . '/bug77565.zip');
var_dump($phar['1.zip']->getFilename());
?>
--EXPECT--
string(5) "1.zip"
Binary file not shown.
+36
View File
@@ -0,0 +1,36 @@
--TEST--
Bug #79912 (Phar::decompressFiles not working)
--SKIPIF--
<?php
if (!extension_loaded('phar')) die('skip phar extension is not available');
if (!extension_loaded('zlib')) die('skip zlib extension not available');
?>
--INI--
phar.readonly=0
--FILE--
<?php
$phar = new Phar(__DIR__ . "/bug79912.phar");
$phar->addFromString("test.txt", "This is a test file.This is a test file.This is a test file.");
$file = $phar["test.txt"];
var_dump($file->compress(Phar::GZ)); //true (success)
var_dump($file->getContent());
var_dump($file->isCompressed()); //true (the file is compressed)
var_dump($phar->decompressFiles()); //true (success)
var_dump($file->isCompressed()); //false (the file should not be compressed anymore)
var_dump($phar->extractTo(__DIR__ . "/bug79912")); //true
var_dump(file_get_contents(__DIR__ . "/bug79912/test.txt")); //the extracted file in the folder should be decompressed
?>
--EXPECT--
bool(true)
string(60) "This is a test file.This is a test file.This is a test file."
bool(true)
bool(true)
bool(false)
bool(true)
string(60) "This is a test file.This is a test file.This is a test file."
--CLEAN--
<?php
@unlink(__DIR__ . "/bug79912/test.txt");
@rmdir(__DIR__ . "/bug79912");
@unlink(__DIR__ . "/bug79912.phar");
?>
+1 -1
View File
@@ -48,7 +48,7 @@ __HALT_COMPILER();
string(48) "<?php echo "first stub\n"; __HALT_COMPILER(); ?>"
string(48) "<?php echo "first stub\n"; __HALT_COMPILER(); ?>"
bool(true)
Exception: illegal stub for phar "%sphar_stub_error.phar.php"
Exception: illegal stub for phar "%sphar_stub_error.phar.php" (__HALT_COMPILER(); is missing)
string(48) "<?php echo "first stub\n"; __HALT_COMPILER(); ?>"
bool(true)
string(48) "<?php echo "first stub\n"; __HALT_COMPILER(); ?>"
+1 -1
View File
@@ -12,5 +12,5 @@ try {
?>
===DONE===
--EXPECTF--
phar error: corrupt zip archive, zip file comment truncated in zip-based phar "%sfilecomment.zip"
phar error: end of central directory not found in zip-based phar "%sfilecomment.zip"
===DONE===
+76 -49
View File
@@ -161,6 +161,29 @@ static void phar_zip_u2d_time(time_t time, char *dtime, char *ddate) /* {{{ */
}
/* }}} */
static char *phar_find_eocd(const char *s, size_t n)
{
const char *end = s + n + sizeof("PK\5\6") - 1 - sizeof(phar_zip_dir_end);
/* search backwards for end of central directory signatures */
do {
uint16_t comment_len;
const char *eocd_start = zend_memnrstr(s, "PK\5\6", sizeof("PK\5\6") - 1, end);
if (eocd_start == NULL) {
return NULL;
}
ZEND_ASSERT(eocd_start + sizeof(phar_zip_dir_end) <= s + n);
comment_len = PHAR_GET_16(((phar_zip_dir_end *) eocd_start)->comment_len);
if (eocd_start + sizeof(phar_zip_dir_end) + comment_len == s + n) {
/* we can't be sure, but this looks like the proper EOCD signature */
return (char *) eocd_start;
}
end = eocd_start;
} while (end > s);
return NULL;
}
/**
* Does not check for a previously opened phar in the cache.
*
@@ -205,57 +228,55 @@ int phar_parse_zipfile(php_stream *fp, char *fname, size_t fname_len, char *alia
return FAILURE;
}
while ((p=(char *) memchr(p + 1, 'P', (size_t) (size - (p + 1 - buf)))) != NULL) {
if ((p - buf) + sizeof(locator) <= (size_t)size && !memcmp(p + 1, "K\5\6", 3)) {
memcpy((void *)&locator, (void *) p, sizeof(locator));
if (PHAR_GET_16(locator.centraldisk) != 0 || PHAR_GET_16(locator.disknumber) != 0) {
/* split archives not handled */
php_stream_close(fp);
if (error) {
spprintf(error, 4096, "phar error: split archives spanning multiple zips cannot be processed in zip-based phar \"%s\"", fname);
}
return FAILURE;
if ((p = phar_find_eocd(buf, size)) != NULL) {
memcpy((void *)&locator, (void *) p, sizeof(locator));
if (PHAR_GET_16(locator.centraldisk) != 0 || PHAR_GET_16(locator.disknumber) != 0) {
/* split archives not handled */
php_stream_close(fp);
if (error) {
spprintf(error, 4096, "phar error: split archives spanning multiple zips cannot be processed in zip-based phar \"%s\"", fname);
}
if (PHAR_GET_16(locator.counthere) != PHAR_GET_16(locator.count)) {
if (error) {
spprintf(error, 4096, "phar error: corrupt zip archive, conflicting file count in end of central directory record in zip-based phar \"%s\"", fname);
}
php_stream_close(fp);
return FAILURE;
}
mydata = pecalloc(1, sizeof(phar_archive_data), PHAR_G(persist));
mydata->is_persistent = PHAR_G(persist);
/* read in archive comment, if any */
if (PHAR_GET_16(locator.comment_len)) {
metadata = p + sizeof(locator);
if (PHAR_GET_16(locator.comment_len) != size - (metadata - buf)) {
if (error) {
spprintf(error, 4096, "phar error: corrupt zip archive, zip file comment truncated in zip-based phar \"%s\"", fname);
}
php_stream_close(fp);
pefree(mydata, mydata->is_persistent);
return FAILURE;
}
mydata->metadata_len = PHAR_GET_16(locator.comment_len);
if (phar_parse_metadata(&metadata, &mydata->metadata, PHAR_GET_16(locator.comment_len)) == FAILURE) {
mydata->metadata_len = 0;
/* if not valid serialized data, it is a regular string */
ZVAL_NEW_STR(&mydata->metadata, zend_string_init(metadata, PHAR_GET_16(locator.comment_len), mydata->is_persistent));
}
} else {
ZVAL_UNDEF(&mydata->metadata);
}
goto foundit;
return FAILURE;
}
if (PHAR_GET_16(locator.counthere) != PHAR_GET_16(locator.count)) {
if (error) {
spprintf(error, 4096, "phar error: corrupt zip archive, conflicting file count in end of central directory record in zip-based phar \"%s\"", fname);
}
php_stream_close(fp);
return FAILURE;
}
mydata = pecalloc(1, sizeof(phar_archive_data), PHAR_G(persist));
mydata->is_persistent = PHAR_G(persist);
/* read in archive comment, if any */
if (PHAR_GET_16(locator.comment_len)) {
metadata = p + sizeof(locator);
if (PHAR_GET_16(locator.comment_len) != size - (metadata - buf)) {
if (error) {
spprintf(error, 4096, "phar error: corrupt zip archive, zip file comment truncated in zip-based phar \"%s\"", fname);
}
php_stream_close(fp);
pefree(mydata, mydata->is_persistent);
return FAILURE;
}
mydata->metadata_len = PHAR_GET_16(locator.comment_len);
if (phar_parse_metadata(&metadata, &mydata->metadata, PHAR_GET_16(locator.comment_len)) == FAILURE) {
mydata->metadata_len = 0;
/* if not valid serialized data, it is a regular string */
ZVAL_NEW_STR(&mydata->metadata, zend_string_init(metadata, PHAR_GET_16(locator.comment_len), mydata->is_persistent));
}
} else {
ZVAL_UNDEF(&mydata->metadata);
}
goto foundit;
}
php_stream_close(fp);
@@ -808,6 +829,7 @@ static int phar_zip_changed_apply_int(phar_entry_info *entry, void *arg) /* {{{
zend_off_t offset;
int not_really_modified = 0;
p = (struct _phar_zip_pass*) arg;
uint16_t general_purpose_flags;
if (entry->is_mounted) {
return ZEND_HASH_APPLY_KEEP;
@@ -857,6 +879,11 @@ static int phar_zip_changed_apply_int(phar_entry_info *entry, void *arg) /* {{{
memcpy(central.datestamp, local.datestamp, sizeof(local.datestamp));
PHAR_SET_16(central.filename_len, entry->filename_len + (entry->is_dir ? 1 : 0));
PHAR_SET_16(local.filename_len, entry->filename_len + (entry->is_dir ? 1 : 0));
// set language encoding flag (all filenames have to be UTF-8 anyway)
general_purpose_flags = PHAR_GET_16(central.flags);
PHAR_SET_16(central.flags, general_purpose_flags | (1 << 11));
general_purpose_flags = PHAR_GET_16(local.flags);
PHAR_SET_16(local.flags, general_purpose_flags | (1 << 11));
PHAR_SET_32(central.offset, php_stream_tell(p->filefp));
/* do extra field for perms later */
+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
/* }}} */
+1
View File
@@ -555,6 +555,7 @@ static char **_readline_completion_cb(const char *text, int start, int end)
if (call_user_function(NULL, NULL, &_readline_completion, &_readline_array, 3, params) == SUCCESS) {
if (Z_TYPE(_readline_array) == IS_ARRAY) {
SEPARATE_ARRAY(&_readline_array);
if (zend_hash_num_elements(Z_ARRVAL(_readline_array))) {
matches = rl_completion_matches(text,_readline_command_generator);
} else {
+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);
}
}
+15 -14
View File
@@ -315,6 +315,8 @@ void sdl_restore_uri_credentials(sdlCtx *ctx)
ctx->context = NULL;
}
#define SAFE_STR(a) ((a)?((const char *)a):"")
static void load_wsdl_ex(zval *this_ptr, char *struri, sdlCtx *ctx, int include)
{
sdlPtr tmpsdl = ctx->sdl;
@@ -376,7 +378,7 @@ static void load_wsdl_ex(zval *this_ptr, char *struri, sdlCtx *ctx, int include)
if (node_is_equal_ex(trav2, "schema", XSD_NAMESPACE)) {
load_schema(ctx, trav2);
} else if (is_wsdl_element(trav2) && !node_is_equal(trav2,"documentation")) {
soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", trav2->name);
soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", SAFE_STR(trav2->name));
}
trav2 = trav2->next;
}
@@ -437,7 +439,7 @@ static void load_wsdl_ex(zval *this_ptr, char *struri, sdlCtx *ctx, int include)
soap_error0(E_ERROR, "Parsing WSDL: <service> has no name attribute");
}
} else if (!node_is_equal(trav,"documentation")) {
soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", trav->name);
soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", SAFE_STR(trav->name));
}
trav = trav->next;
}
@@ -547,7 +549,7 @@ static sdlSoapBindingFunctionHeaderPtr wsdl_soap_binding_header(sdlCtx* ctx, xml
}
smart_str_free(&key);
} else if (is_wsdl_element(trav) && !node_is_equal(trav,"documentation")) {
soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", trav->name);
soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", SAFE_STR(trav->name));
}
trav = trav->next;
}
@@ -649,7 +651,7 @@ static void wsdl_soap_binding_body(sdlCtx* ctx, xmlNodePtr node, char* wsdl_soap
}
smart_str_free(&key);
} else if (is_wsdl_element(trav) && !node_is_equal(trav,"documentation")) {
soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", trav->name);
soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", SAFE_STR(trav->name));
}
trav = trav->next;
}
@@ -681,14 +683,14 @@ static HashTable* wsdl_message(sdlCtx *ctx, xmlChar* message_name)
sdlParamPtr param;
if (trav->ns != NULL && strcmp((char*)trav->ns->href, WSDL_NAMESPACE) != 0) {
soap_error1(E_ERROR, "Parsing WSDL: Unexpected extensibility element <%s>", trav->name);
soap_error1(E_ERROR, "Parsing WSDL: Unexpected extensibility element <%s>", SAFE_STR(trav->name));
}
if (node_is_equal(trav,"documentation")) {
trav = trav->next;
continue;
}
if (!node_is_equal(trav,"part")) {
soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", trav->name);
soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", SAFE_STR(trav->name));
}
part = trav;
param = emalloc(sizeof(sdlParam));
@@ -697,7 +699,7 @@ static HashTable* wsdl_message(sdlCtx *ctx, xmlChar* message_name)
name = get_attribute(part->properties, "name");
if (name == NULL) {
soap_error1(E_ERROR, "Parsing WSDL: No name associated with <part> '%s'", message->name);
soap_error1(E_ERROR, "Parsing WSDL: No name associated with <part> '%s'", SAFE_STR(message->name));
}
param->paramName = estrdup((char*)name->children->content);
@@ -739,9 +741,8 @@ static sdlPtr load_wsdl(zval *this_ptr, char *struri)
zend_hash_init(&ctx.portTypes, 0, NULL, NULL, 0);
zend_hash_init(&ctx.services, 0, NULL, NULL, 0);
load_wsdl_ex(this_ptr, struri, &ctx, 0);
zend_try {
load_wsdl_ex(this_ptr, struri, &ctx, 0);
schema_pass2(&ctx);
n = zend_hash_num_elements(&ctx.services);
@@ -768,7 +769,7 @@ static sdlPtr load_wsdl(zval *this_ptr, char *struri)
continue;
}
if (!node_is_equal(trav,"port")) {
soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", trav->name);
soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", SAFE_STR(trav->name));
}
port = trav;
@@ -807,7 +808,7 @@ static sdlPtr load_wsdl(zval *this_ptr, char *struri)
}
}
if (trav2 != address && is_wsdl_element(trav2) && !node_is_equal(trav2,"documentation")) {
soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", trav2->name);
soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", SAFE_STR(trav2->name));
}
trav2 = trav2->next;
}
@@ -909,7 +910,7 @@ static sdlPtr load_wsdl(zval *this_ptr, char *struri)
continue;
}
if (!node_is_equal(trav2,"operation")) {
soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", trav2->name);
soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", SAFE_STR(trav2->name));
}
operation = trav2;
@@ -928,7 +929,7 @@ static sdlPtr load_wsdl(zval *this_ptr, char *struri)
!node_is_equal(trav3,"output") &&
!node_is_equal(trav3,"fault") &&
!node_is_equal(trav3,"documentation")) {
soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", trav3->name);
soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", SAFE_STR(trav3->name));
}
trav3 = trav3->next;
}
@@ -1106,7 +1107,7 @@ static sdlPtr load_wsdl(zval *this_ptr, char *struri)
}
}
} else if (is_wsdl_element(trav) && !node_is_equal(trav,"documentation")) {
soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", trav->name);
soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", SAFE_STR(trav->name));
}
trav = trav->next;
}
+2 -2
View File
@@ -199,7 +199,7 @@ xmlNsPtr node_find_ns(xmlNodePtr node)
int attr_is_equal_ex(xmlAttrPtr node, char *name, char *ns)
{
if (name == NULL || strcmp((char*)node->name, name) == 0) {
if (name == NULL || ((node->name) && strcmp((char*)node->name, name) == 0)) {
if (ns) {
xmlNsPtr nsPtr = attr_find_ns(node);
if (nsPtr) {
@@ -215,7 +215,7 @@ int attr_is_equal_ex(xmlAttrPtr node, char *name, char *ns)
int node_is_equal_ex(xmlNodePtr node, char *name, char *ns)
{
if (name == NULL || strcmp((char*)node->name, name) == 0) {
if (name == NULL || ((node->name) && strcmp((char*)node->name, name) == 0)) {
if (ns) {
xmlNsPtr nsPtr = node_find_ns(node);
if (nsPtr) {
Loaded 100 of 152 files, more files were not shown because too many files have changed in this diff. Show more