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