Skip to content

Type.MakeGenericType and MethodInfo.MakeGenericMethod should be marked dangerous #890

@mthjones

Description

@mthjones

Use of these methods can allow for complete bypass of analyzers. For example, it's possible to make an object that to any outside observer is [Immutable] but has interior mutability with no auditing necessary.

Repro:

using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using static D2L.CodeStyle.Annotations.Objects;

namespace ImmutableBypass {
	[Immutable]
	public interface IImmutableInterface {
		ImmutableArray<string> Values { get; }
		void Oops();
	}

	[Immutable]
	public sealed class DefinitelyAnImmutableType<[Immutable] T> : IImmutableInterface
		where T : ICollection<string>, new()
	{
		public T SuperImmutableProperty { get; } = new T();
		public ImmutableArray<string> Values => SuperImmutableProperty.ToImmutableArray();
		
		public void Oops() {
			SuperImmutableProperty.Add( Guid.NewGuid().ToString() );
		}
	}

	public static class Program {
		public static void Main( string[] args ) {
			IImmutableInterface immutableObj = CreateImmutableObject();

			Console.WriteLine( immutableObj.Values.Length ); // => 0

			immutableObj.Oops();

			Console.WriteLine( immutableObj.Values.Length ); // => 1
		}

		private static IImmutableInterface CreateImmutableObject() {
			Type immutableType = typeof( DefinitelyAnImmutableType<> ).MakeGenericType( typeof( List<string> ) );
			return (IImmutableInterface)Activator.CreateInstance( immutableType );
		}
	}
}

(note: checking that constraints are immutable could also help, but also potentially possible to bypass by just doing an is/as cast at runtime)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions