From 29a027266f27bdb9d27f5d886fd24fb05932f742 Mon Sep 17 00:00:00 2001 From: Andrew Ayers Date: Wed, 22 Apr 2026 10:55:34 -0700 Subject: [PATCH] JIT: Fix uninitialized gtCallMethHnd for indirect calls causing false recursive tail call detection PR #125211 broke the union between gtCallMethHnd and gtCallAddr into separate fields but did not initialize gtCallMethHnd for CT_INDIRECT calls. Since the arena allocator does not zero memory in Release builds, gtCallMethHnd contains stale data that can accidentally match the compiled method's handle, causing gtIsRecursiveCall() to return true. Combined with the CORINFO_VIRTUALCALL_LDVIRTFTN import path (used for generic interface calls in R2R) which creates CT_INDIRECT calls without GTF_CALL_VIRT_* flags, the recursive tail call optimization incorrectly transforms the call into a backward jump, creating an infinite allocating loop. Fix by: 1. Initializing gtCallMethHnd = NO_METHOD_HANDLE in gtNewCallNode for CT_INDIRECT 2. Adding a defense-in-depth check in gtIsRecursiveCall to return false for indirect calls 3. Initializing gtCallMethHnd = NO_METHOD_HANDLE in gtCloneExprCallHelper for CT_INDIRECT Fixes #126930 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/coreclr/jit/compiler.h | 4 ++++ src/coreclr/jit/gentree.cpp | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index f40d4488d3aa3c..31dd2278259588 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -3873,6 +3873,10 @@ class Compiler // Note when inlining, this looks for calls back to the root method. bool gtIsRecursiveCall(GenTreeCall* call, bool useInlineRoot = true) { + if (call->gtCallType == CT_INDIRECT) + { + return false; + } return gtIsRecursiveCall(call->gtCallMethHnd, useInlineRoot); } diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 826fba0d2ce604..8e6c5c7f394f8a 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -9768,6 +9768,7 @@ GenTreeCall* Compiler::gtNewCallNode(gtCallTypes callType, if (callType == CT_INDIRECT) { node->gtCallCookie = nullptr; + node->gtCallMethHnd = NO_METHOD_HANDLE; node->gtControlExpr = (GenTree*)callHnd; } else @@ -11374,7 +11375,8 @@ GenTreeCall* Compiler::gtCloneExprCallHelper(GenTreeCall* tree) /* Copy the union */ if (tree->gtCallType == CT_INDIRECT) { - copy->gtCallCookie = tree->gtCallCookie; + copy->gtCallCookie = tree->gtCallCookie; + copy->gtCallMethHnd = NO_METHOD_HANDLE; } else {