@Documented
@Incubating
@Retention(RetentionPolicy.SOURCE)
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.LOCAL_VARIABLE})
public @interface SafeRegex
Guards the regex operators within the annotated scope against Regular
Expression Denial of Service (ReDoS). Match (==~) and find
(=~) expressions are rewritten at compile time to deadline-guarded
RegexGuard calls which throw
RegexTimeoutException if evaluation, e.g. due to
catastrophic backtracking on adversarial input, exceeds the configured
timeout. Matching semantics are otherwise unchanged, including left-to-right
evaluation of the operands, which the generated call preserves by taking them
in the operator's order.
@SafeRegex(millis = 200)
class Handler {
boolean check(String input) {
input ==~ /(a+)+$/ // rewritten to RegexGuard.matchRegex(input, /(a+)+$/, 200)
}
}
For the find operator, the deadline covers the whole use of the returned
matcher, i.e. it starts when the matcher is created and later matcher
operations such as find() throw once it has passed.
When placed on a field or local variable declaration, only regex operators
lexically within the initializer expression are guarded; later uses of the
variable are unaffected. A guarded field initializer runs, as usual, in the
constructor (or in the static initializer for a static field, where a
timeout surfaces as an ExceptionInInitializerError whose cause is
the RegexTimeoutException).
Limitations: only regex operators lexically visible within the annotated
scope are rewritten. Regex evaluation via method calls such as
String#matches, replaceAll or split, or occurring
in code called from the annotated scope, is not guarded; use
RegexGuard explicitly for those. This is an
opt-in facility, never a blanket default.
| Type | Name and Description |
|---|---|
long |
millisReturns the timeout in milliseconds applied to each guarded regex evaluation within the annotated scope. |