]> source.dussan.org Git - sonarqube.git/commitdiff
Refactor regex that can lead to a stack overflow for large inputs
authorZipeng WU <zipeng.wu@sonarsource.com>
Fri, 11 Dec 2020 10:53:25 +0000 (11:53 +0100)
committersonartech <sonartech@sonarsource.com>
Mon, 14 Dec 2020 20:07:14 +0000 (20:07 +0000)
sonar-plugin-api/src/main/java/org/sonar/api/server/rule/RuleParamType.java
sonar-plugin-api/src/test/java/org/sonar/api/server/rule/RuleParamTypeTest.java

index dd9c4d8409c83a48b38b678bb2ace9e3c0692e7e..563369008caf4e0c3d07b4b3770dba6ff4b32546 100644 (file)
@@ -19,6 +19,7 @@
  */
 package org.sonar.api.server.rule;
 
+import java.util.ArrayList;
 import java.util.List;
 import org.apache.commons.lang.StringEscapeUtils;
 import org.apache.commons.lang.StringUtils;
@@ -40,7 +41,6 @@ public final class RuleParamType {
   public static final RuleParamType INTEGER = new RuleParamType("INTEGER");
   public static final RuleParamType FLOAT = new RuleParamType("FLOAT");
 
-  private static final String CSV_SPLIT_REGEX = ",(?=([^\"]*\"[^\"]*\")*[^\"]*$)";
   private static final String VALUES_PARAM = "values";
   private static final String MULTIPLE_PARAM = "multiple";
   private static final String PARAMETER_SEPARATOR = "=";
@@ -110,7 +110,6 @@ public final class RuleParamType {
     return new RuleParamType(type, true, acceptedValues);
   }
 
-  // TODO validate format
   public static RuleParamType parse(String s) {
     // deprecated formats
     if ("i".equals(s) || "i{}".equals(s)) {
@@ -131,7 +130,7 @@ public final class RuleParamType {
     String format = StringUtils.substringBefore(s, OPTION_SEPARATOR);
     String values = null;
     boolean multiple = false;
-    String[] options = s.split(CSV_SPLIT_REGEX);
+    String[] options = csvFormatSplit(s);
     for (String option : options) {
       String opt = StringEscapeUtils.unescapeCsv(option);
       if (opt.startsWith(VALUES_PARAM + PARAMETER_SEPARATOR)) {
@@ -143,7 +142,26 @@ public final class RuleParamType {
     if (values == null || StringUtils.isBlank(values)) {
       return new RuleParamType(format);
     }
-    return new RuleParamType(format, multiple, values.split(CSV_SPLIT_REGEX));
+    return new RuleParamType(format, multiple, csvFormatSplit(values));
+  }
+
+  private static String[] csvFormatSplit(String input) {
+    List<String> result = new ArrayList<>();
+    boolean betweenQuote = false;
+    int startIndex = 0;
+    for (int i = 0; i < input.length(); i++) {
+      char c = input.charAt(i);
+      if (c == '"') {
+        betweenQuote = !betweenQuote;
+      } else if (!betweenQuote && c == ',') {
+        result.add(input.substring(startIndex, i));
+        startIndex = i + 1;
+      }
+    }
+    if (startIndex < input.length()) {
+      result.add(input.substring(startIndex));
+    }
+    return result.toArray(new String[0]);
   }
 
   @Override
index e45d7011e0ee6b427116f7f4436c0566f3341e7b..99069e38cae9f3812c04be38c2aaad56a1fc801c 100644 (file)
@@ -68,13 +68,13 @@ public class RuleParamTypeTest {
     assertThat(selectList.multiple()).isFalse();
     assertThat(selectList.toString()).isEqualTo("SINGLE_SELECT_LIST,values=\"foo,bar,\"");
 
-    RuleParamType.parse("SINGLE_SELECT_LIST,values=\"foo,bar\",multiple=false");
+    selectList = RuleParamType.parse("SINGLE_SELECT_LIST,values=\"foo,bar\",multiple=false");
     assertThat(selectList.type()).isEqualTo("SINGLE_SELECT_LIST");
     assertThat(selectList.values()).containsOnly("foo", "bar");
     assertThat(selectList.multiple()).isFalse();
     assertThat(selectList.toString()).isEqualTo("SINGLE_SELECT_LIST,values=\"foo,bar,\"");
 
-    RuleParamType.parse("SINGLE_SELECT_LIST,\"values=foo,bar\",\"multiple=false\"");
+    selectList = RuleParamType.parse("SINGLE_SELECT_LIST,\"values=foo,bar\",multiple=false");
     assertThat(selectList.type()).isEqualTo("SINGLE_SELECT_LIST");
     assertThat(selectList.values()).containsOnly("foo", "bar");
     assertThat(selectList.multiple()).isFalse();
@@ -96,7 +96,7 @@ public class RuleParamTypeTest {
     assertThat(selectList.multiple()).isTrue();
     assertThat(selectList.toString()).isEqualTo("SINGLE_SELECT_LIST,multiple=true,values=\"foo,bar,\"");
 
-    RuleParamType.parse("SINGLE_SELECT_LIST,\"values=foo,bar\",\"multiple=true\"");
+    selectList = RuleParamType.parse("SINGLE_SELECT_LIST,\"values=foo,bar\",multiple=true");
     assertThat(selectList.type()).isEqualTo("SINGLE_SELECT_LIST");
     assertThat(selectList.values()).containsOnly("foo", "bar");
     assertThat(selectList.multiple()).isTrue();