2016-06-07 4 views
5

Есть ли способ конвертировать доступ NULL-указателя к исключению C++ в Linux? Что-то похожее на NullPointerException в Java. Я надеюсь, что следующая программа вернется успешно, вместо аварии (предположим, что компилятор не может понять этот доступ указатель NULL во время компиляции):Преобразование NULL-указателя доступа к исключению C++ в Linux/GCC

class NullPointerException {}; 

void accessNullPointer(char* ptr) { 
    *ptr = 0; 
} 

int main() { 
    try { 
     accessNullPointer(0); 
    } catch (NullPointerException&) { 
     return 1; 
    } 
    return 0; 
} 

Я не ожидал какой-либо стандартный способ сделать это, так как указатель NULL доступ под C++ - это неопределенное поведение, просто хочу знать, как это сделать в x86_64 Linux/GCC.

Я сделал некоторые очень примитивные исследования в этом, можно было бы:

  1. Когда указатель NULL доступ под Linux, SIGSEGV будет.
  2. Внутри обработчика SIGSEGV будут доступны сведения о программе и информация о регистре (если для регистрации обработчика сигнала используется sigaction()). Инструкция, которая вызвала SIGSEGV, также доступна, если программа разобрана.
  3. Изменение памяти программы и/или регистрация, а также создавать/поддельный экземпляр исключения (возможно, вызывая UNWIND библиотечных функций на низком уровне, как _Unwind_RaiseException и т.д.)
  4. Наконец возврат из обработчика сигналу, надеется, что программа будет начните процесс разворачивания стека C++, как было выбрано нормальное исключение.

Вот цитата из страницы человека GCC в (-fnon-Call-исключения):

Генерация кода, который позволяет улавливающего инструкции бросать исключения. Обратите внимание, что для этого требуется поддержка времени выполнения платформы, которая не существует повсюду. Более того, он только позволяет командам захвата генерировать исключения, то есть ссылки на память или инструкции с плавающей запятой. Он не позволяет исключать , выброшенным из произвольных обработчиков сигналов, таких как «SIGALRM».

Похоже, что это «определенная платформой среда исполнения» - это именно то, что я хочу. Кто-нибудь знает такую ​​среду выполнения для Linux/x86_64? Или дайте мне некоторую информацию о том, как реализовать такую ​​среду выполнения, если такая среда выполнения уже не существует?

Я хочу, чтобы решение работало в многопоточной программе.

+2

[This] (http://stackoverflow.com/questions/9225415/linux3-gcc46-fnon-call-exceptions-which-signals-are-trapping-instructions) может оказаться полезным. (Я не уверен, что вы думаете, что «среда выполнения» означает, но я уверен, что это не значит, что вы думаете, что это значит.) – molbdnilo

+2

Если вы не будете вынуждены использовать необработанные указатели, было бы возможно написать ваш собственный класс интеллектуальных указателей (аналогично, например, ['std :: shared_ptr'] (http://en.cppreference.com/w/cpp/memory/shared_ptr) или [' std :: unique_ptr'] (http: // en.cppreference.com/w/cpp/memory/unique_ptr)), который вызывает исключение при доступе к неинициализированному указателю. – mindriot

+0

Я думаю, что вы пытаетесь сделать это не очень хорошая идея, так как кажется, что она будет не переносной (как для других компиляторов, так и для другого оборудования). – Walter

ответ

2

Нет, нет хорошего способа сделать это, и не должно быть. Исключения выписываются оператором throw в исходном коде. Это важно для рассуждений о безопасности исключений: вы можете посмотреть на код и увидеть места, где могут быть выброшены исключения, и, возможно, более важно, вы можете посмотреть код и увидеть места, где исключены исключения не будет. Если почти все, что вы делаете, может вызвать исключение, очень сложно написать исключающий код код, не загромождая его предложениями catch. Microsoft попробовала это в своих ранних компиляторах на C++: они справляли обработку исключений C++ поверх структурных исключений их ОС, и результат был катастрофой.

+0

Если опция GCC '-fnon -call-exceptions', предполагается, что простой доступ к памяти может вызвать исключение C++. Я не забочусь о других платформах, BTW. – user416983

+0

«результат был катастрофой» - зависит от того, кого вы спросите, я думаю; в последних версиях mingw-w64, например, есть возможность использовать SEH для реализации исключений C++ и, по-видимому, он хорошо работает –

0

Зарегистрируйте альтернативный сигнальный стек с помощью signalaltstack().

Третий аргумент обработчику обработчика сигнала, зарегистрированный в SA_SIGINFO, является указателем на ucontext_t, который содержит сохраненный регистр. Обработчик сигнала должен настроить это, чтобы имитировать вызов функции.Эта функция может затем выдать исключение.

Возможные осложнения включают в себя необходимость сохранения значений сохраненных регистров вызываемого абонента, красной зоны на x86-64 (которая может быть отключена) и регистра адреса возврата на некоторых ISA, таких как ARM.