SQL CLR assembly fails verification with “Unable to resolve token”
Recently we worked with a customer has an SQL CLR assembly. This customer decided to upgrade from SQL Server 2008 R2 to SQL Server 2012. But this assembly failed to register with SQL Server and he received the following error:
Msg 6218, Level 16, State 2, Line 11
CREATE ASSEMBLY for assembly 'test3.5' failed because assembly 'test3.5' failed verification. Check if the referenced assemblies are up-to-date and trusted (for external_access or unsafe) to execute in the database. CLR Verifier error messages if any will follow this message [ : Test.Test::my_func][mdToken=0x6000001][offset 0x00000000] Unable to resolve token.
First of all, SQL Server 2008 R2 and SQL 2012 use different versions of CLR. SQL 2008 R2 and below uses CLR 2.0/3.5 but SQL 2012 was upgraded to use CLR 4.0 and above.
What's interesting for this customer is that if they compile the assembly using 4.0 compiler, then they could register the assembly by using CREATE ASSEMBLY.
When we compared the IL generated, there is just one difference dealing with a local variable.
For the assembly compiled for 2.0/3.5, you see ".locals init ([0] void& pinned pData)". But for the assembly compiled for 4.0, you see ".locals init ([0] native int& pinned pData)". See a screenshot below with ildasm:
IL generated by 2.0 compiler
IL generated by 4.0 compiler
The IL in question is generated for the code like fixed (void* pData = &buf[1024]). Basically, the intention is to pin the memory for native call.
Cause
There are two changes in CLR that cause CREATE ASSEMBLY to fail. First, CLR 4.0 compiler no longer generate IL "void& pinned" for code like fixed (void* pData = &buf[1024]). Instead, it generates IL like .locals init ([0] native int& pinned pData). Additionally, CLR 4.0 peverify code is updated and no longer recognize that particular IL generated by CLR 2.0 compiler. When you CREATE ASSEMBLY in SQL Server, it has to do peverify to ensure the assembly passes verification. In this case, SQL 2012 uses 4.0 peverify code to verify the assembly compiled with 2.0 compiler. Therefore, it fails.
Solution
There are two solutions for this.
First option is to compile your assembly using CLR 4.0 compiler targeting 4.0 framework. This should be the best option because SQL 2012 uses CLR 4.0.
If you need your assembly to continue to target 2.0/3.5 framework, you can use 4.0 compiler but link 2.0 version of mscorlib.dll. Here is an example command.
C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe /nostdlib+ /noconfig /r:c:\Windows\Microsoft.NET\Framework\v2.0.50727\mscorlib.dll -unsafe -optimize -debug:pdbonly -target:library -out:test.dll test.cs
Repro
Step 1 Save the following code into test.cs
using System;
using System.Collections;
using System.Runtime.InteropServices;
using System.Text;
using System.Reflection;
using System.Reflection.Emit;
using Microsoft.Win32;
namespace Test
{
unsafe public class Test
{
unsafe public delegate void my_Delegate(ushort comp,
ushort func,
void* ptr,
uint length);
public static my_Delegate delegate1;
uint dataLength = 0;
public void my_func (String objectId,
uint component,
uint method,
ushort level,
String caption,
uint offset,
int length,
byte[] buf)
{
fixed (void* pData = &buf[1024])
{
delegate1((ushort)component,
(ushort)method,
pData,
dataLength);
}
}
}
}
Step 2 Compile the assembly
Compile using the following command
C:\Windows\Microsoft.NET\Framework\v3.5\csc.exe -unsafe -optimize -debug:pdbonly -target:library -out:test3.5.dll test.cs
Step 3: CREATE ASSEMBLY
If you "create assembly asem from 'C:\repro2\test3.5.dll' with permission_set=unsafe", you will receive the above error.
Step 4: solution and workaround
But the following two commands won't result in errors
C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe -unsafe -optimize -debug:pdbonly -target:library -out:test4.0.dll test.cs
C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe /nostdlib+ /noconfig /r:c:\Windows\Microsoft.NET\Framework\v2.0.50727\mscorlib.dll -unsafe -optimize -debug:pdbonly -target:library -out:test.dll test.cs
Jack Li | Senior Escalation Engineer | Microsoft SQL Server Support
Comments
- Anonymous
December 14, 2014
Jack, it seems you have a deep knowledge on .net:-)