Самьюэл Алекс
Шрифт:
Предположим, к примеру, что программа выделяет страницу, отображая в памяти файл
/dev/zero
. Память инициализируется как для чтения, так и для записи: int fd = open("/dev/zero", O_RDONLY);
char* memory =
mmap(NULL, page_size, PROT_READ | PROT_WRITE,
MAP_PRIVATE, fd, 0);
close(fd);
Далее программа запрещает запись в эту область памяти, вызывая функцию
mprotect
: mprotect(memory, page_size, PROT_READ);
Существует оригинальная методика контроля памяти: можно защитить область памяти с помощью функций
mmap
и mprotect
, а затем обрабатывать сигнал SIGSEGV
, посылаемый при попытке доступа к этой памяти. Эта методика иллюстрируется в листинге 8.7. Листинг 8.7. (mprotect.c) Обнаружение попыток доступа к памяти благодаря функции
mprotect
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
static int alloc_size;
static char* memory;
void segv_handler(int signal_number) {
printf("memory accessed!\n");
mprotect(memory, alloc_size, PROT_READ | PROT_WRITE);
}
int main {
int fd;
struct sigaction sa;
/* Назначение функции segv_handler обработчиком сигнала
SIGSEGV. */
memset(&sa, 0, sizeof(sa));
sa.sa_handler = &segv_handler;
sigaction(SIGSEGV, &sa, NULL);
/* Выделение одной страницы путем отображения в памяти файла
/dev/zero. Сначала память доступна только для записи. */
alloc_size = getpagesize;
fd = open("/dev/zero", O_RDONLY);
memory =
mmap(NULL, alloc_size, PROT_WRITE, MAP_PRIVATE, fd, 0);
close(fd);
/* Запись на страницу для получения ее копии в частное
использование. */
memory[0] = 0;
/* Запрет на запись в память. */
mprotect(memory, alloc_size, PROT_NONE);
/* Попытка записи в память. */
memory[0] = 1;
/* Удаление памяти. */
printf("all done\n");
munmap(memory, alloc_size);
return 0;
}
Программа работает по следующей схеме.
1. Задается обработчик сигнала
SIGSEGV
. 2. Файл
/dev/zero
отображается в памяти, из которой выделяется одна страница. В эту страницу записывается инициализирующее значение, благодаря чему программе предоставляется частная копия страницы. 3. Программа защищает память, вызывая функцию
mprotect
с флагом PROT_NONE
. 4. Когда программа впоследствии обращается к памяти, Linux посылает ей сигнал
SIGSEGV
, который обрабатывается в функции segv_handler
. Обработчик сигнала отменяет защиту памяти, разрешая выполнить операцию записи. 5. Программа удаляет область память с помощью функции
munmap
. 8.10. Функция nanosleep: высокоточная пауза
Функция
nanosleep
является более точной версией стандартной функции sleep
, принимая указатель на структуру типа timespec
, где время задается с точностью до наносекунды, а не секунды. Правда, особенности работы ОС Linux таковы, что реальная точность оказывается равной 10 мс, но это все равно выше, чем в функции sleep
. Функцию nanosleep
можно использовать в приложениях, где требуется запускать различные операции с короткими интервалами между ними.