jjzjj

c# - finally block when 后编译器生成无限循环

coder 2024-05-21 原文

我使用的是针对 .Net 4.6.2 的标准 VS2015 编译器。

编译器在 finally block 失败后发出无限循环。

一些例子:

调试:

IL_0000: nop
.try
{
    IL_0001: nop
    IL_0002: nop
    IL_0003: leave.s IL_000c
} // end .try
finally
{
    IL_0005: nop
    IL_0006: br.s IL_000a
    // loop start (head: IL_000a)
        IL_0008: nop
        IL_0009: nop
        IL_000a: br.s IL_0008
    // end loop
} // end handler
// loop start (head: IL_000c)
    IL_000c: br.s IL_000c
// end loop

发布:

  .try
    {
        IL_0000: leave.s IL_0004
    } // end .try
    finally
    {
        // loop start
            IL_0002: br.s IL_0002
        // end loop
    } // end handler
    // loop start (head: IL_0004)
        IL_0004: br.s IL_0004
    // end loop

C#源代码

    private void _Simple()
    {
        try
        {

        }
        finally
        {
            for (;;) { }
        }
    }

正如您在 IL_000c 看到的那样是无限循环(由编译器生成)

好的,现在我给你看一个扩展的案例

调试:

IL_0000: nop
.try
{
    IL_0001: nop
    .try
    {
        IL_0002: nop
        IL_0003: nop
        IL_0004: leave.s IL_000d
    } // end .try
    finally
    {
        IL_0006: nop
        IL_0007: newobj instance void [mscorlib]System.Exception::.ctor()
        IL_000c: throw
    } // end handler
    // loop start (head: IL_000d)
        IL_000d: br.s IL_000d
    // end loop
} // end .try
finally
{
    IL_000f: nop
    IL_0010: newobj instance void [mscorlib]System.Exception::.ctor()
    IL_0015: throw
} // end handler

发布:

.try
{
    .try
    {
        IL_0000: leave.s IL_0008
    } // end .try
    finally
    {
        IL_0002: newobj instance void [mscorlib]System.Exception::.ctor()
        IL_0007: throw
    } // end handler
    // loop start (head: IL_0008)
        IL_0008: br.s IL_0008
    // end loop
} // end .try
finally
{
    IL_000a: newobj instance void [mscorlib]System.Exception::.ctor()
    IL_000f: throw
} // end handler

nested finally 后再次产生死循环,但second finally 后没有。 (IL_000d)

源 C#

    private void _DoubleFinallyWithThrowingNewException()
    {
        try
        {
            try
            {

            }
            finally
            {
                throw new Exception();
            }
        }
        finally
        {
            throw new Exception();
        }
    }

再一次,现在在 finally block 中调用的方法抛出了非显式异常。

调试:

IL_0000: nop
.try
{
    IL_0001: nop
    .try
    {
        IL_0002: nop
        IL_0003: nop
        IL_0004: leave.s IL_0010
    } // end .try
    finally
    {
        IL_0006: nop
        IL_0007: ldarg.0
        IL_0008: call instance void System.Reflection.Emit.FactoryTests::ThrowException()
        IL_000d: nop
        IL_000e: nop
        IL_000f: endfinally
    } // end handler

    IL_0010: nop
    IL_0011: leave.s IL_001d
} // end .try
finally
{
    IL_0013: nop
    IL_0014: ldarg.0
    IL_0015: call instance void System.Reflection.Emit.FactoryTests::ThrowException()
    IL_001a: nop
    IL_001b: nop
    IL_001c: endfinally
} // end handler

IL_001d: ret

发布:

    .try
{
    .try
    {
        IL_0000: leave.s IL_0010
    } // end .try
    finally
    {
        IL_0002: ldarg.0
        IL_0003: call instance void System.Reflection.Emit.FactoryTests::ThrowException()
        IL_0008: endfinally
    } // end handler
} // end .try
finally
{
    IL_0009: ldarg.0
    IL_000a: call instance void System.Reflection.Emit.FactoryTests::ThrowException()
    IL_000f: endfinally
} // end handler

IL_0010: ret

C# 源代码

    private void ThrowException()
    {
        throw new Exception();
    }

    private void _DoubleFinallyWithThrowingNewExceptionNotInline()
    {
        try
        {
            try
            {

            }
            finally
            {
                ThrowException();
            }
        }
        finally
        {
            ThrowException();
        }
    }

为什么first unreachable finally block后会产生死循环?

为什么没有生成EndFinally OpCode?

@编辑1

在 Release模式下添加了一些 msil。

@编辑2

添加非空尝试异常的示例

元数据 .maxStack 变量设置为 1,现有的 .local 变量有点困惑 - 没有代码与此变量相关联。

调试:

.maxstack 1
.locals init (
    [0] object someVar,
    [1] valuetype [mscorlib]System.DateTime
)

IL_0000: nop
.try
{
    IL_0001: nop
    .try
    {
        IL_0002: nop
        IL_0003: ldarg.0
        IL_0004: call instance void System.Reflection.Emit.FactoryTests::ThrowException()
        IL_0009: nop
        IL_000a: nop
        IL_000b: leave.s IL_0014
    } // end .try
    finally
    {
        IL_000d: nop
        IL_000e: newobj instance void [mscorlib]System.Exception::.ctor()
        IL_0013: throw
    } // end handler
    // loop start (head: IL_0014)
        IL_0014: br.s IL_0014
    // end loop
} // end .try
finally
{
    IL_0016: nop
    IL_0017: newobj instance void [mscorlib]System.Exception::.ctor()
    IL_001c: throw
} // end handler

前面的对象[0]已经被跳过,但是DateTime还在。 发布:

.maxstack 1
.locals init (
    [0] valuetype [mscorlib]System.DateTime
)

.try
{
    .try
    {
        IL_0000: ldarg.0
        IL_0001: call instance void System.Reflection.Emit.FactoryTests::ThrowException()
        IL_0006: leave.s IL_000e
    } // end .try
    finally
    {
        IL_0008: newobj instance void [mscorlib]System.Exception::.ctor()
        IL_000d: throw
    } // end handler
    // loop start (head: IL_000e)
        IL_000e: br.s IL_000e
    // end loop
} // end .try
finally
{
    IL_0010: newobj instance void [mscorlib]System.Exception::.ctor()
    IL_0015: throw
} // end handler`

C#:

private void _ExceptionLeaveReplacementAtFinallyAfterFinallyNonEmpty()
    {
        try
        {
            try
            {
                ThrowException();
            }
            finally
            {
                throw new Exception();
            }
            object someVar = DateTime.Now.GetHashCode();
        }
        finally
        {
            throw new Exception();
        }
    }

或者(Msil 相同):

    private void _ExceptionLeaveReplacementAtFinallyAfterFinallyNonEmpty()
    {
        try
        {
            try
            {
                ThrowException();
            }
            finally
            {
                throw new Exception();
            }
        }
        finally
        {
            throw new Exception();
        }
        object someVar = DateTime.Now.GetHashCode();

最佳答案

这是设计使然。只要你不能到达那个无限循环:-)
感谢您报告此问题!!!

=== 更长的版本:

当“finally”没有终止(包含抛出或无限循环)时,try 语句之后的代码从语言预期中变得不可访问。因为它是不可访问的,所以它允许没有任何代码,即使,例如,该方法需要返回一个值。
事实上,由于通常在正常代码中存在的各种不变量在无法访问的代码中没有强制执行,因此编译器会防御性地删除无法访问的代码,即使它存在。这不仅仅是一种优化,它通常是正确性所必需的。与其防止/检测/修复无法访问的代码中的违规行为,不如将其删除更干净。

现在,IL 规范要求“离开”操作码指向有效的目标指令。特别是它不关心分支是否被非终止的 finally 阻塞。但是我们没有任何有效的代码可以指向,所以我们需要注入(inject)一段“登陆”的代码。它必须很小。我们也知道它永远无法到达,但它也不能危及该方法已经建立的静态正确性。

无限循环就是这样的最小代码段。
顺便说一句,另一种可能性是“抛出空值”,但历史上使用了无限循环。

不,NOP 不会起作用,因为它会使下一条指令验证器可达,这可能会导致违反其他 IL 规则,例如“不要丢弃到方法的末尾,必须使用 ret”。

关于c# - finally block when 后编译器生成无限循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40182734/

有关c# - finally block when 后编译器生成无限循环的更多相关文章

  1. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

    我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

  2. ruby - 树顶语法无限循环 - 2

    我脑子里浮现出一些关于一种新编程语言的想法,所以我想我会尝试实现它。一位friend建议我尝试使用Treetop(Rubygem)来创建一个解析器。Treetop的文档很少,我以前从未做过这种事情。我的解析器表现得好像有一个无限循环,但没有堆栈跟踪;事实证明很难追踪到。有人可以指出入门级解析/AST指南的方向吗?我真的需要一些列出规则、常见用法等的东西来使用像Treetop这样的工具。我的语法分析器在GitHub上,以防有人希望帮助我改进它。class{initialize=lambda(name){receiver.name=name}greet=lambda{IO.puts("He

  3. ruby-on-rails - 在 Ruby 中循环遍历多个数组 - 2

    我有多个ActiveRecord子类Item的实例数组,我需要根据最早的事件循环打印。在这种情况下,我需要打印付款和维护日期,如下所示:ItemAmaintenancerequiredin5daysItemBpaymentrequiredin6daysItemApaymentrequiredin7daysItemBmaintenancerequiredin8days我目前有两个查询,用于查找maintenance和payment项目(非排他性查询),并输出如下内容:paymentrequiredin...maintenancerequiredin...有什么方法可以改善上述(丑陋的)代

  4. ruby - 在 jRuby 中使用 'fork' 生成进程的替代方案? - 2

    在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',

  5. ruby - 如何使用 Ruby aws/s3 Gem 生成安全 URL 以从 s3 下载文件 - 2

    我正在编写一个小脚本来定位aws存储桶中的特定文件,并创建一个临时验证的url以发送给同事。(理想情况下,这将创建类似于在控制台上右键单击存储桶中的文件并复制链接地址的结果)。我研究过回形针,它似乎不符合这个标准,但我可能只是不知道它的全部功能。我尝试了以下方法:defauthenticated_url(file_name,bucket)AWS::S3::S3Object.url_for(file_name,bucket,:secure=>true,:expires=>20*60)end产生这种类型的结果:...-1.amazonaws.com/file_path/file.zip.A

  6. ruby - RuntimeError(自动加载常量 Apps 多线程时检测到循环依赖 - 2

    我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("

  7. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

  8. ruby-on-rails - Ruby on Rails - 为文本区域和图片生成列 - 2

    我是Rails的新手,所以请原谅简单的问题。我正在为一家公司创建一个网站。那家公司想在网站上展示它的客户。我想让客户自己管理这个。我正在为“客户”生成一个表格,我想要的三列是:公司名称、公司描述和Logo。对于名称,我使用的是name:string但不确定如何在脚本/生成脚手架终端命令中最好地创建描述列(因为我打算将其设置为文本区域)和图片。我怀疑描述(我想成为一个文本区域)应该仍然是描述:字符串,然后以实际形式进行调整。不确定如何处理图片字段。那么……说来话长:我在脚手架命令中输入什么来生成描述和图片列? 最佳答案 对于“文本”数

  9. C# 到 Ruby sha1 base64 编码 - 2

    我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha

  10. ruby-on-rails - 如何生成传递一些自定义参数的 `link_to` URL? - 2

    我正在使用RubyonRails3.0.9,我想生成一个传递一些自定义参数的link_toURL。也就是说,有一个articles_path(www.my_web_site_name.com/articles)我想生成如下内容:link_to'Samplelinktitle',...#HereIshouldimplementthecode#=>'http://www.my_web_site_name.com/articles?param1=value1¶m2=value2&...我如何编写link_to语句“alàRubyonRailsWay”以实现该目的?如果我想通过传递一些

随机推荐