C 双重自由或腐败崩溃

C 双重自由或腐败崩溃,c,memory-management,malloc,free,glibc,C,Memory Management,Malloc,Free,Glibc,我有一个从数据库读/写的程序(smbanner),最近我添加了一个加密例程,在DB write上加密数据,在DB read上解密数据(smbanner通过调用其他地方的一些DB读/写例程进行读/写…在那些DB例程中,我注入了加密调用)。我还要补充一点,我把它扔到了我的膝盖上,而C语言离我的第一语言还差得远,所以请友好一点 我所有的代码都编译得很好,cppcheck静态分析说它很好,多个环境运行它也很好。。。除了一个。在这种环境下,我得到以下信息: [root@mndemo update]# **

我有一个从数据库读/写的程序(smbanner),最近我添加了一个加密例程,在DB write上加密数据,在DB read上解密数据(smbanner通过调用其他地方的一些DB读/写例程进行读/写…在那些DB例程中,我注入了加密调用)。我还要补充一点,我把它扔到了我的膝盖上,而C语言离我的第一语言还差得远,所以请友好一点

我所有的代码都编译得很好,cppcheck静态分析说它很好,多个环境运行它也很好。。。除了一个。在这种环境下,我得到以下信息:

[root@mndemo update]# *** glibc detected *** /home/silentm/bin/smbanner: double free or corruption (!prev): 0x000000000455e750 ***
======= Backtrace: =========
/lib64/libc.so.6[0x374e075e66]
/lib64/libc.so.6[0x374e0789b3]
/lib64/libc.so.6(fclose+0x14d)[0x374e0664cd]
/home/silentm/bin/smbanner[0x4b6ffb]
/home/silentm/bin/smbanner[0x480f00]
/home/silentm/bin/smbanner[0x40dcac]
/lib64/libc.so.6(__libc_start_main+0xfd)[0x374e01ed5d]
/home/silentm/bin/smbanner[0x403849]
======= Memory map: ========
00400000-00613000 r-xp 00000000 09:01 25886937                           /home/silentm/bin/smbanner
00813000-008e7000 rw-p 00213000 09:01 25886937                           /home/silentm/bin/smbanner
008e7000-00b11000 rw-p 00000000 00:00 0 
01091000-0456f000 rw-p 00000000 00:00 0                                  [heap]
3569000000-35691b9000 r-xp 00000000 09:00 917372                         /usr/lib64/libcrypto.so.1.0.1e
35691b9000-35693b8000 ---p 001b9000 09:00 917372                         /usr/lib64/libcrypto.so.1.0.1e
35693b8000-35693d3000 r--p 001b8000 09:00 917372                         /usr/lib64/libcrypto.so.1.0.1e
35693d3000-35693df000 rw-p 001d3000 09:00 917372                         /usr/lib64/libcrypto.so.1.0.1e
35693df000-35693e3000 rw-p 00000000 00:00 0 
374dc00000-374dc20000 r-xp 00000000 09:00 783364                         /lib64/ld-2.12.so
374de1f000-374de20000 r--p 0001f000 09:00 783364                         /lib64/ld-2.12.so
374de20000-374de21000 rw-p 00020000 09:00 783364                         /lib64/ld-2.12.so
374de21000-374de22000 rw-p 00000000 00:00 0 
374e000000-374e18a000 r-xp 00000000 09:00 783367                         /lib64/libc-2.12.so
374e18a000-374e38a000 ---p 0018a000 09:00 783367                         /lib64/libc-2.12.so
374e38a000-374e38e000 r--p 0018a000 09:00 783367                         /lib64/libc-2.12.so
374e38e000-374e38f000 rw-p 0018e000 09:00 783367                         /lib64/libc-2.12.so
374e38f000-374e394000 rw-p 00000000 00:00 0 
374e400000-374e417000 r-xp 00000000 09:00 783373                         /lib64/libpthread-2.12.so
374e417000-374e617000 ---p 00017000 09:00 783373                         /lib64/libpthread-2.12.so
374e617000-374e618000 r--p 00017000 09:00 783373                         /lib64/libpthread-2.12.so
374e618000-374e619000 rw-p 00018000 09:00 783373                         /lib64/libpthread-2.12.so
374e619000-374e61d000 rw-p 00000000 00:00 0 
374e800000-374e802000 r-xp 00000000 09:00 783380                         /lib64/libdl-2.12.so
374e802000-374ea02000 ---p 00002000 09:00 783380                         /lib64/libdl-2.12.so
374ea02000-374ea03000 r--p 00002000 09:00 783380                         /lib64/libdl-2.12.so
374ea03000-374ea04000 rw-p 00003000 09:00 783380                         /lib64/libdl-2.12.so
374ec00000-374ec15000 r-xp 00000000 09:00 783377                         /lib64/libz.so.1.2.3
374ec15000-374ee14000 ---p 00015000 09:00 783377                         /lib64/libz.so.1.2.3
374ee14000-374ee15000 r--p 00014000 09:00 783377                         /lib64/libz.so.1.2.3
374ee15000-374ee16000 rw-p 00015000 09:00 783377                         /lib64/libz.so.1.2.3
374f400000-374f483000 r-xp 00000000 09:00 783388                         /lib64/libm-2.12.so
374f483000-374f682000 ---p 00083000 09:00 783388                         /lib64/libm-2.12.so
374f682000-374f683000 r--p 00082000 09:00 783388                         /lib64/libm-2.12.so
374f683000-374f684000 rw-p 00083000 09:00 783388                         /lib64/libm-2.12.so
3750800000-3750816000 r-xp 00000000 09:00 783389                         /lib64/libgcc_s-4.4.7-20120601.so.1
3750816000-3750a15000 ---p 00016000 09:00 783389                         /lib64/libgcc_s-4.4.7-20120601.so.1
3750a15000-3750a16000 rw-p 00015000 09:00 783389                         /lib64/libgcc_s-4.4.7-20120601.so.1
3757c00000-3757d49000 r-xp 00000000 09:00 929936                         /usr/lib64/libxml2.so.2.7.6
3757d49000-3757f48000 ---p 00149000 09:00 929936                         /usr/lib64/libxml2.so.2.7.6
3757f48000-3757f51000 rw-p 00148000 09:00 929936                         /usr/lib64/libxml2.so.2.7.6
3757f51000-3757f53000 rw-p 00000000 00:00 0 
7f657423e000-7f657424a000 r-xp 00000000 09:00 783433                     /lib64/libnss_files-2.12.so
7f657424a000-7f657444a000 ---p 0000c000 09:00 783433                     /lib64/libnss_files-2.12.so
7f657444a000-7f657444b000 r--p 0000c000 09:00 783433                     /lib64/libnss_files-2.12.so
7f657444b000-7f657444c000 rw-p 0000d000 09:00 783433                     /lib64/libnss_files-2.12.so
7f657444c000-7f6574451000 rw-p 00000000 00:00 0 
7f6574465000-7f6574467000 rw-p 00000000 00:00 0 
7fff289a1000-7fff28bcf000 rw-p 00000000 00:00 0                          [stack]
7fff28bff000-7fff28c00000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
要读/写的数据库例程如下所示(我省略了这些函数中的无关代码——用省略号表示):

加密例程如下(从技术上讲,数据只是一个字节数组;但实际上是字符串)。它们遍历数组中的每个字节,并一次对每个字节进行加密:

int encrypt_db_rawData(char *data, size_t data_size) {
  int ret = 0;
  char *buf_out;                   //where the whole encrypted byte "string" gets assembled
  char obuf;                       //declare our per-byte output buffer
  int ilen, olen;                  //stuff needed by EVP_CipherUpdate
  EVP_CIPHER_CTX ctx;              //declare our EVP cipher context
  int currbyte

  /* ... setup cipher context for encryption (omitted) ... */

  buf_out = malloc(data_size);
  memset(buf_out, 0x00, data_size); //initialize buffer

  for(currbyte = 0; currbyte <= data_size - 1; currbyte++) {
    ret = EVP_CipherUpdate(&ctx, &obuf, &olen, &data[currbyte], 1); //actually do the encryption, outputting the current data byte to obuf as an encrypted byte
    if(ret != 1) {
      //encryption failed, so abort the entire function (no data modified)
      free(buf_out);
      return ret;
    }
    buf_out[currbyte] = obuf; //encryption of this byte succeeded, so append the encrypted byte to the main output buffer (which may be saved back into *data when all is done)
  }

  memcpy((void*)data, buf_out, data_size); //NOTE: not sure if we really need to cast as a void*, but doesn't seem to hurt (since the calling routine uses void*data instead of char*data)
  free(buf_out);
  return ret;
}

int decrypt_db_rawData(char *data, size_t data_size) {
  int ret = 0;
  char *buf_out;                   //where the whole decrypted byte "string" gets assembled
  char obuf;                       //declare our per-byte output buffer
  int ilen, olen;                  //stuff needed by EVP_CipherUpdate
  EVP_CIPHER_CTX ctx;              //declare our EVP cipher context
  int currbyte;

  /* ... setup cipher context for decryption (omitted) ... */

  buf_out = malloc(data_size);
  memset(buf_out, 0x00, data_size); //initialize buffer

  for(currbyte = 0; currbyte <= data_size - 1; currbyte++) {
    ret = EVP_CipherUpdate(&ctx, &obuf, &olen, &data[currbyte], 1); //actually do the decryption, outputting the current data byte to obuf as an decrypted byte
    if(ret != 1) {
      //decryption failed, so abort the entire function (no data modified)
      free(buf_out);
      return ret;
    }
    buf_out[currbyte] = obuf; //decryption of this byte succeeded, so append the decrypted byte to the main output buffer (which may be saved back into *data when all is done)
  }

  memcpy((void*)data, buf_out, data_size); //NOTE: not sure if we really need to cast as a void*, but doesn't seem to hurt (since the calling routine uses void*data instead of char*data)
  free(buf_out);
  return ret;
}
int-encrypt\u-db\u-rawData(字符*数据,大小数据大小){
int-ret=0;
char*buf_out;//整个加密字节“string”的组装位置
char obuf;//声明每字节输出缓冲区
int-ilen,olen;//EVP\u CipherUpdate需要的东西
EVP_CIPHER_CTX CTX;//声明我们的EVP密码上下文
int currbyte
/*…设置加密的密码上下文(省略)*/
buf_out=malloc(数据大小);
memset(buf_out,0x00,数据大小);//初始化缓冲区

对于(currbyte=0;currbyte而言,问题在于trueBase正在执行的字节/指针移位…可能与我的memcpy操作中的一些内存空间重叠。Valgrind对于快速发现这一点至关重要!感谢@lrleon

以下是我在DB写入例程中更新的代码:

ENTRY sfuint
bt3Write _FL((fd, data))
ISFILE *fd _DL
void *data _EL
{
  ...
  void *dataCopy = malloc(fd->reclen - BASEOFFSET);          //for saving a copy of the data, in its non-encrypted form, so later logic will work
  memcpy(dataCopy, trueBase(data), fd->reclen - BASEOFFSET); //copy aside the raw unencrypted data for safe-keeping while we encrypt, next
  encrypt_db_rawData(data, fd->reclen-BASEOFFSET);           //encrypt the data
  lioWrite(fd -> fdData, recno, trueBase(data));             //write encrypted data to database
  memcpy(trueBase(data), dataCopy, fd->reclen - BASEOFFSET); //now that the write is complete, restore the non-encrypted data, so stuff works right later
  if(dataCopy)
    free(dataCopy);
  ...
}

使用
valgrind
@lrleon,我将尝试安装并运行,同时等待响应。感谢您的提示。仅此错误(外行术语)就表示
free()所使用的参数值
在程序结束前两次都是相同的值。请尝试valgrind、strace、gdb或任何其他调试器,以查看问题所在。valgrind似乎正在跟踪它…它正在报告以下情况:==6626==大小为8的无效写入==6626==在0x4A08D53:memcpy(mc_replace_strem.c:882)==6626==通过0x571D91:bt3Write(isamv3.c:2166)通过0x40DC28:main(smbanner.c:5424)=6626==地址0x4d1cfc8是大小为1816的块之前的8个字节alloc'd==6626==在0x4A06A2E:malloc(vg_replace_malloc.c:270)==6626==通过0x571D68:bt3Write(isamv3.c:2165)..=6626==通过0x40DC28:main(smbanner.c:5424)问题在于trueBase正在进行的字节/指针移动…可能在我的memcpy操作中重叠了一些内存空间。Valgrind对于快速发现这一点至关重要!
ENTRY sfuint
bt3Write _FL((fd, data))
ISFILE *fd _DL
void *data _EL
{
  ...
  void *dataCopy = malloc(fd->reclen - BASEOFFSET);          //for saving a copy of the data, in its non-encrypted form, so later logic will work
  memcpy(dataCopy, trueBase(data), fd->reclen - BASEOFFSET); //copy aside the raw unencrypted data for safe-keeping while we encrypt, next
  encrypt_db_rawData(data, fd->reclen-BASEOFFSET);           //encrypt the data
  lioWrite(fd -> fdData, recno, trueBase(data));             //write encrypted data to database
  memcpy(trueBase(data), dataCopy, fd->reclen - BASEOFFSET); //now that the write is complete, restore the non-encrypted data, so stuff works right later
  if(dataCopy)
    free(dataCopy);
  ...
}