我的团队正在尝试查找.NET中出现错误消息的位置windows service,该服务封装了一个由Microsoft构建并驻留在我们的服务器上的Web服务,以支持我们使用的业务产品.微软亲自告诉我们,我们收到的错误实际上是他们的错误之一,但他们无法确定它发生的地点或原因.这是一个关键的业务流程,给我们的团队带来了很多心痛.
就我们所知,这个错误是随机发生的,并且没有我们可以通过查看堆栈跟踪发现的共同点.堆栈跟踪的最后一次调用是我们的方法调用,试图从服务中读取响应,没有提示我们在对服务的方法调用中发生错误的位置或原因.Microsoft Windows服务未将任何错误记录到事件查看器.
我们希望通过查找正在抛出的文字错误消息字符串来跟踪此错误的来源.如果我们可以识别生成此错误的方法调用,我们可以更接近于缩小如何解决此错误.
虽然我们无法访问此服务的源代码,但我们可以使用IL反汇编程序(idlasm.exe)查看IL.我已经为一些程序集转储了IL,但它们不是文字字符串.
是否可以在IL中找到文字字符串?我认为它是编码的 - 我只是不了解IL以确定在哪里查看,或者如何识别IL中的字符串.如果它不作为带有IL中的方法的文字字符串存在,并存储在资源中,那么还可以找到错误消息?
堆栈跟踪,替换了应用程序名称.
Raw Error: There is insufficient memory to execute this function.
This can be caused by recursive function calls. Contact your system administrator.
at System.Web.Services.Protocols.SoapHttpClientProtocol.ReadResponse(SoapClientMessage message, WebResponse response, Stream responseStream, Boolean asyncCall)
at System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke(String methodName, Object[] parameters)
at Product.DoSomething() in c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\root\da35f853\f48bba34\App_WebReferences.jygjwt-a.0.cs:line 701
at Product.DoSomething() in E:\Sites\Example.com\App_Code\File.vb:line 1105
at ASP.shop_checkout_aspx.ProcessCheckout() in E:\Sites\Example.com\processcheckout.aspx:line 546
Run Code Online (Sandbox Code Playgroud)
一些附注是在此错误消息时有足够的内存可用,并且当发生此错误时,对任何方法的每次后续调用都会返回相同的错误.它只会通过重新启动Microsoft服务来平息.
我们缩小了对我们网站使用的服务的每一次调用,但无法重现此消息.我们可以在生产中使用大约1000倍的流量来重载开发中的服务,并导致内存不足异常(通过消耗所有内存),但不会Can be导致"由递归函数调用引起的"消息.微软声称的Agian是他们的产品特别抛出的一个独特错误.
更新
我们设法在.etx文件中找到文字错误消息,如下所示:
// ÚÄÄÄÄÄÄÄÄÄ¿
// ÚÄ´ STACK ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ …Run Code Online (Sandbox Code Playgroud) 我正在使用Mono.Cecil编写一个小型IL编织应用程序,这需要我在IL级别上操作目标程序集.
我的问题很简单,但我仍然觉得这件事很混乱.这些ldfld和ldflda说明之间有什么实际区别?
我已经咨询了msdn,看来在ldfld获取字段的值时,ldflda获取字段的地址.好的......但是这意味着什么?我首先想到前者用于值类型(和字符串),后者用于引用类型,但我编译了一个C#片段并在Reflector中检查它,这证明我错了.
在C#编译器发出ldflda的时候ldfld,我找不到任何明显的模式,而我的搜索没有透露任何可以解释这一点的文章.那么何时使用ldflda而不是ldfld?
任何帮助将非常感谢.
我尝试使用以下策略为递归方法生成IL,首先我使用以下代码片段定义类型
private void InitializeAssembly(string outputFileName)
{
AppDomain appDomain = AppDomain.CurrentDomain;
AssemblyName assemblyName = new AssemblyName(outputFileName);
assemblyBuilder = appDomain.DefineDynamicAssembly(assemblyName,
AssemblyBuilderAccess.Save);
moduleBuilder = assemblyBuilder.DefineDynamicModule(outputFileName, outputFileName + ".exe");
typeBuilder = moduleBuilder.DefineType(typeName, TypeAttributes.Public);
methodBuilder = typeBuilder.DefineMethod("Main",
MethodAttributes.Static | MethodAttributes.Public,
typeof(void),
System.Type.EmptyTypes);
ilGen = methodBuilder.GetILGenerator();
}
Run Code Online (Sandbox Code Playgroud)
接下来,我开始为递归方法生成IL,如下所示.
MethodBuilder method = typeBuilder.DefineMethod(
“MethodName”,
MethodAttributes.Static | MethodAttributes.Public,
NodeTypeToDotNetType(func.RetType),
parameters);
ILGenerator ilOfMethod = method.GetILGenerator();
method.DefineParameter();
Run Code Online (Sandbox Code Playgroud)
为了在方法体内调用方法本身,我使用了以下构造,
ilOfMethod.Emit(OpCodes.Call, typeBuilder.GetMethod("MethodName", new System.Type[] {typeof(arg1),typeof(arg2),etc}));
Run Code Online (Sandbox Code Playgroud)
最后使用以下方法保存生成的组件.
private void SaveAssembly(string outputFileName)
{
ilGen.Emit(OpCodes.Ret);
typeBuilder.CreateType();
moduleBuilder.CreateGlobalFunctions();
assemblyBuilder.SetEntryPoint(methodBuilder);
assemblyBuilder.Save(outputFileName + ".exe");
}
Run Code Online (Sandbox Code Playgroud)
不幸的是,由于递归方法调用构造,在方法内部返回null,因此无效.这里的问题是方法内的递归调用(即ilOfMethod.Emit(OpCodes.Call, typeBuilder.GetMethod("MethodName", …
C#有一个条件运算符和IF语句,我怀疑条件运算符只是语法糖.因此在编译时它将与IF操作相同.
然而,他们没有(见下文),他们确实有不同的IL.试图绕过它,我的假设是,这是条件运算符得到的性能优化,因为它的范围有限.
想知道我的假设是否正确,也许还有更多内容?
同样在IF的IL中,有一些关于int值的检查(L_000c,L_000d,L_000f),我无法弄清楚其含义.这使我认为这是一个更强大的解决方案,因为IF的范围更广,代价是性能.
var result = "";
if (Environment.Is64BitOperatingSystem)
{
result = "Yes";
}
else
{
result = "No";
}
Console.WriteLine(result);
Run Code Online (Sandbox Code Playgroud)
条件运算符的代码(我意识到差异,但无论我如何改变它 - 分配给变量等......它几乎没有区别)
Console.WriteLine("Is the OS x64? {0}", Environment.Is64BitOperatingSystem ? "Yes" : "No");
Run Code Online (Sandbox Code Playgroud)
IL为IF
L_0001: ldstr ""
L_0006: stloc.0
L_0007: call bool [mscorlib]System.Environment::get_Is64BitOperatingSystem()
L_000c: ldc.i4.0
L_000d: ceq
L_000f: stloc.2
L_0010: ldloc.2
L_0011: brtrue.s L_001d
L_0013: nop
L_0014: ldstr "Yes"
L_0019: stloc.0
L_001a: nop
L_001b: br.s L_0025
L_001d: nop
L_001e: ldstr "No"
L_0023: stloc.0
L_0024: nop …Run Code Online (Sandbox Code Playgroud) 由于不了解值类型的变量实际上是什么,因此引用类型和值类型之间的差异通常会让初学者感到困惑.我们知道:
是否有可能检查每种变量以查看值或实际参考本身?引用是否存储为某种编码值?我知道引用可以通过值传递,所以我假设如此.
我认为这有助于新人了解他们,并且非常有趣.
今天我正在使用Entity Framework,我已经读过为C#创建的IL与以下代码的VB.NET不同:
VB.NET:
Dim ctx As New TravelEntities
Sub Main()
CallContext()
CallContext()
CallContext()
End Sub
Private Sub CallContext()
Dim someCustomer = From x In ctx.Customer
Where x.CustomerId.Equals(5)
Select x
Console.WriteLine(someCustomer.Count())
End Sub
Run Code Online (Sandbox Code Playgroud)
C#:
private static TravelEntities ctx = new TravelEntities();
static void Main(string[] args)
{
CallContext();
CallContext();
CallContext();
}
private static void CallContext()
{
var someCustomer = from x in ctx.Customer
where x.CustomerId.Equals(5)
select x;
Console.WriteLine(someCustomer.Count());
}
Run Code Online (Sandbox Code Playgroud)
他们产生以下IL:
VB:
.method private static void CallContext() cil managed
{
// Code size …Run Code Online (Sandbox Code Playgroud) 我试图运行出现的文档页面上的示例代码System.Reflection.Emit.LocalBuilder类,但它看来,调用LocalBuilder.SetLocalSymInfo(string, int, int)没有做任何事情,因为IL反汇编显示了这个作为IL的SampleAssembly.dll:
.method public static string Function1(int32 A_0) cil managed
{
// Code size 10 (0xa)
.maxstack 1
.locals init (string V_0,
int32 V_1)
IL_0000: ldarg.0
IL_0001: stloc.1
IL_0002: ldstr "string value"
IL_0007: stloc.0
IL_0008: ldloc.0
IL_0009: ret
} // end of method Example::Function1
Run Code Online (Sandbox Code Playgroud)
为什么不在Dissasembler中列出变量名(myString和myInt)?
环境信息:
编辑:正如我在评论中提到的,有一个SampleAssembly.pdb文件与SampleAssembly.dll文件一起生成.
我一直在使用LINQPad中的一些C#语句来理解发出的中间语言代码.
我首先尝试了以下代码:
var Container = new {Name = "James"};
Console.WriteLine(Container.Name);
Run Code Online (Sandbox Code Playgroud)
并且看到以下六行IL发射:
IL_0001: ldstr "James"
IL_0006: newobj <>f__AnonymousType0<System.String>..ctor
IL_000B: stloc.0
IL_000C: ldloc.0
IL_000D: callvirt <>f__AnonymousType0<System.String>.get_Name
IL_0012: call System.Console.WriteLine
Run Code Online (Sandbox Code Playgroud)
这是我所期望的,并且非常好地演示了匿名类型是如何只读/不可变的,因为没有set_Name属性.
接下来我尝试了这些陈述:
dynamic Container = new System.Dynamic.ExpandoObject();
Container.Name = "James";
Console.WriteLine(Container.Name);
Run Code Online (Sandbox Code Playgroud)
这会导致大量的IL被释放.我不会在这里粘贴它,但你可以在这个pastebin中找到它.
我理解在管理动态类型和ExpandoObject方面存在相当多的开销,但我不明白为什么看起来System.Console.WriteLine在这种情况下调用是通过内部反射来执行的.
IL_0072: ldstr "WriteLine"
....
IL_00BF: ldtoken System.Console
Run Code Online (Sandbox Code Playgroud)
在第一段代码中,在检索并存储属性之后,它是一个调用的单行IL语句System.Console.WriteLine.
那么为什么一个dynamic类型的呼叫需要额外的所有这些?
我有一些我写的自定义IL,它不会通过PEVerify.我得到的错误是
$ peverify foo.exe Microsoft (R) .NET Framework PE Verifier. Version 4.0.30319.17929 Copyright (c) Microsoft Corporation. All rights reserved. [IL]: Error: [Z:\virtualbox_shared\foo.exe : HelloWorld.Program::Main][offset 0x00000021] Stack height at all points must be determinable in a single forward scan of IL. 1 Error(s) Verifying foo.exe
然而,该程序将运行正常,没有任何例外.以下是相关方法的IL:
.method private static hidebysig
default void Main (string[] args) cil managed
{
// Method begins at RVA 0x2050
.entrypoint
// Code size 54 (0x36)
.maxstack 2
//custom IL
ldc.i4 1
ldc.i4 1
ceq
switch(first, second) …Run Code Online (Sandbox Code Playgroud) 因此,今天我使用ILSpy + dotPeek反映了一个使用ILSpy + dotPeek的仲裁.NET程序集,以便在我偶然发现这个奇怪的部分(虚拟示例)时更深入地了解IL代码的工作原理:
public class SomeBaseClass {
public SomeBaseClass(SomeType[] iExpectACollection) {
...
}
}
public class SomeDerivedClass {
public SomeDerivedClass(SomeType onlyOneInstance) {
SomeType[] collection;
if(onlyOneInstance != null)
collection = new SomeType[] { onlyOneInstance };
base.\u002Ector(collection);
}
}
Run Code Online (Sandbox Code Playgroud)
据我所看到的,派生类不调用摆在首位的基础构造,而是做一些事onlyOneInstance,并随后调用是基构造.
我的问题是:在完成一些工作后,是否可以在C#中显式调用基础构造函数?或者这只能在IL中使用?我知道它很容易在Java中使用super(),但是我从未在.NET中看到它.
编辑
我刚和老板谈过,他可以发布一些真实的图书馆代码(这是我们公司的内部代码之一):
**IL PART**
.method public hidebysig specialname rtspecialname
instance void .ctor (
string contextId,
class MyComp.NetStack.BufferManager bufferManager,
class MyComp.NetStack.TcpChannelQuotas quotas,
class [System]System.Security.Cryptography.X509Certificates.X509Certificate2 clientCertificate,
class [System]System.Security.Cryptography.X509Certificates.X509Certificate2[] clientCertificateChain,
class [System]System.Security.Cryptography.X509Certificates.X509Certificate2 serverCertificate,
class MyComp.NetStack.EndpointDescription endpoint, …Run Code Online (Sandbox Code Playgroud) il ×10
c# ×7
.net ×6
reflection ×2
vb.net ×2
.net-4.0 ×1
clr ×1
dynamic ×1
inheritance ×1
peverify ×1
verification ×1