Merge branch 'wryun-gregex-handle-multiple-failed-optimise-matches-with-fallback' into 'main'

gregex: clean up usage of _GRegex.jit_status

Closes #2824

See merge request GNOME/glib!3750
This commit is contained in:
Philip Withnall 2023-12-18 11:23:56 +00:00
commit 4608b87469
2 changed files with 63 additions and 21 deletions

View File

@ -252,6 +252,13 @@ struct _GRegex
GRegexMatchFlags orig_match_opts; /* options used as default match options, gregex values */
uint32_t jit_options; /* options which were enabled for jit compiler */
JITStatus jit_status; /* indicates the status of jit compiler for this compiled regex */
/* The jit_status here does _not_ correspond to whether we used the JIT in the last invocation,
* which may be affected by match_options or a JIT_STACK_LIMIT error, but whether it was ever
* enabled for the current regex AND current set of jit_options.
* JIT_STATUS_DEFAULT means enablement was never tried,
* JIT_STATUS_ENABLED means it was tried and successful (even if we're not currently using it),
* and JIT_STATUS_DISABLED means it was tried and failed (so we shouldn't try again).
*/
};
/* TRUE if ret is an error code, FALSE otherwise. */
@ -918,35 +925,47 @@ enable_jit_with_match_options (GMatchInfo *match_info,
/* no new options enabled */
if (new_jit_options == old_jit_options)
return match_info->regex->jit_status;
{
g_assert (match_info->regex->jit_status != JIT_STATUS_DEFAULT);
return match_info->regex->jit_status;
}
retval = pcre2_jit_compile (match_info->regex->pcre_re, new_jit_options);
switch (retval)
if (retval == 0)
{
case 0: /* JIT enabled successfully */
match_info->regex->jit_status = JIT_STATUS_ENABLED;
match_info->regex->jit_options = new_jit_options;
/* Set min stack size for JIT to 32KiB and max to 512KiB */
match_info->jit_stack = pcre2_jit_stack_create (1 << 15, 1 << 19, NULL);
pcre2_jit_stack_assign (match_info->match_context, NULL, match_info->jit_stack);
return JIT_STATUS_ENABLED;
case PCRE2_ERROR_NOMEMORY:
g_debug ("JIT compilation was requested with G_REGEX_OPTIMIZE, "
"but JIT was unable to allocate executable memory for the "
"compiler. Falling back to interpretive code.");
return JIT_STATUS_DISABLED;
case PCRE2_ERROR_JIT_BADOPTION:
g_debug ("JIT compilation was requested with G_REGEX_OPTIMIZE, "
"but JIT support is not available. Falling back to "
"interpretive code.");
return JIT_STATUS_DISABLED;
break;
default:
g_debug ("JIT compilation was requested with G_REGEX_OPTIMIZE, "
"but request for JIT support had unexpectedly failed (error %d). "
"Falling back to interpretive code.", retval);
return JIT_STATUS_DISABLED;
break;
}
else
{
match_info->regex->jit_status = JIT_STATUS_DISABLED;
switch (retval)
{
case PCRE2_ERROR_NOMEMORY:
g_debug ("JIT compilation was requested with G_REGEX_OPTIMIZE, "
"but JIT was unable to allocate executable memory for the "
"compiler. Falling back to interpretive code.");
break;
case PCRE2_ERROR_JIT_BADOPTION:
g_debug ("JIT compilation was requested with G_REGEX_OPTIMIZE, "
"but JIT support is not available. Falling back to "
"interpretive code.");
break;
default:
g_debug ("JIT compilation was requested with G_REGEX_OPTIMIZE, "
"but request for JIT support had unexpectedly failed (error %d). "
"Falling back to interpretive code.",
retval);
break;
}
}
return match_info->regex->jit_status;
g_assert_not_reached ();
}

View File

@ -2517,6 +2517,28 @@ test_unmatched_named_subpattern (void)
g_regex_unref (regex);
}
static void
test_compiled_regex_after_jit_failure (void)
{
GRegex *regex = NULL;
char string[LARGE_TEST_STRING_LEN];
g_test_summary ("Test that failed OPTIMIZE regex doesn't cause issues on subsequent matches");
g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/2824");
regex = g_regex_new ("^(?:[ \t\n]|[^[:cntrl:]])*$", G_REGEX_OPTIMIZE, 0, NULL);
/* Generate large enough string to cause JIT failure on this regex. */
memset (string, '*', LARGE_TEST_STRING_LEN);
string[LARGE_TEST_STRING_LEN - 1] = '\0';
g_assert_true (g_regex_match (regex, string, 0, NULL));
/* Second assert here is the key - does the first JIT overflow mess up our state? */
g_assert_true (g_regex_match (regex, string, 0, NULL));
g_regex_unref (regex);
}
int
main (int argc, char *argv[])
{
@ -2537,6 +2559,7 @@ main (int argc, char *argv[])
g_test_add_func ("/regex/compile-errors", test_compile_errors);
g_test_add_func ("/regex/jit-unsupported-matching", test_jit_unsupported_matching_options);
g_test_add_func ("/regex/unmatched-named-subpattern", test_unmatched_named_subpattern);
g_test_add_func ("/regex/compiled-regex-after-jit-failure", test_compiled_regex_after_jit_failure);
/* TEST_NEW(pattern, compile_opts, match_opts) */
TEST_NEW("[A-Z]+", G_REGEX_CASELESS | G_REGEX_EXTENDED | G_REGEX_OPTIMIZE, G_REGEX_MATCH_NOTBOL | G_REGEX_MATCH_PARTIAL);