We recently conducted an interview with Microsoft's .NET team based entirely upon questions submitted by our members. Part one included comments from the team on the security of the .NET platform. In this installment, we hear from members of the team about performance and obfuscation options.
Want to do this again?
Who is the most important person in the development universe? If you could ask that person five questions, what would they be? Participate in the next community interview by sending us an e-mail with your suggestions or posting them to our discussion.
Is reverse engineering worth the trouble?
Builder.com: Obviously .NET executables can be de-compiled into IL source. There's some concern about the possibility of reverse engineering IL source into a higher-level .NET language, like C#. Given that one attempting to do so knew the original language, is this possible? If so, does Microsoft have plans for any kind of obfuscator?
Eric Meijer, program manager on the common language runtime: On a general level, all code is de-compilable—whether it be C++, VB, .NET, or Java. As far as ease of de-compilation goes, Java byte code is just as easy, if not easier, to de-compile than .NET Framework MSIL. Earlier versions of VB weren't that much different. It's just the nature of software development.
In most cases, it shouldn't matter. For any mid-to-large software application, decompiling code doesn't bring much to the table. It could take you years to go through and really grasp the flow the code, what it's doing where, and more importantly, the rationale behind a particular algorithm. By the time you developed that understanding of your competitor's intellectual property, they'd be light years ahead in product development. Realistically, your time would be better spent just coding from scratch.
There are, however, some who want to go the extra mile and get that extra layer of protection that obfuscation provides. Microsoft decided not to ship an obfuscator with Visual Studio .NET or the .NET Framework so as not to be the one to kick off the inevitable arms race between obfuscators and de-compilers that we've seen with Java and other major programming languages over the years. There are, however, several third-party obfuscators available, among them are: LSW DotNet-IL-Obfuscator, Dotfuscator, and Demeanor for .NET.
C# vs. VB.NET performance
Builder.com: It's been rumored that C# compiles to moderately faster IL code than does VB.NET. I did a little rough and ready testing to check that using Beta 2, and my experiments bore this out. The VB.NET compiler seemed to insert a lot of spurious NOP codes in the IL it generated. Could you explain this?
Mahesh Prakriya, Lead Program Manager in the Common Language Runtime (CLR) team: One cannot draw general conclusions out of no ops in IL or by inspecting IL. JIT [the Just In Time compiler] could convert it to the same exact x86 in either case due to JIT optimizations. NOPs are not important; they have no effect on the code that is ultimately generated.
There is no architectural reason why C# will be any faster or slower than VB when they do the same thing. But VB supports a different set of features and semantics (dynamic typing of variables, arrays with nonzero lower bounds, implicit late binding, on-error goto error handling, etc.); thus, code that looks like it is equivalent, may not be. Looking at the IL with ILDASM will make this clear in any particular example.
I think it is fair to say, however, that after someone has gone and tuned an app in both languages, the difference is very likely to be small to nonexistent. In the end, some of the differences are inherent due to extra calls into and allocations due to the need for a runtime Microsoft.VisualBasic.dll, which C# doesn't have (nice to be a new language with no backward compatibility requirements).
Paul Vick, development lead for the Visual Basic .NET core compiler technology: The VB compiler generates extra NOPs in its code when the user specifies that they want maximally debuggable code (in the command-line case, this is equivalent to the switches /debug+ /optimize-). The NOPs are there to give nice stepping behavior in the debugger. For example, if you have an If...End If statement, there is no "code" for the End If line. However, it's nice to give the user a step on that line, so we insert a NOP and associate that NOP with the End If line in the PDB. If you either say that you don't want debuggable code (/debug-) or that you want optimized IL (/optimize+), we won't generate the NOPs.
If memory serves, there was a problem in Beta 2 and before where the default project template for VB projects had /optimize- even for retail configurations. Thus, unless you knew to go into the project properties for the retail configuration and set the right switch, you would still get the NOPs in retail code. This bug was found before [the final release] and fixed.
As to the larger question, it is possible, first of all, that the VC# compiler will produce better IL than the VB compiler in some situations and vice versa. This is an inescapable, given the fact that two different teams produced two different compilers. However, in most cases, the compilers will produce equivalent IL. And in those identified cases where one compiler produces better IL than the other, it was considered a bug in the less-optimal compiler and fixed.
Second, the two languages are different. If my memory serves, some of the differences noted in the Builder.com article stemmed directly from differences in the semantics of the two languages. Even though the syntax may look the same, the meaning may be different and might generate different IL. This is also inescapable. I would also point out that this works both ways; there are situations where VB produces faster code than VC#.
In the end, I would argue that one would be hard pressed to find an overall performance advantage between VC# and VB. There is no question that there are specific situations and programs that might favor one over the other. But no blanket statement is really possible.