标签: stack-overflow

在语言解释器中防止StackOverflow

F#作为一种语言非常适合编写语言解释器或编译器,但是,有一件事情让我们不知所措:StackOverflowException.

众所周知,无法捕获SO异常,无法从中恢复.防止这种异常的一种显而易见的技术是在你进行时计算堆栈的深度.开销,是的,但是可行,也许在每个功能中都没有必要.

使用F#,这种技术虽然没有带来太多好处.我们在解释器的动态生成表达式中大量使用尾调用优化技术.我们在SO异常中遇到的问题是:

  • 我们如何通知用户,而不是崩溃整个当前的AppDomain?
  • 如果我们计算堆栈深度,我们如何知道函数是TCO还是内联,所以我们不必计算?
  • 如果我们采用另一种方法(比如以给定的深度间隔检查堆栈本身),是否有任何(已知的)方法可以在不严重影响性能的情况下执行此操作?

只是增加堆栈大小不会有足够的帮助,我们希望给用户一个可记录的错误,最好是由调用应用程序捕获.为此,我们需要能够手动抛出异常,这使它可以捕获.但我们如何确定合适的时机?

更新:
Hans Passant在这里正确地提出了可预测性.但是,使用此DSL的程序员期望(某些)调用获得TCO,因此他们不希望有强大的堆栈限制.他们知道自己在做什么.尽管如此,他们的程序仍然需要能够优雅地消亡,至少在任何调用应用程序(即使用我们的库的C#程序)都不会受到损害的情况下.

.net stack-overflow compiler-construction f# tail-recursion

17
推荐指数
1
解决办法
389
查看次数

在C#中使用递归

在使用递归来避免堆栈溢出时是否有任何一般规则?

c# stack-overflow recursion

16
推荐指数
3
解决办法
2万
查看次数

使用WinDbg和ADPlus帮助捕获StackOverflowException

精简版

我想要一个ADPlus脚本,它将在第一次机会StackOverflowException上执行完全内存转储,然后清除任何内容,并忽略所有其他异常类型.

日志版本

在发布新的ASP.NET代码之后,我们开始获得间歇性的StackOverflowExceptions.我们已经寻找无限递归和自上次已知良好安装以来添加的修订版中的所有常见嫌疑人,并且找不到任何内容.该网站将运行长达一个小时,然后崩溃.

我们使用了WinDbg和SOS,并尝试使用ADPlus获取崩溃日志,使用以下命令:

adplus -crash -o D:\Crash -NoDumpOnFirst -iis
Run Code Online (Sandbox Code Playgroud)

-NoDumpOnFirst的原因是我们只能在繁忙的服务器上重现生产中的这个错误.为了对每个第一次机会异常执行minidump(嘿,它发生),调试器必须暂停IIS工作进程足够长时间写出一个16兆字节的文件,因此请求排队并且应用程序变得不稳定.因为这个错误可能需要长达一个小时才能让它变得难看,这是有问题的.

所以使用-NoDumpOnFirst,我得到一个转储文件,WinDbg输出这些线程:

PDB symbol for mscorwks.dll not loaded
ThreadCount: 69
UnstartedThread: 0
BackgroundThread: 69
PendingThread: 0
DeadThread: 0
Hosted Runtime: no
                                      PreEmptive   GC Alloc           Lock
       ID OSID ThreadOBJ    State     GC       Context       Domain   Count APT Exception
XXXX    1  c6c 000fa758  11808221 Disabled 3b49ee4c:3b49efe8 00120888     1 Ukn (Threadpool Worker)
XXXX    2 1294 000fd258      b220 Enabled  00000000:00000000 000df4e0     0 Ukn (Finalizer)
XXXX    3 1eb0 0011cdd0    80a220 Enabled  00000000:00000000 000df4e0     0 Ukn (Threadpool …
Run Code Online (Sandbox Code Playgroud)

asp.net stack-overflow windbg adplus

16
推荐指数
1
解决办法
6130
查看次数

16
推荐指数
4
解决办法
8万
查看次数

如何实现"无堆栈"解释语言?

我正在制作自己的类似Lisp的解释语言,我想做尾调优化.我想从C堆栈中释放我的解释器,这样我就可以管理自己从函数到函数的跳转以及我自己的堆栈魔法来实现TCO.(我真的不是指无堆栈本身,只是调用不向C堆栈添加帧的事实.我想使用我自己的堆栈,不会随着尾调用而增长).就像Stackless Python一样,不像Ruby或者......标准Python我猜.

但是,由于我的语言是Lisp派生词,所有对s表达式的评估目前都是以递归方式完成的(因为这是我想到的最明显的方式来做这种非线性,高度分层的过程).我有一个eval函数,每次遇到函数调用时都会调用Lambda :: apply函数.apply函数然后调用eval来执行函数体,依此类推.相互堆栈饥饿的非尾部C递归.我目前使用的唯一迭代部分是评估一系列连续的s表达式.

(defun f (x y)
    (a x y)) ; tail call! goto instead of call. 
             ; (do not grow the stack, keep return addr)

(defun a (x y)
    (+ x y))

; ...

(print (f 1 2)) ; how does the return work here? how does it know it's supposed to
                ; return the value here to be used by print, and how does it know
                ; how to continue execution here??
Run Code Online (Sandbox Code Playgroud)

那么,我如何避免使用C递归?或者我可以使用跳过c函数的某种goto吗?也许是longjmp?我真的不知道.请耐心等待,我主要是自编(Internet)教程.

lisp stack-overflow recursion stack interpreter

16
推荐指数
3
解决办法
2792
查看次数

如何避免递归函数的StackOverflowError

我正在编写一个函数,可以调用自己大约5000次.当然,我得到了一个StackOverflowError.有什么方法可以用相当简单的方式重写这段代码吗?:

void checkBlocks(Block b, int amm) {

    //Stuff that might issue a return call

    Block blockDown = (Block) b.getRelative(BlockFace.DOWN);
    if (condition) 
        checkBlocks(blockDown, amm);


    Block blockUp = (Block) b.getRelative(BlockFace.UP);
    if (condition) 
        checkBlocks(blockUp, amm);

    //Same code 4 more times for each side

}
Run Code Online (Sandbox Code Playgroud)

那么,我们可以称之为功能的深度有多大限制?

java stack-overflow

16
推荐指数
2
解决办法
1万
查看次数

应该是代码行的内存漏洞"printf("%s",argv [1]);" 被描述为堆栈溢出?

今天,我从Elance.com上做了一个简短的"C++技能测试".一个问题如下:

以下代码行的安全漏洞是什么:

printf("%s", argv[1]);

选项1:格式字符串

选项2:堆栈溢出 < - 这被Elance标记为正确答案

在最初几秒钟看到问题后(或自动使问题无效),用户被提供10秒钟来回答此问题.(还有另外两个明显不相关的答案,没有被Elance标记为正确答案.)

我正在寻找缓冲区溢出缓冲区溢出作为选项.

我本能地不喜欢答案堆栈溢出,因为在我10秒内我精神上使用了我认为是"Stack Overflow"标准定义:

在软件中,当堆栈指针超出堆栈限制时,会发生堆栈溢出.调用堆栈可能包含有限数量的地址空间,通常在程序开始时确定...

根据"Stack Overflow"的定义,在没有堆栈溢出的情况下完全可以实现缓冲区溢出 ; 只有当程序试图在调用程序的总堆栈分配之外写入时才会发生堆栈溢出(无论是由于缓冲区溢出,还是由于它是否是合法写入,例如为基于堆栈的变量分配内存过多而次).

我的10秒本能告诉我,"缓冲区溢出"是对上面有问题的代码行的更准确的描述 - 因为通常(根据我的经验),有足够的空字符('\0')通过RAM中的垃圾数据来填充,以避免在这种情况下实际的堆栈溢出,但实现中的缓冲区溢出似乎是合理可能的,甚至可能.(但是,这可能printf在这里读的垃圾可能会认为argc == 1,这样有没有用户提供的argv[1];如果argv[1]存在,或许可以假设很可能是调用函数还没有插入NULL的这不是在问题陈述是否.argv[1]为当下.)

因为我想象这里可能存在缓冲区溢出问题,即使没有堆栈溢出,我回答了格式字符串,因为简单地通过传递不同的格式字符串"%.8s",问题可以大部分避免,所以它看起来像一个整体更通用,因此更好,回答.

我的回答被标记为错误.正确答案标记为"Stack Overflow".

现在我想到,如果假设argv[1]存在,那么唯一可能的缓冲区溢出是堆栈溢出,在这种情况下,堆栈溢出实际上可能是正确的答案.但是,即使在这种情况下,将这称为堆栈溢出也不会被认为是奇怪的吗?缓冲区溢出是否是描述此问题的更好方法,即使假设argv[1]存在?而且,如果argv[1]存在的,是不是非常不正确地指出,问题是 …

c++ stack-overflow printf buffer-overflow language-lawyer

16
推荐指数
1
解决办法
1217
查看次数

x64和x32中的不同行为展开堆栈

为什么在下面详述的场景中,堆栈空间在x64中增加但在x32中使用相同的代码减少?

背景:

我们的客户可以使用域语言编写脚本,该语言在运行时使用递归技术解释并在Web服务器上执行.它们可能会在抛出异常的脚本中出错,此异常会被捕获并记录.

由于这种递归技术,我们通过检查用作解释器执行脚本的堆栈空间来防止堆栈溢出异常,并在我们实际耗尽堆栈之前终止脚本.

在32位模式下,一切运行良好,当脚本编写器Exception生成错误时,它被记录,堆栈展开,在此期间堆栈上剩余的空间增加,脚本很好地终止.

在64位模式下,一切都不太好,当脚本编写Exception器生成错误时,它被记录,堆栈展开,在此期间堆栈上剩余的空间减少.这是非常糟糕的,因为有可能如果脚本碰巧使用了大量的堆栈空间并抛出然后解除堆栈并记录错误本身的行为导致StackOverflowException隐藏原始异常,软管IIS并杀死所有机上要求(坏,非常糟糕,非常糟糕).

重新创建问题:

这是一个控制台应用程序,它模拟我在生产中使用的代码,并在设置为x64时重新创建问题,并在x32中正常工作.

using System;
using System.ComponentModel;
using System.Runtime.InteropServices;

namespace ConsoleApplication16
{
    class Program
    {
        const Int32 MaxNumberRecursions = 10;
        static Int32 _currentRecursionDepth;
        static UInt64 _lastSpaceUsed;

        static void Main(string[] args)
        {
            System.Diagnostics.Debug.WriteLine(String.Format("Is64BitProcess = {0}", System.Environment.Is64BitProcess));
            try
            {
                _lastSpaceUsed = GetStackBytesLeft();
                RecurseXTimes();
            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.WriteLine(e);
            }
        }

        unsafe static void RecurseXTimes()
        {
            System.Diagnostics.Debug.WriteLine("--> RecurseXTimes()");
            ReportStackSpaceUsage();

            try
            {
                _currentRecursionDepth++;
                if (_currentRecursionDepth > MaxNumberRecursions)
                { …
Run Code Online (Sandbox Code Playgroud)

.net c# stack-overflow exception stack-unwinding

15
推荐指数
1
解决办法
569
查看次数

Elixir无限递归是否会溢出堆栈?

许多不同如何渡上药剂编程表达认为存储状态或运行的无限循环是基于旋转数据断开成代理或任务,或者由需要状态的功能的无限递归惯用任一完成.他们没有提到递归的深度或任何其他警告的任何限制.

由于搜索"Elixir堆栈溢出"只会导致对此网站的点击,让我删除歧义并在此处询问:Elixir中有哪些实现保证确保无限递归作为'循环'的方法不会导致堆栈溢出,特别是当沿途传输状态信息时?

stack-overflow elixir

15
推荐指数
1
解决办法
1478
查看次数

在展开堆栈时嵌套异步方法中的StackOverflowExceptions

我们有很多嵌套的异步方法,看到我们并不真正理解的行为.以这个简单的C#控制台应用程序为例

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace AsyncStackSample
{
  class Program
  {
    static void Main(string[] args)
    {
      try
      {
        var x = Test(index: 0, max: int.Parse(args[0]), throwException: bool.Parse(args[1])).GetAwaiter().GetResult();
        Console.WriteLine(x);
      }
      catch(Exception ex)
      {
        Console.WriteLine(ex);
      }
      Console.ReadKey();
    }

    static async Task<string> Test(int index, int max, bool throwException)
    {
      await Task.Yield();

      if(index < max)
      {
        var nextIndex = index + 1;
        try
        {
          Console.WriteLine($"b {nextIndex} of {max} (on threadId: {Thread.CurrentThread.ManagedThreadId})");

          return await Test(nextIndex, …
Run Code Online (Sandbox Code Playgroud)

.net c# stack-overflow async-await

15
推荐指数
1
解决办法
847
查看次数