Windows 7-CreateProcess W / DEBUG нарушение доступа к процессу



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




  • прекрасно работает в WinXP, но не в win7

  • использует CreateProcess () с DEBUG_PROCESS (поэтому я могу дождаться завершения программы перед завершением).

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

  • Если я изменюсь на NORMAL_PRIORITY_CLASS, программа будет выполняться так, как она должна (но я теряю возможность ждать перед завершением, так как я могу сделать это только во время отладки)

  • код ошибки дает мне STATUS_ACCESS_VIOLATION

  • У меня отключен UAC и установка исполняемого файла для запуска от имени администратора и с совместимостью 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;


}

693   3  

3 ответов:

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

Чтобы увидеть, было ли исключение фатальным (т. е. не обрабатывается с первого раза) проверка 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;
    }

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

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

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

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

Comments

    Ничего не найдено.