客户说 valgrind 报告 ecpg内存泄露,实际到底如何呢?
用程序来进行验证:我的test.pc 程序:
复制代码
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int tst_connectdb(const char *Uid,const char *Pswd,const char *Host,char *SqlErrm){
EXEC SQL BEGIN DECLARE SECTION;
varchar sUserid[10];
varchar sPasswd[10];
varchar sHostname[10];
EXEC SQL END DECLARE SECTION;
memset(sUserid.arr, '\0',sizeof(sUserid.arr));
memset(sPasswd.arr, '\0',sizeof(sPasswd.arr));
memset(sHostname.arr, '\0',sizeof(sHostname.arr));
if (Uid == NULL || Pswd == NULL ||
Host == NULL || SqlErrm == NULL){
return -1;
}
strcpy((char *)sUserid.arr, Uid);
sUserid.len = (unsigned short)strlen((char *)sUserid.arr);
strcpy((char *)sPasswd.arr, pcDbPswd);
sPasswd.len = (unsigned short)strlen((char *)sPasswd.arr);
strcpy((char *)sHostname.arr, pcHostname);
sHostname.len = (unsigned short)strlen((char *)sHostname.arr);
EXEC SQL CONNECT TO:sHostname AS TST_DBCONN USER:sUserid IDENTIFIED BY:sPasswd;
if (sqlca.sqlcode!=0){
return -1;
}
return 0;
}
int main(){
int ist=0;
char * perr;
perr = (char *) malloc (sizeof(char)*64);
const char * pusr="testusr";
const char * ppass="testpass";
const char * phost="testhost";
ist= tst_connectdb(pusr,ppass,phost,perr);
free(perr);
return 0;
}
复制代码
而预编译而成的程序如下 test.c:
复制代码
/* Processed by ecpg (4.7.0) */
/* These include files are added by the preprocessor */
#include <ecpglib.h>
#include <ecpgerrno.h>
#include <sqlca.h>
/* End of automatic include section */
#line 1 "test.pc"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int tst_connectdb(const char *Uid,const char *pcDbPswd,const char *pcHostname,char *pcSqlErrm){
/* exec sql begin declare section */
#line 7 "test.pc"
struct varchar_sUserid_1 { int len; char arr[ 10 ]; } sUserid ;
#line 8 "test.pc"
struct varchar_sPasswd_2 { int len; char arr[ 10 ]; } sPasswd ;
#line 9 "test.pc"
struct varchar_sHostname_3 { int len; char arr[ 10 ]; } sHostname ;
/* exec sql end declare section */
#line 10 "test.pc"
memset(sUserid.arr, '\0',sizeof(sUserid.arr));
memset(sPasswd.arr, '\0',sizeof(sPasswd.arr));
memset(sHostname.arr, '\0',sizeof(sHostname.arr));
if (Uid == NULL || pcDbPswd == NULL ||
pcHostname == NULL || pcSqlErrm == NULL){
return -1;
}
strcpy((char *)sUserid.arr, Uid);
sUserid.len = (unsigned short)strlen((char *)sUserid.arr);
strcpy((char *)sPasswd.arr, pcDbPswd);
sPasswd.len = (unsigned short)strlen((char *)sPasswd.arr);
strcpy((char *)sHostname.arr, pcHostname);
sHostname.len = (unsigned short)strlen((char *)sHostname.arr);
{ ECPGconnect(__LINE__, 0, sHostname.arr , sUserid.arr , sPasswd.arr , "TST_DBCONN", 0); }
#line 29 "test.pc"
if (sqlca.sqlcode!=0){
return -1;
}
return 0;
}
int main(){
int ist=0;
char * perr;
perr = (char *) malloc (sizeof(char)*64);
const char * pusr="testusr";
const char * ppass="testpass";
const char * phost="testhost";
ist= tst_connectdb(pusr,ppass,phost,perr);
free(perr);
return 0;
}
复制代码
对test.c进行编译后,用valgrind进行检验:
valgrind ./test.o
复制代码
[root@post1 gao]# /usr/local/pgsql/bin/ecpg -o test.c test.pc
[root@post1 gao]# gcc -o test.o test.c -I /usr/local/pgsql/include -L/usr/local/pgsql/lib -lecpg
[root@post1 gao]# valgrind ./test.o
==4965== Memcheck, a memory error detector
==4965== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==4965== Using Valgrind-3.8.0 and LibVEX; rerun with -h for copyright info
==4965== Command: ./test.o
==4965==
==4965== Invalid free() / delete / delete[] / realloc()
==4965== at 0x4006A9D: free (vg_replace_malloc.c:446)
==4965== by 0xB0321D: free_mem (in /lib/libc-2.5.so)
==4965== by 0xB02D96: __libc_freeres (in /lib/libc-2.5.so)
==4965== by 0x4001468: _vgnU_freeres (vg_preloaded.c:62)
==4965== by 0xA83013: _Exit (in /lib/libc-2.5.so)
==4965== by 0xA06EA3: (below main) (in /lib/libc-2.5.so)
==4965== Address 0x4000b78 is not stack'd, malloc'd or (recently) free'd
==4965==
==4965==
==4965== HEAP SUMMARY:
==4965== in use at exit: 220 bytes in 1 blocks
==4965== total heap usage: 31 allocs, 31 frees, 35,279 bytes allocated
==4965==
==4965== LEAK SUMMARY:
==4965== definitely lost: 0 bytes in 0 blocks
==4965== indirectly lost: 0 bytes in 0 blocks
==4965== possibly lost: 0 bytes in 0 blocks
==4965== still reachable: 220 bytes in 1 blocks
==4965== suppressed: 0 bytes in 0 blocks
==4965== Rerun with --leak-check=full to see details of leaked memory
==4965==
==4965== For counts of detected and suppressed errors, rerun with: -v
==4965== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 21 from 8)
[root@post1 gao]#
复制代码
对于 invalid free()那一段,可以忽略不计。这是因为,即使是 int main(){},也会这么报错。
最关键的就是:still reachable: 220 bytes in 1 blocks
为了研究其原因,把如下这一段代码注释掉:
/**
EXEC SQL CONNECT TO :sHost AS TST_DBCONN USER:sUserid IDENTIFIED BY :sPasswd;
if (sqlca.sqlcode!=0){
return -1;
}
*/
再看 valgrind ./test.o 就不再出现 still reachable 信息了:
==4990== HEAP SUMMARY:
==4990== in use at exit: 0 bytes in 0 blocks
==4990== total heap usage: 1 allocs, 2 frees, 64 bytes allocated
==4990==
==4990== All heap blocks were freed -- no leaks are possible
所以,EXEC SQL CONNECT 会导致 valgrind 判断它有未释放的内存。
那么是否真的如此呢,其实并不是泄露,而是valgrind 对 ecpg识别得不好。我们下回接着研究。
本文转自健哥的数据花园博客园博客,原文链接:http://www.cnblogs.com/gaojian/archive/2012/08/14/2637891.html,如需转载请自行联系原作者