Tech Off Thread

7 posts

Forum Read Only

This forum has been made read only by the site admins. No new threads or comments can be added.

How to programmatically prevent a crash report on a specific process?

Back to Forum: Tech Off
  • User profile image
    BitFlipper

    I have a "scanner" exe written in C# (both 32-bit and 64-bit versions) that I start from another C# "master" process. The master and scanner processes communicates via WCF IPC (NetNamedPipeBinding).

    This scanner process recursively scans a specified folder for unmanaged DLLs, and queries the DLLs to determine whether they are of a specific type (unmanaged VST audio plugins, in this case).

    The reason the scanner process is started from another master process is because the scanner process is expected to crash when it comes across a flaky plugin, or possibly a DLL that is not a VST plugin at all. In fact I have a few of them that either crash the scanner process, or hangs it due to LoadLibrary itself hanging.

    The master process does a good job of detecting and recovering from a failed scan, and will start up another scanner process if the first one crashed.

    However, the problem I have is that I noticed that if the scanner process crashes, that an entry is made into the Windows Reliability Monitor. I need to prevent these scanner processes from being logged in this way when they crash. I know I can disable Reliability Monitor but this is not a satisfactory solution for a "shipping" product (even though this is just a pet project, but still, I'm trying to do the right thing...). I need to do this programmatically and then only on the scanner processes themselves.

  • User profile image
    Charles

    I'm not sure you can/want to do this... For example, if you are able to instruct Windows to ignore crashes for individual processes, then in some sense you have added an unreliability factor to Windows... Does that make sense?

    It seems odd to me that your design relies on crashes/hangs to satisfy your tests. Further, any flaky plug-in should be reported so that the owners of said plug-in can fix it using the data made available via Watson - which will eventually end up in the plug-in owners inbox.

    Is your design correct? Can you achieve your goals in a different way - other than testing for process hangs and crashes?

    C

  • User profile image
    cheong

    @BitFlipper:And why would you need LoadLibrary to check, aren't you going to LoadLibraryEx() as datafile or image and read it directly to check (metadata or string search... you should be able to get the proper decorated names by looking at your existing plugins directly.)

    Back to the origional question, although it's not recommanded behaviour... you might just try to attach your implementation of debugger to the process, or use ImageExecutionOption to attach when your application hangs.

    Now you has two problem: 1) figure out how to create a minimal mixed-mode debugger; 2) how to make sure your application fails in consistant manner so you can recover and pretend the problem does not exist. Writing in .NET adds another level to the challenge as code do not look the same x86/x64 environments.

    Recent Achievement unlocked: Code Avenger Tier 4/6: You see dead program. A lot!
    Last modified
  • User profile image
    BitFlipper

    To Charles & cheong:

    Yes, this is unfortunately how it needs to work. This isn't my design at all, this is how you are supposed to scan for VST DLLs. Basically, this is how it works:

    1. User gives the audio application a list of folders to scan.
    2. Scanner enumerates through all files and finds all files with a *.dll extension.
    3. For each DLL, scanner calls LoadLibrary to load the DLL (prays the DLL doesn't crash or hang).
    4. If LoadLibray fails, try again, but this time load it from a 64-bit scanner. VST plugins can be either 32-bit or 64-bit.
    5. Scanner calls GetProcAdress to find the "main" function.
    6. Scanner calls main and gets return value (prays the DLL doesn't crash or hang - some do).
    7. If the return value is non-zero, cast it to an int* and check to see whether the int value is the "magic" value of 'VstP' that signifies that it is a VST DLL (prays the value that main returned is actually allocated memory).
    8. If the correct "magic" value is detected, casts the value returned from main to an AEffect structure (prays the allocated memory is actually a full AEffect structure). See here for an example of what this structure looks like. 
    9. Get various VST related pieces of info from this structure.
    10. As an additional test to see whether the VST plugin is fit for usage within the audio application, the scanner can call into a few of the functions whose pointers are also stored in the AEffect structure to see whether those calls crash or not.

    @ cheong: So as you can see, using LoadLibraryEx isn't going to help, as there is no way to scan for metadata in this case. The VST spec doesn't define such metadata. 

    @ Charles: It isn't that my design relies on crashes/hangs to satisfy tests, instead my design needs to work around the fact that these tests can and do hang/crash.

    EDIT: As far as not wanting to log the crashes, the reason is that from what I can tell from the crash reports, it doesn't neccessarily show that the crash occurred in the DLL I was trying to load, but in my scanner exe. In fact of the dozens and dozens of reports I have, none show anything other than my scanner as the culprit. Quite useless, which is why disabling it in this case would be desirable. 

    Since my main app is starting the scanner processes programmatically, even if my main app is running under the debugger, those canner processes are not running under the debugger, so they are logged if they crash. I really don't care to have my scanner logged as the culprit when it clearly isn't.

  • User profile image
    Sven Groot

    Doesn't .Net wrap native SEH exceptions in Exception objects? In which case it'd be a matter of just wrapping everything in a try/catch block and terminating the process cleanly. Otherwise, you'd have to make the scanner native code and manually wrap the tests in a SEH try/catch block (note: C++ try/catch doesn't catch SEH exceptions by default). At least I think that might work.

  • User profile image
    BitFlipper

    @Sven Groot:

    I have try/catch blocks in all the strategic places. I am still in the process of figuring out which unmanaged crashes get cought by the managed try/catch blocks, and which are not.

    More problematic is what happens if the P/Invoke call hangs? I have one VST that causes a hang when calling LoadLibrary on it. So far the only thing that works in that case is to call Process.Kill from the master process, and this causes the scanner process to be logged in the crash logs (which is what I'm trying to prevent).

  • User profile image
    BitFlipper

    The answer:

    From the process that might crash, call the Win32 functionSetErrorMode with flags SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX.

    In addition, in the managed method that contains the try/catch around the P/Invoke call into the unmanaged code, add the following attribute: HandleProcessCorruptedStateExceptionsAttribute. This will cause these exceptions to be passed on to the managed code (Windows won't just kill the process anymore). I believe this behavior is new in 4.0. Before 4.0 (or maybe 3.5, not sure), this category of exceptions was passed on to managed code regardless.

    Of course once I catch any nasty AccessViolationException or anything similar, I immediately signal that the scan has failed, the process exits and a new process is started to scan the next DLL. The good thing is that there is no longer a nasty Windows Error Reporting entry made for the crashed process (thanks to the SetErrorMode call).

Conversation locked

This conversation has been locked by the site admins. No new comments can be made.