почему mremap после доступа только 4096 байт памяти? - PullRequest
0 голосов
/ 01 декабря 2018

В приведенном ниже коде начинаются mmap (initlen = 10), позже - переназначение (nsize = 400000) и доступ к адресу памяти с переназначением. Доступ от 0x7ffff7f8c000 до 0x7ffff7f8cfff - это нормально, но в 0x7ffff7f8d000 возникает ошибка доступа

#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после того, как gdb показывает, что регион /tmp/task.0 равен 0x7ffff7f8c000-0x7ffff7fee000, ошибка доступа в 0x7ffff7f8d000, почему ???

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>

1 Ответ

0 голосов
/ 01 декабря 2018

Это не относится к mremap.Это просто, как работают сопоставления файлов.SIGBUS означает, что вы пытались получить доступ к файловой области после ее EOF (см. Справочную страницу mmap (3)).

SIGBUS Попытка доступа к части буфера, которая не соответствует файлу (например,за пределами конца файла, включая случай, когда другой процесс урезал файл).

Это отличается от SIGSEGV, который отправляется при попытке доступа к виртуальному адресу, который не существуетв вашем процессе, или когда возникает ошибка защиты (например, попытка записи в адресе только для чтения).

Чтобы ответить на вопрос, почему вы можете получить доступ к первым 0xfff-байтам, не получая SIGBUS (даже если размер файла составляет всего 10 байт)), это происходит потому, что управление памятью происходит с точки зрения 4096-байтовых страниц.Обратите внимание, что, хотя вы можете получить доступ к байтам 10..4095, этот регион не поддерживается файлом.Все, что вы пишете в эти байты, не будет записано в файл.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...