巨大的映射文件上的 strstr
strstr on huge mmapped file
我打开巨大的 (11Gb) 文件,将其映射到内存,但无法在文件中搜索字符串
我的密码是
if ( (fd = open("l", O_RDONLY)) < 0 ) err_sys("Cant open file");
if ( fstat(fd, &statbuf) < 0 ) err_sys("Cant get file size");
printf("size is %ld\n", statbuf.st_size);
if ( (src = mmap(0, statbuf.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED ) err_sys("Cant mmap");
printf("src pointer is at %ld\n", src);
char * index = strstr(src, "bin/bash");
printf("needle is at %ld\n", index);
它适用于小文件,但适用于大资源 returns 0. 我应该使用什么函数来搜索巨大的映射文件?
输出为:
size is 11111745740
src pointer is at 140357526544384
needle is at 0
您不应使用 strstr()
在内存映射文件中搜索文本:
- 如果文件是二进制文件,它很可能包含会很快停止搜索的空字节。这可能是您观察到的。
- 如果文件是纯文本,但不包含匹配项,
strstr
将继续扫描文件末尾,通过尝试读取未映射的内存来调用未定义的行为。
您可以改为使用具有等效语义但应用于原始内存而不是 C 字符串的函数,memmem()
,在 Linux 和 BSD 系统上可用:
void *memmem(const void *p1, size_t size1, const void *p2, size_t size2);
请注意,您还使用了错误的 printf
格式:src
和 index
应该是 %p
并且您可能更愿意将偏移量打印为 ptrdiff_t
或 unsigned long long
:
if ((fd = open("l", O_RDONLY)) < 0)
err_sys("Cannot open file");
if (fstat(fd, &statbuf) < 0)
err_sys("Cannot get file size");
printf("size is %llu\n", (unsigned long long)statbuf.st_size);
if ((src = mmap(0, statbuf.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED)
err_sys("Cannot mmap");
printf("src pointer is at %p\n", (void*)src);
char *index = memmem(src, statbuf.st_size, "bin/bash", strlen("bin/bash"));
printf("needle is at %p\n", (void*)index);
if (index != NULL)
printf("needle is at offset %llu\n", (unsigned long long)(index - src));
如果 memmem
在您的平台上不可用,这里有一个简单的实现:
#include <string.h>
void *memmem(const void *haystack, size_t n1, const void *needle, size_t n2) {
const unsigned char *p1 = haystack;
const unsigned char *p2 = needle;
if (n2 == 0)
return (void*)p1;
if (n2 > n1)
return NULL;
const unsigned char *p3 = p1 + n1 - n2 + 1;
for (const unsigned char *p = p1; (p = memchr(p, *p2, p3 - p)) != NULL; p++) {
if (!memcmp(p, p2, n2))
return (void*)p;
}
return NULL;
}
我打开巨大的 (11Gb) 文件,将其映射到内存,但无法在文件中搜索字符串
我的密码是
if ( (fd = open("l", O_RDONLY)) < 0 ) err_sys("Cant open file");
if ( fstat(fd, &statbuf) < 0 ) err_sys("Cant get file size");
printf("size is %ld\n", statbuf.st_size);
if ( (src = mmap(0, statbuf.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED ) err_sys("Cant mmap");
printf("src pointer is at %ld\n", src);
char * index = strstr(src, "bin/bash");
printf("needle is at %ld\n", index);
它适用于小文件,但适用于大资源 returns 0. 我应该使用什么函数来搜索巨大的映射文件?
输出为:
size is 11111745740
src pointer is at 140357526544384
needle is at 0
您不应使用 strstr()
在内存映射文件中搜索文本:
- 如果文件是二进制文件,它很可能包含会很快停止搜索的空字节。这可能是您观察到的。
- 如果文件是纯文本,但不包含匹配项,
strstr
将继续扫描文件末尾,通过尝试读取未映射的内存来调用未定义的行为。
您可以改为使用具有等效语义但应用于原始内存而不是 C 字符串的函数,memmem()
,在 Linux 和 BSD 系统上可用:
void *memmem(const void *p1, size_t size1, const void *p2, size_t size2);
请注意,您还使用了错误的 printf
格式:src
和 index
应该是 %p
并且您可能更愿意将偏移量打印为 ptrdiff_t
或 unsigned long long
:
if ((fd = open("l", O_RDONLY)) < 0)
err_sys("Cannot open file");
if (fstat(fd, &statbuf) < 0)
err_sys("Cannot get file size");
printf("size is %llu\n", (unsigned long long)statbuf.st_size);
if ((src = mmap(0, statbuf.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED)
err_sys("Cannot mmap");
printf("src pointer is at %p\n", (void*)src);
char *index = memmem(src, statbuf.st_size, "bin/bash", strlen("bin/bash"));
printf("needle is at %p\n", (void*)index);
if (index != NULL)
printf("needle is at offset %llu\n", (unsigned long long)(index - src));
如果 memmem
在您的平台上不可用,这里有一个简单的实现:
#include <string.h>
void *memmem(const void *haystack, size_t n1, const void *needle, size_t n2) {
const unsigned char *p1 = haystack;
const unsigned char *p2 = needle;
if (n2 == 0)
return (void*)p1;
if (n2 > n1)
return NULL;
const unsigned char *p3 = p1 + n1 - n2 + 1;
for (const unsigned char *p = p1; (p = memchr(p, *p2, p3 - p)) != NULL; p++) {
if (!memcmp(p, p2, n2))
return (void*)p;
}
return NULL;
}