[英]stack overflow on stepping into a function
當我使用 VS 2015 在調試模式下進入一個函數時,出現堆棧溢出錯誤。這是確切的消息,以防萬一:
TestProgram.exe 中 0x0000000140D9F018 處未處理的異常:0xC00000FD:堆棧溢出(參數: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;
}
}
這是讓我困惑的地方:
cereal::XMLInputArchive arSettingsObject(ss, pSettings->XML_TAG);
然后不僅堆棧溢出錯誤消失了,而且該函數按預期運行,成功執行了 `if' 塊(因此它成功地創建了一個 'cereal::XMLInputArchive',從字符串流中加載它,等等)。在這兩種情況下(當函數運行時,以及當它導致堆棧溢出時),都會使用相同的輸入參數(大約 300 個字符的 base64 編碼 xml)調用它。
因此,不知何故,當我在所有代碼未注釋的情況下進行編譯時,我會導致函數的執行/內存分配出現問題,但我不明白是什么。
哦,是的,如果這有幫助,當我收到堆棧溢出錯誤時,調用堆棧會將其放在最上面:
TestProgram.exe!__chkstk()
除此之外,它看起來與函數成功運行時相同(這也讓我認為沒有遞歸)。
[編輯]
在搜索 __chkstk() 之后,我剛剛找到/閱讀了這篇 SO 文章: _chkstk() 函數的目的是什么?
這讓我認為這不是傳統的堆棧溢出錯誤,我要求太多內存,而是函數中的某些內容試圖引用內存中的非法位置,這導致 VS 報告堆棧溢出。 但是,如果函數甚至沒有執行,我仍然不確定為什么/如何發生這種情況,因為該塊不會運行。
預先感謝您對可能導致此類行為的任何見解。
我有一種不好的感覺,我錯過了一些關於函數調用的基本知識。
事實證明,當您超過 .exe 版本中聲明的最大堆棧大小時, _chkstk()
會引發堆棧溢出。 你的解決方案呢? 增加它。 雖然也可以考慮刪除代碼中的冗余位:
首先,考慮在進入函數時,我們需要確保堆棧上有足夠的空間用於函數的所有局部變量。 讓我們看看那些是什么:
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()
變量作為開始。 這意味着該函數分配了大量內存! 注釋掉單個聲明解決了這個問題指向貪婪的內存罪魁禍首。 但是等等,你有兩個,你可以逃脫一個意味着合並你重復的聲明可能會帶來好處:
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 語句之后終止,並且聲明它的所有返回路徑都需要它。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.