Skip to main content

Java

Describes how recheck checks a regular expression of the java dialect.

Engine​

recheck follows the syntax and the semantics of Java 27's java.util.regex.Pattern.

Settings​

The java dialect has no settings.

$ recheck --dialect=java '/^(a|a)*$/'

Flags and Units​

The matching unit is utf16-code-point (see Matching Units).

recheck supports the following flags of java.util.regex, written as the letters of their inline flags.

FlagPattern flagInlineNotes
cCANON_EQ(?c)Not supported (see Syntax Limitations).
dUNIX_LINES(?d)Only \n is a line terminator for ., ^ and $.
iCASE_INSENSITIVE(?i)Only between ASCII characters, unless with u or U.
mMULTILINE(?m)
sDOTALL(?s)
uUNICODE_CASE(?u)
xCOMMENTS(?x)
UUNICODE_CHARACTER_CLASS(?U)It implies UNICODE_CASE.

Syntax Limitations​

The following constructs are not supported, and they are reported as unsupported.

  • The canonical equivalence ((?c)).
  • \N{name} (e.g. \N{EM DASH}).
  • The grapheme cluster boundary (\b{g}).

The Pattern flag LITERAL has no flag letter, so it cannot be given (Pattern.quote makes a pattern matching the same strings).

Approximations​

  • Java has optimizations of loops that recheck does not model, so an attack that recheck reports may not work on Java, and the runtime-attack verification checks whether it does.
  • \G matches only at the start of the input, since recheck models a search from there, not one from a later position (e.g. the second call of Matcher#find).
  • Java compiles a repetition into a node that depends on its body (Curly, GroupCurly or Loop), and the nodes differ in captures, \R and empty iterations. recheck does not reproduce the differences, and it repeats any node as Loop does. For example, ^(?:(.)b)*cb\1$ does not match "abcba" in Java, since GroupCurly does not restore the capture on backtracking, and ^\R*\n$ does not match "\r\n", since Curly does not backtrack into \R.
  • Java tries the starts of a look-behind from the shortest by the lengths that its TreeInfo computes, where \X adds nothing to the maximum and the lengths can overflow as int. recheck does not reproduce them, and it tries the starts from the longest by the lengths of the body, as for PCRE. For example, (?<=\X)a never matches in Java, and (?<=(a|aa))b captures "a" of "aab" in Java, but "aa" in recheck.
  • With x, Java skips whitespace and comments also inside constructs (e.g. (?<n a>x), a{1 ,2} and \x4 1), and recheck skips them at the same places. recheck does not reproduce three quirks there: Java drops the & of [a& b], reads \uD83D\ uDE00 as one surrogate pair, and rejects [a- [b]], while recheck reads them as [a&b], \uD83D followed by \ and uDE00, and [a\-b].

Runtime-Attack Verification​

  • Command: java --source 17 <file>.java.
  • Matching: Matcher#find.
  • Engine limits: none.
  • Engine errors: StackOverflowError, OutOfMemoryError.
  • Environment variable: RECHECK_JAVA.

java runs the program as a single-file source-code program, which needs a JDK 17 or later.