2011-01-30 2 views
7

Иногда ошибки могут вызвать исключение нарушения доступа к памяти.Как генерируется исключение нарушения доступа

Как именно это исключение запускается? Какой механизм работает за кулисами?

Нужна ли поддержка со стороны центрального процессора (начиная с каким процессором?)/От операционной системы (начиная с какой версией?)/От компилятора (начиная с какой версией?)

Edit:

Один конкретный сценарий, который я хочу понять лучше:

Следующий код может привести к исключению нарушения доступа.

TCHAR* czXXX= _T("ABCDEFG"); 
czXXX[0]= 'A'; 

Я думаю, czXXX указывает на блок памяти только для чтения, но что именно происходит?

ответ

11

нарушение доступа к памяти большая тема :)

The Protection of Information in Computer Systems (с 1973 :) вынимает из механизма сегментов, где выделяются базом процессы и связаны; любая попытка доступа к памяти за пределами диапазона base:base+bound означала, что программа сделала что-то глупое и должна быть убита.

Линейка процессоров 80x86 реализует базовую поддержку сегмента, а ядро ​​безопасности GEMSOS - это ядерная система, сертифицированная A1, на основе этого механизма.

Но сегменты не очень динамичны, и почти все современные операционные системы - это системы paging, что страница в память, когда она недоступна. Это зависит от процессора, имеющего блок управления памятью MMU, который проверяет все обращения к памяти за правильными привилегиями и наличие/отсутствие правильного отображения памяти. Когда процесс пытается получить доступ к памяти, которая в настоящее время не отображается в ОЗУ, MMU сигнализирует CPU о том, что произошла ошибка, а ЦП приостанавливает процесс для загрузки запрошенной страницы памяти с диска. (Или, если память не должна отображаться для процесса, скажем, она пытается получить доступ к 0x0 или к случайной ячейке памяти, которая не была сопоставлена ​​с mmap или аналогичными примитивами выделения памяти, она убивает процесс.)

Intel 80386 был первым чипом Intel для поддержки пейджинга, поэтому Windows «386 Enchanced Mode» был , поэтому намного лучше, чем режим 286.

Компиляторы не задействованы, но CPU, MMU и ядро ​​операционной системы должно все работают вместе.

+0

Что делать, если RAM и диск полны? –

+0

@Scott 混合 理论 нормально, если ОЗУ будет полной или почти полной - неиспользуемая оперативная память - это потерянное ОЗУ. Поскольку производительность ухудшается, чем больше компьютер должен использовать пространство подкачки, обычно люди будут пытаться запускать столько программного обеспечения, сколько поместится в память. Когда пространство подкачки заполнено, ядро ​​начнет возвращать ошибки для выделения памяти или уничтожит целые процессы, чтобы освободить место. Ищите «OOM Killer» для получения подробной информации об этом. – sarnold

0
void Kaboom() 
{ 
    int* certain_death = NULL; 
    *certain_death = 0; 
} 
+1

На самом деле ваш пример имеет неопределенное поведение в соответствии со стандартом;) – undercover

6

В архитектуре x86 (и большинстве других также) это начинается с MMU - модуля управления памятью. MMU используется для перевода адресов виртуальной памяти на адреса физической памяти. Если запрашивается недопустимый адрес (0x00000000 или что-то слишком высокое), MMU будет ловить (прерывать) ОС (это действительно делается для каждого доступа не в кэше TLB (Translate Lookaside Buffer - MMU translation) «)). Здесь ОС сможет сказать, что это незаконный доступ к памяти и распространяется в пользовательское приложение через механизм, зависящий от ОС (сигналы в Linux (SIGSEGV), я не знаком с Windows достаточно, чтобы сказать, как это делается в этом).

Эта функция доступна для любого современного процессора, ОС и компилятора. Основным требованием является MMU, который присутствует во всех, кроме самых простых встроенных ЦП. Я сомневаюсь, что в настоящее время работает какой-либо ПК, который не поддерживает это.

Редактировать:

После OP редактирования, когда используется символьная строка, память помещается в сегменте .text исполняемого файла. Здесь сидят двоичный код и постоянные значения. Естественно, что в большинстве ОС это доступно только для чтения (особенно в Linux с различными улучшениями безопасности). Когда вы пытаетесь изменить значение литеральной строки, вы в основном пытаетесь записать в постоянную память, что приведет к нарушению доступа. Опять же, это улавливается MMU, который видит команду записи в адрес памяти только для чтения.

+1

Механизм, зависящий от ОС, называется «структурированные исключения» в Windows: http://msdn.microsoft.com/en-us/library/ms680657%28v=vs .85% 29.aspx – sbk

2

При попытке доступа к адресу памяти, компьютер проходит через несколько этапов:

  • Если адрес является частью текущего сегмента памяти, доступ предоставляется.
  • В противном случае, если сегмент адреса находится в памяти с соответствующим разрешением доступа, предоставляется доступ.

Если адрес отсутствует в памяти, ЦП будет генерировать исключение проверки памяти. На данный момент операционная система берет верх.

  • Если сегмент доступен в виртуальной памяти с соответствующим разрешением доступа, он будет загружен в память и назначается менеджер виртуальной памяти; доступ затем предоставляется.

Если на данный момент память недоступна, существует одна из двух возможностей. Либо адрес недоступен, либо у вас нет необходимых разрешений (например, попытка записи в постоянную память). В этом случае операционная система будет передавать нарушение доступа к процессу.

Что касается версий процессоров и ОС, то это любая система, которая позволяет виртуальную память. Я не знаю подробностей об этом.

1

памяти может произойти нарушение доступа здесь также:

delete pSample; 

//again deleting the same memory! 
delete pSample; 

В таких случаях возбуждается исключение из модели памяти ОС. В основном это ОС, задачей которой является проверка доступа к памяти из любого процесса!

2

Все эти ответы очень хорошо объясняют, что происходит на уровне процессора. Как уже упоминалось, как только процессор вызывает прерывание для os, все меняется с помощью разных операционных систем.

В Windows используется механизм, известный как «Structured exceptions». Очень важно не путать это с исключениями C++, они разные. Структурированные исключения концептуально работают так же, как и исключения C++, тем, что они разматывают стек, ищущий обработчик. Поскольку Structured Exceptions являются агностическими, они делают не деструкторами вызовов или выполняют какую-либо очистку.

Структурированные Исключения могут быть пойманы с

__try 
{ 
    //Usual code 
} 
__except(EXCEPTION_EXECUTE_HANDLER) 
{ 
    //Handling code 
} 
__finally 
{ 
    //Cleanup 
} 

Имейте в виду, однако, что как только вы получите Structured Exception, ваша программа уже разбился, так нет разумный способ «восстановления».

Дополнительная информация о SEH.

Смежные вопросы