Windows 7 - CreateProcess с DEBUG_PROCESS нарушением прав доступа - PullRequest
3 голосов
/ 07 января 2012

окей ... сгорел на этом ... чесал голову весь день.У меня есть очень простая, одноразовая c ++ DLL (StartApplication.dll), используемая для запуска приложения.

  • Прекрасно работает в WinXP, но не в win7
  • Использует CreateProcess () с DEBUG_PROCESS (поэтому я могу дождаться завершения программы перед завершением).
  • Если я наблюдаю за процессами в диспетчере задач, я вижу, как запускается процесс, но окно не создается, и больше ничего не происходит
  • Если я изменю на NORMAL_PRIORITY_CLASS, программа будет выполняться так, как должна (но я теряю способностьподождите, прежде чем завершить, поскольку я могу сделать это только во время отладки)
  • Код ошибки дает мне STATUS_ACCESS_VIOLATION
  • У меня отключен контроль учетных записей, и настройка исполняемого файла на запуск от имени администратора и совместимость с WinXP ничего не делает

Вот код.Любые мысли будут с благодарностью

    //...blah blah...handful of stuff preceding this to set up command line and
    //directories etc....not of use here probably...

SECURITY_ATTRIBUTES sa = {0}; sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.bInheritHandle = TRUE;

STARTUPINFO si = {0}; si.cb = sizeof(si);
si.dwFlags = STARTF_USESTDHANDLES;

si.hStdOutput = (NULL == stdOutFileName)? INVALID_HANDLE_VALUE :
    ::CreateFile(stdOutFileName, GENERIC_WRITE, FILE_SHARE_READ, &sa
        , CREATE_ALWAYS, 0, NULL);

si.hStdError = (NULL == stdErrFileName)? INVALID_HANDLE_VALUE :
    ::CreateFile(stdErrFileName, GENERIC_WRITE, FILE_SHARE_READ, &sa
        , CREATE_ALWAYS, 0, NULL)        
PROCESS_INFORMATION pi = {0};
if (::CreateProcess(useApplicationName? applicationName : NULL, processCommandLine
    , NULL, NULL, TRUE, /*NORMAL_PRIORITY_CLASS*/DEBUG_PROCESS, NULL, currentDirectory, &si, &pi)) 
{
    BOOL cont = TRUE;
    while (cont) 
    {
        DWORD continueStatus = DBG_CONTINUE;

        DEBUG_EVENT debugEvent = {0};
        if (!::WaitForDebugEvent(&debugEvent, INFINITE)) 
        { 
            errorCode = ErrorCode_Other;
            ::TerminateProcess(pi.hProcess, 0);
            break;
        }
        else
        {
            switch (debugEvent.dwDebugEventCode) 
            {
                case EXCEPTION_DEBUG_EVENT: 
                    switch (debugEvent.u.Exception.ExceptionRecord.ExceptionCode) 
                    {
                        case EXCEPTION_ACCESS_VIOLATION:
                        case EXCEPTION_DATATYPE_MISALIGNMENT:
                        case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
                        case EXCEPTION_FLT_DENORMAL_OPERAND: 
                        case EXCEPTION_FLT_DIVIDE_BY_ZERO:
                        case EXCEPTION_FLT_INEXACT_RESULT:
                        case EXCEPTION_FLT_INVALID_OPERATION:
                        case EXCEPTION_FLT_OVERFLOW:
                        case EXCEPTION_FLT_STACK_CHECK:
                        case EXCEPTION_FLT_UNDERFLOW:
                        case EXCEPTION_INT_DIVIDE_BY_ZERO:
                        case EXCEPTION_INT_OVERFLOW:
                        case EXCEPTION_PRIV_INSTRUCTION:
                        case EXCEPTION_IN_PAGE_ERROR:
                        case EXCEPTION_ILLEGAL_INSTRUCTION:
                        case EXCEPTION_NONCONTINUABLE_EXCEPTION:
                        case EXCEPTION_STACK_OVERFLOW:
                        case EXCEPTION_INVALID_DISPOSITION:
                        case EXCEPTION_INVALID_HANDLE:
                            errorCode = ErrorCode_ApplicationException; 
                            *exceptionCode = debugEvent.u.Exception.
                                ExceptionRecord.ExceptionCode;
                            ::TerminateProcess(pi.hProcess, 0);
                            break;
                        default:
                            ;
                    }
                    break;

                case EXIT_PROCESS_DEBUG_EVENT:
                    cont = FALSE;   
                    break;
                default:
                    ;
            } 
            ::ContinueDebugEvent(debugEvent.dwProcessId, debugEvent.dwThreadId
                , continueStatus);
        }    
    }

    ::GetExitCodeProcess(pi.hProcess, reinterpret_cast<LPDWORD>(exitCode));

    ::CloseHandle(pi.hProcess);
    ::CloseHandle(pi.hThread);
}
if (INVALID_HANDLE_VALUE != si.hStdOutput)
    ::CloseHandle(si.hStdOutput);
if (INVALID_HANDLE_VALUE != si.hStdError)
    ::CloseHandle(si.hStdError);

return errorCode;

}

Ответы [ 3 ]

3 голосов
/ 07 января 2012

Ваш код завершает весь процесс после возникновения первого исключения. Обычно вы должны позволить программе позаботиться об исключениях, только если исключение не было обработано, процесс завершится.

Чтобы узнать, было ли исключение фатальным (т. Е. Не обрабатывалось в первый раз), проверьте u.Exception.dwFirstChance:

  • Если это 0, установите соответствующие коды ошибок и завершите.
  • в противном случае, исключение возникло впервые, вы должны вызвать ContinueDebugEvent с DBG_EXCEPTION_NOT_HANDLED, чтобы передать исключение процессу.

EDIT

Если вы хотите только наблюдать за исключениями, а не обрабатывать их внутри отладчика, вы всегда должны продолжать с DBG_EXCEPTION_NOT_HANDLED.

Есть один улов:

Непосредственно перед запуском основного потока Windows вызывает исключение INT3, которое необходимо передать процессу (DBG_CONTINUE).

Псевдокод:

bool FirstInt3 = true;

while (cont) 
{
    DWORD continueStatus = DBG_EXCEPTION_NOT_HANDLED;

    // ....

    switch(...)
    {
        case EXCEPTION_DEBUG_EVENT: 
            if(!FirstChance)
            {
                // Fatal exception

                // Log Exception that terminated the program here
                // Don't do anything else, Windows automatically terminates the process
                // You will get an EXIT_PROCESS_DEBUG_EVENT on the next event
            }
            switch (debugEvent.u.Exception.ExceptionRecord.ExceptionCode) 
            {
                case EXCEPTION_BREAKPOINT:
                    if(FirstInt3)
                    {
                        FirstInt3 = false;
                        continueStatus = DBG_CONTINUE;
                        break;
                    }
                default:
                    // Log ExceptionCode here
                    break;
            }
            break;
    }
2 голосов
/ 10 января 2012

Если я правильно вас понял, вы используете DEBUG_PROCESS просто для того, чтобы вы могли дождаться завершения процесса. Это серьезное излишество.

Чтобы дождаться завершения процесса, используйте WaitForSingleObject (или другую подходящую функцию ожидания) в pi.hProcess.

1 голос
/ 07 января 2012

@ pezcode прав - не просто заканчивайте процесс при получении первого исключения от отладчика, пусть он работает нормально.Отладчик (ваш код) в любом случае получит все исключения, возникающие в отладчике (исключения первого шанса).

Я бы посоветовал вам сначала минимизировать логику цикла отладчика, а также стараться не подключать и обрабатывать обработчики.Сначала будьте проще, а затем двигайтесь вперед.

...