Skip to content

Commit b7e8b48

Browse files
committed
Allow enabling/disabling PCRE JIT after regex was compiled
Previously, when the regex was first encountered it would be compiled with or without JIT and be executed accordingly. With this PR, a regex will be executed with or without JIT depending on the current state of PCRE_G(jit). Moreover, if the regex was previously compiled with JIT disabled, JIT compilation will be done when executing the regex for the first time after enabling the JIT.
1 parent 3b0e619 commit b7e8b48

File tree

1 file changed

+42
-28
lines changed

1 file changed

+42
-28
lines changed

ext/pcre/php_pcre.c

Lines changed: 42 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@
3939
#define PREG_GREP_INVERT (1<<0)
4040

4141
#define PREG_JIT (1<<3)
42+
/* Whether JIT compiling has been attempted. This is necessary to avoid retrying JIT compilation
43+
* repeatedly when compilation fails. */
44+
#define PREG_JIT_ATTEMPTED (1<<4)
4245

4346
#define PCRE_CACHE_SIZE 4096
4447

@@ -585,6 +588,28 @@ static zend_always_inline size_t calculate_unit_length(pcre_cache_entry *pce, co
585588
}
586589
/* }}} */
587590

591+
static uint32_t pcre_jit_compile_regex(pcre2_code *re) {
592+
int rc = pcre2_jit_compile(re, PCRE2_JIT_COMPLETE);
593+
if (EXPECTED(rc >= 0)) {
594+
size_t jit_size = 0;
595+
if (!pcre2_pattern_info(re, PCRE2_INFO_JITSIZE, &jit_size) && jit_size > 0) {
596+
return (PREG_JIT|PREG_JIT_ATTEMPTED);
597+
}
598+
} else if (rc == PCRE2_ERROR_NOMEMORY) {
599+
php_error_docref(NULL, E_WARNING,
600+
"Allocation of JIT memory failed, PCRE JIT will be disabled. "
601+
"This is likely caused by security restrictions. "
602+
"Either grant PHP permission to allocate executable memory, or set pcre.jit=0");
603+
PCRE_G(jit) = 0;
604+
} else {
605+
PCRE2_UCHAR error[128];
606+
pcre2_get_error_message(rc, error, sizeof(error));
607+
php_error_docref(NULL, E_WARNING, "JIT compilation failed: %s", error);
608+
pcre_handle_exec_error(PCRE2_ERROR_INTERNAL);
609+
}
610+
return PREG_JIT_ATTEMPTED;
611+
}
612+
588613
/* {{{ pcre_get_compiled_regex_cache */
589614
PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache_ex(zend_string *regex, int locale_aware)
590615
{
@@ -626,7 +651,13 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache_ex(zend_string *regex, in
626651
if (key != regex) {
627652
zend_string_release_ex(key, 0);
628653
}
629-
return (pcre_cache_entry*)Z_PTR_P(zv);
654+
pcre_cache_entry *pce = (pcre_cache_entry*)Z_PTR_P(zv);
655+
#ifdef HAVE_PCRE_JIT_SUPPORT
656+
if (!(pce->preg_options & PREG_JIT_ATTEMPTED) && PCRE_G(jit)) {
657+
pce->preg_options |= pcre_jit_compile_regex(re);
658+
}
659+
#endif
660+
return pce;
630661
}
631662

632663
p = ZSTR_VAL(regex);
@@ -806,24 +837,7 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache_ex(zend_string *regex, in
806837

807838
#ifdef HAVE_PCRE_JIT_SUPPORT
808839
if (PCRE_G(jit)) {
809-
/* Enable PCRE JIT compiler */
810-
rc = pcre2_jit_compile(re, PCRE2_JIT_COMPLETE);
811-
if (EXPECTED(rc >= 0)) {
812-
size_t jit_size = 0;
813-
if (!pcre2_pattern_info(re, PCRE2_INFO_JITSIZE, &jit_size) && jit_size > 0) {
814-
poptions |= PREG_JIT;
815-
}
816-
} else if (rc == PCRE2_ERROR_NOMEMORY) {
817-
php_error_docref(NULL, E_WARNING,
818-
"Allocation of JIT memory failed, PCRE JIT will be disabled. "
819-
"This is likely caused by security restrictions. "
820-
"Either grant PHP permission to allocate executable memory, or set pcre.jit=0");
821-
PCRE_G(jit) = 0;
822-
} else {
823-
pcre2_get_error_message(rc, error, sizeof(error));
824-
php_error_docref(NULL, E_WARNING, "JIT compilation failed: %s", error);
825-
pcre_handle_exec_error(PCRE2_ERROR_INTERNAL);
826-
}
840+
poptions |= pcre_jit_compile_regex(re);
827841
}
828842
#endif
829843
efree(pattern);
@@ -1263,7 +1277,7 @@ PHPAPI void php_pcre_match_impl(pcre_cache_entry *pce, zend_string *subject_str,
12631277

12641278
/* Execute the regular expression. */
12651279
#ifdef HAVE_PCRE_JIT_SUPPORT
1266-
if ((pce->preg_options & PREG_JIT) && options) {
1280+
if ((pce->preg_options & PREG_JIT) && options && PCRE_G(jit)) {
12671281
count = pcre2_jit_match(pce->re, (PCRE2_SPTR)subject, subject_len, start_offset2,
12681282
PCRE2_NO_UTF_CHECK, match_data, mctx);
12691283
} else
@@ -1405,7 +1419,7 @@ PHPAPI void php_pcre_match_impl(pcre_cache_entry *pce, zend_string *subject_str,
14051419

14061420
/* Execute the regular expression. */
14071421
#ifdef HAVE_PCRE_JIT_SUPPORT
1408-
if ((pce->preg_options & PREG_JIT)) {
1422+
if ((pce->preg_options & PREG_JIT) && PCRE_G(jit)) {
14091423
if (PCRE2_UNSET == start_offset2 || start_offset2 > subject_len) {
14101424
pcre_handle_exec_error(PCRE2_ERROR_BADOFFSET);
14111425
break;
@@ -1625,7 +1639,7 @@ PHPAPI zend_string *php_pcre_replace_impl(pcre_cache_entry *pce, zend_string *su
16251639

16261640
/* Execute the regular expression. */
16271641
#ifdef HAVE_PCRE_JIT_SUPPORT
1628-
if ((pce->preg_options & PREG_JIT) && options) {
1642+
if ((pce->preg_options & PREG_JIT) && options && PCRE_G(jit)) {
16291643
count = pcre2_jit_match(pce->re, (PCRE2_SPTR)subject, subject_len, start_offset,
16301644
PCRE2_NO_UTF_CHECK, match_data, mctx);
16311645
} else
@@ -1800,7 +1814,7 @@ PHPAPI zend_string *php_pcre_replace_impl(pcre_cache_entry *pce, zend_string *su
18001814
}
18011815

18021816
#ifdef HAVE_PCRE_JIT_SUPPORT
1803-
if (pce->preg_options & PREG_JIT) {
1817+
if ((pce->preg_options & PREG_JIT) && PCRE_G(jit)) {
18041818
count = pcre2_jit_match(pce->re, (PCRE2_SPTR)subject, subject_len, start_offset,
18051819
PCRE2_NO_UTF_CHECK, match_data, mctx);
18061820
} else
@@ -1881,7 +1895,7 @@ static zend_string *php_pcre_replace_func_impl(pcre_cache_entry *pce, zend_strin
18811895

18821896
/* Execute the regular expression. */
18831897
#ifdef HAVE_PCRE_JIT_SUPPORT
1884-
if ((pce->preg_options & PREG_JIT) && options) {
1898+
if ((pce->preg_options & PREG_JIT) && options && PCRE_G(jit)) {
18851899
count = pcre2_jit_match(pce->re, (PCRE2_SPTR)subject, subject_len, start_offset,
18861900
PCRE2_NO_UTF_CHECK, match_data, mctx);
18871901
} else
@@ -2008,7 +2022,7 @@ static zend_string *php_pcre_replace_func_impl(pcre_cache_entry *pce, zend_strin
20082022
break;
20092023
}
20102024
#ifdef HAVE_PCRE_JIT_SUPPORT
2011-
if ((pce->preg_options & PREG_JIT)) {
2025+
if ((pce->preg_options & PREG_JIT) && PCRE_G(jit)) {
20122026
count = pcre2_jit_match(pce->re, (PCRE2_SPTR)subject, subject_len, start_offset,
20132027
PCRE2_NO_UTF_CHECK, match_data, mctx);
20142028
} else
@@ -2551,7 +2565,7 @@ PHPAPI void php_pcre_split_impl(pcre_cache_entry *pce, zend_string *subject_str,
25512565
options = (pce->compile_options & PCRE2_UTF) ? 0 : PCRE2_NO_UTF_CHECK;
25522566

25532567
#ifdef HAVE_PCRE_JIT_SUPPORT
2554-
if ((pce->preg_options & PREG_JIT) && options) {
2568+
if ((pce->preg_options & PREG_JIT) && options && PCRE_G(jit)) {
25552569
count = pcre2_jit_match(pce->re, (PCRE2_SPTR)subject, ZSTR_LEN(subject_str), start_offset,
25562570
PCRE2_NO_UTF_CHECK, match_data, mctx);
25572571
} else
@@ -2654,7 +2668,7 @@ PHPAPI void php_pcre_split_impl(pcre_cache_entry *pce, zend_string *subject_str,
26542668
}
26552669

26562670
#ifdef HAVE_PCRE_JIT_SUPPORT
2657-
if (pce->preg_options & PREG_JIT) {
2671+
if ((pce->preg_options & PREG_JIT) && PCRE_G(jit)) {
26582672
count = pcre2_jit_match(pce->re, (PCRE2_SPTR)subject, ZSTR_LEN(subject_str), start_offset,
26592673
PCRE2_NO_UTF_CHECK, match_data, mctx);
26602674
} else
@@ -2894,7 +2908,7 @@ PHPAPI void php_pcre_grep_impl(pcre_cache_entry *pce, zval *input, zval *return
28942908

28952909
/* Perform the match */
28962910
#ifdef HAVE_PCRE_JIT_SUPPORT
2897-
if ((pce->preg_options & PREG_JIT) && options) {
2911+
if ((pce->preg_options & PREG_JIT) && options && PCRE_G(jit)) {
28982912
count = pcre2_jit_match(pce->re, (PCRE2_SPTR)ZSTR_VAL(subject_str), ZSTR_LEN(subject_str), 0,
28992913
PCRE2_NO_UTF_CHECK, match_data, mctx);
29002914
} else

0 commit comments

Comments
 (0)