linux下C编程free()时出现飘忽诡异的段错误(核心已转储)问题

先说一下问题现场。

代码如下

free(volthisframe->Tops);
free(volthisframe->Bots);
printf("what\n");
free(volthisframe->SCTops);
free(volthisframe->SCBots);


运行时出现段错误,“what”随机出现,也就是说可能是打印前出现段错误,也可能是打印后出现段错误。但最终定位就在这几行free里面。

人格保证,各个指针都有初始化,都有检查,代码这里没有列出来而已。

困扰了我2,3天时间,因为完全无法解释free出现段错误这个问题背后的原因,指针是绝对正常的。后来查阅了大量资料,终于理了个脉络出来,大概知道怎么回事了。进一步的debug还在进行中。。。

提醒:这只是泛泛而谈,因为内存管理的问题跟语言、编译器、操作系统都有关系,windows下和linux就大不相同,本文也没有想精确定位,只是给个思路而已。

下面是具体分析,首先是参考资料

参考资料


编号


名称


作者


内容


1


http://baike.baidu.com/link?url=-1euetbsnxgUONmVs3jA5eexMlkm5GJVTRIrcn1z3KwFVrDT-Ei6qtcxKxWAm229u6pWvOq0KKnWuWogahdeoK


“堆栈”的百度百科,杂七杂八讲了一大堆东西。


2


http://imatlab.lofter.com/post/286ffc_a6ead7


局部变量数组过大造成的段错误


3


http://www.oschina.net/question/617142_65867?sort=default&p=1#answers


典型的数组越界


4


http://blog.csdn.net/misskissc/article/details/10757975


子函数返回的时候,数据区、栈区的内容是否有效的问题。


5


http://www.cnblogs.com/panfeng412/archive/2011/11/06/2237857.html


各种段错误及其调试方法


6


http://bbs.chinaunix.net/thread-1332271-1-1.html


局部变量作为实参传递出现错误


7


http://blog.csdn.net/wind19/article/details/5964090


C中的内存管理,


8


http://blog.csdn.net/wind19/article/details/5964137


C中堆和栈的数组越界,局部变量是放在栈中的


9


http://www.cs.ucsb.edu/~pconrad/cs16/10W/extraLabs/el01/


UCSB的C语言课程关于段错误的实验内容

这个问题跟C语言和编译器的内存分配,linux的内存管理都有关系,一个一个来。

出现段错误的情况,基本还是栈溢出(使用的内存空间大于系统默认分配的栈空间)[2][5]

数组越界[3]

访问不存在的地址(指针NULL)[5]

访问系统保护的内存地址[5]

访问只读的内存地址[5]

关于入栈、出栈 [1]讲了一点,在子函数调用的时候的情况,注意这只是多数情况,具体的系统很可能不一样


栈: 在函数调用时,在大多数的C编译器中,参数是由右往左入栈的,然后是函数中的局部变量。注意静态变量是不入栈的。

当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向函数的返回地址,也就是主函数中的下一条指令的地址,程序由该点继续运行。

[5]里面讲了很复杂的调试方法,但用在IDE里面用gdb可以很方便找到位置。关键是linux下,对于段错误的报警存在可能的偏差!

比如[3],在数组越界的时候并未实时报警,而是在free的时候才报警。

实际上我也是这种情况,应该是volthisframe->Tops和Bots都越界了,但是到free的时候才随机选一个报警。甚至是下一个free才报警。定位都很困难,定位到free也不解决任何问题。。。

OK,总结如下,主要是[7][8]说的最清楚



BSS、数据段、代码段是编译器预分配的,

BSS段即未初始化的全局变量和静态变量的空间,读写。运行时初始化

数据段即已初始化的全局变量和静态变量的空间,读写。已由编译器初始化

代码段,就是代码空间,有的编译器和系统允许修改这一部分。

堆栈都由系统分配。

堆:很多系统都是从虚拟内存里面直接给,大小几乎不限。malloc和free类的内存空间就在这里。

栈,这个是重点

系统指定的空间,每个程序大小是统一的。linux下默认是8M。用ulimit查看修改。

局部变量就放在这里面,如果出现子函数调用的情况,除了子函数的局部变量和子函数的实参(其实也是局部变量)之外,父函数的返回地址也会入栈[1]。返回时如有返回值,也会压入栈中。调用时的入栈顺序是:

返回地址、实参、局部变量。

出栈相反。

栈就会带来很多问题。看了[4],我再总结如下:

局部变量的有效区间:本函数的存在时空。本函数返回之后,栈的内容其实还在,但随时可能被其它函数入栈顶替。

局部变量的地址作为实参传入:入栈的是父函数的局部变量的地址,其实是可以的,因为这时候父函数肯定还没结束。栈内空间依然保留,而且可读写。

根据[7],局部变量数组越界其实是在栈里面,而全局变量数组越界是在数据段或者BSS段里面。

而堆里面越界是在系统的虚拟内存里面。

Bingle!

最终原因:

很可能这是造成堆里面越界不能及时反映的原因,等到free的时候系统才发现不对头。因为使用的时候系统也没有随时监视,系统无法得知。

但无法理解系统为啥free这时候会发现不对,free里面可能有检查。猜测有记录使用了那些堆。

所以,我应该是指针在过程中使用的时候出现越界的情况,但在free时系统才报错,而且还不一定在哪儿报,可能是越界的指针本身free时,也可能是被侵犯的指针free时。我这里就是volthisframe->Tops和volthisframe->Bots两个指针都越界了(这两个是同步用的),但有时会在free(volthisframe->SCTops)时报错!

由于是嵌入式,为节省内存空间,我的指针使用极度繁杂,这下够的我搞!

时间: 2024-11-05 18:32:07

linux下C编程free()时出现飘忽诡异的段错误(核心已转储)问题的相关文章

Linux下运行C++程序出现"段错误(核心已转储)"的原因

今天写程序出现了“段错误(核心已转储)"的问题,查了一下资料,加上自己的实践,总结了以下几个方面的原因. 1.内存访问出错  这类问题的典型代表就是数组越界. 2.非法内存访问 出现这类问题主要是程序试图访问内核段内存而产生的错误. 3.栈溢出  Linux默认给一个进程分配的栈空间大小为8M.c++申请变量时,new操作申请的变量在堆中,其他变量一般在存储在栈中.  因此如果你数组开的过大变会出现这种问题.  首先我们先看一下系统默认分配的资源: 1 ulimit -a 可以看到默认分配的栈大

Linux下Socket编程

http://blog.chinaunix.net/uid-20733992-id-3450058.html 原文地址:Linux下Socket编程 作者:yulianliu1218 Linux下Socket编程 什么是Socket Socket接口是TCP/IP网络的API,Socket接口定义了许多函数或例程,程序员可以用它们来开发TCP/IP网络上的应用程序.要学Internet上的TCP/IP网络编程,必须理解Socket接口. Socket接口设计者最先是将接口放在Unix操作系统里面

Linux下Socket编程的端口问题( Bind error: Address already in use )

Linux下Socket编程的端口问题( Bind error: Address already in use ) 在进行linux网络编程时,每次修改了源代码并再次编译运行时,常遇到下面的地使用错误: Bind error: Address already in use 虽然用Ctrl+C强制结束了进程,但错误依然存在,用netstat -an |grep 5120和ps aux |grep 5120都还能看到刚才用Ctrl+C“强制结束”了的进程,端口还是使用中,只好每次用kill结束进程,

Linux下Shell编程

Linux的shell编程 1.什么是shell? 当一个用户登录Linux系统之后,系统初始化程序init就为每一个用户运行一个称为shell(外壳)的程序. shell就是一个命令行解释器,它为用户提供了一个向Linux内核发送请求以便运行程序的界面系统级程序,用户可以用shell来启动.挂起.停止甚至是编写一些程序.一般的Linux系统都将bash作为默认的shell. 2.几种流行的shell 目前流行的shell有ash.bash.ksh.csh.zsh等,可以用下面的命令来查看she

linux下多线程编程

最近研究mysql源码,各种锁,各种互斥,好在我去年认真学了<unix环境高级编程>, 虽然已经忘得差不多了,但是学过始终是学过,拿起来也快.写这篇文章的目的就是总结linux 下多线程编程,作为日后的参考资料. 本文将介绍linux系统下多线程编程中,线程同步的各种方法.包括: 互斥量(mutex) 读写锁 条件变量 信号量 文件互斥 在介绍不同的线程同步的方法之前,先简单的介绍一下进程和线程的概念, 它们的优缺点,线程相关的API,读者——写者问题和哲学家就餐问题. 基础知识 1. 进程和

Linux下socket编程,附带tcp例子

1.网络中进程之间如何通信? 本地的进程间通信(IPC)有很多种方式,但可以总结为下面4类: 消息传递(管道.FIFO.消息队列) 同步(互斥量.条件变量.读写锁.文件和写记录锁.信号量) 共享内存(匿名的和具名的) 远程过程调用(Solaris门和Sun RPC) 但这些都不是本文的主题!我们要讨论的是网络中进程之间如何通信?首要解决的问题是如何唯一标识一个进程,否则通信无从谈起!在本地可以通过进程PID来唯一标识一个进程,但是在网络中这是行不通的.其实TCP/IP协议族已经帮我们解决了这个问

linux下Bash编程循环语句特殊用法之编写脚本(十)

linux下Bash编程while语句特殊用法之编写脚本(十) 1.循环控制: break:中断整个循环语句,即退出循环后执行脚本后面的语句 continue:中断当前本次循环,提前进入下一轮循环 exit:结束脚本运行 2.while死循环,即当不知道循环多少次时 格式 : while :; do 循环语句 done 3.while从输入重定向文件中每行读取并赋值给read变量 格式:  while read LINE;do 循环语句 done < 路径文件 4.实例脚本 4.1.找出/etc

Linux 下互联网络编程的基础知识

2019-10-07 关键字:Linux 网络编程基础 TCP/IP 协议里有两种不同的协议: 1.TCP协议 用于检测网络传输中的差错. 2.IP协议 用于对不同网络进行互联. 简单说就是 TCP 负责纠错,IP 负责传输. 网络体系结构: 网络体系结构就是将复杂的网络通信过程按照一定的规则进行分层,从而能使整个的网络通信过程更加清晰. 这一分层的核心思想有二: 1.每一层实现不同的功能,并对其上层做透明传输. 2.每一层都会使用到其下一层所提供的服务,并对其上一层提供服务. 早期的网络体系结

Linux下socket编程基本知识

本文档主要讲解了Linux下socket编程的一些基本知识,主要包括套接字和字节序的概念,以及一些常用的结构体和函数. 本文是在网易云课堂学习过程中的记录,这个老师讲得很不错,推荐大家围观. Linux网络编程 Linux网络编程|人工智能物联网 1.概念 1.1套接字(socket) Socket(套接字)是一种通讯机制,它包含一整套的调用接口和数据结构的定义,它给应用进程提供了使用如TCP/UDP等网络协议进行网络通讯的手段. Linux中的网络编程通过socket接口实现,socket既是