堆栈错误

写此文的目的是为了说明:
-> 并非所有的异常都能够做到“不弹框优雅地退出”,堆栈错误因为可能影响安全,所以在异常处理时被加以了限制;
-> 堆、栈的头部、尾部被破坏,共有4种情况,现象其实是不一样的,应当加以区分。知道这一点应该能够为排查错误带来一些帮助。

  1. 先来一个“普通的”异常:除零异常
#include <string.h>
#include <stdio.h>
#include <excpt.h>
#include <stdlib.h>

int main()
{
    int a = 1;
    int b = 0;
    int ab = a / b;
    return 0;
}

发生除零异常的运行结果

==========
2. 除零异常是可以被正常捕获并处理的

#include <string.h>
#include <stdio.h>
#include <excpt.h>
#include <stdlib.h>

int MyMain()
{
    int a = 1;
    int b = 0;
    printf("-----start-----\n");
    int ab = a / b;
    printf("-----finish-----\n");
    return 0;
}

int main()
{
    __try
    {
        MyMain();
    }
    __except (EXCEPTION_EXECUTE_HANDLER)
    {
        printf("!!!!! Quit with Exception In MyMain !!!!!\n");
        exit(-1);
    }
}

除零异常被捕获并处理掉

==========
3.堆头部被破坏

#include <string.h>
#include <stdio.h>
#include <excpt.h>
#include <stdlib.h>

int MyMain()
{
    char *c = new char[5];
    c[0] = 'a';
    c[1] = 'b';
    c[2] = 'c';
    c[3] = 'd';
    c[4] = '\0';
    c[-1] = 'z';

    printf("c=%s\n", c);

    printf("-----start-----\n");
    delete c;
    printf("-----finish-----\n");
    return 0;
}

int main()
{
    __try
    {
        MyMain();
    }
    __except (EXCEPTION_EXECUTE_HANDLER)
    {
        printf("!!!!! Quit with Exception In MyMain !!!!!\n");
        exit(-1);
    }
}

堆头部被修改
注意以下几点:
(1) 红色框部分:wrote to memory before start of heap buffer。
(2) 堆错误即使加了异常处理语句,也会弹出错误框。
(3) 当堆头部被修改后,仍可以正常读取堆内容。
(4) 在释放资源时才会发生异常。
(5) 如果点击“中止”,则程序随即停止;如果点击“重试”,则进入异常处理程序(说明其实还是能捕获到的,只是无法直接隐藏错误窗口);如果点击忽略,则程序继续进行。下图依次显示了点击“中止”“重试”“忽略”的情况。
点击“中止”“重试”“忽略”的情况

==========
4. 堆尾部被破坏

#include <string.h>
#include <stdio.h>
#include <excpt.h>
#include <stdlib.h>

int MyMain()
{
    char *c = new char[5];
    c[0] = 'a';
    c[1] = 'b';
    c[2] = 'c';
    c[3] = 'd';
    c[4] = '\0';
    c[5] = 'z';

    printf("c=%s\n", c);

    printf("-----start-----\n");
    delete c;
    printf("-----finish-----\n");
    return 0;
}

int main()
{
    __try
    {
        MyMain();
    }
    __except (EXCEPTION_EXECUTE_HANDLER)
    {
        printf("!!!!! Quit with Exception In MyMain !!!!!\n");
        exit(-1);
    }
}

堆尾部被破坏
注意以下几点:
(1) 红色框部分:wrote to memory after end of heap buffer。
其他同堆头部被破坏的信息。

==========
5. 栈头部被破坏

#include <string.h>
#include <stdio.h>
#include <excpt.h>
#include <stdlib.h>

int MyMain()
{
    char c[5];
    memset(c, 0, sizeof(c));
    c[0] = 'a';
    c[1] = 'b';
    c[2] = 'c';
    c[3] = 'd';
    c[4] = '\0';
    c[-1] = 'z';

    printf("c=%s\n", c);

    printf("-----start-----\n");
    delete c;
    printf("-----finish-----\n");
    return 0;
}

int main()
{
    __try
    {
        MyMain();
    }
    __except (EXCEPTION_EXECUTE_HANDLER)
    {
        printf("!!!!! Quit with Exception In MyMain !!!!!\n");
        exit(-1);
    }
}

栈头部被破坏
注意以下几点:
(1) 栈错误即使加了异常处理语句,也会弹出错误框。
(2) 当栈头部被修改后,仍可以正常读取堆内容。
(3) 在释放资源时才会发生异常。
(4) 如果点击“中止”,则程序随即停止;如果点击“重试”,则进入异常处理程序(说明其实还是能捕获到的,只是无法直接隐藏错误窗口);如果点击忽略,则程序继续进行,仍会继续抛出异常,再次点击忽略,再次抛出异常,第三次点击继续,程序进入异常处理。下图依次显示了点击“中止”“重试”“忽略”的情况。
点击忽略

再次点击忽略

第三次点击忽略

==========
6.栈尾部被破坏

#include <string.h>
#include <stdio.h>
#include <excpt.h>
#include <stdlib.h>

int MyMain()
{
    char c[5];
    memset(c, 0, sizeof(c));
    c[0] = 'a';
    c[1] = 'b';
    c[2] = 'c';
    c[3] = 'd';
    c[4] = '\0';
    c[5] = 'z';

    printf("c=%s\n", c);

    printf("-----start-----\n");
    delete c;
    printf("-----finish-----\n");
    return 0;
}

int main()
{
    __try
    {
        MyMain();
    }
    __except (EXCEPTION_EXECUTE_HANDLER)
    {
        printf("!!!!! Quit with Exception In MyMain !!!!!\n");
        exit(-1);
    }
}

栈尾部被破坏
注意以下几点:
(1) 点击两次忽略后,程序结束。与栈头部错误有所区别。(可能因为头部指针没有问题,所以没有报“_CrtIsValidHeapPointer(pUserData)”异常)
点击忽略

再次点击忽略

关于异常无法捕获的补充材料请参考:
Error的博文
Error的博文

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

皓月如我

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值