1

我正在尝试重现 mremap 的工作以增加 mmap 的内存/文件。我大致遵循了这个例子,但它是为匿名地图设计的,而我希望它是一个命名文件(这是一个编程语言解释器,所以这个文件相当于解释器状态的“核心转储”)。

由于#if-blocks 的嵌套,原文很难阅读。所以这是“提取的”,而是真实的代码(对于我正在调试的编译路径)。完整的源代码可以在这里查看,但它不包含有问题的代码,因为它还没有被提交,因为它不起作用。:) 不过,mremap 版本和 malloc 后备版本都在那里。

unsigned pgsz /*= getpagesize()*/ = 4096;

typedef struct {
    int fd;
    unsigned char *base;
    unsigned used;
    unsigned max;
} mfile;

/* reallocate and possibly move mem->base */
mfile *growmem(mfile *mem,
               unsigned sz)
{
    void *tmp;
    int newfd;

    printf("growmem: %p %u + %u\n", mem->base, mem->max, sz);
    if (sz < pgsz) sz = pgsz;
    else sz = (sz/pgsz + 1) * pgsz;
    sz += mem->max;
    printf("growmem: new size: %u\n", sz);

    msync(mem->base, mem->used, MS_SYNC);
    newfd = dup(mem->fd);
    tmp = mmap(NULL, sz, 
            PROT_READ|PROT_WRITE,
            MAP_SHARED | (mem->fd == -1? MAP_ANONYMOUS : 0), 
            newfd, 0); 

    if (tmp == MAP_FAILED)
        error(VMerror, "unable to grow memory");

    memcpy(tmp, mem->base, mem->used);
    munmap(mem->base, mem->max);
    mem->fd = newfd;

    mem->base = tmp;
    mem->max = sz;
    return mem;
}

这似乎在调用时有效,但程序稍后崩溃。我还没有准确地追踪到哪里,但是基于跟踪主 eval 循环,它看起来非常像内存的新部分不可写访问。失败的运算符分配一个新的字典对象。而且我怀疑我通过重新使用相同的文件描述符做了一些愚蠢的事情。编辑:新文件描述符,相同的段错误。

Breakpoint 2, eval (ctx=0x80049a70) at src/bin/itp.c:482
482         object t = top(ctx->lo, ctx->es, 0);
(gdb) 
Continuing.
evalload <name "dict">
eval
Executing: <operator 24>
Stack: 0:<integer 1>1:<integer 0>2:<integer 0>3:<integer 1>4:<integer 0>5:<integer 0>6:<array L 229 100 78 0>7:<integer 1>8:<dict L 102 16 658 0>9:<integer 8>
Dict Stack: 0:<dict G 358 10 10 0>1:<dict G 358 100 188 0>2:<dict L 102 100 9 0>3:<dict G 486 24 310 0>4:<dict L 102 6 80 0>
Exec Stack: 0:<operator 60>1:<array G 357 2 387 6>2:<boolean false>3:<array G 325 17 416 14>4:<operator 54>5:<operator 63>6:<array G 453 18 414 0>7:<array G 325 1 414 17>8:<array G 325 4 413 5>9:<boolean false>10:<file>11:<file>12:<array L 101 3 103 16>13:<array L 101 1 113 4>14:<operator 24>
   2929 [main] itp 613952 exception::handle: Exception: STATUS_ACCESS_VIOLATION
  10097 [main] itp 613952 open_stackdumpfile: Dumping stack trace to itp.exe.stackdump





Program received signal SIGSEGV, Segmentation fault.
0x61129ab9 in memset () from /usr/bin/cygwin1.dll
(gdb) 
Continuing.
warning: SuspendThread failed. (winerr 6)
[Inferior 1 (process 613952) exited with code 0105400]
(gdb) 

追踪了确切的路线。当尝试触摸一些新内存时,它在以后的分配中失败。

unsigned mfalloc(mfile *mem,
                 unsigned sz) 
{
    unsigned adr = mem->used;

    if (sz) {
        if (sz + mem->used >= mem->max)
            mem = growmem(mem,sz);
        mem->used += sz; 
        memset(mem->base+adr, 0, sz);  //bzero(mem->base+adr, sz);
        /* bus error with mremap(SHARED,ANON)! */
    }   
    return adr;
}

我究竟做错了什么?

PS。我在错误调用之前暂停了调试器。如果任何变量值有用,我可以得到它们。是 12,因此mem->fd我们没有遇到此代码之前遇到的完全相同的 SHARED/ANON 错误,但是在 mmap 调用中需要进行一些调整以避免这种组合。

编辑:它似乎可以毫无问题地访问内存/文件的旧内容。这是新的空间,无法使用。现有的打开文件会阻止更大的连续地图吗?唔。也许我应该 msync,然后是 munmap,然后是 fdclose,然后重新打开和 mmap。...这需要重新设计来测试它,因为 mfile 结构需要存储文件名。...

4

1 回答 1

0

如果地图请求的大小更大,Cygwin 似乎mmap不会自动增加文件大小。所以ftruncate首先。

于 2013-11-14T18:40:54.480 回答