std::bad_alloc 不会陷入任何调用堆栈帧中

发布于 2024-11-26 22:29:51 字数 1606 浏览 1 评论 0原文

如果 new 运算符无法分配内存,只有当我在 new 语句周围放置一个 try-catch 块时,才会捕获异常 std::bad_alloc。如果我将 try-catch 块放在下面几个堆栈帧的调用者中,则它不会被捕获,并且我会遇到异常程序终止。为什么会出现这种情况?这是在 Microsoft Visual Studio 2008 上。

编辑:好的,这是不起作用的代码。下面的函数是我调用 new 的地方,下面的函数是它下面的堆栈帧。最后一个函数是我有 catch 子句的地方,但它没有被捕获。

void HTTPResponseBuff::grow()
{
    if (m_nMaxSize > m_nStartConstGrowSize)
        m_nMaxSize += m_nConstGrowSize;
    else
        m_nMaxSize = 2 * m_nMaxSize;

    char* pTmp = new char[m_nMaxSize];
    . . . 
}

void HTTPResponseBuff::write(const char* pBuf, size_t len)
{
    char* pCh;
    while (getRemainingCapacity(pCh) < len)
        grow();
    . . . 
}

size_t HTTPTransport::responseCallback(void *pRespData, size_t size,
                             size_t nmemb, void *pRespBuff)
{
    const char* pChar = (const char*)pRespData;
    register int respDataLen = size * nmemb;    
    ((HTTPResponseBuff*)pRespBuff)->write(pChar, respDataLen);
    return respDataLen;
}

A few curl library stackframes here. These are C code, not C++.

ISTATUS HTTPTransport::invoke()
{
    invokeCleanup();

    //make the HTTP call
    CURLcode retCode;
    try{
    retCode = curl_easy_perform(m_pCurl);
    }
    catch(std::bad_alloc& ba)
    {
        strcpy(m_pErrMsg,ba.what());
        m_status = IFAILURE;
    }
}

另外,我捕获 bad_alloc 时的堆栈帧(在紧邻新语句的 catch 子句中)位于: http://s289.photobucket.com/albums/ll211/spiderman2_photo_bucket/?action=view&current=bad_alloc.jpg

If the new operator fails to allocate memory, the exception std::bad_alloc is only getting caught if I put a try-catch block immediately surrounding the new statement. If I instead have the try-catch block in a caller a few stackframes down below, it is not getting caught there and I'm getting an abnormal program termaination. Why does this happen? This is on Microsoft Visual Studio 2008.

Edit: Ok, here is the code that is not working. The function immediately below is where I'm calling the new, and the ones below are the stackframes below it. The last function is where I have the catch clause but it doesn't get caught there.

void HTTPResponseBuff::grow()
{
    if (m_nMaxSize > m_nStartConstGrowSize)
        m_nMaxSize += m_nConstGrowSize;
    else
        m_nMaxSize = 2 * m_nMaxSize;

    char* pTmp = new char[m_nMaxSize];
    . . . 
}

void HTTPResponseBuff::write(const char* pBuf, size_t len)
{
    char* pCh;
    while (getRemainingCapacity(pCh) < len)
        grow();
    . . . 
}

size_t HTTPTransport::responseCallback(void *pRespData, size_t size,
                             size_t nmemb, void *pRespBuff)
{
    const char* pChar = (const char*)pRespData;
    register int respDataLen = size * nmemb;    
    ((HTTPResponseBuff*)pRespBuff)->write(pChar, respDataLen);
    return respDataLen;
}

A few curl library stackframes here. These are C code, not C++.

ISTATUS HTTPTransport::invoke()
{
    invokeCleanup();

    //make the HTTP call
    CURLcode retCode;
    try{
    retCode = curl_easy_perform(m_pCurl);
    }
    catch(std::bad_alloc& ba)
    {
        strcpy(m_pErrMsg,ba.what());
        m_status = IFAILURE;
    }
}

Also the stackframes at the time I caught the bad_alloc (in the catch clause immediately surrounding the new statement) is here: http://s289.photobucket.com/albums/ll211/spiderman2_photo_bucket/?action=view¤t=bad_alloc.jpg

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

∝单色的世界 2024-12-03 22:29:51

您提到了异常源和 try-catch 之间的第三方函数。
如果这些第三方函数不是 c++(例如具有 c 链接,如用 c 编写的 libcurl),则异常处理将无法按预期工作。我在使用 gcc 的项目中遇到了同样的问题。

您需要在回调中捕获所有异常,然后再通过第三方层传播,并使用错误代码(或自定义机制)将信息传递给调用者或完全放弃使用异常。


正如您问我做了什么:我通过可用的 void 指针将调用者的上下文对象注入到回调中。因此,我将上下文对象更改为具有 ErrorStatus 和 ErrorMessage 成员,并使用它们通过 C 层传播错误。

struct Context{
    ErrorCode errorCode;
    const char* errorMessage;
    //other stuff
}

void callback(T arg, void* context){
   try{
      new(int);
   }catch(std::exception &e){
       context.errorCode=getErrorCode(e);
       context.errorMessage=e.what();
   }

}

void caller(){
    Context context;
    thirdparty_function(context);

}

如果您不担心线程安全,您也可以使用全局变量。

也就是说,以这种方式处理内存不足错误可能会很棘手,因为您应该避免为错误消息分配额外的内存

You mentioned third party functions inbetween the exception origin and the try-catch.
If these thirdparty functions are not c++(for example have c linkage, like libcurl being written in c) then the exception handling will not work as expected. I had the same issue with a project using gcc.

You need to catch all exceptions in your callbacks before they propagate through the third party layer and use error codes( or a custom mechanism) to get the information into your caller or give up on using the exceptions entirely.


As you ask what I did: I had a context object from the caller injected into the callback through a void pointer available. So I changed the context object to have ErrorStatus and ErrorMessage members and used these to propagate errors through the C-Layer.

struct Context{
    ErrorCode errorCode;
    const char* errorMessage;
    //other stuff
}

void callback(T arg, void* context){
   try{
      new(int);
   }catch(std::exception &e){
       context.errorCode=getErrorCode(e);
       context.errorMessage=e.what();
   }

}

void caller(){
    Context context;
    thirdparty_function(context);

}

If you are not worried about thread safety you also could use global variables for that.

That said, handling out of memory errors this way could be tricky, because you should avoid allocating additional memory for error messages

动听の歌 2024-12-03 22:29:51

如果可能的话,发布您的代码,没有您的代码我已经编写了一个小测试,即使有更多的堆栈帧,try/catch 似乎也能正常工作(该示例与 gcc 一起工作正常):

void foo()
{
    int* myarray= new int[1000000000];
}

void foo1()
{
     int i = 9;
     foo();
}

void foo2()
{
     int j = 9;
     foo1();
}

int main () {
  try
  {
         foo2();
  }
  catch (exception& e)
  {
    cout << "Standard exception: " << e.what() << endl;
  }
  system("pause");
  return 0;
}

输出是

标准异常:St9bad_alloc

Post your code if possible, without your code I have wrote a small testing and the try/catch seems to be working fine even with a few more stackframe away(the example works fine with gcc):

void foo()
{
    int* myarray= new int[1000000000];
}

void foo1()
{
     int i = 9;
     foo();
}

void foo2()
{
     int j = 9;
     foo1();
}

int main () {
  try
  {
         foo2();
  }
  catch (exception& e)
  {
    cout << "Standard exception: " << e.what() << endl;
  }
  system("pause");
  return 0;
}

The output is

Standard exception: St9bad_alloc

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文