Являются ли LLVM "фатальными ошибками" действительно фатальными? - PullRequest
0 голосов
/ 25 января 2020

Мне интересно, действительно ли фатальные ошибки LLVM "фатальны" - ie. они делают недействительным все состояние системы и не подлежат восстановлению.

Например (я использую интерфейс llvm- c), поведение по умолчанию следующего кода:

   LLVMMemoryBufferRef mb = LLVMCreateMemoryBufferWithMemoryRange(somedata, data_length, "test", 0);
   LLVMModuleRef module; 
   if (LLVMParseBitcode2(mb, &module) != 0) {
      fprintf(stderr, "could not parse module bitcode");
   }

означает, что если указатель somedata указывает на недопустимый битовый код, fprintf никогда не выполняется, но вместо этого весь процесс прерывается со своим собственным сообщением о фатальной ошибке на stderr.

Однако, предположительно, существует интерфейс для лови такие ошибки: LLVMFatalErrorHandler. Однако после установки обработчика ошибок процесс все равно просто прерывается без вызова обработчика ошибок.

Документация в LLVM в целом очень плохая, а интерфейс C практически не документирован. Но кажется, что в супер-fr agile дизайне весь процесс принудительно прерывается, если какой-то битовый код поврежден!

Итак, мне интересно, подразумевает ли здесь «фатальный», как обычно, что если возникает такая ошибка, мы не можем восстановить и продолжать использовать библиотеку (например, пробовать другой битовый код или, например, восстанавливать старый), или если это не действительно «фатальная» ошибка, и мы можем получить FatalErrorHandler или какие-либо другие средства отлова и уведомления, или предпринять другие действия по исправлению и продолжить программу.

1 Ответ

0 голосов
/ 27 января 2020

Хорошо, после прочтения источника LLVM в течение 10+ часов и привлечения помощи дружественного разработчика LLVM, ответ здесь заключается в том, что на самом деле это не фатальная ошибка!

Функции, вызванные выше в интерфейсе C, устарели и должны были быть удалены; Раньше у LLVM было понятие «глобальный контекст», и это было удалено годами go. Правильный способ сделать это - чтобы эта ошибка могла быть перехвачена и обработана без прерывания процесса - это использовать интерфейс LLVMDiagnosticInfo после создания экземпляра LLVMContext и использования специфических для контекста функций c средства чтения битовых кодов:

   void llvmDiagnosticHandler(LLVMDiagnosticInfoRef dir, void *p) {
      fprintf(stderr, "LLVM Diagnostic: %s\n", LLVMGetDiagInfoDescription(dir));
   }

   ...

   LLVMContextRef llvmCtx = LLVMContextCreate();
   LLVMContextSetDiagnosticHandler(llvmCtx, llvmDiagnosticHandler, NULL);
   LLVMMemoryBufferRef mb = LLVMCreateMemoryBufferWithMemoryRange(somedata, data_length, "test", 0);
   LLVMModuleRef module; 
   if (LLVMGetBitcodeModuleInContext2(llvmCtx, mb, &module) != 0) {
      fprintf(stderr, "could not parse module bitcode");
   }

LLVMDiagnosticInfo также содержит код "серьезности", который указывает на серьезность ошибки (иногда возвращаются простые предупреждения или подсказки производительности). Кроме того, как я и подозревал, это не тот случай, когда неудачный анализ двоичного кода делает недействительной библиотеку или состояние контекста.

Код, который прерывался с сообщением об ошибке, представлял собой простой пробел, позволяющий старым приложениям, которые все еще называют старые функции API работой - они устанавливают контекст и минимальный обработчик ошибок, который ведет себя таким образом.

...