当我从 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
[...]
虽然它也给了我执行停止的代码行,但这确实对我没有帮助,因为在调试模式下执行完全相同的代码路径(但成功)。
所以我想知道:实际上可能是版本和调试版本的堆栈大小不同?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;
//[...]
}