Commit graph

2468 commits

Author SHA1 Message Date
Alex Dowad
31d43164e8 Merge branch 'PHP-8.2' into PHP-8.3
* PHP-8.2:
  Return value of mb_get_info can be NULL
2023-11-27 21:13:21 +02:00
Alex Dowad
d8ef868b92 Return value of mb_get_info can be NULL
This has been the case at least since PHP 5.4. Thanks to Girgias for
pointing it out.

It appears that there are several global variables internal to mbstring
which can be queried via mb_get_info() and which could be NULL, but
at the very least, we know that "mbstring.http_input" is one of them.
2023-11-27 20:53:37 +02:00
Niels Dossche
6176538d99 Fix GH-11992: utf_encodings.phpt fails on Windows 32-bit
Similar bug as before in #10776, but now in other code.

Closes GH-12726.
2023-11-19 16:45:53 +01:00
Alex Dowad
81e236cde5 Fix infinite loop when mb_detect_encoding is used on UTF-8 BOM
This bug was introduced in cb840799b4.

Thanks to Ignace Nyamagana Butera for discovering this bug and
to Sebastian Bergmann for doing an initial investigation and opening
a bug ticket.
2023-10-28 18:51:06 +02:00
Alex Dowad
0c22276888
PHP_HAVE_BUILTIN_USUB_OVERFLOW macro is defined even if __builtin_usub_overflow not available
...So conditionally including code which uses __builtin_usub_overflow
(for performance) if the macro is defined is not correct. We also need
to check if the macro is defined as a non-zero value.

Apparently this broke the build for a user whose C compiler is GCC
4.9.4. Sorry, user! That was my fault!

Thanks to Jakub Zelenka for reporting the issue.
2023-10-23 14:05:48 +01:00
Levi Morrison
08c3b332a1
fix mbstring.c -Wsingle-bit-bitfield-constant-conversion (#12327)
These were both local variables, so there isn't much value in using
bitfields in the first place.
2023-10-02 22:07:39 -06:00
Ilija Tovilo
6b74f1f745
xfail mbstring test on Windows 32-bit 2023-09-03 14:22:40 +02:00
Alex Dowad
81faab9235 Improve mb_detect_encoding accuracy for text containing vowels with macrons
Among other world languages, the Māori language commonly uses vowels
with macrons.
2023-08-25 12:09:55 +02:00
Ilija Tovilo
7364b7bc0b
Fix uaf of MBSTRG(all_encodings_list)
We need to remove the value from the GC buffer before freeing it. Otherwise
shutdown will uaf when running the gc. Do that by switching from
zend_hash_destroy to zend_array_destroy, which should also be faster for freeing
members due to inlining of i_zval_ptr_dtor.

Closes GH-11822
2023-07-31 13:31:50 +02:00
George Peter Banyard
af3c220abb Deprecate passing a negative width to mb_strimwidth() 2023-07-17 05:01:13 +01:00
Niels Dossche
b2a54bc6af Merge branch 'PHP-8.2'
* PHP-8.2:
  Fix GH-11300: license issue: restricted unicode license headers
2023-07-01 22:03:08 +02:00
Niels Dossche
297fec099e Merge branch 'PHP-8.1' into PHP-8.2
* PHP-8.1:
  Fix GH-11300: license issue: restricted unicode license headers
2023-07-01 21:56:40 +02:00
Niels Dossche
ee42621ff6 Fix GH-11300: license issue: restricted unicode license headers
Closes GH-11572.
2023-07-01 21:55:21 +02:00
Niels Dossche
78d98e50c4 Fix GH-11567: mb_str_pad causes access violation
When not providing a pad string, *and* not having other defaulted
arguments, the function would crash on a NULL pad zend_string*.
Despite testing with an empty pad string, the issue wasn't found because
when using named arguments the pad string *is* filled in.
2023-06-30 16:40:43 +02:00
nielsdos
14a868b7a9 Fix GH-11514: PHP 8.3 build fails with --enable-mbstring enabled
I tweaked the #if check such that the workaround only applies on GCC
versions older than 8.0.
I tested this with GCC 7.5, 8.4, 9.4, GCC 13.1.1, and Clang 10.0.

Closes GH-11516.
2023-06-23 18:24:01 +02:00
Ilija Tovilo
6c015ae8fe
mbstring count_demerits in reverse order (#11493)
This way we can avoid moving candidates that would be eliminated after.
2023-06-21 11:20:43 +02:00
Niels Dossche
68591632b2
[RFC] Implement mb_str_pad() (#11284)
Closes GH-10203.
2023-06-20 21:22:04 +02:00
Alex Dowad
443927e3e8 Fix GH-11476: crash with count_demerits negative-size-param
Co-authored-by: Ilija Tovilo <ilija.tovilo@me.com>
Co-authored-by: Niels Dossche <7771979+nielsdos@users.noreply.github.com>
2023-06-19 22:05:15 +02:00
Alex Dowad
6930ef5837 Merge branch 'PHP-8.2'
* PHP-8.2:
  Fix mb_strlen is wrong length for CP932 when 0x80.
2023-05-30 14:02:16 -07:00
Alex Dowad
c33589ea11 Merge branch 'PHP-8.1' into PHP-8.2
* PHP-8.1:
  Fix mb_strlen is wrong length for CP932 when 0x80.
2023-05-30 13:45:36 -07:00
Yuya Hamada
c50172e812 Fix mb_strlen is wrong length for CP932 when 0x80. 2023-05-30 13:44:30 -07:00
Niels Dossche
03b163b2b3
Remove unused variable err in mb_send_mail() (#11285) 2023-05-21 11:27:32 +02:00
Alex Dowad
18ca489347 Convert mbfilter_conv{,_r}_map_tbl to return bool
Thanks to Girgias for pointing this out.
2023-05-20 21:27:48 -07:00
Alex Dowad
8e6be14372 Fix problem with CP949 conversion when 0xC9 precedes byte lower than 0xA1
This bug was introduced in e837a8800b. In that commit, I increased the
performance of CP949 text conversion, but accidentally broke the case
where 0xC9 (illegal byte to start a character) is followed by a valid
character with a first byte less than 0xA1. The 'broken' behavior is
that both the 0xC9 byte and the following valid character would be
converted to error markers.
2023-05-20 21:27:48 -07:00
Alex Dowad
f337c92050 Test mb_strlen for all text encodings supported by mbstring
When combining all the CJK encoding conversion code in a single file,
I combined some redundant mblen tables. This check will help to ensure
that all the mblen tables are correct.
2023-05-20 21:27:48 -07:00
Alex Dowad
245daedb41 Move kana translation tables to mbfilter_cjk.c
These (static) tables were defined in a header file, which was included
in two different .c files. That will result in two copies of the tables
being included in the PHP binary.

But the tables were only used in one of the two .c files. Move it where
it is used to avoid needlessly bloating the binary. (I checked in a
hex editor and confirmed that while the previous binary contained two
copies of these tables, it now only contains one.)
2023-05-20 21:27:48 -07:00
Alex Dowad
175154dbcc Optimize conversion of CP932 text to Unicode
Conversion of CP932 text to UTF-8 using `mb_convert_encoding` is
now about 20% faster than before.
2023-05-20 21:27:48 -07:00
Alex Dowad
73633bf1c3 Optimize conversion of SJIS-2004 text to Unicode
Conversion of SJIS-2004 text to UTF-8 using `mb_convert_encoding` is
now about 60% faster than before. (Many other mbstring functions will
also be faster now on SJIS-2004 text.)
2023-05-20 21:27:48 -07:00
Alex Dowad
c717c79a09 Combine CJK encoding conversion code in a single source file
This will make it easier to combine duplicated code between all the
CJK text encodings (a significant amount is already combined in this
commit, such as the repeated definitions of SJIS_DECODE and
SJIS_ENCODE), but I hope to remove even more redundancy in the future.

The table used to implement mb_strlen for CP932 has been changed to
the same table as "SJIS-win".
2023-05-20 21:27:48 -07:00
Alex Dowad
7914b8cefd Use pakutoma's encoding check functions for mb_detect_encoding even in non-strict mode
In 6fc8d014df, pakutoma added specialized validity checking functions
for some legacy text encodings like ISO-2022-JP and UTF-7. These
check functions perform a more strict validity check than the encoding
conversion functions for the same text encodings. For example, the
check function for ISO-2022-JP verifies that the string ends in the
correct state required by the specification for ISO-2022-JP.

These check functions are already being used to make detection of text
encoding more accurate when 'strict' detection mode is enabled.

However, since the default is 'non-strict' detection (a bad API design
but we're stuck with it now), most users will not benefit from
pakutoma's work. I was previously reluctant to enable this new logic
for non-strict detection mode. My intention was to reduce the scope of
behavior changes, since almost *any* behavior change may affect *some*
user in a way we don't expect.

However, we definitely have users whose (production) code was broken
by the changes I made in 28b346bc06, and enabling pakutoma's check
functions for non-strict detection mode would un-break it. (See
GH-10192 as an example.) The added checks do also make sense.

In non-strict detection mode, we will not immediately reject candidate
encodings whose validity check function returns false; but they will
be much less likely to be selected. However, failure of the validity
check function is weighted less heavily than an encoding error detected
by the encoding conversion function.
2023-05-16 07:01:07 -07:00
Alex Dowad
3ab10da758 Take order of candidate encodings into account when guessing text encoding
The documentation for mb_detect_encoding says that this function
"Detects the most likely character encoding for string `string` from an
ordered list of candidates".

Prior to 28b346bc06, mb_detect_encoding did not really attempt to
determine the "most likely" text encoding for the input string. It
would just return the first candidate encoding for which the string was
valid. In 28b346bc06, I amended this function so that it uses heuristics
to try to guess which candidate encoding is "most likely".

However, the caller did not have any way to indicate which candidate
text encoding(s) they consider to be more likely, in case the
heuristics applied are inconclusive. In the language of Bayesian
probability, there was no way for the caller to indicate their 'prior'
assignment of probabilities.

Further, the documentation for mb_detect_encoding also says that the
second parameter `encodings` is "a list of character encodings to try,
in order". The documentation clearly implies that the order of
the `encodings` argument should be significant.

Therefore, amend mb_detect_encoding so that while it still uses
heuristics to guess the most likely text encoding for the input string,
it favors those which are earlier in the list of candidate encodings.

One complication is that many callers of mb_detect_encoding use it
in this way:

    mb_detect_encoding($string, mb_list_encodings());

In a majority of cases, this is bad code; mb_detect_encoding will both
be much slower and the results will be less reliable than if a smaller
list of candidates is used. However, since such code already exists and
people are using it in production, we should not unnecessarily break it.
The order of candidate encodings obviously does not express any prior
belief of which candidates are more likely in this case, and treating
it as if it did will degrade the accuracy of the result.

Since mb_list_encodings now returns a single, immutable array on each
call, we can avoid that problem by turning off the new behavior when
we receive the array of encodings returned by mb_list_encodings.
This implementation means that if the user does this:

    $a = mb_list_encodings();
    mb_detect_encoding($string, $a);

...then the order of candidate encodings will not be considered.
However, if the user explicitly initializes their own array of all
supported legacy text encodings, then the order *will* be considered.

The other functions which also follow this new behavior are:

• mb_convert_variables
• mb_convert_encoding (when multiple candidate input encodings are
  listed)

Other places where "detection" (or really "guessing") of text encoding
may be performed include:

• mb_send_mail
• Zend engine, when determining the encoding of a PHP script
• mbstring processing of HTTP request contents, when http_input INI
  parameter is set to a list

In these cases, the new logic based on order of candidate encodings
is *not* enabled. It *might* be logical to consider the order of
candidate encodings in some or all of these cases, but I'm not sure if
that is true, so it seems wiser to avoid more behavior changes than is
necessary. Further, ever since the new encoding detection heuristics
were implemented in 28b346bc06, we have not received any complaints of
user code being broken in these areas. So I am reluctant to "fix what
isn't broken".

Well, some might say that applying the new detection heuristics
to mb_send_mail, etc. in 28b346bc06 was "fixing what wasn't broken",
but (cough cough) I don't have any comment on that...
2023-05-16 07:01:07 -07:00
Alex Dowad
97e29bed9e Use shared, immutable array for return value of mb_list_encodings
This will allow us to easily check in other mbstring functions if the
list of all supported encodings, returned by mb_list_encodings, is
passed in as input to another function.

Co-authored-by: Ilija Tovilo <ilija.tovilo@me.com>
2023-05-16 07:01:07 -07:00
Ilija Tovilo
6408fb21f6
Merge branch 'PHP-8.2'
* PHP-8.2:
  Added negative offset test for mb_strrpos
  Fix segfault in mb_strrpos/mb_strripos with ASCII encoding and negative offset
2023-05-15 10:41:22 +02:00
Randy Geraads
c5a623ba5e
Added negative offset test for mb_strrpos
Should expose https://github.com/php/php-src/issues/11217
2023-05-15 10:36:37 +02:00
Ilija Tovilo
aa553af911
Fix segfault in mb_strrpos/mb_strripos with ASCII encoding and negative offset
We're setting the encoding from PHP_FUNCTION(mb_strpos), but mbfl_strpos would
discard it, setting it to mbfl_encoding_pass, making zend_memnrstr fail due to a
null-pointer exception.

Fixes GH-11217
Closes GH-11220
2023-05-15 10:36:37 +02:00
Niels Dossche
b915a1d8d7 Fix uninitialised variable warning in mbfilter_sjis.c
Compiling in release mode with UBSAN gives me the following compiler warning:
```
In function ‘mb_wchar_to_sjismac’:
mbfilter_sjis.c:1419:89: warning: ‘i’ may be used uninitialized [-Wmaybe-uninitialized]
 1419 | buf->state = (i << 24) | (index << 16) | (w & 0xFFFF);
      |                 ^~
mbfilter_sjis.c:1398:42: note: ‘i’ was declared here
 1398 | for (int i = 0; i < code_tbl_m_len; i++) {
      |          ^
```

Since the if condition will always be taken after the goto, we can get
rid of the warning by moving the label inside the if.

Signed-off-by: Alex Dowad <alexinbeijing@gmail.com>
2023-04-30 13:51:52 +02:00
Javier Eguiluz
732d92c0e5
[skip ci] Fix various typos and grammar issues (#11143) 2023-04-28 11:05:32 +02:00
Alex Dowad
6df7557e43 mb_parse_str, mb_http_input, and mb_convert_variables use fast text conversion code for automatic encoding detection
For mb_parse_str, when mbstring.http_input (INI parameter) is a list of
multiple possible text encodings (which is not the case by default),
this new implementation is about 25% faster.

When mbstring.http_input is a single value, then nothing is changed.
(No automatic encoding detection is done in that case.)
2023-04-12 19:57:52 +02:00
Alex Dowad
c211e67b4e Remove XFAIL from test cases for mb_strcut when used with JIS or ISO-2022-JP encoding
The documentation for mb_strcut states:

    mb_strcut(
        string $string,
        int $start,
        ?int $length = null,
        ?string $encoding = null
    ): string

    mb_strcut() extracts a substring from a string similarly to mb_substr(),
    but operates on bytes instead of characters. If the cut position happens
    to be between two bytes of a multi-byte character, the cut is performed
    starting from the first byte of that character.

My understanding of the $length parameter for mb_strcut is that it
specified the range of bytes to extract from $string, and that all
characters encoded by those bytes should be included in the returned
string, even if that means the returned string would be longer than
$length bytes. This can happen either if 1) there is more than one way
to encode the same character in $encoding, and one way requires more
bytes than the other, or 2) $encoding uses escape sequences.

However, discussion with users of mb_strcut indicates that many of them
interpret $length as the maximum length of the *returned* string.
This is also the historical behavior of the function.

Hence, there is no need to modify the behavior of mb_strcut and then
remove XFAIL from these test cases afterwards. We can keep the current
behavior.
2023-04-02 13:52:14 +02:00
Alex Dowad
c4fb049bf6 For UTF-7, emit error marker if Base64 section ends abruptly after first half of surrogate pair
This (rare) situation was already handled correctly for the 1st and 2nd
of every 3 codepoints in a Base64-encoded section of a UTF-7 string.
However, it was not handled correctly if it happened on the 3rd,
6th, 9th, etc. codepoint of such a Base64-encoded section.
2023-03-27 11:34:11 +02:00
pakutoma
b721d0f71e Fix phpGH-10648: add check function pointer into mbfl_encoding
Previously, mbstring used the same logic for encoding validation as for
encoding conversion.

However, there are cases where we want to use different logic for validation
and conversion. For example, if a string ends up with missing input
required by the encoding, or if a character is input that is invalid
as an encoding but can be converted, the conversion should succeed and
the validation should fail.

To achieve this, a function pointer mb_check_fn has been added to
struct mbfl_encoding to implement the logic used for validation.
Also, added implementation of validation logic for UTF-7, UTF7-IMAP,
ISO-2022-JP and JIS.

(The same change has already been made to PHP 8.2 and 8.3; see
6fc8d014df. This commit is backporting the change to PHP 8.1.)
2023-03-25 09:52:10 +02:00
Alex Dowad
57e194e02d Fix compile error in Windows CI job caused by 0779950768
In 6fc8d014df, pakutoma added some additional validation logic to
mb_detect_encoding. Since the implementation of mb_detect_encoding
has changed significantly between PHP 8.2 and 8.3, when merging this
change down from PHP-8.2 into master, I had to port his code over to
the new implementation in master.

However, I did this in a wrong way. In merge commit 0779950768,
the ported code modifies a function argument (to mb_guess_encoding)
which is marked 'const'. In the Windows CI job, MS VC++ rightly
flags this as a compile error.

Adjust the code to accomplish the same thing, but without destructively
modifying 'const' arguments.
2023-03-25 06:02:01 +02:00
Alex Dowad
345abce590 Fix compile errors caused by missing initializers in 0779950768
When I built and tested 0779950768 locally, the build was successful
and all tests passed. However, in CI, some CI jobs are failing due to
compile errors. Fix those.
2023-03-24 22:18:18 +02:00
Alex Dowad
0779950768 Merge branch 'PHP-8.2'
* PHP-8.2:
  Fix phpGH-10648: add check function pointer into mbfl_encoding
2023-03-24 21:15:32 +02:00
pakutoma
6fc8d014df Fix phpGH-10648: add check function pointer into mbfl_encoding
Previously, mbstring used the same logic for encoding validation as for
encoding conversion.

However, there are cases where we want to use different logic for validation
and conversion. For example, if a string ends up with missing input
required by the encoding, or if a character is input that is invalid
as an encoding but can be converted, the conversion should succeed and
the validation should fail.

To achieve this, a function pointer mb_check_fn has been added to
struct mbfl_encoding to implement the logic used for validation.
Also, added implementation of validation logic for UTF-7, UTF7-IMAP,
ISO-2022-JP and JIS.
2023-03-24 20:34:22 +02:00
Ilija Tovilo
9d5f2f1343
Use new ZSTR_INIT_LITERAL macro (#10879) 2023-03-20 16:19:05 +01:00
Alex Dowad
0ce755be26 Implement mb_encode_mimeheader using fast text conversion filters
The behavior of the new mb_encode_mimeheader implementation closely
follows the old implementation, except for three points:

• The old implementation was missing a call to the mbfl_convert_filter
  flush function. So it would sometimes truncate the input string just
  before its end.

• The old implementation would drop zero bytes when QPrint-encoding.
  So for example, if you tried to QPrint-encode the UTF-32BE string
  "\x00\x00\x12\x34", its QPrint-encoding would be "=12=34", which
  does not decode to a valid UTF-32BE string. This is now fixed.

• In some rare corner cases, the new implementation will choose to
  Base64-encode or QPrint-encode the input string, where the old
  implementation would have just added newlines to it. Specifically,
  this can happen when there is a non-space ASCII character, followed
  by a large number of ASCII spaces, followed by a non-ASCII character.

The new implementation is around 2.5-8x faster than the old one,
depending on the text encoding and transfer encoding used. Performance
gains are greater with Base64 transfer encoding than with QPrint
transfer encoding; this is not because QPrint-encoding bytes is slow,
but because QPrint-encoded output is much bigger than Base64-encoded
output and takes more lines, so we have to go through the process of
finding the right place to break a line many more times.
2023-03-15 15:53:08 +02:00
Ilija Tovilo
805dafddbb
Merge branch 'PHP-8.1' into PHP-8.2
* PHP-8.1:
  Enable GitHub actions cancel-in-progress for PRs
  mb_encode_mimeheader does not crash if provided encoding has no MIME name set
2023-03-07 11:02:00 +01:00
Alex Dowad
17f72502d9 Merge branch 'PHP-8.2'
* PHP-8.2:
  mb_encode_mimeheader does not crash if provided encoding has no MIME name set
2023-03-07 11:32:44 +02:00
Alex Dowad
d60833b079 Merge branch 'PHP-8.1' into PHP-8.2
* PHP-8.1:
  mb_encode_mimeheader does not crash if provided encoding has no MIME name set
2023-03-07 11:31:07 +02:00