c++ - 进入函数时堆栈溢出

标签 c++ function stack-overflow

当我使用 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;
    }
}

这是让我感到困惑的地方:

  1. 我正在单步执行函数,所以我不认为可以进行任何递归。当我收到堆栈溢出错误时,它出现在函数的左括号中 - 函数的任何行都没有被调用。
  2. 当我在“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/

相关文章:

c++ - throw 或 delete 表达式可以依赖吗?

c++ - 如何在 FOR 语句中间停止 visual studio 2017 c++ 自动完成)?

c# - 包装 OpenCV C++ 以便与 C# 一起使用

r - 有没有办法在 R 中声明函数参数类型?

c - 如何处理 C 中的堆栈数组分配失败?

c++ - c++ 中 vector 的 bad_alloc 异常

python - 无法弄清楚为什么我收到 UnboundLocalError

javascript - 使用 Javascript 将一个类从一个标签移动到另一个标签

ios - 可以调用 UIKit PushViewController :animated: cause eventual stack overflows (or other anomalies)?

c++ - 为什么缓冲区末尾和保存的帧指针之间有 8 个字节?