2016-11-09 10 views
3

Я пытаюсь понять, почему вызов записи в области, защищенной памятью, не вызывает sigsegv. Рассмотрим пример:write() на защищенной области памяти не вызывает sigsegv, но стандартный доступ делает

void *map_addr; 
unsigned long addr; 

map_addr = (void *)mmap(NULL, 0x4000, PROT_READ_WRITE, MAP_PRIVATE, fd, 0); 
mprotect(map_addr, 0x4000, PROT_NONE); 

addr = (unsigned long)map_addr; 

// case 1: 
*(volatile int*)(addr); // sigsegv sent 
// case 2: 
write(STDOUT_FILENO, map_addr, size); // sigsegv NOT sent 

Вместо отправки sigsegv, писать в этом случае возвращает -1 и устанавливает errno=EFAULT. Почему эта запись имеет такое поведение? Я бы предположил, что запись попыталась бы прочитать по адресу, что создает ошибку sigsegv, но это, очевидно, не так.

+0

Просьба предоставить ссылку на стандарт, где он требует SIGSEGV для неопределенного поведения путем доступа. И вы проверили машинный код? Выполнено? Что говорит отладчик? – Olaf

+0

@Olaf Case 1 выполняет и вводит обработчик для SIGSEGV, как и ожидалось. Если я запустил Случай 2, я не вхожу в обработчик, и запись просто возвращает -1, указав «EFAULT» в errno, поэтому нет сбоя в случае 2. Что касается ссылки, я только что предположил и ввода/вывода на защищенная память сгенерирована sigsegv –

+0

@Olaf Какой стандарт? Стандарт linux? – melpomene

ответ

7

write - системный вызов, поэтому доступ к памяти происходит в ядре, а не в вашем процессе. Ядро сначала проверяет, является ли переданный адрес действительным для вызывающего процесса, а если нет, он просто возвращает EFAULT.

(я не знаю, почему он был разработан, чтобы работать таким образом, хотя.)

+0

Итак, в этом случае 'write' вводит ядро, которое считает, что вызывающий адрес имеет« PROT_NONE »и считает его« EFAULT »? –

+0

Я полностью согласен, если вы сделаете этот переданный адрес * диапазон *. –

+0

@SyntacticFructose Да, точно. – melpomene