From 21df1791de5ff3752dcf7a1c46f199fbddc3684f Mon Sep 17 00:00:00 2001 From: Alexander Zolotov Date: Wed, 18 Jun 2025 15:45:18 +0200 Subject: [PATCH] [textmate] add matching timeout (IJPL-159310) (cherry picked from commit 226cca19649e4b3519cf8dae137f4108f5af0b75) IJ-CR-166227 GitOrigin-RevId: 39234cf628f8553f945b91b0e8a72128f952a3c4 --- .../intellij/textmate/joni/JoniRegexFacade.kt | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/plugins/textmate/joni/src/com/intellij/textmate/joni/JoniRegexFacade.kt b/plugins/textmate/joni/src/com/intellij/textmate/joni/JoniRegexFacade.kt index 6c69ccb85475..d2f043cd604d 100644 --- a/plugins/textmate/joni/src/com/intellij/textmate/joni/JoniRegexFacade.kt +++ b/plugins/textmate/joni/src/com/intellij/textmate/joni/JoniRegexFacade.kt @@ -10,6 +10,7 @@ import org.joni.Region import org.joni.exception.JOniException import org.slf4j.Logger import org.slf4j.LoggerFactory +import kotlin.time.Duration.Companion.milliseconds class JoniRegexFacade(private val myRegex: Regex) : RegexFacade { override fun match(string: TextMateString, checkCancelledCallback: Runnable?): MatchData { @@ -28,25 +29,37 @@ class JoniRegexFacade(private val myRegex: Regex) : RegexFacade { checkCancelledCallback?.run() - val matcher = myRegex.matcher(string.bytes) + val matcher = myRegex.matcher(string.bytes, 0, string.bytes.size, MATCHING_TIMEOUT) try { val matchIndex = matcher.search(gosOffset, byteOffset, string.bytes.size, options) - val matchData = if (matchIndex > -1) matchData(matcher.eagerRegion) else NOT_MATCHED - checkMatched(matchData, string) - return matchData + return when (matchIndex) { + org.joni.Matcher.FAILED -> { + NOT_MATCHED + } + org.joni.Matcher.INTERRUPTED -> { + LOGGER.info("Matching regex was interrupted on string: {}", string.bytes.decodeToString()) + NOT_MATCHED + } + else -> { + matchData(matcher.eagerRegion).also { + checkMatched(it, string) + } + } + } } catch (e: JOniException) { - LOGGER.info("Failed to parse textmate regex '{}' with {}: {}", string, e.javaClass.getName(), e.message) + LOGGER.info("Failed to match textmate regex '{}' with {}: {}", string.bytes.decodeToString(), e.javaClass.getName(), e.message) return NOT_MATCHED } catch (e: ArrayIndexOutOfBoundsException) { - LOGGER.info("Failed to parse textmate regex '{}' with {}: {}", string, e.javaClass.getName(), e.message) + LOGGER.info("Failed to match textmate regex '{}' with {}: {}", string.bytes.decodeToString(), e.javaClass.getName(), e.message) return NOT_MATCHED } } companion object { + private val MATCHING_TIMEOUT = 300.milliseconds.inWholeNanoseconds private val LOGGER: Logger = LoggerFactory.getLogger(JoniRegexFacade::class.java) private fun checkMatched(match: MatchData, string: TextMateString) {