reimplementing mremap in cygwin
I'm trying to reproduce the work of mremap to grow an mmap'ed memory/file.
I've roughly followed this example but it's intended for anonymous maps,
whereas I want it to be a named file (this is a programming language
interpreter, so this file serves the equivalent of a "core dump" of the
interpreter state).
The original is hard to read due to the nesting of #if-blocks. So this is
"extracted", but real code (for the compilation path I'm debugging). The
full source can be viewed here, but it doesn't contain this code in
question, because it hasn't been committed, because it doesn't work. :)
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;
}
This appears to work when called, but the program crashes later. I haven't
tracked down precisely where, but based on tracing the main eval loop it
looks very much like the new portion of the memory is not write
accessible. The operator that fails allocates a new dictionary object. And
I suspect I've done something stupid by re-using the same file-descriptor.
edit: new file descriptor, same segfault.
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)
Tracked down the exact line. It fails in a later allocation, when trying
to touch some of the new memory.
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;
}
What am I doing wrong?
PS. I've got the debugger paused right before the error call. If any of
the variable values would be useful, I can get them. The mem->fd is 12, so
we aren't hitting quite the same SHARED/ANON error that this code has
encountered before, but there is some adjustment to be made in the mmap
call to avoid this combination.
Edit: It appears to be accessing the old contents of the memory/file with
no trouble. It's the new space that isn't usable. Would having an existing
open file prevent a larger contiguous map? Hmm. Perhaps I should msync,
then munmap, the fdclose, then reopen and mmap. ...
No comments:
Post a Comment