Reputation: 1
The below code begin mmap(initlen=10), later remap(nsize=400000) and access remap memory address access 0x7ffff7f8c000 to 0x7ffff7f8cfff is ok, but in the 0x7ffff7f8d000 cause access error
#define _GNU_SOURCE
#include <stdio.h>
#include <limits.h>
#include <stdint.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
int main()
{
int i;
char *p;
void *base;
const int initlen = 10;
const int nsize = 400000;
const char *fname = "/tmp/task.0";
int fd = open(fname, O_CREAT|O_RDWR, 0600);
if (fd == -1) {
return 1;
}
if (ftruncate(fd, initlen) < 0) {
return 1;
}
base = mmap(NULL, initlen, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if (base == MAP_FAILED) {
return 1;
}
// now remap big page.
base = mremap(base, initlen, nsize, MREMAP_MAYMOVE);
if (base == MAP_FAILED) {
printf("mremap fail, %s\n", strerror(errno));
return 1;
}
p = base;
for (i = 0; i < nsize; i++) {
printf("%p\n", p);
*p = i % CHAR_MAX;
++p;
}
return 0;
}
mremap after gdb show the "/tmp/task.0" region is 0x7ffff7f8c000-0x7ffff7fee000, access error in the 0x7ffff7f8d000, why???
37 base = mremap(base, initlen, nsize, MREMAP_MAYMOVE);
(gdb)
38 if (base == MAP_FAILED) {
(gdb)
43 p = base;
(gdb)
44 for (i = 0; i < nsize; i++) {
(gdb) p base
$1 = (void *) 0x7ffff7f8c000
(gdb) i proc mappings
process 3333
Mapped address spaces:
Start Addr End Addr Size Offset objfile
0x400000 0x401000 0x1000 0x0 /tmp/a.out
0x600000 0x601000 0x1000 0x0 /tmp/a.out
0x601000 0x602000 0x1000 0x1000 /tmp/a.out
0x7ffff7a0e000 0x7ffff7bd1000 0x1c3000 0x0 /usr/lib64/libc-2.17.so
0x7ffff7bd1000 0x7ffff7dd0000 0x1ff000 0x1c3000 /usr/lib64/libc-2.17.so
0x7ffff7dd0000 0x7ffff7dd4000 0x4000 0x1c2000 /usr/lib64/libc-2.17.so
0x7ffff7dd4000 0x7ffff7dd6000 0x2000 0x1c6000 /usr/lib64/libc-2.17.so
0x7ffff7dd6000 0x7ffff7ddb000 0x5000 0x0
0x7ffff7ddb000 0x7ffff7dfd000 0x22000 0x0 /usr/lib64/ld-2.17.so
0x7ffff7f8c000 0x7ffff7fee000 0x62000 0x0 /tmp/task.0
0x7ffff7fee000 0x7ffff7ff1000 0x3000 0x0
0x7ffff7ff9000 0x7ffff7ffa000 0x1000 0x0
0x7ffff7ffa000 0x7ffff7ffc000 0x2000 0x0 [vdso]
0x7ffff7ffc000 0x7ffff7ffd000 0x1000 0x21000 /usr/lib64/ld-2.17.so
0x7ffff7ffd000 0x7ffff7ffe000 0x1000 0x22000 /usr/lib64/ld-2.17.so
0x7ffff7ffe000 0x7ffff7fff000 0x1000 0x0
0x7ffffffde000 0x7ffffffff000 0x21000 0x0 [stack]
0xffffffffff600000 0xffffffffff601000 0x1000 0x0 [vsyscall]
Program received signal SIGBUS, Bus error.
0x0000000000400831 in main () at ./test.c:46
46 *p = i % CHAR_MAX;
(gdb) p p
$2 = 0x7ffff7f8d000 <Address 0x7ffff7f8d000 out of bounds>
Upvotes: 0
Views: 240
Reputation: 4179
It is not related to mremap
. It is just how file mappings work.
SIGBUS means that you tried to access file region past its EOF (see manual page mmap(3)).
SIGBUS Attempted access to a portion of the buffer that does not correspond to the file (for example, beyond the end of the file, including the case where another process has truncated the file).
This is different from SIGSEGV, which is sent when you try to access virtual address which doesn't exist in your process, or when protection error occurs (e.g. attempt to write in read-only address).
To answer the question why you can access first 0xfff bytes without getting SIGBUS (even though file size is only 10 bytes), this is because memory management happens in terms of 4096 byte pages. Note however that even though you can access bytes 10..4095, this region is not backed by file. Everything you write into those bytes, won't be written into file.
Upvotes: 1