C语言内存错误常见问题分析

一个迷惑的异常

//之前帮同事调试一段代码的时候,出现了一个让人迷惑的错误:同样的代码,不同的板卡上出现不同情况
//1:使用板卡1刷卡启动充电,刷卡停止,正常
//2:使用板卡1刷卡启动,触发急停停止后,异常,计费线程死机了
//3:使用板卡2,刷卡启动,急停停止,也正常

//常规分析,认为可能是计费线程修改了,导致线程进入死循环,而无法给线程喂狗,于是查找重载的几个计费接口,修改后没有改善
//分析,直流桩无异常,一体化有异常,是否一体化充电控制接口有异常————查看并无明显异常
//最后分析问题如下:
BYTE AxjGetStopChgReason(BYTE bpn)
{
	BYTE bSotpReason;
	BYTE ReasonNum = 52;
	ReadItemEx(BN0, bpn, 0xB885, &bSotpReason); 
    for (BYTE i = 0; i < ReasonNum; i++)
	{
		if (g_tStopReason[i].bClou == bSotpReason)
			return g_tStopReason[i].bAXJ;
	}
    return 0;
}
//因为,g_tStopReason在持续的修改过程中,最终并没有52个了(有些屏蔽了),导致访问到超出g_tStopReason数组外的地方————越界了
//修改为:
BYTE ReasonNum = sizeof(g_tStopReason) / sizeof(g_tStopReason[0]);

//那问题来了,一般来说,越界不是会挂掉吗?为啥这里还正常运行,直流可以而交流不行??
//下面的几点将从原理及现场说明,如果发生越界,可能的现象及后果有哪些

C中常见的与内存有关的错误

内存错误可能的后果

可能立刻报段错误,也可能保护故障,也可能长时间不出错(只是运行结果不对),甚至还有可能没有影响,程序也正常运行,那是什么原理呢?
如下一段为通用的内存管理模式:
内核虚拟内存进程相关的内核数据结构
如页表、task、mmu结构,内核栈等
每个进程一样物理内存
内核代码和数据
用户栈
共享库映射区共享库如libc.so,每个库包含.data和.text区域
brk开始运行时malloc分配的堆
未初始化的数据 .bss
已初始化的数据.data
0x400000开始代码段.text
如果你的内存出错了,具体出错位置:
1:地址定位到其他进程了,地址不是本进程的——segment error
2:地址定位到内核去了————内存保护错误
3:地址定位错了,但还在本进程中,只是指向了别的有用地址————这个后果不唯一,可能的后果包括:
	a:引用的地址是本进程的一个堆空间的,那就会改变堆空间的地址的数据(如果应用指针有修改的话)
	b:引用的地址是本进程的一个栈空间,修改了栈空间的内容,
	但无论怎样,引用内存不会有致命问题(顶多引用数据不正确),修改内存可能会导致:
	a:后续真正该内存的主人过来用的时候,引用地址错了,导致segment error或者其他逻辑错误
	b:修改了地址的内容,后续程序运行过来的时候,数据被修改了,运行逻辑错误。

错误——间接引用坏指针

正常:scanf("%d", &val);
错误:scanf("%d", val);————此时scanf将val解释为一个地址,
最好情况下,程序立即异常终止(内存到了别的内存区),最糟糕情况下,val对应虚拟内存某个合法读/写区域,于是覆盖了这个内存,以此通常会运行相当长一段时间后造成灾难性、令人困惑的后果。

错误——读未初始化的内存

.bss内存一般被加载器初始化为0,但堆内存不是,常见错误就是假设对内存初始化为0.
int *testvec(int **ptra, int *x, int n)
{
    int i,j;
    int *ptrb = (int *)malloc(n * sizeof(int));
    
    for (i=0; i<n; i++)
    {
        for (j=0; j<n; j++)
            ptrb[i] += ptra[i][j] * x[j];
    }
    return y;
}
此事例中,不应该假设ptrb被初始化为0,应该显式初始化为0.

错误——允许栈缓冲区溢出

void bufoverflow()
{
	char buf[32];
    
    gets(buf);
    return ;
}
//此处,gets获得数据可能超过32字节溢出,应该改用限制输出长度的接口,如fgets

错误——价值指针和他们指向对象大小相同

//创建一个n个指针组成数组,每个指针指向一个包含m个int的数组
int **makArray1(int n, int m)
{
    int i;
    int **A = (int **)malloc(n * sizeof(int));//(n * sizeof(int *))
    
    for (i=0; i<n; i++)
        A[i] = (int *)malloc(m * sizeof(int));
    
    return A;
}
//int **A = (int **)malloc(n * sizeof(int));实际创建的是int数组,在int和指向int的指针大小相同时运行正常,如果64位机器就结果异常了
//A[i]超出了,但可能超出部分是一个分配块边界,所以可以正常运行,之后程序运行很久后释放块时,分配器(alloc)合并空间失败,没有明显原因,可能提示“action at distance” (在远处起作用)

错误——造成错位

int **makArray2(int n, int m)
{
    int i;
    int **A = (int **)malloc(n * sizeof(int *));
    
    for (i=0; i<=n; i++)
        A[i] = (int *)malloc(m * sizeof(int));
    
    return A;
}
//A[i]初始化试图初始化n+1个元素

错误——引用指针,而不是指针指向的对象

int *binheapdel(int **binheap, int *size)
{
    int *packet = binheap[0];
    
    binheap[0] = binheap[*size -1];
    *size--;	//符号优先级,(*size)--
    heapify(binheap, *size, 0);
    return (packet);
}
//此处,*和--优先级一样,从右向左结合,所以*size--是减少指针自己值,而不是指向整数的值
//幸运的话程序立即失败,更可能发生的是:程序运行很久才有一个不对的结果,此时检查无从查起。

错误——误解指针运算

//忘记了指针的算术运算是以它指向的对象的大小为单位进行的,单位不一定是字节
int *search(int *p, int val)
{
    while(*p && *p!=val)
        p += sizeof(int);	//p++
    
    return p;
}
//每次循环,P越过4个int,实际结果不正确。

错误——引用不存在的位置

int *getptr()
{
    int val=100;
    
    return &val;
}
//返回的指针指向栈的局部变量,然后弹出栈帧,此时指针还是一个合法地址,但不是合法变量了,后续该帧帧被其他函数使用,此处返回的值如被修改就可能导致莫名修改,轻则异常,潜在灾难性后果啊

错误——引用空闲栈块中的数据

int *heaptest(int n, int m)
{
    int i;
    int *x,*y;
    
    x = (int *)malloc(n * sizeof(int));
    ......
    free(x);
    
    y = (int *)malloc(m * sizeof(int));
    for (i = 0; i < m; i++)
        y[i] = x[i]++;		//x已经释放了
    
    return y;
}
//释放后,x[i]可能是某个其他函数申请的堆空间(当然如果内存很小,也可能是某个函数用的一个大的栈),x位置被重写了,此错误会在程序执行后面出现。

错误——引起内存泄漏

void leak(int n)
{
    int *x = (int *)malloc(n * sizeof(int));
    return ;
}
//内存泄漏是缓慢、隐形的杀手
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
有些时候,我们对电脑进行某项操作时,会弹出警告:内存不能为read,出现这种情况是什么原因?又该如何解决?今天u大师就为大家分析此项故障。 造成操作电脑弹出内存不能为read故障的常见原因如下: 1微软IE缓冲溢出漏洞引起 2内存或虚拟内存地址使用抵触造成顺序的运行需要分配一定的内存地址给程序使用,当顺序结束时释放留出空间让给新的顺序使用,win多任务的系统有时前程序未结束又有新的任务开始底要多少内存或虚拟内存来保证我同时运行的工作任务呢?也许win这个问题上没弄好,所以有此错误常常发生,一般运行大型软件或多媒体后出现这种情况 3内存条存在质量问题或是出现某种故障也会出现这个问题 4微软WINDOWS系统的漏洞,window把内存地址0X000000000X0000ffff指定为分配null指针的地址范围,如果顺序试图访问这一地址,则认为是错误。 5.可能是安装了不完全正确装置apach服务,且启动了原故 6.分配给应用程序的内存分配失败 7.应用程序自身出现bug,导致引用了不正常的内存指针 解决此故障,下面的方式可能会有帮助: 1.检查系统中是否有木马或病毒。这类程序为了控制系统往往不负责任地修改系统,从而导致操作系统异常。平常应加强信息安全意识,对来源不明的可执行程序绝不好奇。 2.更新操作系统,让操作系统的装置顺序重新拷贝正确版本的系统文件、修正系统参数。有时候操作系统自身也会有BUG要注意安装官方发行的升级顺序。 3.试用新版本的应用顺序。 4删除然后重新创立Winnt\System32\Wbem\Repository文件夹中的文件:桌面上右击我电脑,然后单击管理,"服务和应用程序"下,单击服务,然后关闭并停止WindowsManagementInstrumentation服务。 删除Winnt\System32\Wbem\Repository文件夹中的所有文件。删除前请创建这些文件的备份副本。 打开"服务和应用程序"单击服务,然后打开并启动WindowsManagementInstrumentation服务。当服务重新启动时,将基于以下注册表项中所提供的信息重新创建这些文件:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WBEM\CIMOM\AutorecoverMOFs

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

技术的微光

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

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

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

打赏作者

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

抵扣说明:

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

余额充值