Select is broken? (.NET 4)

Daniel pinged me today that he stumbled upon odd issue while trying to update Moq to use Castle DynamicProxy 2.2. I investigate a bit more and it appears to be one of these this-cannot-be-happening-select-is-broken situations.

When DynamicProxy tries to replicate an attribute on one method, its CustomAttributeData contains contradictory information. It happens only when running on .NET 4 (the method in question does not have the attribute in previous versions of BCL)

Select is broken

That’s the method in question in Reflector:

Reflector

Here’s simplified code sample that reproduces the issue:

var method = typeof(HtmlInputText).GetMethod("GetDesignModeState", BindingFlags.Instance | BindingFlags.NonPublic);
Debug.Assert(method != null, "method != null");
var attributes = CustomAttributeData.GetCustomAttributes(method);
Debug.Assert(attributes.Count == 1, "attributes.Length == 1");
var attribute = attributes[0];
Debug.Assert(attribute.Constructor.GetParameters().Length == attribute.ConstructorArguments.Count, "This fails");

 

Now – what am I missing? Is this really bug in BCL v4 or am I doing something wrong here?


Posted 04-15-2010 8:10 PM by Krzysztof Koźmic
Filed under:

[Advertisement]

Comments

Sampy wrote re: Select is broken? (.NET 4)
on 04-15-2010 5:07 PM

I'll open with the fact that while I do work at MS, I'm no expert at CLR internals. I'm no slouch but I'm not giving an official answer, just what I see based on the IL and some guessing...

Short answer: It's a security attribute and those are magic and thus seem to give inconsistent information when read in the manner you are reading them.

Long answer: If you dig into the implementation of CustomAttributeData.GetCustomAttributes, you'll see that it loads attributes in two ways and merges the results. First it loads all "custom" attributes. Then it loads all the security attributes. Since each is loaded differently, I decided to dig into the IL for this method and another method with a non-security attribute on it.

Look at the IL in ILDASM for the method in question:

.method family hidebysig newslot virtual

       instance class [mscorlib]System.Collections.IDictionary

       GetDesignModeState() cil managed

{

 .permissionset demand

            = {class 'System.Security.Permissions.SecurityPermissionAttribute, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' = {property bool 'Unrestricted' = bool(true)}}

 // Code size       33 (0x21)

(removing the rest)

Now look at another method on that same class that has a non-security attribute on it:

.method public hidebysig newslot virtual

       instance void  ApplyStyleSheetSkin(class System.Web.UI.Page page) cil managed

{

 .custom instance void [System]System.ComponentModel.EditorBrowsableAttribute::.ctor(valuetype [System]System.ComponentModel.EditorBrowsableState) = ( 01 00 02 00 00 00 00 00 )

 // Code size       64 (0x40)

(snip)

Behold! That looks like something that can read constructor arguements while the other one appears to be working in a totally different manner. My guess is that it's this difference that makes them appear inconsistent in the manner you are reading them in.

As far as a fix, you can try applying the same check for security attributes that the runtime does: "does it inherit from SecurityAttribute?" If it does, you can either skip it or use other means to try and determine how to create it.

I hope this helps. It was kind of a fun little voyage into the bowels of the CLR :)

About The CodeBetter.Com Blog Network
CodeBetter.Com FAQ

Our Mission

Advertisers should contact Brendan

Subscribe
Google Reader or Homepage

del.icio.us CodeBetter.com Latest Items
Add to My Yahoo!
Subscribe with Bloglines
Subscribe in NewsGator Online
Subscribe with myFeedster
Add to My AOL
Furl CodeBetter.com Latest Items
Subscribe in Rojo

Member Projects
DimeCasts.Net - Derik Whittaker

Friends of Devlicio.us
Red-Gate Tools For SQL and .NET

NDepend

SlickEdit
 
SmartInspect .NET Logging
NGEDIT: ViEmu and Codekana
LiteAccounting.Com
DevExpress
Fixx
NHibernate Profiler
Unfuddle
Balsamiq Mockups
Scrumy
JetBrains - ReSharper
Umbraco
NServiceBus
RavenDb
Web Sequence Diagrams
Ducksboard<-- NEW Friend!

 



Site Copyright © 2007 CodeBetter.Com
Content Copyright Individual Bloggers

 

Community Server (Commercial Edition)