当我使用 VS 2015 进入 Debug模式下的函数时,出现堆栈溢出错误。以下是确切的消息,以防万一:
Unhandled exception at 0x0000000140D9F018 in TestProgram.exe: 0xC00000FD: Stack overflow (parameters: 0x0000000000000001, 0x0000000000213000).
我输入的函数如下所示:
void CGUITaskRequest::DecodeAndDeserializeSettings(const std::string& sEncodedSettingsString)
{
auto sDecoded = string_functions::base64_decode(sEncodedSettingsString);
std::stringstream ss(sDecoded);
if (m_eType == ETaskTypes::FILE && m_eSubtype == ETaskSubtypes::OPEN) {
auto pSettings = std::make_shared<CModSettingsFileImport>();
cereal::XMLInputArchive arSettingsObject(ss, pSettings->XML_TAG);
pSettings->load(arSettingsObject);
m_ptrSettings = pSettings;
}
else if (m_eType == ETaskTypes::META && m_eSubtype == ETaskSubtypes::STATUS) {
auto pSettings = std::make_shared<SMetaStatusSettings>();
cereal::XMLInputArchive arSettingsObject(ss, pSettings->XML_TAG); // <- line I comment out to run successfully
pSettings->load(arSettingsObject);
m_ptrSettings = pSettings;
}
}
这是让我感到困惑的地方:
- 我正在单步执行函数,所以我不认为可以进行任何递归。当我收到堆栈溢出错误时,它出现在函数的左括号中 - 函数的任何行都没有被调用。
- 当我在“else if”部分注释掉这一行时:
Cereal ::XMLInputArchive arSettingsObject(ss, pSettings->XML_TAG);
然后不仅堆栈溢出错误消失了,而且该函数按预期运行,成功执行了“if” block (因此它成功地创建了一个“cereal::XMLInputArchive”,从字符串流中加载它,等等)。
在这两种情况下(当函数运行时,以及当它导致堆栈溢出时),都会使用相同的输入参数(大约 300 个 base64 编码的 xml 字符)调用它。
所以,不知何故,当我在所有代码未注释的情况下进行编译时,我导致函数的执行/内存分配出现问题,但我不明白是什么。
哦,是的,如果这有帮助,当我收到堆栈溢出错误时,调用堆栈将其置于顶部:
TestProgram.exe!__chkstk()
除此之外,它看起来与函数成功运行时相同(这也让我认为没有递归)。
[编辑]
搜索 __chkstk() 后,我刚刚找到/阅读了这篇 SO 文章: What is the purpose of the _chkstk() function?
这让我觉得这不是传统的堆栈溢出错误,我在这里要求的内存太多,而是函数中的某些内容试图引用内存中的非法位置,这导致 VS 报告堆栈溢出。但是,我仍然不确定如果该函数甚至没有执行,为什么/如何发生这种情况,因为该 block 将不会运行。
提前感谢您提供有关可能导致此类行为的任何见解。
我有一种不好的预感,我错过了关于函数调用的一些基本知识。
最佳答案
结果是 _chkstk()
throws a stack overflow when you have exceeded the declared maximum stack size declared in an .exe build .那你的解决方案呢? Increase it .尽管还要考虑删除代码中的冗余位:
首先,考虑到在进入函数时,我们需要确保堆栈上有足够的空间容纳您的函数的所有局部变量。让我们看看它们是什么:
void CGUITaskRequest::DecodeAndDeserializeSettings(const std::string& sEncodedSettingsString)
{
/* two variables here */
auto sDecoded = string_functions::base64_decode(sEncodedSettingsString);
std::stringstream ss(sDecoded);
if (m_eType == ETaskTypes::FILE && m_eSubtype == ETaskSubtypes::OPEN) {
/* two more variables here */
auto pSettings = std::make_shared<CModSettingsFileImport>();
cereal::XMLInputArchive arSettingsObject(ss, pSettings->XML_TAG);
pSettings->load(arSettingsObject);
m_ptrSettings = pSettings;
}
else if (m_eType == ETaskTypes::META && m_eSubtype == ETaskSubtypes::STATUS) {
/* and a final pair */
auto pSettings = std::make_shared<SMetaStatusSettings>();
cereal::XMLInputArchive arSettingsObject(ss, pSettings->XML_TAG); // <- line I comment out to run successfully
pSettings->load(arSettingsObject);
m_ptrSettings = pSettings;
}
}
现在假设您在调用堆栈上找到了 _chkstk()
变量。这意味着这个函数 allocates a lot of memory !注释掉单个声明可以解决问题,指向贪婪的内存罪魁祸首。但是等等,你有两个,你可以摆脱一个意味着合并你的重复声明可能会带来好处:
void CGUITaskRequest::DecodeAndDeserializeSettings(const std::string& sEncodedSettingsString)
{
auto sDecoded = string_functions::base64_decode(sEncodedSettingsString);
std::stringstream ss(sDecoded);
/* single declaration*/
cereal::XMLInputArchive arSettingsObject;
if (m_eType == ETaskTypes::FILE && m_eSubtype == ETaskSubtypes::OPEN) {
auto pSettings = std::make_shared<CModSettingsFileImport>();
arSettingsObject = cereal::XMLInputArchive(ss, pSettings->XML_TAG);
pSettings->load(arSettingsObject);
m_ptrSettings = pSettings;
}
else if (m_eType == ETaskTypes::META && m_eSubtype == ETaskSubtypes::STATUS) {
auto pSettings = std::make_shared<SMetaStatusSettings>();
arSettingsObject = cereal::XMLInputArchive(ss, pSettings->XML_TAG); // <- line I comment out to run successfully
pSettings->load(arSettingsObject);
m_ptrSettings = pSettings;
}
}
虽然这改变了 arSettingsObject
的范围,但这不是问题,因为该函数在 if/else 语句之后终止,并且声明它的所有返回路径都需要它。
关于c++ - 进入函数时堆栈溢出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51885838/