程序通过纯粹的意志力溢出调用堆栈

时间:2010-07-21 18:17:03

标签: c objective-c cocoa macos

这是来自a user's crash report的调用堆栈:

Thread 0 Crashed:  Dispatch queue: com.apple.main-thread
0   com.growl.GrowlSafari           0x179d383c writeWithFormat + 25
1   com.growl.GrowlSafari           0x179d388e writeWithFormat + 107
2   com.growl.GrowlSafari           0x179d388e writeWithFormat + 107
3   com.growl.GrowlSafari           0x179d388e writeWithFormat + 107
4   com.growl.GrowlSafari           0x179d388e writeWithFormat + 107
5   com.growl.GrowlSafari           0x179d388e writeWithFormat + 107

迹线在第511帧处截止。

这是writeWithFormat

int writeWithFormat(FILE *file, NSString *format, ...) {
    va_list args;
    va_start(args, format);
    int written = writeWithFormatAndArgs(file, format, args);
    va_end(args);
    return written;
}

正如你所看到的,它并没有自称。

这是它所调用的功能:

int writeWithFormatAndArgs(FILE *file, NSString *format, va_list args) {
    return 0;
    return fprintf(file, "%s\n", [[[[NSString alloc] initWithFormat:format arguments:args] autorelease] UTF8String]);
}

(正如你猜测的那样,这是记录未被激活的代码。)

那么,这段代码如何导致堆栈跟踪?


使用otx进行反汇编:

_writeWithFormatAndArgs:
    +0  00000f68  55                    pushl       %ebp
    +1  00000f69  89e5                  movl        %esp,%ebp
    +3  00000f6b  31c0                  xorl        %eax,%eax
    +5  00000f6d  c9                    leave
    +6  00000f6e  c3                    ret

_writeWithFormat:
    +0  00001823  55                    pushl       %ebp
    +1  00001824  89e5                  movl        %esp,%ebp
    +3  00001826  83ec10                subl        $0x10,%esp
    +6  00001829  31c0                  xorl        %eax,%eax
    +8  0000182b  c9                    leave
    +9  0000182c  c3                    ret

2 个答案:

答案 0 :(得分:3)

在完整崩溃报告中,您可以在二进制文件部分中看到用户已加载两个GrowlSafari副本:

 0x140c000 -  0x140efff +com.growl.GrowlSafari 1.1.6 (1.1.6) <1E774BDF-5CC5-4876-7C66-380EBFEAF190> /Library/InputManagers/GrowlSafari/GrowlSafariLoader.bundle/Contents/PlugIns/GrowlSafari.bundle/Contents/MacOS/GrowlSafari
0x179d2000 - 0x179d4ff7 +com.growl.GrowlSafari 1.2.1 (1.2.1) <10F1EF69-D655-CCEE-DF3A-1F6C0CF541D3> /Applications/GrowlSafari.app/Contents/Resources/GrowlSafari.bundle/Contents/MacOS/GrowlSafari

我在问题中展示的代码来自1.2.1(但很可能它自1.1.6以来没有改变)并且反汇编是1.2.1。

这可能是问题的原因,特别是因为递归似乎实际上是一个混合的方法(感谢Twitter上的@_karsten_ pointing this out)。

答案 1 :(得分:1)

在某处的尾部调用可能导致一个或多个函数从堆栈跟踪中消失,这当然会使调试变得有趣。

在我的脑海中,我可以想到可能导致这种情况的两种可能情况:

  • 格式字符串是NSString的子类,或者在writeWithFormat()期间有一个类别导致调用writeWithFormat()。自定义日志记录代码有时会这样做 - 编写一些通用的自定义日志记录代码非常容易,这些代码可以很好地回调自身。去过也做过。很多次,可悲的是。

  • 内存中的异常导致递归;腐败的物体或其他东西。

对稻草都有点掌握。发布整个崩溃报告。


捆绑包的两个版本在运行时间内进行了调整...所有投注都关闭,直到崩溃再次面对其中一个捆绑包。我敢打赌这就是问题所在。

我还打赌有一些相关的控制台呕吐。