【发布时间】:2014-03-06 15:14:01
【问题描述】:
我有以下代码(它读取进程虚拟内存并使用 libpcre 匹配一些字符串),它编译没有错误,但如果我使用 -Wall 编译它,我会收到一些警告,我将在代码之后显示。
编译后的代码可以运行,但会在*** glibc detected *** ./readmempcreuniq: double free or corruption (fasttop): 0x097b9c80 *** 崩溃,我怀疑问题出在pcre_get_substring(page, vector, pairs, 0, &buff); 线上,因为函数的第一个参数需要'const char *' 但得到'unsigned char *',我怎样才能使它正确?
#ifdef TARGET_64
// for 64bit target (see /proc/cpuinfo addr size virtual)
#define MEM_MAX (1ULL << 48)
#else
#define MEM_MAX (1ULL << 32)
#endif
#define _LARGEFILE64_SOURCE
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/ptrace.h>
#include <pcre.h>
#include <locale.h>
int main(int argc, char **argv)
{
if (argc < 2) {
printf("Usage: %s <pid>\n", argv[0]);
exit(1);
}
char buf[128];
int pid = atoi(argv[1]);
snprintf(buf, sizeof(buf), "/proc/%d/mem", pid);
int fd = open(buf, O_RDONLY);
if (fd == -1) {
fprintf(stderr, "Error opening mem file: %m\n");
exit(1);
}
pcre *f;
pcre_extra *f_ext;
char *pattern = "([0-9]{20,22})";
const char *errstr;
int errchar;
int vector[50];
int vecsize = 50;
int pairs;
const char *buff;
const unsigned char *tables;
int a;
int count = 0;
const char **matches = NULL;
const char **more_matches;
char *loc = setlocale(LC_ALL, 0);
setlocale(LC_ALL, loc);
tables = pcre_maketables();
long ptret = ptrace(PTRACE_ATTACH, pid, 0, 0);
if (ptret == -1) {
fprintf(stderr, "Ptrace failed: %s\n", strerror(errno));
close(fd);
exit(1);
}
unsigned char page[4096];
unsigned long long offset = 0;
while (offset < MEM_MAX) {
lseek64(fd, offset, SEEK_SET);
ssize_t ret;
ret = read(fd, page, sizeof(page));
if (ret > 0) {
page[ret] = '\0';
if((f = pcre_compile(pattern, PCRE_CASELESS|PCRE_MULTILINE, &errstr, &errchar, tables)) == NULL)
{
printf("Error: %s\nCharacter N%i\nPattern:%s\n", errstr, errchar, pattern);
}
else
{
f_ext = pcre_study(f, 0, &errstr);
a = 0;
while((pairs = pcre_exec(f, f_ext, page, sizeof(page), a, PCRE_NOTEMPTY, vector, vecsize)) >=0)
{
pcre_get_substring(page, vector, pairs, 0, &buff);
//printf("%s\n", buff);
more_matches = realloc(matches, (count+1)* sizeof(*more_matches));
if (more_matches!=NULL)
{
matches=more_matches;
matches[count++]=buff;
}
else
{
free(matches);
puts("Error (re)allocating memory");
exit(1);
}
a = vector[1] + 1;
}
int matches_len = count;
const char *uniques[matches_len];
int uniques_len = 0;
int already_exists;
int i, j;
for (i = 0; i < matches_len; i++)
{
already_exists = 0;
for ( j = 0; j < uniques_len; j++)
{
if (!strcmp(matches[i], uniques[j]))
{
already_exists = 1;
break;
}
}
if (!already_exists)
{
uniques[uniques_len] = matches[i];
uniques_len++;
}
}
for (i = 0; i < uniques_len; i++)
{
printf("%s\n", uniques[i]);
}
free(matches);
pcre_free(f);
}
}
offset += sizeof(page);
}
ptrace(PTRACE_DETACH, pid, 0, 0);
close(fd);
return 0;
}
错误:
xtmtrx@server:~/regex/proc$ ./readmempcreuniq 5663
92991999918876543209
99299299292663552673
111992229922222288
119988922220000077
*** glibc detected *** ./readmempcreuniq: double free or corruption (fasttop): 0x097b9c80 ***
======= Backtrace: =========
/lib/libc.so.6(+0x6c0c1)[0xb7dfa0c1]
/lib/libc.so.6(+0x6d930)[0xb7dfb930]
/lib/libc.so.6(+0x71681)[0xb7dff681]
/lib/libc.so.6(realloc+0xe3)[0xb7dffb13]
./readmempcreuniq[0x8048c86]
/lib/libc.so.6(__libc_start_main+0xe7)[0xb7da4ce7]
./readmempcreuniq[0x80488b1]
======= Memory map: ========
08048000-0804a000 r-xp 00000000 fd:01 68388533 /root/regex/proc/readmempcreuniq
0804a000-0804b000 r--p 00001000 fd:01 68388533 /root/regex/proc/readmempcreuniq
0804b000-0804c000 rw-p 00002000 fd:01 68388533 /root/regex/proc/readmempcreuniq
097a1000-097c2000 rw-p 097a1000 00:00 0 [heap]
b7c00000-b7c21000 rw-p b7c00000 00:00 0
b7c21000-b7d00000 ---p b7c21000 00:00 0
b7d66000-b7d80000 r-xp 00000000 fd:01 65901968 /lib/libgcc_s.so.1
b7d80000-b7d81000 r--p 00019000 fd:01 65901968 /lib/libgcc_s.so.1
b7d81000-b7d82000 rw-p 0001a000 fd:01 65901968 /lib/libgcc_s.so.1
b7d8c000-b7d8e000 rw-p b7d8c000 00:00 0
b7d8e000-b7ee5000 r-xp 00000000 fd:01 65901949 /lib/libc-2.12.1.so
b7ee5000-b7ee7000 r--p 00157000 fd:01 65901949 /lib/libc-2.12.1.so
b7ee7000-b7ee8000 rw-p 00159000 fd:01 65901949 /lib/libc-2.12.1.so
b7ee8000-b7eeb000 rw-p b7ee8000 00:00 0
b7eeb000-b7f1e000 r-xp 00000000 fd:01 65901993 /lib/libpcre.so.3.12.1
b7f1e000-b7f1f000 r--p 00032000 fd:01 65901993 /lib/libpcre.so.3.12.1
b7f1f000-b7f20000 rw-p 00033000 fd:01 65901993 /lib/libpcre.so.3.12.1
b7f29000-b7f2c000 rw-p b7f29000 00:00 0
b7f2c000-b7f48000 r-xp 00000000 fd:01 65901940 /lib/ld-2.12.1.so
b7f48000-b7f49000 r--p 0001b000 fd:01 65901940 /lib/ld-2.12.1.so
b7f49000-b7f4a000 rw-p 0001c000 fd:01 65901940 /lib/ld-2.12.1.so
bf8c1000-bf8d6000 rw-p 7ffffffe9000 00:00 0 [stack]
Aborted
使用-Wall 开关编译代码的警告:
xtmtrx@server:~/regex/proc$ gcc -o readmempcreuniq readmempcreuniq.c -lpcre -Wall readmempcreuniq.c:在函数'main'中:readmempcreuniq.c:83:警告:传递参数3中的指针目标 'pcre_exec' 的签名不同/usr/include/pcre.h:286:注意: 预期为 'const char *' 但参数的类型为 'unsigned char *' readmempcreuniq.c:85:警告:传递参数 1 中的指针目标 'pcre_get_substring' 的签名不同/usr/include/pcre.h:297: 注意:预期为 'const char *' 但参数的类型为 'unsigned char *'
编辑:
根据@stdcall 提示,我使用efence 编译了程序,然后在核心转储上使用了 GDB:
xtmtrx@server:~/regex/proc$ ./readmempcreuniq 6036
Electric Fence 2.1 Copyright (C) 1987-1998 Bruce Perens.
5,
Segmentation fault (core dumped)
xtmtrx@server:~/regex/proc$ gdb ./readmempcreuniq core
GNU gdb (GDB) 7.2-ubuntu
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /root/regex/proc/readmempcreuniq...done.
[New Thread 6093]
Reading symbols from /lib/libpcre.so.3...(no debugging symbols found)...done.
Loaded symbols for /lib/libpcre.so.3
Reading symbols from /usr/lib/libefence.so.0...(no debugging symbols found)...done.
Loaded symbols for /usr/lib/libefence.so.0
Reading symbols from /lib/libc.so.6...(no debugging symbols found)...done.
Loaded symbols for /lib/libc.so.6
Reading symbols from /lib/libpthread.so.0...(no debugging symbols found)...done.
Loaded symbols for /lib/libpthread.so.0
Reading symbols from /lib/ld-linux.so.2...(no debugging symbols found)...done.
Loaded symbols for /lib/ld-linux.so.2
Core was generated by `./readmempcreuniq 6036'.
Program terminated with signal 11, Segmentation fault.
#0 0x08048ef8 in main (argc=2, argv=0xbfe1d2d4) at readmempcreuniq.c:125
125 uniques[uniques_len] = matches[i];
似乎@alk 是正确的,问题在于uniques[uniques_len] = matches[i];
新编辑:
根据@alk 的提示,我已经更改了行:
for ( j = 0; j < uniques_len; j++)
到:
for ( j = 0; j < matches_len; j++)
现在段错误在别处:
Program terminated with signal 11, Segmentation fault.
#0 0x08048ea7 in main (argc=2, argv=0xbfaaa3e4) at readmempcreuniq.c:118
118 if (!strcmp(matches[i], uniques[j]))
【问题讨论】:
-
警告是无害的。使用显式强制转换来摆脱它们,或者首先使用
char。 -
我认为我不能只使用
char而不是unsigned char page[4096];,因此我认为我在pcre_get_substring(page, vector, pairs, 0, &buff);上遇到错误,因为此函数需要unsigned char * -
表格必须是无符号字符,页面必须是纯字符。
-
在我的机器上
pcre_get_substring需要纯字符指针。我在在线资源中也找不到任何不同之处。 -
好的。我将再添加一件事,这就是我认为您正在尝试做的事情,建立一个独特的匹配列表)。不能保证它是完美的,因为我不知道 API,但我知道一般的算法(我认为,无论如何)。