andi
andi

Reputation: 922

suppress or intercept CRT checks from instances of CRT from other dlls

My program loads several dlls and calls their functions. The dlls can use different versions of CRT.

When C runtime checks the validity of arguments and finds problems, it calls the invalid parameter handle, which in turn, closes the application, with or without the "Send-Don't send" dialog.

I tried calling *_set_invalid_parameter_handler* but it only works if it is called from within the bad dll. I tried SetErrorMode, but all I managed to do is get the process killed without the dialog.

Is there any way to handle those exceptions? I don't care if some resources are compromised. All I want is to allow users to save the configuration. If the dialog appears, they click on it and kill the process.


EDIT It turns out the solution to load all versions of CRT or to enumerate all DLLs fails. To make all clear, here is a small example to play with:

This would be my main application (let's call the file 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();
}

This application loads a dll that does bad things (it is not developed by me, so I will not accept any solution telling me to fix the bugs there). Lets' call that file extension.c.

#include <stdio.h>

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

To compile, do:

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

The question is what do I do in function fixMyProblem(), so that I don't get the send/don't send dialog on XP or the application has stopped working dialog on 7.

According to David Gladfelter I should do

void fixMyProblem() {
    _set_invalid_parameter_handler(myInvalidParameterHandler);
}

and also do this for each version CRT available. It turns out that even with one single version of CRT (I use the same for both exe and dll), it still does not work. They both use the same version of CRT, but is seems they do not use the same CRT.

If this is is the case, I assume that the stuff I have to change is inside the DLL. Of course, it does not export *_set_invalid_parameter_handler*.

But to be fair to David Heffernan, here is the implementation for his solution:

#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);
}

For my real application, not this test, I get 1 dll fixed (msvcp90.dll). It still does not fix my problem.

I would appreciate any help in solving this.

Upvotes: 2

Views: 1093

Answers (3)

mihaif
mihaif

Reputation: 542

If the dll is built with a statically linked CRT, then the state and functions of the CRT will be local to that instance of the dll. I am assuming the invalid parameter handler used by the CRT is calling the UnhandledExceptionFilter function, from the OS, to show that "nice" error dialog.

You could try to hook functions like UnhandledExceptionFilter or TerminateProcess, making the dll use your own functions instead. You can do this by parsing the Import Address Table of the loaded dll, search for the function name you are interested, and change the address to point to your function.

Upvotes: 4

David Heffernan
David Heffernan

Reputation: 613441

You could always enumerate the modules in your process and if it's a C runtime then get hold of the invalid parameter handler with a call to GetProcAddress.

But you'd be better off trying to fix the bugs at root. Trying to ignore such problems mostly just leads to further problems because memory gets corrupted and so on.

Upvotes: 1

David Gladfelter
David Gladfelter

Reputation: 4213

You could create another DLL that uses the same version of the CRT as the version used by the DLL that causes the invalid parameter handler to be called and register the invalid parameter handler it in that new DLL. The invalid parameter handler is global to the process/CRT-version combination.

If you don't know what version the DLL is using and you can't figure it out, worst-case is you create several DLL's, one for each CRT version:

  • VS 6 static/dynamic/multithreaded/single-threaded
  • VS.NET static/dynamic/multithreaded/single-threaded
  • VS 2003 static/dynamic/multithreaded/single-threaded
  • VS 2005 static/dynamic
  • VS 2008 static/dynamic
  • VS 2010 static/dynamic

You could probably create them as static .lib files and link them all into one (very confused) DLL.

Upvotes: 0

Related Questions