3

Platform is Windows 7 SP1.

I recently spent some time debugging an issue that was caused because a code was passing an invalid parameter to one of the "safe" CRT functions. As a result my application was aborted right away with no warning or anything -- not even a crash dialog.

At first, I tried to figure this out by attaching Windbg to my application. However when the crash happened, by the time the code broke into Windbg pretty much every thread had been killed save for ONE thread on which Windbg had to break into. There was no clue as to what was wrong. So, I attached Visual Studio as a debugger instead and when my application terminated, I saw every thread exiting with error code 0xc0000417. That is what gave me the clue that there is an invalid parameter issue somewhere.

Next, the way I went about trying to debug this is to once again attach Windbg to my application but this time randomly (by trial & error) place breakpoints in various places like kernel32!TerminateThread, kernel32!UnhandledExceptionFilter and kernel32!SetUnhandledExceptionFilter.

Of the lot, placing a break point at SetUnhandledExceptionFilter immediately showed the callstack of the offending thread when the crash occurred and the CRT function that we were calling incorrectly.

Question: Is there anything intuitive that should have told me to place bp on SUEF right away? I would like to understand this a bit better and not do this by trial and error. Second question is w.r.t to the error code I determined via Visual Studio. Without resorting to VS, how do I determine thread exit codes on Windbg?

ForeverLearning
  • 6,352
  • 3
  • 27
  • 33
  • I'd use `procdump -ma -e 1 -n 100 ` to get dumpfiles for every unhandled exception occuring in your process. – Lieven Keersmaekers Jul 01 '16 at 06:35
  • 1
    I don't think that should be necessary. Does `sxe *` help? (Or `sxe 0xc0000417` if you don't want to handle every single floating point overflow) – Thomas Weller Jul 01 '16 at 06:40
  • Related: http://stackoverflow.com/questions/3467444/invalid-cruntime-parameter-itoa-s – Thomas Weller Jul 01 '16 at 06:48
  • This would be a nice debugging exercise. Can you reduce the code to a [mcve]? – Thomas Weller Jul 01 '16 at 06:50
  • @Thomas `sxe 0xc0000417` was one of the first things I tried and that didn't work. I guess its not really an exception code? BTW, its not a floating point overflow (I suppose you made a typo there.) As to a short/isolated example, if you just pass nullptr to printf_s, you should see the same issue. – ForeverLearning Jul 01 '16 at 10:40
  • @LievenKeersmaekers That could be my issue. I don't want to catch first chance exception, so perhaps I should just leave out the `1` from your command line and try with everything else. – ForeverLearning Jul 01 '16 at 10:41
  • @Dilip, there's no harm in trying (both) but as far as knowledge goes, I'd bet my money on Thomas. – Lieven Keersmaekers Jul 01 '16 at 11:15
  • @Thomas I understood what you were saying now. You meant that if I capture all unhandled exceptions, I might be wasting time looking at things that aren't even relevant to me. Apologies! – ForeverLearning Jul 01 '16 at 13:39

1 Answers1

4

i was going to just comment but this became bigger so an answer

setting windbg as postmortem debugger using Windbg -I will also route all the unhandled exception to windbg

Windbg -I should Register windbg as postmortem debugger
by default Auto is set to 1 in AeDebug Registry Key
if you don't want to debug every program you can edit this to 0
to provide you an additional DoYouWanttoDebug option in the wer Dialog

reg query "hklm\software\microsoft\windows nt\currentversion\aedebug"

HKEY_LOCAL_MACHINE\software\microsoft\windows nt\currentversion\aedebug
    Debugger    REG_SZ    "xxxxxxxxxx\windbg.exe" -p %ld -e %ld -g
    Auto    REG_SZ    0

assuming you registered a postmortem debugger and you run this code

#include <stdio.h>
#include <stdlib.h>
int main (void) 
{
    unsigned long input[] = {1,45,0xf001,0xffffffff};
    int i = 0;
    char buf[5] = {0};
    for(i=0;i<_countof(input);i++)
    {
        _ultoa_s(input[i],buf,sizeof(buf),16);
        printf("%s\n",buf);
    }
    return 1;   
}

on the exception you will see a wer dialog like this

enter image description here

you can now choose to debug this program

windows also writes the exit code on unhandled exception to event log

you can use powershell to retrieve one event like this

PS C:\> Get-EventLog -LogName Application -Source "Application Error" -newest 1| format-list


Index              : 577102
EntryType          : Error
InstanceId         : 1000
Message            : Faulting application name: 
ultos.exe, version: 0.0.0.0, time stamp: 0x577680f1
                     Faulting module name: ultos.exe, version: 
0.0.0.0, time stamp: 0x577680f1
                     Exception code: 0xc0000417
                     Fault offset: 0x000211c2
                     Faulting process id: 0x4a8
                     Faulting application start time: 0x01d1d3aaf61c8aaa
                     Faulting application path: E:\test\ulto\ultos.exe
                     Faulting module path: E:\test\ulto\ultos.exe
                     Report Id: 348d86fc-3f9e-11e6-ade2-005056c00008
Category           : Application Crashing Events
CategoryNumber     : 100
ReplacementStrings : {ultos.exe, 0.0.0.0, 577680f1, ultos.exe...}
Source             : Application Error
TimeGenerated      : 7/1/2016 8:42:21 PM
TimeWritten        : 7/1/2016 8:42:21 PM
UserName           :

and if you choose to debug

you can view the CallStack

0:000> kPL
 # ChildEBP RetAddr  
00 001ffdc8 77cf68d4 ntdll!KiFastSystemCallRet
01 001ffdcc 75e91fdb ntdll!NtTerminateProcess+0xc
02 001ffddc 012911d3 KERNELBASE!TerminateProcess+0x2c
03 001ffdec 01291174 ultos!_invoke_watson(
            wchar_t * expression = 0x00000000 "", 
            wchar_t * function_name = 0x00000000 "", 
            wchar_t * file_name = 0x00000000 "", 
            unsigned int line_number = 0, 
            unsigned int reserved = 0)+0x31
04 001ffe10 01291181 ultos!_invalid_parameter(
            wchar_t * expression = <Value unavailable error>, 
            wchar_t * function_name = <Value unavailable error>, 
            wchar_t * file_name = <Value unavailable error>, 
            unsigned int line_number = <Value unavailable error>, 
            unsigned int reserved = <Value unavailable error>)+0x7a
05 001ffe28 0128ad96 ultos!_invalid_parameter_noinfo(void)+0xc
06 001ffe3c 0128affa ultos!common_xtox<unsigned long,char>(
            unsigned long original_value = 0xffffffff, 
            char * buffer = 0x001ffea4 "", 
            unsigned int buffer_count = 5, 
            unsigned int radix = 0x10, 
            bool is_negative = false)+0x58
07 001ffe5c 0128b496 ultos!common_xtox_s<unsigned long,char>(
            unsigned long value = 0xffffffff, 
            char * buffer = 0x001ffea4 "", 
            unsigned int buffer_count = 5, 
            unsigned int radix = 0x10, 
            bool is_negative = false)+0x59
08 001ffe78 012712b2 ultos!_ultoa_s(
            unsigned long value = 0xffffffff, 
            char * buffer = 0x001ffea4 "", 
            unsigned int buffer_count = 5, 
            int radix = 0n16)+0x18
09 001ffeac 0127151b ultos!main(void)+0x52
0a (Inline) -------- ultos!invoke_main+0x1d
0b 001ffef8 76403c45 ultos!__scrt_common_main_seh(void)+0xff
0c 001fff04 77d137f5 kernel32!BaseThreadInitThunk+0xe
0d 001fff44 77d137c8 ntdll!__RtlUserThreadStart+0x70
0e 001fff5c 00000000 ntdll!_RtlUserThreadStart+0x1b
blabb
  • 8,674
  • 1
  • 18
  • 27
  • Thanks! Unfortunately though I already did try making Windbg as the postmortem debugger before posting here. It wasn't helpful :-( You see we are in the business of writing AddIns that run in the process space of Excel.exe. Even if I set up Windbg as AeDebug-ger, it does break when the crash occurs but the call stacks look completely bogus. I even tried making procdump the AeDebug-ger. Whatever dumps it produced that way was no help either. Placing a `bp` @ `kernel32!SetUnhandledExceptionFilter` is the only thing that worked. – ForeverLearning Jul 01 '16 at 18:25
  • @Dilip: Excel might have an unhandled exception handler. Maybe you want to ask on SuperUser on how to find out which AddIn crashes and what the exception code is. – Thomas Weller Jul 02 '16 at 10:27
  • @Dilip if it worked for you then i am happy but Setting A BreakPoint on SETUNHANDLEDEXCEPTIONFILTER is something my thought process cant seem to digest primary reason all it does is setting a callback to be called in case of any unhandled exception so if it broke then it mean some one (may be excel or some module is just setting a handler ) so that doesnt mean an exception happened the whole suef seems to be some kind of mirage to me – blabb Jul 02 '16 at 13:45
  • @blabb I posted here primarily because I am in the same boat as you. I couldn't quite figure out why SUEF was being called. I will update the post with the call stack, so you can see for yourself. – ForeverLearning Jul 02 '16 at 23:27