公开/公告号CN104461890A
专利类型发明专利
公开/公告日2015-03-25
原文格式PDF
申请/专利权人 四川川大智胜软件股份有限公司;
申请/专利号CN201410768041.5
申请日2014-12-12
分类号G06F11/36;
代理机构成都睿道专利代理事务所(普通合伙);
代理人潘育敏
地址 610045 四川省成都市武侯区武科东一路七号
入库时间 2023-12-18 08:05:40
法律状态公告日
法律状态信息
法律状态
2017-05-17
授权
授权
2015-09-09
著录事项变更 IPC(主分类):G06F11/36 变更前: 变更后: 申请日:20141212
著录事项变更
2015-09-09
专利申请权的转移 IPC(主分类):G06F11/36 变更前: 变更后: 登记生效日:20150818 申请日:20141212
专利申请权、专利权的转移
2015-04-22
实质审查的生效 IPC(主分类):G06F11/36 申请日:20141212
实质审查的生效
2015-03-25
公开
公开
一、所属技术领域
本发明涉及航管训练系统,特别涉及使用Qt开发的航管系统用户界面程序的内存使用静 态检查。
二、背景技术
航管训练系统除了仿真核心程序以外,还需要大量用户界面程序完成数据准备、模拟飞 行员操作、受训管制员席位等。在大型的航管训练系统进行长时间的、复杂流程的训练活动 时,对人机界面的稳定运行提出了较高的要求,如不能出现内存泄露、不能中途异常退出等。 本方法对使用QT开发的人机界面进程的源码提供静态检查机制,方便开发人员检查错误,及 时修正缺陷。
Qt是1991年由奇趣科技开发的跨平台C++图形用户界面应用程序开发框架,Qt库中很 多类都以QObject作为他们的基类,QObject的对象总是以树状结构组织自己。当我们创建 一个QObject对象时,可以指定其父对象(也被称为父控件),新创建的对象将被加入到父对 象的子对象(也被称为子控件)列表中。当父对象被析构时,这个列表中的所有对象会被析 构。不但如此,当某个QObject对象被析构时,它会将自己从父对象的列表中删除,以避免 父对象被析构时再次析构自己。
由于QObject对象具有上述析构功能,当我们使用new操作符在堆中创建Qobject对象 时,并不需要使用delete操作符析构它们。
所以编写Qt程序时,开发人员很容易写出内存处理不适当的程序导致内存泄露。
三、发明内容
本发明的目的旨在解决航管训练系统开发中使用Qt开发人机界面中,由于Qt程序特殊 性可能带来的内存泄露问题。
本发明的目的是这样达到的:一种航管训练系统开发中Qt程序内存静态检查方法,其特 征在于:在航管训练系统中运行一个Qt程序内存使用静态的检查程序,该程序运行时将被检 查的代码所在的目录作为运行参数,目录可以有子目录,得到检测结果后,将监测结果输出到 日志文件或控制台。
本方法专门针对Qt程序中两种Qt专属的两种内存泄露情况提供检查能力:Qt控件对象没有 父控件,在堆中new了这个对象;Qt控件对象有父控件。
检测在如下5个模块中进行:
1)、遍历工程目录和子目录下的所有后缀名为.cpp和.h文件,把文件全路径保存为 string类型,再存放到vector类型的cpp_file中;
2)、遍历cpp_file中的每个文件,按行读取文件每行信息,解析new和delete语句, 得到Qt控件对象的创建信息和所有对象的删除信息;
3)、解析得到的Qt控件对象的创建信息存放在newOBJMap中,所有对象的删除信息存 放在deleteOBJMap中;
4)、遍历newOBJMap中的每个元素,在deleteOBJMap中查找对应的元素,如果存在对 应元素,则将信息合并,存放在QtObjectMap中;
5)、遍历QtObjectMap中每个元素,得到检测结果,输出到日志文件或控制台。
所述在1)模块中进行的检测,是通过Windows系统提供的_findfirst()和_findnext() 函数遍历某个工程文件下的所有文件,并把.h和.cpp文件全路径名存放在一个Vector类型 的cpp_file中,具体步骤是:
开始,第一步,控制台获取工程目录,第二步,判断findfrist获取当前目录下第一个实 例句柄,句柄值为-1L?是,结束,否,第三步,findnext根据_findfirst获得的句柄遍历 目录下的所有实例,判断返回值是否为0?是,结束,否,进入第四步,判断此实例为子文 件夹吗?是,当前目录链接文件夹名字得到新的目录,返回第二步,否,进入第五步,判断 此实例为.cpp或.h文件吗?是,第六步,将.cpp和.h文件的全名保存到vector类型的 cpp_file中,返回第三步。
所述在模块2)中进行的检测具体步骤是:
开始,第一步,判断文件结束?是,结束,否,第二步,读取每行文本,保存在string 类型的line中,第三步,判断line为注释吗?是,结束,否,进入第四步,判断是line为 new或delete语句?否,进入第五步,判断是new语句?是,解析line得到的删除对象信 息,文件位置更信息,并将得到的信息保存在deleteOBJMap中,返回第一步;是new语句, 进入第六步,解析语句获得创建对象的类别,第七步,根据类别判断为Qt空间类?不是,结 束,是,第八步,将解析得到的Qt控件,父控件,文件位置信息保存到newOBJMap中,返 回第一步。
所述在模块4)中进行的检测具体步骤是:
开始,第一步,判断newOBJMap结束?是,结束,否,第二步,获取newOBJMap的下一 元素,第三步,判断在deleteOBJMap中找到对应元素?是,第四步,将这两个元素合并,保 存到QtObjectMap,结束;否,把newOBJMap信息保存到QtObjectMap中,无删除信息补空, 回复到第一步。
所述在模块2)进行的检测具体步骤中第三步,判断line是否为注释识别对象分为两种: //行注释,/**/段注释,注释和代码区别对待,设置一个bool变量result区别该行代码 是不是注释即可,Result由解析代码的函数返回值更新;
若为行注释,直接跳过该行即可,并设result为commentEnd,表示注释结束;若为段注 释,且没有在一行中同时出现/*和*/,则result值为commentBegin,表示注释开始;若 在一行中同时出现/*和*/,则result值为commentEnd,表示注释结束;
解析每行代码时,根据result值选择不同的解析函数,parseComment()为解析注释的函数, parseCode()为解析代码的函数;
第七步中,根据类别判断为Qt空间类识别对象时分为两步:
(1)识别出程序中创建对象的语句;
(2)判断识别出的对象是不是Qt对象:Qt控件所属的类都是有继承关系的,且最终的父对 象都为QWidget,针对这种继承树的关系,通过读取InheritTree.ini配置文件建立一个树 的结构,树结构提供了一个接口:findChild(string key,POINTER*p),返回值为指针p指 向树中关键字为key的结点,如果树中不存在关键字为key的结点,则p的值为NULL,把某 个类名作为实参传给key,可判断此类是不是Qt的控件类了,即能判断对象的对象是不是Qt 控件对象。
本发明的积极效果是:有效解决了航管训练系统开发中,使用Qt开发人机界面时,因Qt 特殊性可能带来的内存泄露问题,保证系统的安全。由于本发明方法检测后得到的结果,输 出到日志文件或控制台,开发人员可及时方便地发现问题,及时修正缺陷。对提高航管训练 系统自身的可靠性和实用性有非常现实的积极意义。
四、附图说明
图1是本发明Qt程序内存使用静态检测软件模块组成图。
图2是在模块扫描工程所有.cpp和.h文件流程图。
图3是读inheritTree.ini配置文件生成Qt控件类的继承树示意图。
图4是解析每个文件流程图。
图5是合并newOBJMap和deleteOBJMap流程图。
五、具体实施方式
本发明专门针对航管训练系统开发中使用Qt进行人机界面开发的程序进行静态检查而研 究的新方法,解决Qt程序开发中产生的内存泄露问题。
技术实现的总思路是专门针对Qt开发中两种Qt专属的两种内存泄露情况提供检查能力:
本方法专门针对Qt开发中两种Qt专属的两种内存泄露情况提供检查能力:
Qt控件对象若没有父控件,如果在堆中new了这个对象,那么必须编码实现删除,否则 会有内存泄露;
Qt控件对象有父控件,此时无需程序员手动delete这个Qt控件,因为父控件在析构时, 会自动析构自己的子控件列表里的控件,这是Qt提供的自动内存机制,而程序员可能误写删 除代码,造成内存泄露。
除此之外还有其他属于C++语言使用的中内存泄露和冗余delete的情况,该方法没有涉 及这些情况的检测。
本方法由几个模块组成,如图1所示。
在模块1中,通过Windows系统提供的_findfirst()和_findnext()函数遍历工程目录和 子目录下的所有.cpp和.h文件,把文件全路径保存为string类型,再存放到vector类型的 cpp_file中。
具体步骤是见附图2:
开始,第一步,控制台获取工程目录,第二步,判断findfrist获取当前目录下第一个实 例句柄,句柄值为-1L?是,结束,否,第三步,,findnext根据_findfirst获得的句柄遍历 目录下的所有实例,判断返回值是否为0?是,结束,否,进入第四步,判断此实例为子文 件夹吗?是,当前目录链接文件夹名字得到新的目录,返回第二步,否,进入第五步,判断 此实例为.cpp或.h文件吗?是,将.cpp和.h文件的全名保存到vector类型的cpp_file中, 返回第三步。
在模块2中,遍历cpp_file中的每个文件,按行读取文件每行信息,解析new和delete 语句,得到Qt控件对象的创建信息和所有对象的删除信息。
解析文件中的new和delete语句时,对于某一文件,用getLine()获取文件中的每一行代码。
解析过程见图4,具体步骤是:
开始,第一步,判断文件结束?是,结束,否,第二步,读取每行文本,保存在string 类型的line中,第三步,判断line为注释吗?是,结束,否,进入第四步,判断是line为 new或delete语句?否,进入第五步,判断是new语句?是,解析line得到的删除对象信 息,文件位置更信息,并将得到的信息保存在deleteOBJMap中,返回第一步;是new语句, 进入第六步,解析语句获得创建对象的类别,第七步,根据类别判断为Qt空间类?不是,结 束,是,第八步,将解析得到的Qt控件,父控件,文件位置信息保存到newOBJMap中,返 回第一步。
对于识别注释部分和非注释部分:
注释分两种//行注释,/**/段注释,注释和代码是要区别对待的,设置一个bool变量 result区别该行代码是不是注释即可。Result由解析代码的函数返回值更新。
若为行注释,直接跳过该行即可,并设result为commentEnd(表示注释结束)。若为段注释, 且没有在一行中同时出现/*和*/,则result值为commentBegin(表示注释开始)。若在一 行中同时出现/*和*/,则result值为commentEnd(表示注释结束)。
解析每行代码时,根据result值选择不同的解析函数parseComment()(解析注释的函数), parseCode()(解析代码的函数)。
对于识别QT控件对象分为两步:
(1)识别出程序中创建对象的语句
通过对Qt程序的了解,创建Qt控件对象一般是这种结构。
例如:
QPushButon m_button=new QPushButton(Parent);
此行代码最有标志性的词就是new和’=’了,并且应该是一个独立的new这个关键字,要排 除***new***这种情况。
首先,要从这行代码中获取的信息是:对象名(m_button),类名(QPushButton),父对象 (parent)。
思路是通过”=”,”new”,”()”来获取每个标识符的begin(第一个字符在整行string 中的索引),end(最后一个字符在整行string中的索引)。然后通过begin和end即可获得 每个标示符。
C++中string类提供了很多接口可以直接使用。Substr(begin,len)用来截取子串,find (“arg”)用来寻找索引值,这两个函数的配合使用可完成上述功能。
(2)判断识别出的对象是不是Qt控件对象
考虑到要识别所有的Qt控件对象,是一个繁杂的工作,所以只是找了一些常用的Qt控件对 象,以供识别。但是这不是固定的,如果有新的需要的话,可以在InheritTree.ini配置文 件里手动添加新的对象。
Qt控件所属的类都是有继承关系的,且最终的父对象都为QWidget,针对这种继承树的关系, 建立了一个树的结构,树结构的建立是通过读取InheritTree.ini配置文件建立的。
InheritTree.ini文件结构示例:
[树的高度]
depthNum=n
[高度0]
NodeNum=1//当前高度下结点数目
QWidget=NULL//等号左边是空间类,右边是起父类
[高度1]
...
[高度n-1]
...
树结构提供了一个接口,findChild(std::string key,,TreeNodePointer*p),入口 参数string key,返回值为TreeNodePointer*p,返回值是指针p指向树中关键字为key的结 点,如果树中不存在关键字为key的结点,则p的值为NULL。这个结构能判断树中是否存在 关键字为key的结点。因此,把某个类名作为实参传给key,就可判断此类是不是Qt的控件 类了,也就能判断对象的对象是不是QT控件对象了。这里,TreeNodePointer为数据结构
TreeNodePointer为指向一个描述树形结构节点的指针,该节点内容包括:节点内容key,该 节点的子节点列表child_array,子节点个数child_num,节点的父节点parent。
读inheritTree.ini配置文件生成Qt控件类的继承树参见图3。
在模块3中,解析得到的Qt控件对象的创建信息存放在newOBJMap中,所有对象的删 除信息存放在deleteOBJMap中。
删除对象语句的识别处理方式和在模块2中的识别相同,不再赘述。不过此处因为无法 得到类名,无法判断是不是Qt控件类的对象,所以把所有对象全部保存在下面提到的 deleteOBJMap中。
向deleteOBJMap和newOBJMap里添加删除和创建对象的信息,将上一步识别出的new和 delete语句中的信息保存在以下两个结构体中:
这两个结构体类型的对象分别放在newOBJMap,deleteOBJMap中。
在模块4中,遍历newOBJMap中的每个元素,在deleteOBJMap中查找对应的元素,如 果存在对应元素,则将信息合并,存放在QtObjectMap中;
合并newOBJMap和deleteOBJMap,流程参见附图5。
具体步骤是:开始,第一步,判断newOBJMap结束?是,结束,否,第二步,获取newOBJMap 的下一元素,第三步,判断在deleteOBJMap中找到对应元素?是,将这两个元素合并,保存 到QtObjectMap,结束。否,把newOBJMap信息保存到QtObjectMap中,无删除信息补空, 回复到第一步。
将delteOBJMap和newOBJMap中的信息组合到QTObjectMap中时通过循环迭代,找到 newOBJMap里的每个Qt控件对象,看delteOBJMap中是否有对应的信息,如果有,就把这两 个结构体对象里的信息整合到以下结构体中:
把此结构体对象插入到QTObjectMap中。
在模块5中,遍历QtObjectMap中每个元素,得到检测结果,输出到日志文件或控制台。 根据QTObjectMap中的信息输出检测结果,
在QTObjectMap中的每个对象QTOBJ
最后输出结果到控制台和日志文件中。
最后的结果输出到控制台和日志文件中后,有利于开发人员进行修改:
以检查E://航管训练目录下的所有文件为例,输出示例如下:
疑似内存泄露:objectName(控件对象名)E://航管训练//a.cpp(创建对象文件全目 录)600(行号);
疑似手工删除错误:objectName(控件名)parentName(父控件名)E://航管训练 //a.cpp(创建对象文件全目录)600(行号)E://航管训练//a.cpp(删除对象文件全目录) (行号)。
机译: 一种用于风力发电厂的建筑结构状况检查方法,包括使用评估单元基于从不同建筑物部件中设置的传感器的测量值转换而来的静态值来计算建筑结构的寿命
机译: 一种在武器模拟器中训练和使用枪支的方法,用于执行这种方法的武器模拟器,这种武器模拟器的中央控制计算机以及到该控制计算机的程序的计算机程序
机译: 检测计算机系统上的攻击,特别是病毒类型的攻击,从而使用一种通用方法,该方法能够检测隐藏在数据链中的攻击程序,这些数据链通过可检测的指令加载到内存中