Pull to refresh

Comments 4

При использовании _set_se_translator вы не сможете отследить callstack места, где было брошено C++-исключение.
А в решении, рассмотренном в статье, вы можете однообразно в одном месте получать стек вызовов как для аппаратных, так и для программных исключений.
Мне кажется, что в винде через векторные исключения и минидамп можно добиться неплохих результатов примерно так:
код не проверял, вряд ли он рабочий, просто иллюстрация идеи
//где-то в мэйне

bool MINIDUMPFUNC CreateMinidump(PEXCEPTION_POINTERS ep)
{
  char fm[MAX_PATH];
/* тут формируем имя файла дампа как нам нравится */
  HANDLE hFile = CreateFile(fn,
    GENERIC_WRITE,         
    FILE_SHARE_WRITE,      
    NULL,                  
    CREATE_ALWAYS,         
    FILE_ATTRIBUTE_NORMAL, 
    NULL);                 

  if (hFile == INVALID_HANDLE_VALUE) 
  { 
      cout << "Файл минидампа не создан: " << fn << ". Ошибка: " << GetLastError());
      return false;
  }

  MINIDUMP_EXCEPTION_INFORMATION mei;
  mei.ThreadId = GetCurrentThreadId();
  mei.ExceptionPointers = ep;
  mei.ClientPointers = TRUE; //FALSE

  MINIDUMP_USER_STREAM mus[1] = {0};

  MINIDUMP_USER_STREAM_INFORMATION musi;
  musi.UserStreamCount = sizeof(mus) / sizeof(MINIDUMP_USER_STREAM);
  musi.UserStreamArray = mus;

  BOOL ret = MiniDumpWriteDump(
    GetCurrentProcess(),
    GetCurrentProcessId(),
    hFile,
    (MINIDUMP_TYPE)0,  //Тут можно поиграть с детализацией дампа
    ep ? &mei : NULL,
    &musi,
    NULL);
  CloseHandle(hFile);
  if(!ret)
  {
    cout <<  "Ошибка создания минидампа: " << fn << ". Ошибка: " << GetLastError();
    return false;
  }
  else 
  {
    cout << "Создан минидамп: " << fn;
    return true;
  }
}

LONG WINAPI veh(_EXCEPTION_POINTERS *p)
{
//тут можно поставить фильтр на критические исключения, типа AV и реагировать только на них, в общем вариантов много
  if(  CreateMinidump(ep))
    FatalExit(666); //в принципе после создания дампа можем прибить приложение, но это дело вкуса.
  return EXCEPTION_CONTINUE_SEARCH;
}

auto h = AddVectoredExceptionHandler(1, veh);

int main()
{

//здесь наш небезопасный код

}


RemoveVectoredExceptionHandler(VectoredExceptionHandle);

Единственно надо обеспечить, чтобы наш векторный обработчик регистрировался при аттаче и дерегистрировался при детаче dll-лек в наш процесс. Это тривиально.
Спасибо, действительно, векторные обработчики исключений очень мощный и удобный механизм, с помощью которого можно элегантно получать стек вызовов места, где было брошено исключение (причем как для программного, так и аппаратного типов исключений).
Sign up to leave a comment.

Articles