Browse Source

Painless: Apply true regex limit factor with FIND and MATCH operator (#105670)

`script.painless.regex.enabled`: `true` changes the effective `script.painless.regex.regex.limit-factor`.

This worked if the limit factor was looked up via the static `$COMPILERSETTINGS` such as during a call but it did not work if used via a binary operation such as `FIND`, `=~`, or `MATCH`, `==~`.

Only expose the applied limit factor and use that everywhere.

Fixes: #105669
Stuart Tettemer 1 year ago
parent
commit
b3fc714b87

+ 5 - 0
docs/changelog/105670.yaml

@@ -0,0 +1,5 @@
+pr: 105670
+summary: "Painless: Apply true regex limit factor with FIND and MATCH operation"
+area: Infra/Scripting
+type: bug
+issues: []

+ 9 - 11
modules/lang-painless/src/main/java/org/elasticsearch/painless/CompilerSettings.java

@@ -160,10 +160,14 @@ public final class CompilerSettings {
     }
 
     /**
-     * What is the limit factor for regexes?
-     */
-    public int getRegexLimitFactor() {
-        return regexLimitFactor;
+     * What is the effective limit factor for regexes?
+     */
+    public int getAppliedRegexLimitFactor() {
+        return switch (regexesEnabled) {
+            case TRUE -> Augmentation.UNLIMITED_PATTERN_FACTOR;
+            case FALSE -> Augmentation.DISABLED_PATTERN_FACTOR;
+            case LIMITED -> regexLimitFactor;
+        };
     }
 
     /**
@@ -171,14 +175,8 @@ public final class CompilerSettings {
      * annotation.
      */
     public Map<String, Object> asMap() {
-        int regexLimitFactorToApply = this.regexLimitFactor;
-        if (regexesEnabled == RegexEnabled.TRUE) {
-            regexLimitFactorToApply = Augmentation.UNLIMITED_PATTERN_FACTOR;
-        } else if (regexesEnabled == RegexEnabled.FALSE) {
-            regexLimitFactorToApply = Augmentation.DISABLED_PATTERN_FACTOR;
-        }
         Map<String, Object> map = new HashMap<>();
-        map.put("regex_limit_factor", regexLimitFactorToApply);
+        map.put("regex_limit_factor", getAppliedRegexLimitFactor());
 
         // for testing only
         map.put("testInject0", testInject0);

+ 1 - 1
modules/lang-painless/src/main/java/org/elasticsearch/painless/PainlessScriptEngine.java

@@ -425,7 +425,7 @@ public final class PainlessScriptEngine implements ScriptEngine {
             // Except regexes enabled - this is a node level setting and can't be changed in the request.
             compilerSettings.setRegexesEnabled(defaultCompilerSettings.areRegexesEnabled());
 
-            compilerSettings.setRegexLimitFactor(defaultCompilerSettings.getRegexLimitFactor());
+            compilerSettings.setRegexLimitFactor(defaultCompilerSettings.getAppliedRegexLimitFactor());
 
             Map<String, String> copy = new HashMap<>(params);
 

+ 1 - 1
modules/lang-painless/src/main/java/org/elasticsearch/painless/phase/DefaultUserTreeToIRTreePhase.java

@@ -1076,7 +1076,7 @@ public class DefaultUserTreeToIRTreePhase implements UserTreeVisitor<ScriptScope
             irBinaryMathNode.attachDecoration(new IRDOperation(operation));
 
             if (operation == Operation.MATCH || operation == Operation.FIND) {
-                irBinaryMathNode.attachDecoration(new IRDRegexLimit(scriptScope.getCompilerSettings().getRegexLimitFactor()));
+                irBinaryMathNode.attachDecoration(new IRDRegexLimit(scriptScope.getCompilerSettings().getAppliedRegexLimitFactor()));
             }
 
             irBinaryMathNode.attachDecoration(new IRDBinaryType(binaryType));

+ 10 - 0
modules/lang-painless/src/test/java/org/elasticsearch/painless/RegexLimitTests.java

@@ -73,6 +73,16 @@ public class RegexLimitTests extends ScriptTestCase {
         assertTrue(cbe.getMessage().contains(regexCircuitMessage));
     }
 
+    public void testInjectBinary() {
+        String script = "Pattern p = /.*a.*b.*c.*/; return 'abcxyz123abc' =~ p;";
+        Settings settings = Settings.builder()
+            .put(CompilerSettings.REGEX_LIMIT_FACTOR.getKey(), 1)
+            .put(CompilerSettings.REGEX_ENABLED.getKey(), "true")
+            .build();
+        scriptEngine = new PainlessScriptEngine(settings, scriptContexts());
+        assertEquals(Boolean.TRUE, exec(script));
+    }
+
     public void testRegexInject_DefMethodRef_Matcher() {
         String script = "boolean isMatch(Function func) { func.apply("
             + charSequence