当我从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
。那时的时间是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;
//[...]
}
答案 0 :(得分:1)
我最近用我的应用程序遇到了这种情况。我知道这是一个旧的线索,但无论如何都要回应,意图是其他人可以从调查结果中受益。
传递-fno-stack-protector
确实解决了问题中提出的问题。但是,深入挖掘我们发现,将所有出现的文字数组声明更改为更长的声明确实解决了问题而没有传递编译器标志。
所以改变所有出现的
@[@(1), @(2)]
到
[NSArray arrayWithObjects:@(1), @(2), nil]
可能仅针对我们的应用程序,但希望它也能帮助其他人。