巨大的映射文件上的 strstr

xoi*_*oid 1 c string mmap

我打开巨大的(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);
Run Code Online (Sandbox Code Playgroud)

它适用于小文件,但在巨大的源上返回 0。我应该使用什么函数来搜索巨大的映射文件?

输出是:

size is 11111745740
src pointer is at 140357526544384
needle is at 0
Run Code Online (Sandbox Code Playgroud)

chq*_*lie 6

您不应该使用strstr()在内存映射文件中搜索文本:

  • 如果文件是二进制文件,则它很可能包含空字节,这将很快停止搜索。这可能就是您所观察到的。
  • 如果文件是纯文本,但不包含匹配项,strstr则将继续扫描文件末尾以外的位置,通过尝试读取未映射的内存来调用未定义的行为。

您可以改为使用具有等效语义但应用于原始内存的函数,而不是memmem()在 Linux 和 BSD 系统上可用的 C 字符串:

void *memmem(const void *p1, size_t size1, const void *p2, size_t size2);
Run Code Online (Sandbox Code Playgroud)

请注意,您还使用了错误的printf格式:它应该是%pandsrc并且index您可能更喜欢将偏移量打印为 aptrdiff_t或 an 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));
Run Code Online (Sandbox Code Playgroud)

如果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;
}    
Run Code Online (Sandbox Code Playgroud)