Skip to content

Commit 047a2dd

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 ddb6cad commit 047a2dd

File tree

1 file changed

+44
-28
lines changed

1 file changed

+44
-28
lines changed

ext/pcre/php_pcre.c

Lines changed: 44 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,30 @@ static zend_always_inline size_t calculate_unit_length(pcre_cache_entry *pce, co
585588
}
586589
/* }}} */
587590

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

632665
p = ZSTR_VAL(regex);
@@ -806,24 +839,7 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache_ex(zend_string *regex, in
806839

807840
#ifdef HAVE_PCRE_JIT_SUPPORT
808841
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-
}
842+
poptions |= pcre_jit_compile_regex(re);
827843
}
828844
#endif
829845
efree(pattern);
@@ -1263,7 +1279,7 @@ PHPAPI void php_pcre_match_impl(pcre_cache_entry *pce, zend_string *subject_str,
12631279

12641280
/* Execute the regular expression. */
12651281
#ifdef HAVE_PCRE_JIT_SUPPORT
1266-
if ((pce->preg_options & PREG_JIT) && options) {
1282+
if ((pce->preg_options & PREG_JIT) && options && PCRE_G(jit)) {
12671283
count = pcre2_jit_match(pce->re, (PCRE2_SPTR)subject, subject_len, start_offset2,
12681284
PCRE2_NO_UTF_CHECK, match_data, mctx);
12691285
} else
@@ -1405,7 +1421,7 @@ PHPAPI void php_pcre_match_impl(pcre_cache_entry *pce, zend_string *subject_str,
14051421

14061422
/* Execute the regular expression. */
14071423
#ifdef HAVE_PCRE_JIT_SUPPORT
1408-
if ((pce->preg_options & PREG_JIT)) {
1424+
if ((pce->preg_options & PREG_JIT) && PCRE_G(jit)) {
14091425
if (PCRE2_UNSET == start_offset2 || start_offset2 > subject_len) {
14101426
pcre_handle_exec_error(PCRE2_ERROR_BADOFFSET);
14111427
break;
@@ -1625,7 +1641,7 @@ PHPAPI zend_string *php_pcre_replace_impl(pcre_cache_entry *pce, zend_string *su
16251641

16261642
/* Execute the regular expression. */
16271643
#ifdef HAVE_PCRE_JIT_SUPPORT
1628-
if ((pce->preg_options & PREG_JIT) && options) {
1644+
if ((pce->preg_options & PREG_JIT) && options && PCRE_G(jit)) {
16291645
count = pcre2_jit_match(pce->re, (PCRE2_SPTR)subject, subject_len, start_offset,
16301646
PCRE2_NO_UTF_CHECK, match_data, mctx);
16311647
} else
@@ -1800,7 +1816,7 @@ PHPAPI zend_string *php_pcre_replace_impl(pcre_cache_entry *pce, zend_string *su
18001816
}
18011817

18021818
#ifdef HAVE_PCRE_JIT_SUPPORT
1803-
if (pce->preg_options & PREG_JIT) {
1819+
if ((pce->preg_options & PREG_JIT) && PCRE_G(jit)) {
18041820
count = pcre2_jit_match(pce->re, (PCRE2_SPTR)subject, subject_len, start_offset,
18051821
PCRE2_NO_UTF_CHECK, match_data, mctx);
18061822
} else
@@ -1881,7 +1897,7 @@ static zend_string *php_pcre_replace_func_impl(pcre_cache_entry *pce, zend_strin
18811897

18821898
/* Execute the regular expression. */
18831899
#ifdef HAVE_PCRE_JIT_SUPPORT
1884-
if ((pce->preg_options & PREG_JIT) && options) {
1900+
if ((pce->preg_options & PREG_JIT) && options && PCRE_G(jit)) {
18851901
count = pcre2_jit_match(pce->re, (PCRE2_SPTR)subject, subject_len, start_offset,
18861902
PCRE2_NO_UTF_CHECK, match_data, mctx);
18871903
} else
@@ -2008,7 +2024,7 @@ static zend_string *php_pcre_replace_func_impl(pcre_cache_entry *pce, zend_strin
20082024
break;
20092025
}
20102026
#ifdef HAVE_PCRE_JIT_SUPPORT
2011-
if ((pce->preg_options & PREG_JIT)) {
2027+
if ((pce->preg_options & PREG_JIT) && PCRE_G(jit)) {
20122028
count = pcre2_jit_match(pce->re, (PCRE2_SPTR)subject, subject_len, start_offset,
20132029
PCRE2_NO_UTF_CHECK, match_data, mctx);
20142030
} else
@@ -2551,7 +2567,7 @@ PHPAPI void php_pcre_split_impl(pcre_cache_entry *pce, zend_string *subject_str,
25512567
options = (pce->compile_options & PCRE2_UTF) ? 0 : PCRE2_NO_UTF_CHECK;
25522568

25532569
#ifdef HAVE_PCRE_JIT_SUPPORT
2554-
if ((pce->preg_options & PREG_JIT) && options) {
2570+
if ((pce->preg_options & PREG_JIT) && options && PCRE_G(jit)) {
25552571
count = pcre2_jit_match(pce->re, (PCRE2_SPTR)subject, ZSTR_LEN(subject_str), start_offset,
25562572
PCRE2_NO_UTF_CHECK, match_data, mctx);
25572573
} else
@@ -2654,7 +2670,7 @@ PHPAPI void php_pcre_split_impl(pcre_cache_entry *pce, zend_string *subject_str,
26542670
}
26552671

26562672
#ifdef HAVE_PCRE_JIT_SUPPORT
2657-
if (pce->preg_options & PREG_JIT) {
2673+
if ((pce->preg_options & PREG_JIT) && PCRE_G(jit)) {
26582674
count = pcre2_jit_match(pce->re, (PCRE2_SPTR)subject, ZSTR_LEN(subject_str), start_offset,
26592675
PCRE2_NO_UTF_CHECK, match_data, mctx);
26602676
} else
@@ -2894,7 +2910,7 @@ PHPAPI void php_pcre_grep_impl(pcre_cache_entry *pce, zval *input, zval *return
28942910

28952911
/* Perform the match */
28962912
#ifdef HAVE_PCRE_JIT_SUPPORT
2897-
if ((pce->preg_options & PREG_JIT) && options) {
2913+
if ((pce->preg_options & PREG_JIT) && options && PCRE_G(jit)) {
28982914
count = pcre2_jit_match(pce->re, (PCRE2_SPTR)ZSTR_VAL(subject_str), ZSTR_LEN(subject_str), 0,
28992915
PCRE2_NO_UTF_CHECK, match_data, mctx);
29002916
} else

0 commit comments

Comments
 (0)