Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extend EliminateRedundantTryFinally in ReduceNestingTransform #2959

Merged

Conversation

ElektroKill
Copy link
Contributor

Link to issue(s) this covers:
N/A

Problem

When decompiling EventPipeMetadataGenerator.GenerateMetadata(int eventId, string eventName, long keywords, uint level, uint version, EventOpcode opcode, EventParameterInfo[] parameters) from System.Private.CoreLib from .NET 7.0.4 the decompiler does not completely clean up try finally regions left over from the pinned region decompilation step.

Before change:

internal unsafe byte[] GenerateMetadata(int eventId, string eventName, long keywords, uint level, uint version, EventOpcode opcode, EventParameterInfo[] parameters)
{
	byte[] array = null;
	bool flag = false;
	try
	{
		uint num = (uint)(24 + (eventName.Length + 1) * 2);
		uint num2 = 0u;
		uint num3 = num;
		if (parameters.Length == 1 && parameters[0].ParameterType == typeof(EmptyStruct))
		{
			parameters = Array.Empty<EventParameterInfo>();
		}
		EventParameterInfo[] array2 = parameters;
		foreach (EventParameterInfo eventParameterInfo in array2)
		{
			if (!eventParameterInfo.GetMetadataLength(out var size))
			{
				flag = true;
				break;
			}
			num += size;
		}
		if (flag)
		{
			num = num3;
			num2 = 4u;
			EventParameterInfo[] array3 = parameters;
			foreach (EventParameterInfo eventParameterInfo2 in array3)
			{
				if (!eventParameterInfo2.GetMetadataLengthV2(out var size2))
				{
					parameters = Array.Empty<EventParameterInfo>();
					num = num3;
					num2 = 0u;
					flag = false;
					break;
				}
				num2 += size2;
			}
		}
		uint num4 = ((opcode != 0) ? 6u : 0u);
		uint num5 = ((num2 != 0) ? (num2 + 5) : 0u);
		uint num6 = num5 + num4;
		uint num7 = num + num6;
		array = new byte[num7];
		fixed (byte* ptr = array)
		{
			uint offset = 0u;
			WriteToBuffer(ptr, num7, ref offset, (uint)eventId);
			try
			{
				fixed (char* src = eventName)
				{
					WriteToBuffer(ptr, num7, ref offset, (byte*)src, (uint)((eventName.Length + 1) * 2));
				}
			}
			finally
			{
			}
			WriteToBuffer(ptr, num7, ref offset, keywords);
			WriteToBuffer(ptr, num7, ref offset, version);
			WriteToBuffer(ptr, num7, ref offset, level);
			if (flag)
			{
				WriteToBuffer(ptr, num7, ref offset, 0);
			}
			else
			{
				WriteToBuffer(ptr, num7, ref offset, (uint)parameters.Length);
				EventParameterInfo[] array4 = parameters;
				foreach (EventParameterInfo eventParameterInfo3 in array4)
				{
					if (!eventParameterInfo3.GenerateMetadata(ptr, ref offset, num7))
					{
						return GenerateMetadata(eventId, eventName, keywords, level, version, opcode, Array.Empty<EventParameterInfo>());
					}
				}
			}
			if (opcode != 0)
			{
				WriteToBuffer(ptr, num7, ref offset, 1);
				WriteToBuffer(ptr, num7, ref offset, (byte)1);
				WriteToBuffer(ptr, num7, ref offset, (byte)opcode);
			}
			if (flag)
			{
				WriteToBuffer(ptr, num7, ref offset, num2);
				WriteToBuffer(ptr, num7, ref offset, (byte)2);
				WriteToBuffer(ptr, num7, ref offset, (uint)parameters.Length);
				EventParameterInfo[] array5 = parameters;
				foreach (EventParameterInfo eventParameterInfo4 in array5)
				{
					if (!eventParameterInfo4.GenerateMetadataV2(ptr, ref offset, num7))
					{
						return GenerateMetadata(eventId, eventName, keywords, level, version, opcode, Array.Empty<EventParameterInfo>());
					}
				}
				return array;
			}
			return array;
		}
	}
	catch
	{
		return null;
	}
}

After change:

internal unsafe byte[] GenerateMetadata(int eventId, string eventName, long keywords, uint level, uint version, EventOpcode opcode, EventParameterInfo[] parameters)
{
	byte[] array = null;
	bool flag = false;
	try
	{
		uint num = (uint)(24 + (eventName.Length + 1) * 2);
		uint num2 = 0u;
		uint num3 = num;
		if (parameters.Length == 1 && parameters[0].ParameterType == typeof(EmptyStruct))
		{
			parameters = Array.Empty<EventParameterInfo>();
		}
		EventParameterInfo[] array2 = parameters;
		foreach (EventParameterInfo eventParameterInfo in array2)
		{
			if (!eventParameterInfo.GetMetadataLength(out var size))
			{
				flag = true;
				break;
			}
			num += size;
		}
		if (flag)
		{
			num = num3;
			num2 = 4u;
			EventParameterInfo[] array3 = parameters;
			foreach (EventParameterInfo eventParameterInfo2 in array3)
			{
				if (!eventParameterInfo2.GetMetadataLengthV2(out var size2))
				{
					parameters = Array.Empty<EventParameterInfo>();
					num = num3;
					num2 = 0u;
					flag = false;
					break;
				}
				num2 += size2;
			}
		}
		uint num4 = ((opcode != 0) ? 6u : 0u);
		uint num5 = ((num2 != 0) ? (num2 + 5) : 0u);
		uint num6 = num5 + num4;
		uint num7 = num + num6;
		array = new byte[num7];
		fixed (byte* ptr = array)
		{
			uint offset = 0u;
			WriteToBuffer(ptr, num7, ref offset, (uint)eventId);
			fixed (char* src = eventName)
			{
				WriteToBuffer(ptr, num7, ref offset, (byte*)src, (uint)((eventName.Length + 1) * 2));
			}
			WriteToBuffer(ptr, num7, ref offset, keywords);
			WriteToBuffer(ptr, num7, ref offset, version);
			WriteToBuffer(ptr, num7, ref offset, level);
			if (flag)
			{
				WriteToBuffer(ptr, num7, ref offset, 0);
			}
			else
			{
				WriteToBuffer(ptr, num7, ref offset, (uint)parameters.Length);
				EventParameterInfo[] array4 = parameters;
				foreach (EventParameterInfo eventParameterInfo3 in array4)
				{
					if (!eventParameterInfo3.GenerateMetadata(ptr, ref offset, num7))
					{
						return GenerateMetadata(eventId, eventName, keywords, level, version, opcode, Array.Empty<EventParameterInfo>());
					}
				}
			}
			if (opcode != 0)
			{
				WriteToBuffer(ptr, num7, ref offset, 1);
				WriteToBuffer(ptr, num7, ref offset, (byte)1);
				WriteToBuffer(ptr, num7, ref offset, (byte)opcode);
			}
			if (flag)
			{
				WriteToBuffer(ptr, num7, ref offset, num2);
				WriteToBuffer(ptr, num7, ref offset, (byte)2);
				WriteToBuffer(ptr, num7, ref offset, (uint)parameters.Length);
				EventParameterInfo[] array5 = parameters;
				foreach (EventParameterInfo eventParameterInfo4 in array5)
				{
					if (!eventParameterInfo4.GenerateMetadataV2(ptr, ref offset, num7))
					{
						return GenerateMetadata(eventId, eventName, keywords, level, version, opcode, Array.Empty<EventParameterInfo>());
					}
				}
				return array;
			}
			return array;
		}
	}
	catch
	{
		return null;
	}
}

The code responsible for removing this redundant try-finally was extended to account for a potential additional leave ILAst instruction present in the single block of the try container.

I did not add any unit tests as I was unable to get the compiler to produce an assembly which triggered this bug. In case the assembly I am working with is necessary for easier analysis I have provided it in a zip archive below.

System.Private.CoreLib.zip

@ElektroKill
Copy link
Contributor Author

Any updates on this?

@siegfriedpammer siegfriedpammer merged commit 66e02e3 into icsharpcode:master May 18, 2023
@siegfriedpammer
Copy link
Member

LGTM thank you for the contribution... really sorry for taking so long!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants