mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Report SOE in regular expression find with baloon, avoid SOE for some patterns (IDEA-150928)
This commit is contained in:
@@ -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);
|
||||
}
|
||||
Reference in New Issue
Block a user