Possible to detect use of enum.ToString()?

Does anyone know if it is possible to detect the use of an enum's "ToString()" method?
The reason I ask is because we have started obfuscating our code using Dotfuscator, and of course because that renames the enums, it plays merry hell with any use of enum.ToString()! It'd be great if FXCopy could detect such usage.
Also, I guess we'd need to detect enum.Parse() and other reflection-style access.
Any help would be much appreciated!
[460 byte] By [MatthewWatson] at [2008-3-6]
# 1

It's very easy to detect a call to Enum.ToString(). What exactly is the bad pattern you need to protect against, though? I don't think I understand, exactly, since in most cases, a rename wouldn't be relevant in IL for an enum member (since the underlying literal itself is usually emitted to IL, not the named enum member).



using System;

public enum Test { value = 1}

public class TestClass
{
public static void Main() { Console.WriteLine(Test.value.ToString());}
}

The code above didn't cause a possible issue that I could see. Can you provide the pattern that does? Or otherwise clear up my confusion?

Michael Fanning
VSTS Development: Code Analysis

MichaelFanning-MS at 2007-9-9 > top of Msdn Tech,Visual Studio Team System,Visual Studio Code Analysis and Code Metrics...
# 2
One example: I was writing some data to a text file to be parsed by a C++ program. I was writing the names of the enum values using enum.ToString(). But once I obfuscated the program, the text written to the file changed to "a", "b" etc, after the enum value names were renamed by Dotfuscator.

This of course broke the parsing done by the C++ program.

It was quite clear that was happening, because the unobfuscated version output the correct value and the obfuscated version - with no other changes - output "a", which was the name of the renamed enum value.

Here's a little test program that demonstrates the problem:


internal class Class1
{
enum TestEnum
{
TestEnumValue
}

[STAThread]
static void Main(string[] args)
{
Console.WriteLine( "Enum = " + TestEnum.TestEnumValue.ToString() );
}
}

The IL for the unobfuscated Main() looks like this, and prints "TestEnumValue":

.method private hidebysig static void Main(string[] args) cil managed
{
.custom instance void [mscorlib]System.STAThreadAttribute::.ctor()
.entrypoint
// Code Size: 27 byte(s)
.maxstack 2
L_0000: ldstr "Enum = "
L_0005: ldc.i4.0
L_0006: box ObfuscatedEnum.Class1/TestEnum
L_000b: call instance string [mscorlib]System.Enum::ToString()
L_0010: call string string::Concat(string, string)
L_0015: call void [mscorlib]System.Console::WriteLine(string)
L_001a: ret
}

The obfuscated version looks like this, and prints "a":

.method private hidebysig static void a(string[] A_0) cil managed
{
.custom instance void [mscorlib]System.STAThreadAttribute::.ctor()
.entrypoint
// Code Size: 27 byte(s)
.maxstack 2
L_0000: ldstr "Enum = "
L_0005: ldc.i4.0
L_0006: box a/a
L_000b: call instance string [mscorlib]System.Enum::ToString()
L_0010: call string string::Concat(string, string)
L_0015: call void [mscorlib]System.Console::WriteLine(string)
L_001a: ret
}

MatthewWatson at 2007-9-9 > top of Msdn Tech,Visual Studio Team System,Visual Studio Code Analysis and Code Metrics...
# 3
There are only two situations I can see where calling Enum.ToString() would cause a problem after obfuscation:

Where:

1. The enum value was displayed in the user interface
2. An external process outside of the Framework parsed the enum (such as above)

The first situation should be avoided by using localized versions of the enum. The second situation I would class as rare and I'm wondering if it really quantifies a rule to be written for it. Especially considering that in most situations if the developeer uses Framework methods to parse the string (ie Enum.Parse) then no problems would be encountered.

DavidM.Kean at 2007-9-9 > top of Msdn Tech,Visual Studio Team System,Visual Studio Code Analysis and Code Metrics...
# 4
I wasn't really looking for a rule for this to be build in to FXCop - rather, I was wondering if it would be possible to write my own rule.
You might think it would be a rare occurance, but two out of twelve applications had this problem - and finding it was a bit awkward!
The amount of time wasted for us makes a special in-house rule an attractive option for us!
(By the way, you can't assume that enum.Parse() would be ok, since different applications can end up writing the same value - "a" - for different enums, which makes parsing ambiguous.)
MatthewWatson at 2007-9-9 > top of Msdn Tech,Visual Studio Team System,Visual Studio Code Analysis and Code Metrics...
# 5
Ah. Well, it's fairly straightforward to write a rule that checks for a call to Enum.ToString(). Head to www.gotdotnet.com and go to the samples area. Set the product field to 'FxCop' and search. Look for a couple of custom rule samples I submitted. Both demonstrate parsing IL to examine call sites.

Let us know here if you have further questions.

Michael

MichaelFanning-MS at 2007-9-9 > top of Msdn Tech,Visual Studio Team System,Visual Studio Code Analysis and Code Metrics...
# 6
Will do - thanks!
MatthewWatson at 2007-9-9 > top of Msdn Tech,Visual Studio Team System,Visual Studio Code Analysis and Code Metrics...
# 7
Just to follow this up:
I used Michael's source code to solve the problem - thanks Michael!
I also had to add a rule to detect the boxing of enums, because you can pass an enum value to something like String.Format(), and Enum.ToString() will be called inside String.Format() in an undetectable way.
At the end of the day, it turned out that around 20% of our applications had issues with Enum.ToString(), mostly where some text for an exception message was being generated. So the rules were very useful for us!

MatthewWatson at 2007-9-9 > top of Msdn Tech,Visual Studio Team System,Visual Studio Code Analysis and Code Metrics...

Visual Studio Team System

Site Classified