在 2013 年 1 月 8 日http://technet.microsoft.com/en-us/security/bulletin/ms13-004应用 Microsoft 安全更新后,我们开始在构建服务器和本地的 CI 构建中遇到故障在我们的开发箱上运行测试。
我们得到一个System.InvalidProgramException: Common Language Runtime detected an invalid program。
这只发生在使用使用 Castle Windsor DynamicProxy 的 MSTest 运行测试时,尽管我不相信 DynamicProxy 在这里有问题。
下面是一个会生成异常的示例代码。
[TestMethod]
public void ShouldBeAbleToGenerateADynamicProxyForAnObject()
{
var container = new WindsorContainer();
container.Register(Component.For<TestInterceptor>());
container.Register(Component.For<ISomething>()
.Instance(new TestDependency("Called from test framework."))
.LifeStyle.Transient);
container.Register(Component.For<IService>()
.ImplementedBy<TestService>()
.Interceptors(InterceptorReference.ForType<TestInterceptor>())
.Anywhere
.LifeStyle.Transient);
var service = container.Resolve<IService>();
Assert.AreEqual("Called from test framework.", service.MethodNumberOne());
}
这会生成一个堆栈跟踪,最终在 DynamicProxy 中调用 MixinData 构造函数时引发异常:
Castle.DynamicProxy.MixinData..ctor(IEnumerable`1 mixinInstances) Castle.DynamicProxy.ProxyGenerationOptions.Initialize() Castle.DynamicProxy.Generators.InterfaceProxyWithTargetGenerator.GenerateCode(Type proxyTargetType, Type[] interfaces, ProxyGenerationOptions options) Castle.DynamicProxy.DefaultProxyBuilder。 CreateInterfaceProxyTypeWithTarget(Type interfaceToProxy, Type[] additionalInterfacesToProxy, Type targetType, ProxyGenerationOptions options) Castle.DynamicProxy.ProxyGenerator.CreateInterfaceProxyTypeWithTarget(Type interfaceToProxy, Type[] additionalInterfacesToProxy, Type targetType, ProxyGenerationOptions options) Castle.DynamicProxy.ProxyGenerator.CreateInterfaceProxyWithTarget(Type interfaceToProxy, Type [] additionalInterfacesToProxy,对象目标,ProxyGenerationOptions 选项,IInterceptor[] 拦截器)城堡。Windsor.Proxy.DefaultProxyFactory.Create(IKernel 内核,对象目标,ComponentModel 模型,CreationContext 上下文,Object[] constructorArguments)Castle.MicroKernel.ComponentActivator.DefaultComponentActivator.CreateInstance(CreationContext 上下文,ConstructorCandidate 构造函数,Object[] 参数)Castle.MicroKernel。 ComponentActivator.DefaultComponentActivator.CreateInstance(CreationContext context, ConstructorCandidate constructor, Object[] arguments) Castle.MicroKernel.ComponentActivator.DefaultComponentActivator.Instantiate(CreationContext context) Castle.MicroKernel.ComponentActivator.DefaultComponentActivator.InternalCreate(CreationContext context) Castle.MicroKernel.ComponentActivator.AbstractComponentActivator .Create(CreationContext context, 负担) Castle.MicroKernel.Lifestyle.AbstractLifestyleManager。CreateInstance(CreationContext context, Boolean trackedExternally) Castle.MicroKernel.Lifestyle.AbstractLifestyleManager.Resolve(CreationContext context, IReleasePolicy releasePolicy) Castle.MicroKernel.Handlers.DefaultHandler.ResolveCore(CreationContext context, Boolean requiresDecommission, Boolean instanceRequired, Burden&负担) Castle.MicroKernel。 Handlers.DefaultHandler.Resolve(CreationContext context, Boolean instanceRequired) Castle.MicroKernel.Handlers.AbstractHandler.Resolve(CreationContext context) Castle.MicroKernel.DefaultKernel.ResolveComponent(IHandler handler, Type service, IDictionary additionalArguments, IReleasePolicy policy) Castle.MicroKernel.DefaultKernel .Castle.MicroKernel.IKernelInternal.Resolve(类型服务,IDictionary 参数,IReleasePolicy 策略)Castle.MicroKernel.DefaultKernel。解决(类型服务,IDictionary 参数)Castle.Windsor.WindsorContainer.ResolveT ShouldBeAbleToGenerateADynamicProxyForAnObject() 在 TestCastleWindsorDynamicProxy.cs:第 34 行
我的第一个想法是 DynamicProxy 实际上在创建代理时在安全更新之后生成了无效的 IL,但据我所知,情况并非如此,因为它并没有那么远。我反编译了 Castle 并使用调试器单步执行,当通过如下调用从 ProxyGenerationOptions 类调用 MixinData 构造函数时,我看到根据堆栈跟踪抛出异常(注意:在上面的代码示例中 this.mixins 将是null 但这是预期的并且在被调用的构造函数的代码中正确处理):
this.mixinData = new Castle.DynamicProxy.MixinData(this.mixins);
在 MSTest 运行器之外,一切都按预期工作,我们的应用程序继续运行,并且在 xUnit 甚至使用 MSTest 的 TestDriven.NET 中运行单元测试时,它们不会生成异常。我们只看到此行为从 Visual Studio 运行测试或使用 TFS 和我们的 MSBuild 脚本进行自动化构建。
在我们向 Microsoft 提出支持请求之前,我想我们会问其他人是否经历过类似的事情或对可能导致我们问题的原因有任何想法?
编辑:今天早上经历了一些新事情后,我们发现这实际上似乎与我们正在使用的 Castle NuGet 包有关。当我们使用最新的 NuGet 包引用 Castle 时,我们最终会引用为.NET Client Profile 4编译的 Castle.Core 程序集,此引用是上述异常的原因(为什么?我还不完全确定)。更改对为 .NET 3.5 编译的版本的引用可确保测试在所有场景中都按预期通过。
编辑:经过更多挖掘之后,似乎确实存在一个链接问题(这让我们有理由回到微软,看看他们要说什么)公共语言运行时在单元测试中检测到一个无效的程序错误