Skip to content

Local variable getting modified by function call #13362

@r-ramesh

Description

@r-ramesh

Local variable gets modified by an unrelated function call, with .NET Core 3.0. Admittedly the type in question is a bit weird, lifted from a CoreCLR test case.

In the code snippet below, "instance" mutates from being an object of type GenInt to a List<FieldInfo> magically. Calling GetAllInstanceFields shouldn't modified the local of the caller.

Observed output:
ClrIssueRepro.GenInt
System.Object

Expected output:
ClrIssueRepro.GenInt
ClrIssueRepro.GenInt

Here is the code snippet:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
#pragma warning disable 649, 169
namespace ClrIssueRepro
{
    [StructLayout(LayoutKind.Sequential)]
    public class GenBase<T>
    {
        public T Fld10;

        public int _int0 = 0;
        public double _double0 = 0;
        public string _string0 = "string0";
        public Guid _Guid0 = new Guid();

        public T Fld11;

        public int _int1 = int.MaxValue;
        public double _double1 = double.MaxValue;
        public string _string1 = "string1";
        public Guid _Guid1 = new Guid(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11);

        public T Fld12;
    }

    [StructLayout(LayoutKind.Explicit)]
    public class GenInt : GenBase<int>
    {
        [FieldOffset(0)] public int sFld10;

        [FieldOffset(16)] public int _sint0 = 0;
        [FieldOffset(24)] public double _sdouble0 = 0;
        [FieldOffset(32)] public string _sstring0 = "string0";
        [FieldOffset(40)] public Guid _sGuid0 = new Guid();

        [FieldOffset(56)] public int sFld11;

        [FieldOffset(72)] public int _sint1 = int.MaxValue;
        [FieldOffset(80)] public double _sdouble1 = double.MaxValue;
        [FieldOffset(88)] public string _sstring1 = "string1";
        [FieldOffset(96)] public Guid _sGuid1 = new Guid(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11);

        [FieldOffset(112)] public int sFld12;
    }

    class Program
    {
        private static FieldInfo[] GetAllInstanceFields(Type type)
        {
            List<FieldInfo> result = new List<FieldInfo>();
            for (Type t = type; t != null; t = t.BaseType)
            {
                // Stop iterating once we get to System.ValueType. There should be no fields in it
                // or System.Object, it's base class. This is ok to do for desktop & ProjectN.
                if (t == typeof(ValueType))
                {
                    break;
                }

                FieldInfo[] fieldsOnType = t.GetFields(
                    BindingFlags.Public |
                    BindingFlags.NonPublic |
                    BindingFlags.Instance |
                    BindingFlags.DeclaredOnly);
                result.AddRange(fieldsOnType);
            }

            return result.ToArray();
        }

        private static object CreateInstance(Type t)
        {
            return t.IsValueType ? Activator.CreateInstance(t) : FormatterServices.GetUninitializedObject(t);
        }

        static void Main(string[] args)
        {
            Type type = typeof(GenInt);

            object instance = CreateInstance(type);
            // instance is of type GenInt.

            Console.WriteLine(instance.GetType());

            System.Reflection.FieldInfo[] fields = GetAllInstanceFields(type);
            // is it still?

            Console.WriteLine(instance.GetType());
            Debugger.Break();
        }
    }
}

Metadata

Metadata

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions