From 8824db2708fbf5c6d1fa23f661973a2130efefb1 Mon Sep 17 00:00:00 2001 From: vlad20012 Date: Thu, 12 Sep 2019 16:11:09 +0300 Subject: [PATCH] MACRO: check macro expansion depth during type inference Prevents infinite recursive macros --- .../rust/lang/core/types/infer/TypeInference.kt | 1 + .../lang/core/types/infer/TypeInferenceWalker.kt | 14 ++++++++++++++ .../lang/core/type/RsMacroTypeInferenceTest.kt | 10 ++++++++++ 3 files changed, 25 insertions(+) diff --git a/src/main/kotlin/org/rust/lang/core/types/infer/TypeInference.kt b/src/main/kotlin/org/rust/lang/core/types/infer/TypeInference.kt index 32c51b49d16..4902acd4307 100644 --- a/src/main/kotlin/org/rust/lang/core/types/infer/TypeInference.kt +++ b/src/main/kotlin/org/rust/lang/core/types/infer/TypeInference.kt @@ -814,4 +814,5 @@ object TypeInferenceMarks { val methodPickDerefOrder = Testmark("methodPickDerefOrder") val methodPickCollapseTraits = Testmark("methodPickCollapseTraits") val traitSelectionSpecialization = Testmark("traitSelectionSpecialization") + val reachMacroExprDepthLimit = Testmark("reachMacroExprDepthLimit") } diff --git a/src/main/kotlin/org/rust/lang/core/types/infer/TypeInferenceWalker.kt b/src/main/kotlin/org/rust/lang/core/types/infer/TypeInferenceWalker.kt index e43e358eef5..12a565e45c9 100644 --- a/src/main/kotlin/org/rust/lang/core/types/infer/TypeInferenceWalker.kt +++ b/src/main/kotlin/org/rust/lang/core/types/infer/TypeInferenceWalker.kt @@ -31,6 +31,7 @@ class RsTypeInferenceWalker( ) { private var tryTy: Ty? = returnTy private var yieldTy: Ty? = null + private var macroExprDepth: Int = 0 private val lookup get() = ctx.lookup private val items get() = ctx.items private val fulfill get() = ctx.fulfill @@ -1046,6 +1047,19 @@ class RsTypeInferenceWalker( } private fun inferMacroExprType(macroExpr: RsMacroExpr, expected: Ty?): Ty { + if (macroExprDepth > DEFAULT_RECURSION_LIMIT) { + TypeInferenceMarks.reachMacroExprDepthLimit.hit() + return TyUnknown + } + macroExprDepth++ + try { + return inferMacroExprType0(macroExpr, expected) + } finally { + macroExprDepth-- + } + } + + private fun inferMacroExprType0(macroExpr: RsMacroExpr, expected: Ty?): Ty { val macroCall = macroExpr.macroCall val name = macroCall.macroName val exprArg = macroCall.exprMacroArgument diff --git a/src/test/kotlin/org/rust/lang/core/type/RsMacroTypeInferenceTest.kt b/src/test/kotlin/org/rust/lang/core/type/RsMacroTypeInferenceTest.kt index 34a92366767..7ba7b67838f 100644 --- a/src/test/kotlin/org/rust/lang/core/type/RsMacroTypeInferenceTest.kt +++ b/src/test/kotlin/org/rust/lang/core/type/RsMacroTypeInferenceTest.kt @@ -5,6 +5,8 @@ package org.rust.lang.core.type +import org.rust.lang.core.types.infer.TypeInferenceMarks + class RsMacroTypeInferenceTest : RsTypificationTestBase() { override val followMacroExpansions: Boolean get() = true @@ -124,4 +126,12 @@ class RsMacroTypeInferenceTest : RsTypificationTestBase() { b; } //^ """) + + fun `test infinite recursion`() = testExpr(""" + macro_rules! foo { () => { foo!(); }; } + fn main() { + let a = foo!(); + a; + } //^ + """, TypeInferenceMarks.reachMacroExprDepthLimit) }