Следующий метод отладки имеет весьма узкое применение и в большинстве случаев может оказатся неподходящим. Описанное решение пришло в результате поиска проблемы в чужом коде, написанном в ужасном стиле (смесь С++ и С). Речь пойдет о защите памяти с помощью функции
VirtualProtect. Эта функция позволяет изменить режим доступа к страницам памяти: только чтение, копирование по записи, полное отсутсвие доступа и далее. Полный список флагов можно найти в
документации.
Для целей отладки интересен флаг
PAGE_NOACCESS. Он позволяет ловить запись или, что более важно, чтение за пределами некоторой валидной области памяти. Для удобного применения
VirtualProtect был создан следующий класс:
struct protect_mem_t {
protect_mem_t(void* addr, size_t size) : addr(addr), size(size), is_protected(FALSE) {
protect();
}
~protect_mem_t() { release(); }
BOOL protect() {
if (!is_protected) {
is_protected = VirtualProtect(addr, size, PAGE_NOACCESS, &old_protect);
}
return is_protected;
}
BOOL release() {
if (is_protected)
is_protected = !VirtualProtect(addr, size, old_protect, &old_protect);
return !is_protected;
}
protected:
void* addr;
size_t size;
BOOL is_protected;
DWORD old_protect;
};
Применять его можно следующим образом:
const size_t PAGE_SIZE = 4096;
int main()
{
const size_t var_size = 1024 * 96; // 1024*96 - некоторый размер. Конкретное значение здесь только в качестве примера.
const size_t guard_size = PAGE_SIZE * 2 - var_size%PAGE_SIZE;
__declspec(align(4096)) char some_var[var_size + guard_size];
protect_mem_t guard(&some_var[var_size], PAGE_SIZE);
some_var[5] = 20; // that's ok
char x = some_var[5]; // that's ok
char y = some_var[1024 * 96 + 1024]; // access violation
return 0;
}
В приведенном примере, как и в реальной программе, была добавлена защитная область памяти прямо на стеке. Удачной отладки.