c语言运行程序崩溃(crash)的原因

本文列举并分析了程序崩溃的几种常见原因,包括空指针操作、除0、栈溢出、只读内存修改、堆内存越界和释放后使用等。通过代码示例展示了这些错误导致的程序行为,如Segmentation fault和Floating point exception,并讨论了Glibc对内存管理的影响。此外,还提到了栈溢出导致的段错误问题。
摘要由CSDN通过智能技术生成

转载于https://www.csdn.net/tags/NtDaUgzsNjgyMzUtYmxvZwO0O0OO0O0O.html

文章目录

  1. 常见的程序崩溃示例
  2. 执行结果分析
  3. 常见的程序崩溃示例
    常见的崩溃类型有以下几种:

对空指针指向的内存非法写操作
对空指针指向的内存非法读操作
除0操作
大的临时变量或者递归等导致栈溢出
对只读内存进行写操作
堆越界写操作
对已经释放的内存进行写操作
代码示例:

//corruption.c
#include <stdlib.h>
#include <stdio.h>

void make_corruption(int type)
{
    printf("case %d:\n", type);
    switch (type)
    {
	    case 0:
	    {
	        //对空指针指向的内存非法写操作
	        char *str = NULL;
	        str[0] = 0;
	        break;
	    }
	    case 1:
	    {
	        //对空指针指向的内存非法读操作
	        char *str = NULL;
	        int i = str[0];
	        printf("i=%d", i);
	        break;
	    }
	    case 2:
	    {
	        //除0操作
	        int i = 10;
	        int j = 0;
	        int ret = i / j;
	        printf("ret=%d", ret);
	        break;
	    }
	    case 3:
	    {
	        //大的临时变量导致栈溢出
	        //char str[8 * 1024 * 1024] = {0}; //需要验证时再放开该行,否则栈越界必现死机导致其他case无法验证
	        break;
	    }
	    case 4:
	    {
	        //对只读内存进行写操作
	        char *str = "abc";
	        str[0] = 10;
	        break;
	    }
	    case 5:
	    {
	        //堆越界写操作
	        int *a = (int *)malloc(sizeof(int) * 4);
	        int *b = (int *)malloc(sizeof(int) * 4);
	        printf("a:%p, b:%p\n", a, b);
	        memset(a, 0, sizeof(int) * 8);
	        free(a);
	        free(b);
	        break;
	    }
	    case 6:
	    {
	        //对已经释放的内存进行写操作。
	        #if 0
	        	//没有死机
				char *str = (char *)malloc(SMALL_MEMORY);
				free(str);
				memset(str, 0, SMALL_MEMORY);
			#else
				//coredump
				char *str = (char *)malloc(LARGE_MEMORY);
				free(str);
				memset(str, 0, LARGE_MEMORY);
			#endif
	        break;
	    }
	    default:
	    {
	        printf("to do.\n");
	    }
    }

    return;
}

int main()
{
    int type = 0;
    scanf("%d", &type);
    //制造程序崩溃
    make_corruption(type);

    return 0;
}
  1. 执行结果分析
    [root@localhost all_kinds_corrupt]# gcc -g corruption.c -o corrupt
    [root@localhost all_kinds_corrupt]# ./corrupt
    0
    case 0:
    Segmentation fault (core dumped)
    [root@localhost all_kinds_corrupt]# ./corrupt
    1
    case 1:
    Segmentation fault (core dumped)
    [root@localhost all_kinds_corrupt]# ./corrupt
    2
    case 2:
    Floating point exception (core dumped)
    [root@localhost all_kinds_corrupt]# ./corrupt
    4
    case 4:
    Segmentation fault (core dumped)
    [root@localhost all_kinds_corrupt]# ./corrupt
    5
    case 5:
    a:0x1ca9ac0, b:0x1ca9ae0
    free(): invalid pointer
    Segmentation fault (core dumped)
    [root@localhost all_kinds_corrupt]# ./corrupt
    6
    case 6:
    我们可以看到,case 6在两种不同内存大小情况下表现一同:
    (1)小内存情况下没有死机,这是因为Glibc会将该内存放到unsorted bin,此时内存没有进行合并或者重新分配出去,可以进行写操作。
    (2)对于大内存情况,Glibc会通过调用mmap(大于128K)从系统申请内存,在free之后会直接归还给操作系统,此时进行写操作是非法的。
    至于Glibc对于不同大小的内存管理,则需要另外一篇文章来进行详细讲解了。

我们把case 3的代码放开,重新编译执行:

[root@localhost all_kinds_corrupt]# ./corrupt
100
段错误 (核心已转储)
type=100时应该是走进default分支,但实际上程序产生了段错误,其原因就是栈溢出。我们可以通过ulimit -s查看栈的默认大小,通常为8M。

[root@localhost all_kinds_corrupt]# ulimit -s
8192

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值