Repository: dotnet/runtime
File: src/coreclr/jit/objectalloc.cpp (C++)

Code before:

            case GT_CALL:
            {
                GenTreeCall* const call = parent->AsCall();

                if (call->IsHelperCall())
                {
                    canLclVarEscapeViaParentStack =
                        !Compiler::s_helperCallProperties.IsNoEscape(comp->eeGetHelperNum(call->gtCallMethHnd));
                }
                else if (call->IsSpecialIntrinsic())
                {
                    // Some known special intrinsics don't escape. At this moment, only the ones accepting byrefs
                    // are supported. In order to support more intrinsics accepting objects, we need extra work
                    // on the VM side which is not ready for that yet.
                    //
                    switch (comp->lookupNamedIntrinsic(call->gtCallMethHnd))
                    {
                        case NI_System_SpanHelpers_ClearWithoutReferences:
                        case NI_System_SpanHelpers_Fill:
                        case NI_System_SpanHelpers_Memmove:
                        case NI_System_SpanHelpers_SequenceEqual:
                            canLclVarEscapeViaParentStack = false;
                            break;

                        default:
                            break;
                    }
                }
                else if (call->IsDelegateInvoke())
                {
                    if (tree == call->gtArgs.GetThisArg()->GetNode())
                    {
                        JITDUMP("Delegate invoke this...\n");
                        canLclVarEscapeViaParentStack = false;
                    }
                }

                // Note there is nothing special here about the parent being a call. We could move all this processing
                // up to the caller and handle any sort of tree that could lead to escapes this way.
                //
                // We have it this way because we currently don't expect to see other escaping references on failed
                // GDV paths, though perhaps with multi-guess GDV that might change?
                //
                // In particular it might be tempting to look for references in uncatchable BBJ_THROWs or similar
                // and enable a kind of "partial escape analysis" where we copy from stack to heap just before the
                // point of escape. We would have to add pseudos for this like we do for GDV, but we wouldn't
                // necessarily need to do the predicate analysis or cloning.
                //
                if (isEnumeratorLocal)
                {

Review comment (security):
technically, only the last (value) may escape? not sure if it's useful to know that the length arg does or doesn't

Code after:

            case GT_CALL:
            {
                GenTreeCall* const call = parent->AsCall();

                if (call->IsHelperCall())
                {
                    canLclVarEscapeViaParentStack =
                        !Compiler::s_helperCallProperties.IsNoEscape(comp->eeGetHelperNum(call->gtCallMethHnd));
                }
                else if (call->IsSpecialIntrinsic())
                {
                    // Some known special intrinsics don't escape. At this moment, only the ones accepting byrefs
                    // are supported. In order to support more intrinsics accepting objects, we need extra work
                    // on the VM side which is not ready for that yet.
                    //
                    switch (comp->lookupNamedIntrinsic(call->gtCallMethHnd))
                    {
                        case NI_System_SpanHelpers_ClearWithoutReferences:
                        case NI_System_SpanHelpers_Memmove:
                        case NI_System_SpanHelpers_SequenceEqual:
                            canLclVarEscapeViaParentStack = false;
                            break;

                        case NI_System_SpanHelpers_Fill:
                            // For Fill only the first (byref span) arg does not escape
                            //
                            if (tree == call->gtArgs.GetUserArgByIndex(0)->GetNode())
                            {
                                canLclVarEscapeViaParentStack = false;
                            }
                            break;

                        default:
                            break;
                    }
                }
                else if (call->IsDelegateInvoke())
                {
                    if (tree == call->gtArgs.GetThisArg()->GetNode())
                    {
                        JITDUMP("Delegate invoke this...\n");
                        canLclVarEscapeViaParentStack = false;
                    }
                }

                // Note there is nothing special here about the parent being a call. We could move all this processing
                // up to the caller and handle any sort of tree that could lead to escapes this way.
                //
                // We have it this way because we currently don't expect to see other escaping references on failed
                // GDV paths, though perhaps with multi-guess GDV that might change?