客户说 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识别得不好。我们下回接着研究。