Skip to content

AllowChangingInputArguments System.InvalidProgramException #127

@Son1x90

Description

@Son1x90

The Following code gives the following runtime error:
System.InvalidProgramException Common Language Runtime detected an invalid program.

Minimalistic Setup:

using MethodBoundaryAspect.Fody.Attributes;
using System.Reflection;

internal class Program
{

    [AllowChangingInputArguments]
    public class AsyncWrapperAttribute : OnMethodBoundaryAspect
    {

        public override void OnEntry(MethodExecutionArgs args)
        {
            Console.WriteLine("testing");
        }

    }

    class FodyTestClass
    {
        [AsyncWrapper]
        public bool FillGuids(out Guid guid1, out Guid guid2)
        {
            guid1 = Guid.NewGuid();
            guid2 = Guid.NewGuid();
            return true;
        }
    }


    private static void Main(string[] args)
    {
        FodyTestClass fodyTestClass = new FodyTestClass();
        fodyTestClass.FillGuids(out Guid guid1, out Guid guid2);


        Console.WriteLine("Hello, World!");
    }
}

Full Code: Method wrapper for WPF running functions without SynchronizationContext
Goal: Being able to set out params

using MethodBoundaryAspect.Fody.Attributes;
using System.Reflection;

internal class Program
{

    [AllowChangingInputArguments]
    public class AsyncWrapperAttribute : OnMethodBoundaryAspect
    {
        private static AsyncLocal<bool> isExecuting = new AsyncLocal<bool>();

        public override void OnEntry(MethodExecutionArgs args)
        {
            if (isExecuting.Value)
                return;

            var method = args.Method as MethodInfo;
            if (method == null)
                throw new InvalidOperationException("Method is not a valid MethodInfo.");

            var parameters = method.GetParameters();
            object[] arguments = new object[args.Arguments.Length];
            Array.Copy(args.Arguments, arguments, args.Arguments.Length);

            isExecuting.Value = true;

            try
            {
                object result = null;

                ExecuteWithoutSynchronizationContext(() =>
                {
                    object[] tempArguments = new object[arguments.Length];
                    Array.Copy(arguments, tempArguments, arguments.Length);
                    result = method.Invoke(args.Instance, tempArguments);

                    for (int i = 0; i < parameters.Length; i++)
                        if (parameters[i].IsOut || parameters[i].ParameterType.IsByRef)
                            args.Arguments[i] = tempArguments[i];
                });

                args.ReturnValue = result;
                args.FlowBehavior = FlowBehavior.Return;
            }
            finally
            {
                isExecuting.Value = false;
            }
        }

        private void ExecuteWithoutSynchronizationContext(Action action)
        {
            var currentContext = SynchronizationContext.Current;
            try
            {
                SynchronizationContext.SetSynchronizationContext(null);
                action();
            }
            finally
            {
                SynchronizationContext.SetSynchronizationContext(currentContext);
            }
        }
    }

    class FodyTestClass
    {
        [AsyncWrapper]
        public bool FillGuids(out Guid guid1, out Guid guid2)
        {
            guid1 = Guid.NewGuid();
            guid2 = Guid.NewGuid();
            return true;
        }
    }


    private static void Main(string[] args)
    {
        FodyTestClass fodyTestClass = new FodyTestClass();
        fodyTestClass.FillGuids(out Guid guid1, out Guid guid2);


        Console.WriteLine("Hello, World!");
    }
}

Minimal Repro

Running Minimalistic Setup will give the Exception on the following line:
fodyTestClass.FillGuids(out Guid guid1, out Guid guid2);

Running the Full code without the AllowChangingInputArguments attribute results in:
not set parameters (guid1 & guid2 both are Guid.Empty) in the Main function after line
fodyTestClass.FillGuids(out Guid guid1, out Guid guid2);

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions