Report SOE in regular expression find with baloon, avoid SOE for some patterns (IDEA-150928)

This commit is contained in:
Maxim.Mossienko
2017-06-30 14:55:22 +02:00
parent 108e4ffd18
commit 7a7ed86507
4 changed files with 67 additions and 3 deletions
@@ -927,6 +927,31 @@ public class FindManagerTest extends DaemonAnalyzerTestCase {
assertTrue(!findResult.isStringFound());
}
public void testRegExpSOEWhenMatch2() throws InterruptedException {
String text = "package com.intellij.demo;\n" +
"\n";
for(int i = 0; i < 10; ++i) text += text;
text += "public class Foo {}";
FindModel findModel = FindManagerTestUtils.configureFindModel("package((?:\\n|.)+)class (\\w+)");
findModel.setRegularExpressions(true);
FindResult findResult = myFindManager.findString(text, 0, findModel, null);
assertTrue(findResult.isStringFound());
findModel = FindManagerTestUtils.configureFindModel("package((.|\\n)+)class (\\w+)");
findModel.setRegularExpressions(true);
findResult = myFindManager.findString(text, 0, findModel, null);
assertTrue(findResult.isStringFound());
findModel = FindManagerTestUtils.configureFindModel("package(([^\\n]|\\n)+)class (\\w+)");
findModel.setRegularExpressions(true);
findResult = myFindManager.findString(text, 0, findModel, null);
assertTrue(!findResult.isStringFound()); // SOE, no match
}
public void testFindRegexpThatMatchesWholeFile() throws Exception {
FindModel findModel = FindManagerTestUtils.configureFindModel("[^~]+\\Z");
findModel.setRegularExpressions(true);
@@ -15,6 +15,7 @@
*/
package com.intellij.find;
import com.intellij.Patches;
import com.intellij.openapi.util.UserDataHolderBase;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
@@ -937,8 +938,19 @@ public class FindModel extends UserDataHolderBase implements Cloneable {
Pattern pattern = myPattern;
if (pattern == PatternUtil.NOTHING) {
int flags = isCaseSensitive() ? Pattern.MULTILINE : Pattern.MULTILINE | Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE;
if (toFind.contains("\\n") && Patches.JDK_SOE_IN_REGEXP) { // if needed use DOT_ALL for modified pattern to avoid SOE
String modifiedStringToFind = StringUtil.replace(toFind, "\\n|.", ".");
modifiedStringToFind = StringUtil.replace(modifiedStringToFind, ".|\\n", ".");
if (!modifiedStringToFind.equals(toFind)) {
flags |= Pattern.DOTALL;
toFind = modifiedStringToFind;
}
}
try {
myPattern = pattern = Pattern.compile(toFind, isCaseSensitive() ? Pattern.MULTILINE : Pattern.MULTILINE | Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);
myPattern = pattern = Pattern.compile(toFind, flags);
}
catch (PatternSyntaxException e) {
myPattern = pattern = null;
@@ -30,11 +30,15 @@ import com.intellij.lang.LanguageUtil;
import com.intellij.lang.ParserDefinition;
import com.intellij.lexer.Lexer;
import com.intellij.navigation.NavigationItem;
import com.intellij.notification.NotificationDisplayType;
import com.intellij.notification.NotificationGroup;
import com.intellij.notification.NotificationType;
import com.intellij.notification.impl.NotificationsConfigurationImpl;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.IdeActions;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.*;
@@ -65,6 +69,7 @@ import com.intellij.ui.ReplacePromptDialog;
import com.intellij.usages.ChunkExtractor;
import com.intellij.usages.UsageViewManager;
import com.intellij.usages.impl.SyntaxHighlighterOverEditorHighlighter;
import com.intellij.util.containers.ConcurrentIntObjectMap;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.Predicate;
import com.intellij.util.messages.MessageBus;
@@ -100,6 +105,7 @@ public class FindManagerImpl extends FindManager {
private static final Key<Boolean> HIGHLIGHTER_WAS_NOT_FOUND_KEY = Key.create("com.intellij.find.impl.FindManagerImpl.HighlighterNotFoundKey");
private FindUIHelper myHelper;
private static final NotificationGroup GROUP = new NotificationGroup("Find Problems", NotificationDisplayType.STICKY_BALLOON, false);
public FindManagerImpl(Project project, FindSettings findSettings, UsageViewManager anotherManager, MessageBus bus) {
myProject = project;
@@ -475,7 +481,7 @@ public class FindManagerImpl extends FindManager {
}
if (model.isRegularExpressions()){
return findStringByRegularExpression(text, offset, model);
return findStringByRegularExpression(text, offset, model, file);
}
final StringSearcher searcher = createStringSearcher(model);
@@ -730,7 +736,10 @@ public class FindManagerImpl extends FindManager {
return syntaxHighlighter;
}
private static FindResult findStringByRegularExpression(CharSequence text, int startOffset, FindModel model) {
private FindResult findStringByRegularExpression(CharSequence text,
int startOffset,
FindModel model,
VirtualFile file) {
Matcher matcher = compileRegExp(model, text);
if (matcher == null) {
return NOT_FOUND_RESULT;
@@ -757,9 +766,24 @@ public class FindManagerImpl extends FindManager {
return new FindResultImpl(start, end);
}
} catch (StackOverflowError soe) {
String stringToFind = model.getStringToFind();
if (!ApplicationManager.getApplication().isHeadlessEnvironment() &&
ourReportedPatterns.put(stringToFind.hashCode(), Boolean.TRUE) == null) {
String content = stringToFind + " produced stack overflow when matching content of the file";
LOG.info(content);
//noinspection SSBasedInspection
GROUP.createNotification("Regular expression failed to match",
content + " " + file.getPath(),
NotificationType.ERROR,
null
).notify(myProject);
}
return NOT_FOUND_RESULT;
}
}
private static final ConcurrentIntObjectMap<Boolean> ourReportedPatterns = ContainerUtil.createConcurrentIntObjectMap();
private static Matcher compileRegExp(FindModel model, CharSequence text) {
Pattern pattern = model.compileRegExp();
@@ -137,4 +137,7 @@ public class Patches {
public static final boolean JDK_BUG_ID_8032832 = SystemInfo.isJavaVersionAtLeast("1.8.0_20");
public static final boolean JDK_BUG_ID_8147994 = !SystemInfo.isMac && !SystemInfo.isJavaVersionAtLeast("1.8.0_102");
// IDEA-175066 / https://stackoverflow.com/questions/31676277/stackoverflowerror-in-regular-expression
public static final boolean JDK_SOE_IN_REGEXP = (true);
}