Because the subpattern names are persistent, and the fact that the
symbol table destruction is skipped when using fast_shutdown,
this means the refcounts will not be updated for the destruction of
the arrays that hold the subpattern name keys.
To solve this, detect this situation and duplicate the strings.
Closes GH-17132.
libpcre2 can return the special value -1 for a non-match.
In this case we get pointer overflow, although it doesn't matter in
practice because the pointer will be in bounds and the copy length will
be 0. Still, we should fix the UBSAN warning.
Closes GH-16205.
There are two related issues, each tested.
First problem:
What happens is that on the CLI SAPI we have a per-request pcre cache,
and on there the request shutdown for the pcre module happens prior to
the remaining live object destruction. So when the SPL object wants to
clean up the regular expression object it gets a use-after-free.
Second problem:
Very similarly, the non-persistent resources are destroyed after request
shutdown, so on the CLI SAPI the pcre request cache is already gone, but
if a userspace stream references a regex in the pcre cache, this breaks.
Two things that come immediately to mind:
- We could fix it by no longer treating the CLI SAPI special and just use
the same lifecycle as the module. This simplifies the pcre module code
a bit too. I wonder why we even have the separation in the first place.
The downside here is that we're using more the system allocator
than Zend's allocator for cache entries.
- We could modify the shutdown code to not remove regular expressions
with a refcount>0 and modify php_pcre_pce_decref code such that it
becomes php_pcre_pce_decref's job to clean up when the refcount
becomes 0 during shutdown. However, this gets nasty quickly.
I chose the first solution here as it should be reliable and simple.
Closes GH-15064.
PCRE2_EXTRA_CASELESS_RESTRICT is only available as of pcre2 10.43.
Note: no check is necessary for pcre2_set_compile_extra_options because
it is available since pcre2 10.30, which is the minimum version PHP
requires.
Adds support for "Caseless restricted" matching added in PCRE2lib
10.43 with the "r" modifier.
This is `PCRE2_EXTRA_CASELESS_RESTRICT` in PCRE2. This is an "extra"
option, which means it is not possible to pass this option as
pcre2_compile() function parameter.
This option is passed in a pcre2_set_compile_extra_options() call.
Previously, these extra options are set at php_pcre_init_pcre2(),
but after this change, it is possible to customize the options
by adding bits to `eoptions` in pcre_get_compiled_regex_cache_ex().
The tests for this change are ported from upstream test suite[^1].
[^1]: c13d54f658 (diff-8c8312e4eb2d35bb16485404b7b5cc0eaef0bca1aa95ff5febf6a1890048305c)
The code in the attached test used to work correctly in PHP 8.0, but not
in 8.1+. This is because PHP 8.1+ uses a more modern version of pcre2
than PHP 8.0, and that pcre2 versions has a regression.
While upgrading pcre2lib seems to be only done for the master branch, it
is possible to backport upstream fixes to stable branches. This has been
already done in the past in for JIT regressions [1], so it is not
unprecedented.
We backport the upstream pcre2 fix [2].
[1] 788a701e22
[2] https://github.com/PCRE2Project/pcre2/pull/135
Closes GH-12108.
The ZVAL_ARR macro always set the zval type_info to IS_ARRAY_EX, even if the
hash table is immutable. Since in preg_replace_callback_array() we can return
the passed array directly, and that passed array can be immutable, we need to
reset the type_flags to keep the VM from performing ref-counting on the array.
Fixes GH-10968
Closes GH-10970
In 8b3c1a3, this was disallowed to fix#55856, which was a security
issue caused by the /e modifier. The fix that was made was the
"Easier fix" as described in the original report.
With this fix, pattern strings are no longer treated as null terminated,
so null characters can be placed inside and matched against with regex
patterns without security problems, so there is no longer a reason to
give the error. Allowing this is consistent with the behaviour of many
other languages, including JavaScript, and thanks to PCRE2[0], it does
not require manually escaping null characters. Now that we can avoid the
error here without the cost of escaping characters, there is really no
need anymore to stray here from the conventional behaviour.
Currently, null characters are still disallowed before the first
delimiter and in the options section at the end of a regex string, but
these error messages have been updated.
[0] Since PCRE2, pattern strings no longer have to be null terminated,
and raw null characters match as normal.
Closes GH-8114.
We backport the respective upstream fix[1] to our bundled pcre2lib plus
the follow-up fix[2] for a functional regression.
[1] <dc5f966635>
[2] <e7af7efaa1>
Closes GH-7573.
Trimming a potentially over-allocated string appears to be reasonable,
so we drop the condition altogether.
We also re-allocate twice the size needed in the first place, and not
roughly tripple the size.
Closes GH-7231.
The way to fix it is to disable certain match start optimizaions. The
observed performance impact appears negligible ATM, compared to the
functional regression revealed.
A possible side effect might occur if a pattern uses (*COMMIT) or
(*MARK), which is however not a very broadly used syntax in PHP. Still
this should be observed and handled by possibly adding a possibility to
reverse PCRE2_NO_START_OPTIMIZE on the user side.
One test shows a behavior change, where instead of int 0 the match
would produce an error and return false. Except strict comparison
is used, this should be acceptable.
Signed-off-by: Anatol Belski <ab@php.net>
(cherry picked from commit d188ca7688)
Signed-off-by: Anatol Belski <ab@php.net>
The way to fix it is to disable certain match start optimizaions. The
observed performance impact appears negligible ATM, compared to the
functional regression revealed.
A possible side effect might occur if a pattern uses (*COMMIT) or
(*MARK), which is however not a very broadly used syntax in PHP. Still
this should be observed and handled by possibly adding a possibility to
reverse PCRE2_NO_START_OPTIMIZE on the user side.
One test shows a behavior change, where instead of int 0 the match
would produce an error and return false. Except strict comparison
is used, this should be acceptable.
Signed-off-by: Anatol Belski <ab@php.net>
(cherry picked from commit d188ca7688)
Signed-off-by: Anatol Belski <ab@php.net>
The way to fix it is to disable certain match start optimizaions. The
observed performance impact appears negligible ATM, compared to the
functional regression revealed.
A possible side effect might occur if a pattern uses (*COMMIT) or
(*MARK), which is however not a very broadly used syntax in PHP. Still
this should be observed and handled by possibly adding a possibility to
reverse PCRE2_NO_START_OPTIMIZE on the user side.
One test shows a behavior change, where instead of int 0 the match
would produce an error and return false. Except strict comparison
is used, this should be acceptable.
Signed-off-by: Anatol Belski <ab@php.net>
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.