进入函数时堆栈溢出
stack overflow on stepping into a function
当我使用 VS 2015 在调试模式下进入函数时遇到堆栈溢出错误。这是准确的消息,以防万一:
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;
}
}
这是让我困惑的地方:
- 我单步执行函数,所以我认为不会有任何递归进行。当我收到堆栈溢出错误时,它位于函数的左括号中 - none 甚至调用了函数的行。
- 当我在 'else if' 部分注释掉这一行时:
cereal::XMLInputArchive arSettingsObject(ss, pSettings->XML_TAG);
然后不仅堆栈溢出错误消失了,而且函数 运行s 也如预期的那样,成功执行了 `if' 块(所以它成功地创建了一个 'cereal::XMLInputArchive',从字符串流加载它,等等) .
在这两种情况下(当函数 运行s 时,以及当它导致堆栈溢出时),都会使用相同的输入参数调用它(大约 300 个 base64 编码的字符 xml)。
所以,不知何故,当我在所有代码未注释的情况下进行编译时,我导致函数的 execution/memory 分配出现问题,但我不明白是什么。
哦,是的,以防万一,当我收到堆栈溢出错误时,调用堆栈将其置于顶部:
TestProgram.exe!__chkstk()
除此之外,它看起来与函数 运行 成功时相同(这也让我认为没有递归)。
[编辑]
搜索 __chkstk() 后,我只是 found/read 这篇 SO 文章:
What is the purpose of the _chkstk() function?
这让我觉得这不是传统的堆栈溢出错误,我要求的内存太多,而是函数中的某些内容试图引用内存中的非法位置,这导致 VS报告堆栈溢出。但是,我仍然不确定 why/how 如果该函数甚至没有执行是否会发生这种情况,因为该块不会 运行.
提前感谢您提供有关可能导致此类行为的原因的任何见解。
我有一种不好的预感,我错过了关于函数调用的一些基本知识。
结果是 _chkstk()
throws a stack overflow when you have exceeded the declared maximum stack size declared in an .exe build. Your solution then? Increase it。尽管也考虑删除代码中的冗余位:
首先,考虑到在进入函数时,我们需要确保堆栈上有足够的space用于您的函数的所有局部变量。让我们看看它们是什么:
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 语句之后终止,并且声明它的所有 return 路径都需要它.
当我使用 VS 2015 在调试模式下进入函数时遇到堆栈溢出错误。这是准确的消息,以防万一:
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;
}
}
这是让我困惑的地方:
- 我单步执行函数,所以我认为不会有任何递归进行。当我收到堆栈溢出错误时,它位于函数的左括号中 - none 甚至调用了函数的行。
- 当我在 'else if' 部分注释掉这一行时:
cereal::XMLInputArchive arSettingsObject(ss, pSettings->XML_TAG);
然后不仅堆栈溢出错误消失了,而且函数 运行s 也如预期的那样,成功执行了 `if' 块(所以它成功地创建了一个 'cereal::XMLInputArchive',从字符串流加载它,等等) .
在这两种情况下(当函数 运行s 时,以及当它导致堆栈溢出时),都会使用相同的输入参数调用它(大约 300 个 base64 编码的字符 xml)。
所以,不知何故,当我在所有代码未注释的情况下进行编译时,我导致函数的 execution/memory 分配出现问题,但我不明白是什么。
哦,是的,以防万一,当我收到堆栈溢出错误时,调用堆栈将其置于顶部:
TestProgram.exe!__chkstk()
除此之外,它看起来与函数 运行 成功时相同(这也让我认为没有递归)。
[编辑]
搜索 __chkstk() 后,我只是 found/read 这篇 SO 文章: What is the purpose of the _chkstk() function?
这让我觉得这不是传统的堆栈溢出错误,我要求的内存太多,而是函数中的某些内容试图引用内存中的非法位置,这导致 VS报告堆栈溢出。但是,我仍然不确定 why/how 如果该函数甚至没有执行是否会发生这种情况,因为该块不会 运行.
提前感谢您提供有关可能导致此类行为的原因的任何见解。
我有一种不好的预感,我错过了关于函数调用的一些基本知识。
结果是 _chkstk()
throws a stack overflow when you have exceeded the declared maximum stack size declared in an .exe build. Your solution then? Increase it。尽管也考虑删除代码中的冗余位:
首先,考虑到在进入函数时,我们需要确保堆栈上有足够的space用于您的函数的所有局部变量。让我们看看它们是什么:
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 语句之后终止,并且声明它的所有 return 路径都需要它.