GetType() can lie?

C#Types

C# Problem Overview


Based on the following question asked a few days ago in SO: GetType() and polymorphism and reading Eric Lippert's answer, I started thinking if making GetType() not be virtual really ensured that an object could not lie about its Type.

Specifically, Eric's answer states the following:

> The framework designers are not going to add an incredibly dangerous feature such as allowing an object to lie about its type merely to make it consistent with three other methods on the same type.

Now the question is: can I make an object that does lie about its type without it being immediately obvious? I may be profoundly wrong here and I'd love clarification if that is the case, but consider the following code:

public interface IFoo
{
    Type GetType();
}

And the following two implementations of said interface:

public class BadFoo : IFoo
{
    Type IFoo.GetType()
    {
        return typeof(int);
    }
}

public class NiceFoo : IFoo
{
}

Then if you run the following simple program:

static void Main(string[] args)
{
    IFoo badFoo = new BadFoo();
    IFoo niceFoo = new NiceFoo();
    Console.WriteLine("BadFoo says he's a '{0}'", badFoo.GetType().ToString());
    Console.WriteLine("NiceFoo says he's a '{0}'", niceFoo.GetType().ToString());
    Console.ReadLine();
}

Sure enough badFoo outputs an erroneous Type.

Now I don't know if this has any serious implications based on Eric describing this behavior as an "incredibly dangerous feature", but could this pattern pose a credible threat?

C# Solutions


Solution 1 - C#

Nice question! The way I see it, you could only really mislead a fellow developer if GetType was virtual on object, which it isn't.

What you did is akin to shadowing GetType, like this:

public class BadFoo
{
    public new Type GetType()
    {
        return typeof(int);
    }
}

with this class (and using the sample code from the MSDN for the GetType() method) you could indeed have:

int n1 = 12;
BadFoo foo = new BadFoo();

Console.WriteLine("n1 and n2 are the same type: {0}",
                  Object.ReferenceEquals(n1.GetType(), foo.GetType()));	
// output: 
// n1 and n2 are the same type: True

so, yikes, you've successfully lied, right? Well, yes and no... Consider that using this as an exploit would mean using your BadFoo instance as an argument to a method somewhere, that expects likely an object or a common base type for a hierarchy of objects. Something like this:

public void CheckIfInt(object ob)
{
	if(ob.GetType() == typeof(int))
	{
		Console.WriteLine("got an int! Initiate destruction of Universe!");
	}
	else
	{
		Console.WriteLine("not an int");
	}
}

but CheckIfInt(foo) prints "not an int".

So, basically (back to your example), you could really only exploit your "lying type" with code that someone wrote against your IFoo interface, which is very explicit about the fact that it has a "custom" GetType() method.

Only if GetType() was virtual on object you would be able to craft a "lying" type that could be used with methods like CheckIfInt above to create havoc in libraries written by someone else.

Solution 2 - C#

There are two ways of being sure about the Type:

  1. Use typeof on the Type which can't be overloaded

    > IFoo badFoo = new BadFoo(); > IFoo niceFoo = new NiceFoo(); >
    > Console.WriteLine("BadFoo says he's a '{0}'", badFoo.GetType().ToString()); > Console.WriteLine("NiceFoo says he's a '{0}'", niceFoo.GetType().ToString()); >
    > Console.WriteLine("BadFoo really is a '{0}'", typeof(BadFoo)); > Console.WriteLine("NiceFoo really is a '{0}'", typeof(NiceFoo)); > Console.ReadLine();

  2. Cast the instance to an object and call the GetType() Method

    > IFoo badFoo = new BadFoo(); > IFoo niceFoo = new NiceFoo(); >
    > Console.WriteLine("BadFoo says he's a '{0}'", badFoo.GetType().ToString()); > Console.WriteLine("NiceFoo says he's a '{0}'", niceFoo.GetType().ToString()); >
    > Console.WriteLine("BadFoo really is a '{0}'", ((object)badFoo).GetType()); > Console.WriteLine("NiceFoo really is a '{0}'", ((object)niceFoo).GetType()); > Console.ReadLine();

Solution 3 - C#

No, you can't make GetType lie. You are only introducing a new method. Only code that are aware of this method will call it.

You cannot for example make third-party or framework code call your new GetType method instead of the real one, since that code does not know that your method exists and will therefore never call it.

You can however confuse your own developers with such a declaration. Any code that is compiled with your declaration and that use parameters or variables typed as IFoo or any type derived from that will indeed use your new method instead. But since that only affects your own code it does not really impose a "threat".

If you do want to provide a custom type description for a class this should be done using a Custom Type Descriptor, perhaps by annotating your class with a TypeDescriptionProviderAttribute. This can be useful in some situations.

Solution 4 - C#

Well, actually there is already a type which can lie in GetType: any nullable type.

This code:

int? x = 0; int y = 0;
Console.WriteLine(x.GetType() == y.GetType());

outputs True.


Actually, it's not the int? who is lying, just implicit cast to object turns int? into a boxed int. But nevertheless you cannot tell int? from int with GetType().

Solution 5 - C#

I don't think it will, since every library code that calls GetType will declare the variable as 'Object' or as a Generic type 'T'

The following code:

    public static void Main(string[] args)
    {
        IFoo badFoo = new BadFoo();
        IFoo niceFoo = new NiceFoo();
        PrintObjectType("BadFoo", badFoo);
        PrintObjectType("NiceFoo", niceFoo);
        PrintGenericType("BadFoo", badFoo);
        PrintGenericType("NiceFoo", niceFoo);
    }

    public static void PrintObjectType(string actualName, object instance)
    {
        Console.WriteLine("Object {0} says he's a '{1}'", actualName, instance.GetType());
    }

    public static void PrintGenericType<T>(string actualName, T instance)
    {
        Console.WriteLine("Generic Type {0} says he's a '{1}'", actualName, instance.GetType());
    }

prints:

> Object BadFoo says he's a 'TypeConcept.BadFoo' > > Object NiceFoo says he's a 'TypeConcept.NiceFoo' > > Generic Type BadFoo says he's a 'TypeConcept.BadFoo' > > Generic Type NiceFoo says he's a 'TypeConcept.NiceFoo'

The only time this kind of code will result in bad scenario's is in your own code, where you declare the parameter type as IFoo

    public static void Main(string[] args)
    {
        IFoo badFoo = new BadFoo();
        IFoo niceFoo = new NiceFoo();
        PrintIFoo("BadFoo", badFoo);
        PrintIFoo("NiceFoo", niceFoo);
    }

    public static void PrintIFoo(string actualName, IFoo instance)
    {
        Console.WriteLine("IFoo {0} says he's a '{1}'", actualName, instance.GetType());
    }

> IFoo BadFoo says he's a 'System.Int32' > > IFoo NiceFoo says he's a 'TypeConcept.NiceFoo'

Solution 6 - C#

Worst that can happen as far as I can tell is misleading innocent programmers who happen to use the poisoned class, for example:

Type type = myInstance.GetType();
string fullName = type.FullName;
string output;
if (fullName.Contains(".Web"))
{
    output = "this is webby";
}
else if (fullName.Contains(".Customer"))
{
    output = "this is customer related class";
}
else
{
    output = "unknown class";
}

If myInstance is instance of a class such as you describe in the question, it will just be treated as unknown type.

So my answer is no, can't see any real threat here.

Solution 7 - C#

You have some options if you want to play safe against that kind of hack:

Cast to object first

You can call the original GetType() method by first casting the instance to an object:

 Console.WriteLine("BadFoo says he's a '{0}'", ((object)badFoo).GetType());

results in:

BadFoo says he's a 'ConsoleApplication.BadFoo'

Use template method

Using this template method will also give you the real type:

static Type GetType<T>(T obj)
{
    return obj.GetType();
}

GetType(badFoo);

Solution 8 - C#

There is a difference between object.GetType and IFoo.GetType. GetType is called at compile time on not known objects, an not on Interfaces. In your example, with output badFoo.GetType it is expected bahaviour, because you overload the method. Only thing is, that other programmers can get confused of this behaviour.

But if you use typeof() it will output that the type is the same, and you can't overwrite typeof().

Also the programmer can see at compile time, which method GetType he invokes.

So to your question: This pattern can not pose a credible threat, but it is also not best style of coding.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionInBetweenView Question on Stackoverflow
Solution 1 - C#Paolo FalabellaView Answer on Stackoverflow
Solution 2 - C#Johannes WanzekView Answer on Stackoverflow
Solution 3 - C#Mårten WikströmView Answer on Stackoverflow
Solution 4 - C#VladView Answer on Stackoverflow
Solution 5 - C#MoeriView Answer on Stackoverflow
Solution 6 - C#Shadow Wizard Says No More WarView Answer on Stackoverflow
Solution 7 - C#huysentruitwView Answer on Stackoverflow
Solution 8 - C#bpoissView Answer on Stackoverflow