Skip to content

Commit

Permalink
Merge #5084
Browse files Browse the repository at this point in the history
5084: MACRO: Avoid infinite recursion in macros control flow r=vlad20012 a=ortem

Fixes #5083

Co-authored-by: ortem <ortem00@gmail.com>
  • Loading branch information
bors[bot] and artemmukhin committed Mar 12, 2020
2 parents 7499bc3 + 219a835 commit 14e66af
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 0 deletions.
10 changes: 10 additions & 0 deletions src/main/kotlin/org/rust/lang/core/cfg/CFGBuilder.kt
Expand Up @@ -10,6 +10,7 @@ import org.rust.lang.core.cfg.CFGBuilder.ScopeCFKind.Break
import org.rust.lang.core.cfg.CFGBuilder.ScopeCFKind.Continue
import org.rust.lang.core.psi.*
import org.rust.lang.core.psi.ext.*
import org.rust.lang.core.resolve.DEFAULT_RECURSION_LIMIT
import org.rust.lang.core.types.regions.Scope
import org.rust.lang.core.types.regions.ScopeTree
import org.rust.lang.core.types.ty.TyNever
Expand Down Expand Up @@ -43,6 +44,7 @@ class CFGBuilder(
private val pred: CFGNode get() = preds.peek()
private val loopScopes: Deque<LoopScope> = ArrayDeque()
private val breakableBlockScopes: Deque<BlockScope> = ArrayDeque()
private var nestedMacroCallsCount: Int = 0

private inline fun finishWith(callable: () -> CFGNode) {
result = callable()
Expand Down Expand Up @@ -253,6 +255,12 @@ class CFGBuilder(
}

override fun visitMacroCall(macroCall: RsMacroCall) {
if (nestedMacroCallsCount > DEFAULT_RECURSION_LIMIT) {
finishWithUnreachableNode(addAstNode(macroCall, pred))
return
}
nestedMacroCallsCount++

val subExprsExit = when (val argument = macroCall.macroArgumentElement) {
is RsExprMacroArgument -> argument.expr?.let { process(it, pred) }
is RsIncludeMacroArgument -> argument.expr?.let { process(it, pred) }
Expand Down Expand Up @@ -287,6 +295,8 @@ class CFGBuilder(
else -> error("unreachable")
}

nestedMacroCallsCount--

val subElementsExit = subExprsExit ?: run {
val subPathsIdents = PsiTreeUtil.findChildrenOfAnyType(
macroCall,
Expand Down
Expand Up @@ -9,6 +9,7 @@ import org.rust.lang.core.psi.*
import org.rust.lang.core.psi.ext.*
import org.rust.lang.core.psi.ext.RsBindingModeKind.BindByReference
import org.rust.lang.core.psi.ext.RsBindingModeKind.BindByValue
import org.rust.lang.core.resolve.DEFAULT_RECURSION_LIMIT
import org.rust.lang.core.resolve.VALUES
import org.rust.lang.core.types.GatherLivenessContext
import org.rust.lang.core.types.borrowck.ConsumeMode.Copy
Expand Down Expand Up @@ -110,6 +111,8 @@ enum class MutateMode {
}

class ExprUseWalker(private val delegate: Delegate, private val mc: MemoryCategorizationContext) {
private var nestedMacroCallsCount: Int = 0

fun consumeBody(body: RsBlock) {
val function = body.parent as? RsFunction ?: return

Expand Down Expand Up @@ -311,6 +314,11 @@ class ExprUseWalker(private val delegate: Delegate, private val mc: MemoryCatego
}

private fun walkMacroCall(macroCall: RsMacroCall) {
if (nestedMacroCallsCount > DEFAULT_RECURSION_LIMIT) {
return
}
nestedMacroCallsCount++

when (val argument = macroCall.macroArgumentElement) {
is RsExprMacroArgument -> argument.expr?.let(::walkExpr)
is RsIncludeMacroArgument -> argument.expr?.let(::walkExpr)
Expand Down Expand Up @@ -347,6 +355,7 @@ class ExprUseWalker(private val delegate: Delegate, private val mc: MemoryCatego

else -> error("unreachable")
}
nestedMacroCallsCount--
}

private fun walkStmt(stmt: RsStmt) {
Expand Down
Expand Up @@ -616,4 +616,17 @@ class RsBorrowCheckerMovesTest : RsInspectionsTestBase(RsBorrowCheckerInspection
}
}
""", checkWarn = false)

fun `test infinitely recursive macro call`() = checkByText("""
macro_rules! infinite_macro {
($ e:expr) => { infinite_macro!($ e) };
}
struct S;
fn main() {
let x = S;
infinite_macro!(x);
}
""", checkWarn = false)
}
17 changes: 17 additions & 0 deletions src/test/kotlin/org/rust/lang/core/cfg/RsControlFlowGraphTest.kt
Expand Up @@ -951,6 +951,23 @@ class RsControlFlowGraphTest : RsTestBase() {
Exit
""")

fun `test infinitely recursive macro call`() = testCFG("""
macro_rules! infinite_macro {
() => { infinite_macro!() };
}
fn foo() {
1;
infinite_macro!();
2;
}
""", """
Entry
1
1;
infinite_macro ! ( )
Termination
""")


private fun testCFG(@Language("Rust") code: String, expectedIndented: String) {
InlineFile(code)
Expand Down

0 comments on commit 14e66af

Please sign in to comment.