Commit graph

897 commits

Author SHA1 Message Date
Alex Dowad
67051eb8ed Fix segfault caused by use of 'pass' encoding when mbstring converts multipart form POST data
When mbstring.encoding_translation=1, and PHP receives an (RFC1867)
form-based file upload, and the Content-Disposition HTTP header contains
a filename for the uploaded file, PHP will internally invoke mbstring
code to 1) try to auto-detect the text encoding of the filename, and if
that succeeds, 2) convert the filename to internal text encoding.

In such cases, the candidate text encodings which are considered during
"auto-detection" are those listed in the INI parameter
mbstring.http_input. Further, mbstring.http_input is one of the few
contexts where mbstring allows the magic string "pass" to appear in
place of an actual text encoding name.

Before mbstring's encoding auto-detection function was reimplemented,
the old implementation would never return "pass", even if "pass" was the
only candidate it was given to choose from. It is not clear if this was
intended by the original developers or not. This behavior was the result
of some rather subtle details of the implementation.

After mbstring's auto-detection function was reimplemented, if the new
implementation was given only one candidate to choose, and it was not
running in 'strict' mode, it would always return that candidate, even
if the candidate was the non-encoding "pass".

The upshot of all of this: Previously, if
mbstring.encoding_translation=1 and mbstring.http_input=pass, encoding
conversion of RFC1867 filenames would never be attempted. But after
the reimplementation, encoding 'conversion' would occur (uselessly).

Further, in December 2022, I reimplemented the relevant bit of
encoding conversion code. When doing this, I never bothered to
implement encoding/decoding routines for the non-encoding "pass",
because I thought that they would never be used. Well, in the one case
described above, those routines *would* have been used, had they
actually existed. Because they didn't exist, we get a nice NULL pointer
dereference and ensuing segfault instead.

Instead of 'fixing' this by adding encoding/decoding routines for the
non-encoding "pass", I have modified the function which the RFC1867
form-handling code invokes to auto-detect input encoding. This function
will never return "pass" now, just like the previous implementation.

Thanks to the GitHub user 'tstangner' for reporting this bug.
2024-01-24 17:15:27 +02:00
Alex Dowad
1e92d47f41 Do not allow zend.script_encoding to be set to 'pass'
When investigating another bug reported by GitHub user 'tstangner',
I discovered that PHP segfaults when the INI parameter
zend.script_encoding is set to "pass". This bug dates back to
December 2022 (caused by yours truly in 953864661a).

If any PHP users in the wild were actually setting zend.script_encoding
to "pass" (which would be an utterly useless thing to do), I expect that
someone would have filed a bug report by now. The absence of such bug
reports is evidence that nobody is doing this.

Hence, it seems that the best fix is simply to disallow "pass" as a
choice for zend.script_encoding. The internal function
'php_mb_zend_encoding_list_parser' which I am modifying to accomplish
this has no other in-tree callers, aside from the 'exif' extension.
Further, exif only calls the function with a few hard-coded values, and
none of them are the string "pass", so this change will not have any
impact on exif.
2024-01-21 14:51:54 +02:00
Alex Dowad
e814197371 Fix bug in mb_get_substr_slow (sometimes outputs wrong number of characters)
Thanks to Maurício Fauth for finding and reporting this bug.

The bug was introduced in October 2022. It originally only affected
text encodings which do not have a fixed byte width per characters
and for which mbstring does not have an mblen_table. However, I recently
made another change to mbstring, such that mb_substr no longer relies
on the mblen_table even if one is available. Because of this change,
the bug earlier introduced in October 2022 now affected a greater
number of text encodings, including UTF-8.
2023-12-20 14:32:53 +02:00
Alex Dowad
ec348a12d1 Character indices used by mb_strpos and mb_substr have same meaning, even on invalid strings
Starting many years ago, libmbfl included a 'mblen_table' for selected
text encodings. This table allows looking up the byte length of a
(possibly multi-byte) character from the value of the first byte.
libmbfl uses these tables to optimize certain operations; if a
text-processing operation can be performed using an mblen_table,
it may not be necessary to decode the text to codepoints. Since
libmbfl's decoding filters are generally slow, this improves
performance.

Since mbstring is (or was) based on libmbfl, it has always used
these mblen_tables to implement some functions. This design has a
significant downside. Let me explain:

While some mbstring functions are implemented by converting input text
to codepoints and operating on the codepoints, others operate directly
on the original input bytes (using an mblen_table to identify character
boundaries). Both of these implementation styles, if correctly coded,
yield equivalent results on valid strings. However, on strings which
contain encoding errors, the results are often different.

When decoding byte strings to codepoints using some text encoding,
mbstring uses the non-existent codepoint 0xFFFFFFFF to represent a
byte sequence which cannot be decoded. Then, when mbstring indexes into
the resulting sequence of codepoints, the index of any particular
character depends on the number of such 'error markers' which were
produced during the decoding process. In contrast, when an mblen_table
is used to split a byte sequence into characters, there is no question
of counting encoding errors; rather, table lookups into the mblen_table
are used to repeatedly 'bite off' some number of bytes (which are
treated as one 'character'). In the presence of encoding errors, these
two methods of mapping between byte indices and character indices are
inherently different and will rarely agree.

(For completeness, it must be said that some internal mbstring code
which operates only on UTF-8 text uses a third method for mapping
between byte indices and character indices, that is: counting
non-continuation UTF-8 bytes, which are all bytes whose binary
representation is NOT like 0b10xxxxxx. This method happens to agree with
the method which involves decoding the input text to codepoints and then
counting the codepoints.)

I have been aware of this issue for years, but only recently became
aware that in the case of mb_strstr, mb_strpos, and mb_substr,
this issue can cause seriously unintuitive behavior (and even security
vulnerabilities). This was reported by Stefan Schiller.

Stefan Schiller shared the following example for mb_strstr:

    var_dump(mb_strstr("\xf0start", "start", false, "UTF-8"));
    // string(2) "rt"

Similarly, when mb_strpos and mb_substr are used to identify and
extract a substring from a string with encoding errors, Stefan Schiller
pointed out that the extracted portion may be completely different than
desired. This is because (for UTF-8 strings) mb_strpos works by counting
non-continuation bytes, but mb_substr uses an mblen_table.

Since some mbstring functions *cannot* be implemented using an
mblen_table, as long as mblen_tables are used, similar inconsistencies
cannot be totally avoided. But the mblen_tables are critical to
mbstring's performance. Or are they? Benchmarking mb_substr on various
UTF-8, SJIS, and EUC-JP strings revealed something interesting.
On all SJIS and EUC-JP test cases, mb_substr was slightly faster when
the mblen_table based code was deleted. For some UTF-8 test cases, the
mblen_table-based code was a tiny bit faster, while for others the
fallback code was a touch faster; in no case was the difference
significant.

Therefore, the simple fix is to delete the mblen_table-based
implementation of mb_substr.

Aside from making the function behave consistently with other mbstring
functions on invalid strings, there is ONE case where behavior is now
different on valid strings: that is, on SJIS-Mac (MacJapanese) strings
which contain any of the following code units:

0x85AB-0x85AD, 0x85BF, 0x85C0, 0x85C1, 0x8645, 0x864B, 0x865D, 0x869E,
0x86CE, 0x86D3-0x86D5, 0x86D6, 0x8971, 0x8792, 0x879D, 0x87FB, 0x87FC,
0xEB41, 0xEB42, 0xEB50, 0xEB5B, 0xEB5D, 0xEB60-0xEB6E, and all from
0xEB81 and above.

All of these SJIS-Mac code units share the (very unusual) property that
they do not correspond to any one Unicode codepoint. When converting
from SJIS-Mac to Unicode, these must be converted to 2, 3, 4, or 5
codepoints each.

The previous, mblen_table-based implementation of mb_substr would treat
all of these SJIS-Mac byte sequences as 'one character'. Now, they are
treated as multiple characters (one for each of the Unicode codepoints
which they decode to). The new behavior is more consistent with other
mbstring functions.

I don't know if SJIS-Mac users will like this change or not (probably
most will never notice), but the BC break is justified by the very
real security impact of the previous, inconsistent behavior.

Finally, I should comment on whether similar changes are needed
elsewhere. The remaining functions which use an mblen_table are:
mb_str_split, mb_strcut, and various search functions (such as
mb_strpos). The search functions are only affected now when they
receive a positive 'offset' parameter specifying where to start
searching from.

The search functions should definitely be fixed so they do not use
an mblen_table to implement the 'offset' parameter. I am not convinced
that there is any good reason to change mb_str_split and mb_strcut.
2023-12-10 14:40:30 +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
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
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
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
Niels Dossche
03b163b2b3
Remove unused variable err in mb_send_mail() (#11285) 2023-05-21 11:27:32 +02: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
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
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
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
Alex Dowad
7c1ee5a02a mb_encode_mimeheader does not crash if provided encoding has no MIME name set 2023-03-07 11:30:21 +02:00
Alex Dowad
86ec0bc55c Fix failure of AVX2-accelerated mb_check_encoding on 32-bit MS Windows
Thanks to Ilija Tovilo for noticing and reporting this problem. Thanks
also to Michael Voříšek for finding the StackOverflow post which
explained the reason for the failure.
2023-03-04 20:42:41 +02:00
Alex Dowad
8995f60258 mb_decode_mimeheader obeys RFC 2047 regarding underscores and QPrint encoding 2023-02-22 23:19:57 +02:00
Alex Dowad
157ca654f2 Implement mb_decode_mimeheader using fast text conversion filters
The new implementation is 2.5x-3x faster.

If an invalid charset name was used, the old implementation would get
'stuck' trying to parse the charset name and would not interpret any
other MIME encoded words up to the end of the input string. The new
implementation fixes this bug.

If an (invalid) encoded word ends abruptly and a new (valid) encoded
word starts, the old implementation would not decode the valid encoded
word. The new implementation also fixes this.

Otherwise, the behavior of the new implementation has been designed to
closely match that of the old implementation.
2023-02-22 23:08:03 +02:00
Alex Dowad
a85adb170c Remove unneeded function mbfl_name2no_encoding 2023-02-22 23:08:03 +02:00
George Peter Banyard
0685f30a5c
Merge branch 'PHP-8.2'
* PHP-8.2:
  Fix GH-10627: mb_convert_encoding crashes PHP on Windows
  ext/mbstring: fix new_value length check
2023-02-20 13:47:58 +00:00
George Peter Banyard
73f9ffc5cd
Merge branch 'PHP-8.1' into PHP-8.2
* PHP-8.1:
  Fix GH-10627: mb_convert_encoding crashes PHP on Windows
  ext/mbstring: fix new_value length check
2023-02-20 13:41:11 +00:00
Niels Dossche
ed0c0df351
Fix GH-10627: mb_convert_encoding crashes PHP on Windows
Fixes GH-10627

The php_mb_convert_encoding() function can return NULL on error, but
this case was not handled, which led to a NULL pointer dereference and
hence a crash.

Closes GH-10628

Signed-off-by: George Peter Banyard <girgias@php.net>
2023-02-20 13:33:11 +00:00
Max Kellermann
243865ae57
ext/mbstring: fix new_value length check
Commit 8bbd0952e5 added a check rejecting empty strings; in the
merge commiot 379d9a1cfc however it was changed to a NULL check,
one that did not make sense because ZSTR_VAL() is guaranteed to never
be NULL; the length check was accidently removed by that merge commit.

This bug was found by GCC's -Waddress warning:

 ext/mbstring/mbstring.c:748:27: warning: the comparison will always evaluate as ‘true’ for the address of ‘val’ will never be NULL [-Waddress]
   748 |         if (!new_value || !ZSTR_VAL(new_value)) {
       |                           ^

Closes GH-10532

Signed-off-by: George Peter Banyard <girgias@php.net>
2023-02-20 13:32:56 +00:00
Alex Dowad
c8ec2ed730 Add AVX2-accelerated UTF-16 decoding/encoding routines
As with other SIMD-accelerated functions in php-src, the new UTF-16
encoding and decoding routines can be compiled either with AVX2
acceleration "always on", "always off", or else with runtime detection
of AVX2 support.

With the new UTF-16 decoder/encoder, conversion of extremely short
strings (as in several bytes) has the same performance as before,
and conversion of medium-length (~100 character) strings is about 65%
faster, but conversion of long (~10,000 character) strings is around
6 times faster.

Many other mbstring functions will also be faster now when handling
UTF-16; for example, mb_strlen is almost 3 times faster on medium
strings, and almost 9 times faster on long strings. (Why does mb_strlen
benefit more from AVX2 acceleration than mb_convert_encoding? It's
because mb_strlen only needs to decode, but not re-encode, the input
string, and the UTF-16 decoder benefits much more from SIMD
acceleration than the UTF-16 encoder.)
2023-02-05 20:06:42 +02:00
Alex Dowad
8f318c383d Add specialized UTF-8 validation function for hosts with no SSE2/AVX2 support
In a GitHub thread, Michael Voříšek and Kamil Tekiela mentioned that
the PCRE2 function `pcre_match` can be used to validate UTF-8, and that
historically it was more efficient than mbstring's `mb_check_encoding`.

`mb_check_encoding` is now much faster on hosts with SSE2, and much
faster again on hosts with AVX2. However, while all x86-64 CPUs support
at least SSE2, not all PHP users run their code on x86-64 hardware.
For example, some use recent Macs with ARM CPUs.

Therefore, borrow PCRE2's UTF-8 validation function as a fallback for
hosts with no SSE2/AVX2 support. On long UTF-8 strings, this code is
50% faster than mbstring's existing fallback code.
2023-01-26 20:58:24 +02:00
Alex Dowad
63c50cc87e Add AVX2-accelerated version of mb_check_encoding for UTF-8 only
From some local benchmarks which I ran, the AVX2-based version is about
2.8x faster than the SSE2-based version on long (~10,000 byte) strings,
1.6x faster on medium (~100 byte) strings, and just about the same
on very short strings.

I followed the example of the code in the 'standard' module, using
preprocessor directives so that the code can be compiled in any of
4 ways:

1) With no AVX2 support at all (for example, when PHP is compiled for
   CPU architectures other than AMD64)
2) For CPUs with AVX2 only (for example, when PHP is built with
   CCFLAGS='-march=native' on a host which implements AVX2)
3) With runtime detection of AVX2 performed by the dynamic linker;
   this requires a dynamic linker which supports the STT_GNU_IFUNC
   symbol type extension to the ELF binary standard. This is true of
   glibc's dynamic linker, as of late 2009.
4) With runtime detection of AVX2 performed by the module init function.
   The detection is done by checking the output of CPUID and then a
   function pointer is set accordingly. In this case, all calls to the
   UTF-8 validation routine are indirect calls through that
   function pointer.
2023-01-26 09:49:58 +02:00
Alex Dowad
d14ed12783 Adjust code to finish validating remaining 0-8 bytes at end of UTF-8 string
This code is a few percent faster for short UTF-8 strings. For long
(~10,000 byte) strings, it is also consistently faster on my local
microbenchmarks, but by less than 1%.
2023-01-26 09:49:58 +02:00
Alex Dowad
4f36623c1e Use RETURN_STR_COPY in mb_output_handler
This means the same thing and makes the code read a tiny bit better.

Thanks to Nikita Popov for the tip.
2023-01-22 13:53:04 +02:00
Alex Dowad
6f53dbb83e mb_scrub does not attempt to scrub known-valid UTF-8 strings 2023-01-22 13:53:04 +02:00
Alex Dowad
23dab38fe9 Use smart_str as dynamic buffer for extra headers in mb_send_mail 2023-01-21 23:12:58 +02:00
Alex Dowad
8a73a68190 Use fast encoding conversion filters in mb_send_mail 2023-01-21 23:12:58 +02:00
Jakub Zelenka
443eb50a4c
Merge branch 'PHP-8.2' 2023-01-19 19:06:38 +00:00
Jakub Zelenka
cc931af35d
Fix GH-8086: Introduce mail.mixed_lf_and_crlf INI
When this INI option is enabled, it reverts the line separator for
headers and message to LF which was a non conformant behavior in PHP 7.
It is done because some non conformant MTAs fail to parse CRLF line
separator for headers and body.

This is used for mail and mb_send_mail functions.
2023-01-19 19:05:39 +00:00
Alex Dowad
cb840799b4 mb_detect_encoding is more accurate on strings with UTF-8/16 BOM
Thanks to the GitHub user 'titanz35' for pointing out that the new
implementation of mb_detect_encoding had poor detection accuracy on
UTF-8 and UTF-16 strings with a byte-order mark.
2023-01-19 08:40:39 +02:00
Alex Dowad
8902e47f3d Simplify checks (in mb_fast_check_utf8) for overlong code units and invalid codepoint values 2023-01-18 17:14:53 +02:00
Alex Dowad
d58f70455b Simplify check (in mb_fast_check_utf8) for seeing if 16 bytes are all ASCII characters 2023-01-18 17:14:53 +02:00