Приклад
int *ptr;
*ptr = 1000;
Чи можу я виявити виняток щодо порушення доступу до пам'яті, використовуючи стандартний C ++, не використовуючи жодної специфіки Microsoft.
Приклад
int *ptr;
*ptr = 1000;
Чи можу я виявити виняток щодо порушення доступу до пам'яті, використовуючи стандартний C ++, не використовуючи жодної специфіки Microsoft.
Відповіді:
Ні. C ++ не створює винятку, коли ви робите щось погане, що спричинить удар продуктивності. Такі речі, як порушення доступу або поділ на нульові помилки, скоріше нагадують "машинні" винятки, а не речі, які ви можете вловити.
Прочитайте і плачте!
Я зрозумів це. Якщо ви не кинете з обробника, обробник просто продовжить, а також виняток.
Магія трапляється, коли ви кидаєте власний виняток і обробляєте це.
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <tchar.h>
void SignalHandler(int signal)
{
printf("Signal %d",signal);
throw "!Access Violation!";
}
int main()
{
typedef void (*SignalHandlerPointer)(int);
SignalHandlerPointer previousHandler;
previousHandler = signal(SIGSEGV , SignalHandler);
try{
*(int *) 0 = 0;// Baaaaaaad thing that should never be caught. You should write good code in the first place.
}
catch(char *e)
{
printf("Exception Caught: %s\n",e);
}
printf("Now we continue, unhindered, like the abomination never happened. (I am an EVIL genius)\n");
printf("But please kids, DONT TRY THIS AT HOME ;)\n");
}
sigaltstack) (за винятком випадків, коли це дозволяє розгортання виключення C ++), і кожна функція виконання, яка обробляє сам механізм розмотування, повинна бути безпечною для сигналу.
signal(SIGSEGV, SIG_DFL);
Існує дуже простий спосіб вловити будь-який виняток (ділення на нуль, порушення доступу тощо) у Visual Studio за допомогою блоку try -> catch (...). Досить незначного налаштування параметрів проекту. Просто увімкніть параметр / EHa у налаштуваннях проекту. Див. Властивості проекту -> C / C ++ -> Генерація коду -> Змінити параметр Enable C ++ Exceptions на "Так з винятками SEH" . Це воно!
Детальніше див. Тут: http://msdn.microsoft.com/en-us/library/1deeycx5(v=vs.80).aspx
Принаймні для мене signal(SIGSEGV ...)підхід, згаданий в іншій відповіді , не працював на Win32 з Visual C ++ 2015 . Що зробили роботу для мене було використовувати _set_se_translator()знайдено в eh.h. Це працює так:
Крок 1 ) Переконайтеся, що ви увімкнули Так із винятками SEH (/ EHa) у Властивості проекту / C ++ / Генерація коду / Увімкнути винятки C ++ , як зазначено у відповіді Володимира Фрицького .
Крок 2 ) Виклик _set_se_translator(), передача покажчика функції (або лямбда-сигналу) для нового перекладача винятків . Його називають перекладачем, оскільки він, в основному, просто приймає виняток низького рівня і перекидає його як щось простіше для лову, наприклад std::exception:
#include <string>
#include <eh.h>
// Be sure to enable "Yes with SEH Exceptions (/EHa)" in C++ / Code Generation;
_set_se_translator([](unsigned int u, EXCEPTION_POINTERS *pExp) {
std::string error = "SE Exception: ";
switch (u) {
case 0xC0000005:
error += "Access Violation";
break;
default:
char result[11];
sprintf_s(result, 11, "0x%08X", u);
error += result;
};
throw std::exception(error.c_str());
});
Крок 3 ) Влаштуйте виняток, як зазвичай:
try{
MakeAnException();
}
catch(std::exception ex){
HandleIt();
};
Цей тип ситуації залежить від реалізації, і, отже, для того, щоб затримати механізм, йому знадобиться механізм, що відповідає постачальнику. З Microsoft це буде стосуватися SEH, а * nix - сигналу
Загалом, хоча вловлювати виняток щодо порушення доступу дуже погана ідея. Практично немає способу відновити виняток AV, а спроба зробити це призведе до ускладнення пошуку помилок у вашій програмі.
Як зазначалося, на платформі Windows не існує способу, який не відповідає Microsoft / компілятору. Однак, очевидно, корисно ловити такі типи винятків звичайним способом спроби {} catch (виняток ex) {} для звітування про помилки та більш витонченого виходу з вашого додатка (як каже JaredPar, програма зараз, мабуть, має проблеми) . Ми використовуємо функцію _se_translator_ у простій обгортці класу, яка дозволяє нам вловлювати такі винятки в обробнику спроб:
DECLARE_EXCEPTION_CLASS(datatype_misalignment)
DECLARE_EXCEPTION_CLASS(breakpoint)
DECLARE_EXCEPTION_CLASS(single_step)
DECLARE_EXCEPTION_CLASS(array_bounds_exceeded)
DECLARE_EXCEPTION_CLASS(flt_denormal_operand)
DECLARE_EXCEPTION_CLASS(flt_divide_by_zero)
DECLARE_EXCEPTION_CLASS(flt_inexact_result)
DECLARE_EXCEPTION_CLASS(flt_invalid_operation)
DECLARE_EXCEPTION_CLASS(flt_overflow)
DECLARE_EXCEPTION_CLASS(flt_stack_check)
DECLARE_EXCEPTION_CLASS(flt_underflow)
DECLARE_EXCEPTION_CLASS(int_divide_by_zero)
DECLARE_EXCEPTION_CLASS(int_overflow)
DECLARE_EXCEPTION_CLASS(priv_instruction)
DECLARE_EXCEPTION_CLASS(in_page_error)
DECLARE_EXCEPTION_CLASS(illegal_instruction)
DECLARE_EXCEPTION_CLASS(noncontinuable_exception)
DECLARE_EXCEPTION_CLASS(stack_overflow)
DECLARE_EXCEPTION_CLASS(invalid_disposition)
DECLARE_EXCEPTION_CLASS(guard_page)
DECLARE_EXCEPTION_CLASS(invalid_handle)
DECLARE_EXCEPTION_CLASS(microsoft_cpp)
Оригінальний клас вийшов з цієї дуже корисної статті:
Не механізм обробки винятків, але ви можете використовувати механізм signal (), який надається C.
> man signal
11 SIGSEGV create core image segmentation violation
Запис у покажчик NULL, ймовірно, спричинить сигнал SIGSEGV
signal()є частиною стандарту posix. Windows реалізує стандарт posix (як це робить Linux та unix)
Подібне порушення означає, що з кодом щось серйозно не так, і воно ненадійне. Я бачу, що програма може захотіти зберегти дані користувача таким чином, що, сподіваємося, не буде писати над попередніми даними, в надії, що дані користувача ще не пошкоджені, але за визначенням не існує стандартного методу боротьби з невизначеною поведінкою.