AccessViolationException when accessing a mustoverride property in a class library
Asked Answered
M

1

11

This is a little complex, but I'll try and explain clearly.

I have a class library for common code components; and I tried to make some common ConfigurationHandler base classes, to simplify creating custom configuration sections, collections and elements.

What I've ended up with is:

The ConfigurationSectionBase class is generic, taking TConfElementCollection As {ConfigurationElementCollection, New} as a type constraint.

This ConfigurationSectionBase class contains a Public MustOverride Property Collection As TConfElementCollection.

The idea is that in the project using the class library, they simply have to override the collection and decorate it with the <ConfigurationProperty("CollectionName")> attribute, e.g:

<ConfigurationProperty("CollectionName")>
Public Overrides Property Collection As DerivedConfigurationElementCollection
    Get
        Return TryCast(Me("CollectionName"), DerivedConfigurationElementCollection)
    End Get
    Set(value As DerivedConfigurationElementCollection)
        Me("CollectionName") = value
    End Set
End Property

This was working fine - in the using application I could create the section, then in my config handler class I could call

Dim section As DerivedSection = (TryCast(Config.GetSection("DerivedSection"), DerivedSection))
Dim coll as DerivedConfigurationElementCollection = section?.Collection

My next thought, then, was why not abstract the Config Handler class also, and move that into a base class?

This proved more complex, but I ended up with the following code in a ConfigurationHandlerBase class in the DLL:

Protected Function GetCollection(Of TCollection As ConfigurationElementCollection, TSection As {ConfigurationSectionBase(Of TCollection), New})(sectionName as String) As TCollection
    Dim s As TSection = (TryCast(Config.GetSection(sectionName), TSection))
    Return s?.Collection ' AccessViolationException is thrown on this line

To try and diagnose the problem, I made a String property in the same manner as the Collection (MustOverride in the ConfigurationSectionBase class in the DLL , overridden in the using application), then tried accessing that from the class library - and again, the same issue.

So I think the issue is something to do with MustOverride and the DLL code not recognising that the Derived class has overridden the Property.

If I return the TSection from the DLL method instead, then access the Collection property in the application that uses the DLL; I can access the Collection fine.

The weird thing is, If I put a breakpoint in, Visual Studio will quite happily show me the contents of the Collection property, without throwing any Exceptions.

Also, if I replace (TryCast(Config.GetSection(sectionName), TSection)) with new TSection(), I still get an AccessViolationException - so it's nothing to do with the fact that I'm accessing the Config File, as far as I can see.

Has anyone come across this before; or what could my next steps be for troubleshooting this Exception?

Meris answered 16/2, 2018 at 10:14 Comment(2)
@HansPassant see dropbox.com/s/ios84hb46jul649/Projects.zip?dl=0Meris
Looks like a compiler or jitter bug on the null conditional operator with generics (haven't looked closely at which one yet). Replace Dim coll As TCollection = s?.Collection with Dim coll As TCollection = IIf(s Is Nothing, Nothing, s.Collection) and the problem disappears. Of course, if the compiler was working correctly these statements should be equivalent.Arbitrary
M
9

You are a victim of a vb.net compiler code generation bug, it mangles the code for the ConfigurationHandlerBase.GetCollection() method. It inappropriately optimizes the property getter call for the Collection property, using a constrained call. Easiest way to see it is to run PEVerify.exe on the TestCollection.dll assembly, albeit that the error message looks misleading to me:

[IL]: Error: [C:\temp\temp\TestClassLibrary\TestClassLibrary\bin\Debug\testclasslibrary.dll : TestClassLibrary.ConfigurationHandlerBase`1[TDerivedConfigHandler]::GetCollection[TCollection,TSection]][offset 0x00000024] The 'this' argument to a constrained call must have ByRef type. 1 Error(s) Verifying testclasslibrary.dll

Searching for the error message however lands you on this github.com issue. Marked as fixed 3 months ago, I think it was this SO question that got it repaired. It isn't always obvious when such fixes make it to our machines. Not today.

The workaround proposed in the github issue does not appear to be effective. Simplest workaround I see is to avoid the elvis operator and get back to basics, rewrite:

   Dim coll As TCollection = s?.Collection
   Return coll

To:

   If s Is Nothing Then return Nothing Else Return s.Collection
Mothering answered 21/2, 2018 at 11:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.