objective-c - 发布二进制文件中的堆栈溢出,但 Xcode-Debugger 中没有堆栈溢出

标签 objective-c xcode macos cocoa crash-reports

当我从 Xcode 中启动我的 (Cocoa)-App 时,它运行得非常好。但是,当我存档/发布它时,该版本将会崩溃。弹出的错误报告器显示:

[...]    
Crashed Thread:  0  Dispatch queue: com.apple.main-thread

Exception Type:  EXC_CRASH (SIGABRT)
Exception Codes: 0x0000000000000000, 0x0000000000000000

Application Specific Information:
[9082] stack overflow

Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0   libsystem_kernel.dylib          0x00007fff944a7212 __pthread_kill + 10
1   libsystem_c.dylib               0x00007fff9290caf4 pthread_kill + 90
2   libsystem_c.dylib               0x00007fff92950e9e __abort + 159
3   libsystem_c.dylib               0x00007fff92951d17 __stack_chk_fail + 195
[...] 

虽然它还为我提供了执行停止的代码行,但这实际上对我没有帮助,因为在 Debug模式下执行完全相同的代码路径(但成功)。

所以我想知道:发布版本和调试版本的堆栈大小实际上可能不同吗? Mac(64 位/Mountain Lion)上的堆栈到底有多大?我不知道在堆栈上放入了太多的数据......

如果堆栈上有太多数据,我需要避免哪些模式来减少堆栈负载?

[更新]

好的,我通过添加 -fno-stack-protector 标志来运行我的应用程序。 (顺便说一句:我正在使用 LLVM 进行编译)

在此之前,我逐行查看了崩溃的代码,发现了以下我不明白的行为: 方法 foo(x) 调用 bacon(x)x 是 8,并且未经修改地从 foo 传递到 bacon。然而,当我进入 bacon(x) 时,x 突然变成了 4295939448(每次)。如果我设置 -fno-stack-protector ,则该值是正确的。

在我天真的眼中,这看起来好像堆栈保护器在堆栈中的某个位置设置了魔法值 4295939448 并使其成为只读。当我的函数将它们的参数放在堆栈上时,在某些时候参数 x 恰好被放在那个魔术地址上,因此无法写入(后续参数似乎被正确写入)。在我的例子中,x 是一个缓冲区长度参数,这自然会导致缓冲区溢出和崩溃。

有人对堆栈保护器有更深入的了解吗?为什么会发生这种情况?在什么情况下禁用堆栈保护器是安全合法的,在什么情况下又是危险的?

[更新2:原始代码]

此方法调用下面的另一个Decrypt。此时 stIVLen 为 8

BOOL CEracomSE::Decrypt(
PBYTE pMsg, size_t stLen,
const CSK* pKey /* = NULL */,
PBYTE pIV /* = NULL */, size_t stIVLen /* = 0 */,
FBM fbm /* = FBM_CBC */,
PADDING padding /* = NO_PADDING */
)
{
    //stIVLen == 8
    return Decrypt( (uint64_t)0, pMsg, stLen, pKey, pIV, stIVLen, fbm, padding ); 
}

调用Decrypt时stIVLen为4295939448,其他参数仍然正确

BOOL CEracomSE::Decrypt(
    uint64_t qwOffset, 
    PBYTE pMsg, size_t stLen,
    const CSK* pKey /* = NULL */,
    PBYTE pIV /* = NULL */, size_t stIVLen /* = 0 */,
    FBM fbm /* = FBM_CBC */,
    PADDING padding /* = NO_PADDING */
    )
{
    //stIVLen now is 4295939448
    BYTE a_iv[16] = {0};
    size_t a_iv_len;
    BYTE a_key[32] = {0};
    size_t a_key_len = 0;
    size_t nBytes;
    size_t nDataOffset;
    size_t nRemainingData = stLen;
    bool ret;
    //[...]
}

最佳答案

我最近在使用我的应用程序时遇到了这种情况。我知道这是一个旧线程,但无论如何做出回应,目的是让其他人可以从研究结果中受益。

传递-fno-stack-protector确实解决了问题中建议的问题。然而,深入挖掘后我们发现,将所有出现的文字数组声明更改为更长的声明确实可以解决问题,而无需传递编译器标志。

因此更改所有出现的

@[@(1), @(2)]

[NSArray arrayWithObjects:@(1), @(2), nil]

可能仅适用于我们的应用程序,但希望它也能对其他人有所帮助。

关于objective-c - 发布二进制文件中的堆栈溢出,但 Xcode-Debugger 中没有堆栈溢出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12898783/

相关文章:

objective-c - id 的 isKindofClass

xcode - Swift Facebook 图粉丝页公开照片

xcode - 我可以在 Xcode 7 中使用 Swift 3 吗?

macos - 如何获取 NSFontManager 选择的字体?

java - Mac 上跨应用程序信息保存在哪里

linux - 带回调的 Posix 串行连接

定义为副本的 Objective-C block 属性不起作用

iphone - 在 Objective-c 中编码二维数组

ios - 向服务器发送获取数据的请求,发生错误 : The resource could not be loaded

ios - 奇怪的 Xcode 分析结果