我正在尝试重现 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 结构需要存储文件名。...