当前位置:首页 > > 充电吧
[导读]这是我一直收藏的一篇文章,出处已经无法知道。根据自己实践增加了部分说明,现在分享出来。 该方法只能定位 显性 泄漏,定位到的C语句一定产生泄漏了,但可能这个位置是 “ 理论上 ” 不会出问题的代码.那

这是我一直收藏的一篇文章,出处已经无法知道。

根据自己实践增加了部分说明,现在分享出来。

 

该方法只能定位 显性 泄漏,定位到的C语句一定产生泄漏了,但可能这个位置是 “ 理论上 ” 不会出问题的代码.那么这是由于同进程内其他代码泄漏而影响了进程的堆区或栈区(隐性泄漏,这个地方不会产生data abort exception),然后被定位出来的代码才被动地显性泄露 , 产生data abort 。

首先在DEBUG版本中定位DATA ABORT的方法,地球人应该都知道了吧,我就不废话了。Platform   Builder或VS2005、EVC这类IDE工具会在DEBUG模式下自动停在出错的那句,情况就很显然了。

RELEASE版本下的泄漏就要稍微麻烦一点,如何快速定位呢?


案例一:用EVC编译的应用程序泄漏

首先我做了一个内存泄漏的程序MemoryLeakTest.exe,里面做了一个泄漏的函数 :

编译的时候注意先在project settings里的Link页里勾选“Generate mapfile”,会生成一个map文件。

另外,VS2005/VS2008也可以在工程属性中找到类似的选项,然后指定 MAP 文件名即可。


把编译出来的RELEASE版本可执行文件放到CE5平台下运行。出错的时候串口打印了一句

Data Abort: Thread=83ad1d38 Proc=820266d0 'MemoryLeakTest.exe'
AKY=00000021 PC=00011008(MemoryLeakTest.exe+0x00001008) RA=00011030(MemoryLeakTest.exe+0x00001030) BVA=81000000 FSR=0000000d

这句是系统自动输出的。我们得到了一个关键的信息:PC指针。和PC指针在MemoryLeakTest.exe中的偏移量。然后打开编译时生成的MemoryLeakTest.map文件,文件 内容如下:

MemoryLeakTest

Timestamp is 46fcbb17 (Fri Sep 28 16:28:07 2007)

Preferred load address is 00010000

Start         Length     Name                   Class
0001:00000000 00000258H .text                   CODE
0002:00000000 00000014H .xdata                  DATA
0002:00000014 00000014H .idata$2                DATA
0002:00000028 00000014H .idata$3                DATA
0002:0000003c 00000010H .idata$4                DATA
0002:0000004c 0000000cH .idata$6                DATA
0002:00000058 00000000H .edata                  DATA
0003:00000000 00000010H .idata$5                DATA
0003:00000010 00000004H .CRT$XCA                DATA
0003:00000014 00000004H .CRT$XCZ                DATA
0003:00000018 00000004H .CRT$XIA                DATA
0003:0000001c 00000004H .CRT$XIZ                DATA
0003:00000020 00000004H .CRT$XPA                DATA
0003:00000024 00000004H .CRT$XPZ                DATA
0003:00000028 00000004H .CRT$XTA                DATA
0003:0000002c 00000004H .CRT$XTZ                DATA
0003:00000030 00000009H .bss                    DATA
0004:00000000 00000038H .pdata                  DATA
0005:00000000 00000010H .rsrc$01                DATA
0005:00000010 00000000H .rsrc$02                DATA

  Address         Publics by Value              Rva+Base     Lib:Object

 0001:00000000       ?MemoryLeak@@YAXXZ        00011000 f   MemoryLeakTest.obj
0001:00000010       WinMain                    00011010 f   MemoryLeakTest.obj
0001:0000002c       WinMainCRTStartup          0001102c f   corelibc:pegwmain.obj
0001:000000a0       _cinit                     000110a0 f   corelibc:crt0dat.obj
0001:00000210       exit                       00011210 f   corelibc:crt0dat.obj
0001:00000228       _XcptFilter                00011228 f   coredll:COREDLL.dll
0001:00000238       __C_specific_handler       00011238 f   coredll:COREDLL.dll
0001:00000248       LocalFree                  00011248 f   coredll:COREDLL.dll
0002:00000014       __IMPORT_DESCRIPTOR_COREDLL 00012014     coredll:COREDLL.dll
0002:00000028       __NULL_IMPORT_DESCRIPTOR   00012028     coredll:COREDLL.dll
0003:00000000       __imp___C_specific_handler 00013000     coredll:COREDLL.dll
0003:00000004       __imp_LocalFree            00013004     coredll:COREDLL.dll
0003:00000008       __imp__XcptFilter          00013008     coredll:COREDLL.dll
0003:0000000c       /177COREDLL_NULL_THUNK_DATA 0001300c     coredll:COREDLL.dll
0003:00000010       __xc_a                     00013010     corelibc:crt0init.obj
0003:00000014       __xc_z                     00013014     corelibc:crt0init.obj
0003:00000018       __xi_a                     00013018     corelibc:crt0init.obj
0003:0000001c       __xi_z                     0001301c     corelibc:crt0init.obj
0003:00000020       __xp_a                     00013020     corelibc:crt0init.obj
0003:00000024       __xp_z                     00013024     corelibc:crt0init.obj
0003:00000028       __xt_a                     00013028     corelibc:crt0init.obj
0003:0000002c       __xt_z                     0001302c     corelibc:crt0init.obj
0003:00000030       __onexitend                00013030     

 entry point at        0001:0000002c

 Static symbols

 0001:0000010c       doexit                     0001110c f   corelibc:crt0dat.obj

OK,首先,里面有一句“Preferred load address is 00010000”,这意味着DATA ABORT那句的PC=00011008(MemoryLeakTest.exe+0x00001008) 我们必须把括号里的0x1008加上这个load address的偏移量,得到0x11008(注意不能直接用PC,一会儿再给个案例就知道了),然后我们在函数偏移列表里看Rva+Base这栏,找到0x11008落在了MemoryLeak函数的地址范围里,所以是MemoryLeak函数泄漏了。


案例二:在OAL层做了一个泄漏的函数,用Platform Builder进行RELEASE版编译并LINK到NK.exe里,然后应用程序MemoryLeakPB.exe调用该函数导致泄漏

步骤类似,只是Platform Builder默认就会在RELEASE目录下生成.map文件。应用程序去调用泄漏的OAL函数时,出现

Data Abort: Thread=822fc000 Proc=820267c0 'MemoryLeakPB.exe'
AKY=00000041 PC=8023e3c8(NK.EXE+0x0003e3c8) RA=8023e1d4(NK.EXE+0x0003e1d4) 
BVA=8e000000 FSR=00000005

注意我们这次是NK.EXE里制造泄漏,所以PC指针不是在0x00011008这样的Slot 0低地址了,而是在0x80000000以上的KERNEL区域了。
nk.map很长,我选择关键段落来贴

************************************************************
kern

 Timestamp is 46fca696 (Fri Sep 28 15:00:38 2007)

  Preferred load address is 00010000

 ...
0001:0003d2c8       OALIoCtlHal_GetDeviceId    0004e2c8 f   oal_ioctl:deviceid.obj
0001:0003d398       OALIoCtlHal_MemoryLeak     0004e398  f   oal_ioctl:leaktest.obj
0001:0003d438       OALIoCtlHal_DdkCall        0004e438 f   oal_io:ioctl.obj
...
************************************************************

所以 NK.EXE + 0x0003e3c8 = 0x10000(Preferred load address) + 0x0003e3c8 = 0x4e3c8, 落在了OALIoCtlHal_MemoryLeak函数里

结论:原理上很简单,就是利用DATA ABORT消息中的PC值,配合MAP文件可以快速定位到泄漏的函数。定位到之后,嘿嘿,谁LEAK谁请客咯。

 

用上文的方法,不但网友kevin没有成功定位到泄漏的原因(见后面回帖,他定位到微软USBFN的MDD层代码),我这项目组里的人也没抓到原因(定位到PRIVATE下LoadLibrary函数相关的代码)。昨晚我想了下,这个方法的确有漏洞,早上我做了个试验,建立个DialogBox,主处理函数如下



我运行了几次,每次该进程的BaseAddr = 0x1A000000,  而  &gpTest = 0x1A013860 ,在进程的全局变量区; malloc 之后 gpTest = 0x00030230 在进程的堆区。所以我 :
(1) 在 ID_LEAK 按钮按下后,模拟一次内存泄漏,直接对 &gpTest 地址上的数值改写,把 malloc 后的 0x00030230 改成 0x00000000,  注意虽然该处已经泄漏了,但是并没有产生 data abort exception.

(此处当然不会出错!如果出错,那么给 gpTest 赋值为空时一样会出错)
(2) 然后在 ID_CLOSE 按钮按下后,装做不知道前面那处泄漏,代码风格严谨地先判断下指针是否为空,然后试图在 malloc 得到的堆区  0x00030230 地址上写个值,但是由于 gpTest 这个指针已经被改写为指向其他进程空间了,所以在 *gpTest = 1 这句产生 data abort exception 并停下来了。

(说明  gpTest  的值被误修改了,否则不会出错)
(3) 所以,按照上文的方法,只能抓到 *gpTest = 1 这句泄露,而实际上这句是无辜的,真正的元凶 *((int*)0x1A013860) = 0x1C000000 这句却没有被抓出来。

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: 驱动电源

在工业自动化蓬勃发展的当下,工业电机作为核心动力设备,其驱动电源的性能直接关系到整个系统的稳定性和可靠性。其中,反电动势抑制与过流保护是驱动电源设计中至关重要的两个环节,集成化方案的设计成为提升电机驱动性能的关键。

关键字: 工业电机 驱动电源

LED 驱动电源作为 LED 照明系统的 “心脏”,其稳定性直接决定了整个照明设备的使用寿命。然而,在实际应用中,LED 驱动电源易损坏的问题却十分常见,不仅增加了维护成本,还影响了用户体验。要解决这一问题,需从设计、生...

关键字: 驱动电源 照明系统 散热

根据LED驱动电源的公式,电感内电流波动大小和电感值成反比,输出纹波和输出电容值成反比。所以加大电感值和输出电容值可以减小纹波。

关键字: LED 设计 驱动电源

电动汽车(EV)作为新能源汽车的重要代表,正逐渐成为全球汽车产业的重要发展方向。电动汽车的核心技术之一是电机驱动控制系统,而绝缘栅双极型晶体管(IGBT)作为电机驱动系统中的关键元件,其性能直接影响到电动汽车的动力性能和...

关键字: 电动汽车 新能源 驱动电源

在现代城市建设中,街道及停车场照明作为基础设施的重要组成部分,其质量和效率直接关系到城市的公共安全、居民生活质量和能源利用效率。随着科技的进步,高亮度白光发光二极管(LED)因其独特的优势逐渐取代传统光源,成为大功率区域...

关键字: 发光二极管 驱动电源 LED

LED通用照明设计工程师会遇到许多挑战,如功率密度、功率因数校正(PFC)、空间受限和可靠性等。

关键字: LED 驱动电源 功率因数校正

在LED照明技术日益普及的今天,LED驱动电源的电磁干扰(EMI)问题成为了一个不可忽视的挑战。电磁干扰不仅会影响LED灯具的正常工作,还可能对周围电子设备造成不利影响,甚至引发系统故障。因此,采取有效的硬件措施来解决L...

关键字: LED照明技术 电磁干扰 驱动电源

开关电源具有效率高的特性,而且开关电源的变压器体积比串联稳压型电源的要小得多,电源电路比较整洁,整机重量也有所下降,所以,现在的LED驱动电源

关键字: LED 驱动电源 开关电源

LED驱动电源是把电源供应转换为特定的电压电流以驱动LED发光的电压转换器,通常情况下:LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: LED 隧道灯 驱动电源
关闭