- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我有以下代码(它读取进程虚拟内存并使用 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: In function 'main': readmempcreuniq.c:83: warning: pointer targets in passing argument 3 of 'pcre_exec' differ in signedness /usr/include/pcre.h:286: note: expected 'const char *' but argument is of type 'unsigned char *' readmempcreuniq.c:85: warning: pointer targets in passing argument 1 of 'pcre_get_substring' differ in signedness /usr/include/pcre.h:297: note: expected 'const char *' but argument is of type '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]))
最佳答案
在循环的下一轮之前 free()
之后,您永远不会将 matches
重置为 NULL
。因此,它在第一轮重新分配后仍保留原始值。
要么在进入内部处理循环之前将其设置为 NULL
(在第一遍时冗余),要么将其返回设置为 NULL
在 free(matches)
之后立即执行。或者,您可以简单地将其设置为具有初始 NULL
值的下一个外部循环的包含范围,但前面提到的更改是我能想到的最小的更改。
示例
matches = NULL; // HERE
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;
}
或者……
for (i = 0; i < uniques_len; i++)
{
printf("%s\n", uniques[i]);
}
free(matches);
matches = NULL; // or HERE
pcre_free(f);
更多内容
继续我所注意到的事情:
这个:
ssize_t ret;
ret = read(fd, page, sizeof(page));
if (ret > 0) {
page[ret] = '\0';
似乎试图设置一个空字符终止符。如果是这样,您将在填充满的缓冲区上调用未定义的行为。应该是这样的:
ssize_t ret = read(fd, page, sizeof(page)-1); // NOTE SPACE FOR TERM
if (ret > 0) {
page[ret] = 0;
如果缓冲区的大小是特定的(你选择 4K 是有原因的)它应该是 4097 以确保最大精确的 4K 缓冲区。
还有一个……
您正在阅读的页面,我不能声称它是或不需要像我之前在代码中显示的那样被终止。但是假设它是并且你做了我建议的(或者.. 没有),这看起来也是错误的:
while((pairs = pcre_exec(f, f_ext, page, sizeof(page), a, PCRE_NOTEMPTY, vector, vecsize)) >=0)
这里你传递的是整个缓冲区的大小; 不是您读取的实际数据的大小。我是第一个告诉你我不熟悉 API 的人,但我很确定这应该是:
// notice the length of the buffer passed, ret
while((pairs = pcre_exec(f, f_ext, page, ret, a, PCRE_NOTEMPTY, vector, vecsize)) >=0)
换句话说,在读取数据量过小时,您是在告诉它数据比实际长度要长。同样,我对他们的 API 很天真,但这似乎是合理的。
独特匹配...
希望更容易阅读。
int matches_len = count, uniques_len = 0;
int i = 0, j = 0;
const char *uniques[matches_len];
for (i=0; i < matches_len; ++i)
{
for (j = 0; j < uniques_len; ++j)
{
if (!strcmp(matches[i], uniques[j]))
break;
}
if (j == uniques_len)
uniques[uniques_len++] = matches[i];
}
for (i = 0; i < uniques_len; ++i)
printf("%s\n", uniques[i]);
继续...
在每页之后将 count
重置为零。在 free(matches) 之后; matches = NULL;
会是个好地方。
值得注意。一旦文件读取开始失败,您的外循环中就没有退出案例,因此文件上会有很多砰砰声,无法超出其结尾。直到达到限制器计数。
最后的想法
我认为这与您想要做的很接近:
#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>
#include <ctype.h>
int main(int argc, char **argv)
{
// CHANGE TO ACCEPT PROC-ID FROM CMDLINE
int pid = 5916;
setlocale(LC_ALL,"");
const char *error = NULL;
int erroffset = 0;
const char **uniques = NULL;
size_t uniques_len = 0;
const char regex[] = "[0-9A-Fa-f]{8}";
pcre* re = pcre_compile (regex, /* the pattern */
PCRE_MULTILINE|PCRE_DOTALL|PCRE_NEWLINE_ANYCRLF,
&error, /* for error message */
&erroffset, /* for error offset */
0); /* use default character tables */
if (!re)
{
printf("pcre_compile failed (offset: %d), %s\n", erroffset, error);
return -1;
}
// start proc trace
long ptret = ptrace(PTRACE_ATTACH, pid, 0, 0);
if (ptret == -1)
{
fprintf(stderr, "Ptrace failed: %s\n", strerror(errno));
exit(1);
}
char path[256];
snprintf(path, sizeof(path), "/proc/%d/maps", pid);
FILE *maps = fopen(path, "r");
snprintf(path, sizeof(path), "/proc/%d/mem", pid);
int mem = open(path, O_RDONLY);
if(maps && (mem != -1))
{
char buf[BUFSIZ + 1];
while(fgets(buf, BUFSIZ, maps))
{
long long unsigned int start, end;
if (sscanf(buf, "%llx-%llx", &start, &end) != 2)
break;
printf("reading %llx - %llx\n", start, end);
lseek64(mem, start, SEEK_SET);
while (start < end)
{
char page[4096] = {0};
int rd = read(mem, page, sizeof(page));
if (rd < 0)
break;
start += sizeof(page);
int ov[128] = {0};
unsigned int ov_len = 0;
int rc = 0;
while ((rc = pcre_exec(re, 0, page, (int)(rd), ov_len, 0, ov, 128)) >= 0)
{
int i = 0;
for(; i < rc; ++i)
{
const char *sp = NULL;
pcre_get_substring(page, ov, rc, i, &sp);
// search unique list
size_t j=0;
for (;j<uniques_len;++j)
{
if (!strcmp(sp, uniques[j]))
break;
}
if (uniques_len == j)
{
const char **tmp = realloc(uniques, (uniques_len+1)*sizeof(*uniques));
if (tmp == NULL)
{
perror("Failed to resize uniques.");
pcre_free_substring(sp);
}
else
{
uniques = tmp;
uniques[uniques_len++] = sp;
}
}
else
{ // delete string. not needed
pcre_free_substring(sp);
}
}
ov_len = ov[2*(rc-1)]+1;
}
}
}
fclose(maps);
close(mem);
}
size_t n = 0;
for (; n<uniques_len; ++n)
{
printf("%s\n", uniques[n]);
pcre_free_substring(uniques[n]);
}
printf("total uniques: %lu\n", uniques_len);
free(uniques);
ptrace(PTRACE_DETACH, pid, 0, 0);
return 0;
}
警告。我对这个 API 了解零,但我在这里看到并在线简要回顾了一些内容。 YMMV UAYOR。但似乎你一直都拥有它。只是累积独立于页面的唯一值(我认为这仍然是一个问题,页面边界,但那是另一天)。
关于c - Linux POSIX C LibPCRE `double free or corruption (fasttop)` 崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21657732/
是否有详细说明从一个 POSIX 版本更改为另一个版本的文档?我正在寻找一些东西,在表格 View 中,详细说明从 2004 年到 2008 年的变化 最佳答案 有点。这是Rationale ,每卷一
根据POSIX FAQ ,该标准已于 2013 年由 IEEE 修订和批准。 与 2008 年的先前标准相比有何变化? 最佳答案 根据 online edition 中的摘要, POSIX.1-2
我正在开发一个简单的并行应用程序,我想在其中使用单个进程来维护有关一系列工作进程的状态信息。设置一个 POSIX 消息队列似乎相对容易,其中所有工蜂都可以向状态维护者发送定期更新。我的问题? POSI
计划使用 posix 信号量来同步 2 个进程。不太确定使用哪个 - 命名或未命名。 各自的优缺点是什么?我如何决定使用哪个?在哪些情况下,一种优于另一种? 谢谢。 最佳答案 如果这两个进程不相关,则
嵌套参数替换在 Zsh 中有效: $ param=abc # nested remove prefix ${...#a} and remove suffix ${...%c} => $ printf
更新:整个问题出在一条错误线上,这是我的 C++ 代码中的语法错误。 在 Linux 上我发现 #define _NSIG 64 在 asm-generic/signal.h ,
我在网上遇到了两个 POSIX 文档。 http://pubs.opengroup.org/onlinepubs/009695399/ (IEEE 标准 1003.1,2004 年版) Abstrac
我正在开发一个简单的软件来检查我是否能够使用我研究过的 POSIX 定时器和信号进行编程。 我正在尝试做一个简单的程序来启动计时器并在一定的纳秒内发出信号 下面的程序运行得不好,所以我写了一些关于我的
如果我有一个通过 shell 运行的应用程序,是否有 POSIX 文档说 --help需要支持吗?我会这么认为,因为这似乎是最流行的终端应用程序(GNU 工具等)中的标准做法。 我很好奇我是否可以使用
自适应 AUTOSAR 基于什么 POSIX PSE51? 在学习自适应 AUTOSAR 时,我发现“自适应 AUTOSAR 基于 POSIX PSE51”。 但是,我不明白什么是 POSIX PSE
GNU bash manual说到shell参数有以下一段话: The command builtin does not prevent builtins that take assignment s
我应该在我的嵌入式 Linux 环境中使用 System V 消息队列还是 Posix 消息队列?项目中常用什么? 最佳答案 两者都有相同的基本工具——信号量、共享内存和消息队列。它们为这些工具提供了
用 tsearch 填充了 POSIX 二叉树后,如何清理整棵树? GCC 提供了 tdestroy 作为扩展,但是如果你想使用 POSIX-only 函数,你该怎么做呢? 我当前的实现使用 twal
来自 C++ 应用程序。为 AIX、HP-UX、Linux、OSX 和 Solaris 编译是否有一种简单的方法来确定应用程序是否可用。在系统启动后 5 分钟内运行? 在 Windows 上我可以这样
System V IPC 和 POSIX IPC 之间有什么区别? 为什么我们有两个标准? 如何决定使用哪些 IPC 函数? 最佳答案 两者都有相同的基本工具——信号量、共享内存和消息队列。它们提供的
根据this ,POSIX 库不包含 getopt.h。但是,我在 unistd.h 中找到了这个: #ifdef __USE_POSIX2 /* Get definitions and proto
我正在尝试使用 POSIX 共享内存和 POSIX 信号量构建客户端服务器应用程序。我是否必须将信号量放在共享内存段内,或者信号量是否可以只是全局变量?我希望遵守 POSIX 约定。 最佳答案 不,信
尝试读取 Rust fn 中任意用户的主目录,并使用 posix::pwd crate。 不幸的是,我找不到任何使用 FFI 的好例子,并且一直在处理关于指针和类型可变性的各种类型错误。 我的(非编译
我阅读了一个信号的手册页使用 man 7 signal我看到两种类型的信号。所以,我有一个问题, Linux 中的POSIX 可靠信号 和POSIX 实时信号 有什么区别? 最佳答案 如今,将这些表述
据我所知,ucontext 提供了比 setjmp 更好的东西。但它已被弃用,现在已从 POSIX 规范中删除。那么它为什么会出现,又为什么会被移除? 最佳答案 makecontext的签名来自 uc
我是一名优秀的程序员,十分优秀!