подавить или перехватить проверки CRT из экземпляров CRT из других библиотек - PullRequest
2 голосов
/ 24 мая 2011

Моя программа загружает несколько библиотек и вызывает их функции. DLL могут использовать разные версии CRT.

Когда среда выполнения C проверяет правильность аргументов и обнаруживает проблемы, она вызывает недопустимый дескриптор параметра, который, в свою очередь, закрывает приложение с или без диалога «Send-Don't send».

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

Есть ли способ обработать эти исключения? Мне все равно, если некоторые ресурсы скомпрометированы. Все, что я хочу, это разрешить пользователям сохранять конфигурацию. Если диалоговое окно появляется, они щелкают по нему и убивают процесс.


EDIT Оказывается, решение загрузить все версии CRT или перечислить все библиотеки DLL не удается. Чтобы прояснить ситуацию, вот небольшой пример для игры:

Это будет мое основное приложение (давайте назовем файл application.c ):

#include <windows.h>

void myInvalidParameterHandler(const wchar_t* expression, const wchar_t* function, const wchar_t* file, unsigned int line, uintptr_t pReserved) {
   wprintf(L"Invalid parameter detected in function %s. File: %s Line: %d\n", function, file, line);
   wprintf(L"Expression: %s\n", expression);
}

void fixMyProblem() {
}

int main(int argc, char **argv) {
    HMODULE hModule = LoadLibrary("extension.dll");
    void (WINAPI *function)() = GetProcAddress(hModule, "function");
    fixMyProblem();
    function();
}

Это приложение загружает dll, которая делает плохие вещи (оно не разработано мной, поэтому я не приму никакого решения, говорящего мне, чтобы исправить ошибки там). Позволяет вызвать этот файл extension.c .

#include <stdio.h>

__declspec(dllexport) void function() {
    printf("do bad stuff");
    fopen(NULL, "r");
}

Для компиляции выполните:

cl extension.c /link /OUT:extension.dll /DLL
cl application.c

Вопрос в том, что мне делать в функции fixMyProblem () , чтобы я не получил диалоговое окно отправить / не отправить в XP или приложение перестало работать диалоговое окно 7.

По словам Дэвида Гладфелтера, я должен сделать

void fixMyProblem() {
    _set_invalid_parameter_handler(myInvalidParameterHandler);
}

, а также сделать это для каждой версии ЭЛТ. Оказывается, что даже с одной версией CRT (я использую одну и ту же для exe и dll), она все равно не работает. Они оба используют одинаковую версию ЭЛТ, но, похоже, они не используют одинаковую ЭЛТ.

Если это так, я предполагаю, что материал, который я должен изменить, находится внутри DLL. Конечно, он не экспортирует * _set_invalid_parameter_handler *.

Но, если честно, Дэвид Хеффернан, вот реализация его решения:

#include <Psapi.h>
#pragma comment(lib, "Psapi.lib")
void fixMyProblem() {
    HANDLE hProcess = GetCurrentProcess();
    HMODULE *hModules;
    DWORD requiredSize = 0;
    DWORD secondRequiredSize = 0;
    if (!EnumProcessModules(hProcess, NULL, 0, &requiredSize)) {
        printf("oops\n");
        return;
    }
    hModules = malloc(requiredSize);
    if (EnumProcessModules(hProcess, hModules, requiredSize, &secondRequiredSize)) {
        int i;
        int loadedModules = min(requiredSize, secondRequiredSize) / sizeof(HMODULE);
        for (i = 0; i < loadedModules; i++) {
            void *(WINAPI *_set_invalid_parameter_handler_function)(void *) = (void *(WINAPI *)(void *)) GetProcAddress(hModules[i], "_set_invalid_parameter_handler");
            if (_set_invalid_parameter_handler_function != NULL) {
                _set_invalid_parameter_handler_function(myInvalidParameterHandler);
                printf("fixed dll %d\n", i);
            }
        }
    } else {
        printf("oops\n");
    }
    free(hModules);
}

Для моего реального приложения, а не для этого теста, я исправляю 1 dll (msvcp90.dll). Это все еще не решает мою проблему.

Буду признателен за помощь в решении этой проблемы.

Ответы [ 3 ]

4 голосов
/ 16 ноября 2012

Если dll построен со статически связанным CRT, то состояние и функции CRT будут локальными для этого экземпляра dll. Я предполагаю, что обработчик недопустимых параметров, используемый CRT, вызывает функцию UnhandledExceptionFilter из ОС, чтобы показать этот «хороший» диалог ошибки.

Вы можете попытаться перехватить такие функции, как UnhandledExceptionFilter или TerminateProcess, заставив dll использовать вместо вас ваши собственные функции. Вы можете сделать это путем анализа таблицы адресов импорта загруженной библиотеки DLL, поиска интересующего вас имени функции и изменения адреса, чтобы он указывал на вашу функцию.

1 голос
/ 22 июня 2011

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

Но вам лучше попытаться исправить ошибки в корне. Попытки игнорировать такие проблемы в основном приводят к дальнейшим проблемам, поскольку память повреждена и т. Д.

0 голосов
/ 22 июня 2011

Вы можете создать другую библиотеку DLL, которая использует ту же версию CRT, что и версия, используемая библиотекой DLL, что вызывает вызов обработчика недопустимых параметров, и зарегистрировать его в этой новой библиотеке DLL.Недопустимый обработчик параметров является глобальным для комбинации процесс / CRT-версия.

Если вы не знаете, какую версию использует DLL, и не можете понять, в худшем случае вы создадите несколько библиотек DLL, по одной для каждой версии CRT:

  • VS 6 статический / динамический / многопоточный / однопоточный
  • VS.NET статический / динамический / многопоточный / однопоточный
  • VS 2003 статический / динамический / многопоточный / однопоточный
  • VS 2005 статический / динамический
  • VS 2008 статический / динамический
  • VS 2010 статический / динамический

Возможно, вы можете создать их как статические .lib-файлы исвязать их всех в одну (очень запутанную) DLL.

...