valgrind 报告 ecpg内存泄露

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

原文地址:https://www.cnblogs.com/gaojian/p/2637891.html