[Webkit-unassigned] [Bug 52198] Opening twitter home page (own tweets) crashes without dump in r75478

bugzilla-daemon at webkit.org bugzilla-daemon at webkit.org
Tue Jan 18 06:06:53 PST 2011


https://bugs.webkit.org/show_bug.cgi?id=52198





--- Comment #27 from Adam Roben (aroben) <aroben at apple.com>  2011-01-18 06:06:53 PST ---
(From update of attachment 79248)
I just spent a while trying to make sure that the problem really is that we're failing to load QTMovieWin.dll, and learned a bit about WinDbg in the process. I figured I'd document it here for posterity (i.e., my future self who has forgotten all of this).

MSDN says that the delay-load machinery throws exceptions when it fails to load a DLL or find an entry point in that DLL [1]. That seems to match what we're seeing here, so I wanted to see what the exception being thrown was.

The backtrace in comment 25 shows a call to RaiseException. Here's the function declaration from MSDN [2]:

void WINAPI RaiseException(
  __in  DWORD dwExceptionCode,
  __in  DWORD dwExceptionFlags,
  __in  DWORD nNumberOfArguments,
  __in  const ULONG_PTR *lpArguments
);

MSDN also says "The exception passes a pointer to a DelayLoadInfo structure in the LPDWORD value that can be retrieved by GetExceptionInformation in the EXCEPTION_RECORD structure, ExceptionInformation[0] field." [1] The docs for EXCEPTION_RECORD [3] made me think that the DelayLoadInfo must be passed in the lpArguments parameter. So I wanted to see if we could inspect that parameter.

After loading the dump into WinDbg (Ctrl+D) and setting up the symbol path (.sympath), I wanted to find RaiseException's paramters. The WINAPI calling convention is __stdcall, which passes arguments on the stack right-to-left [4]. So, let's find the stack for RaiseException:

0:000> kb 2
ChildEBP RetAddr  Args to Child              
0013f52c 027b8fcc c06d007e 00000000 00000001 kernel32!RaiseException+0x53
0013f594 027b2c7b 00000054 0013f550 00000002 WebKit!__delayLoadHelper2+0x13b [f:\dd\vctools\delayimp\delayhlp.cpp @ 331]

The first number in each row is the base pointer for the function (i.e., where the stack pointer was when the function was called). The second number is the return address that we should jump back to when the function is finished. The next three numbers are the first three arguments to the function. For RaiseException, this gives us the dwExceptionCode (0xc06d007e), dwExceptionFlags (0), and nNumberOfArguments (1) arguments. Unfortunately, it doesn't give us lpArguments! But, having nNumberOfArguments set to 1 does imply that we're right about the DelayLoadInfo struct is being passed in lpArguments. The exception code also gives a clue that we're interpreting things correctly: in [1], we see that 0x6d should be part of the exception code, and indeed it seems to be.

To get the fourth argument, we're going to have to look at the stack ourselves. Let's look at the stack around RaiseException's EBP (looking at ESP at this point probably wouldn't be helpful, as we're already 0x53 bytes into RaiseException, and it's probably moved the stack pointer farther down by now):

0:000> dds 0013f52c l6
0013f52c  0013f594
0013f530  027b8fcc WebKit!__delayLoadHelper2+0x13b [f:\dd\vctools\delayimp\delayhlp.cpp @ 331]
0013f534  c06d007e
0013f538  00000000
0013f53c  00000001
0013f540  0013f5a0

The left column is the memory address, the right column is the 4-byte word stored at that address. (I wish the rows were reversed, since the stack grows down from higher addresses. Oh well!) Going from the top row to the bottom, which means we're going backwards in time, we see:

0013f52c  0013f594

The EBP of the previous frame; RaiseException must have pushed it onto the stack before storing its own base pointer in EBP.

0013f530  027b8fcc WebKit!__delayLoadHelper2+0x13b [f:\dd\vctools\delayimp\delayhlp.cpp @ 331]

The return address; this was pushed here by the call instruction.

0013f534  c06d007e
0013f538  00000000
0013f53c  00000001

The first three arguments to RaiseException that we saw in the backtrace, which means the next row is...

0013f540  0013f5a0

The fourth argument, AKA lpArguments!

lpArguments is a ULONG_PTR*. We know there's only one argument being passed (from the nNumberOfArguments parameter), so lpArguments[0] should be a pointer to that DelayLoadInfo struct:

0:000> dd 0013f5a0 l1
0013f5a0  0013f550

0x0013f550 is the address of our DelayLoadInfo struct. The declaration of the struct in MSDN shows that it's 36 bytes long [4]. Let's have a look!

0:000> dds 0013f550 l9
0013f550  00000024
0013f554  028c57c4 WebKit!_DELAY_IMPORT_DESCRIPTOR_QTMovieWin_dll
0013f558  028f5374 WebKit!_imp_?initializeQuickTimeQTMovieSA_NXZ
0013f55c  028b1850 WebKit!_sz_QTMovieWin_dll
0013f560  00000001
0013f564  028c5dae WebKit!libxslt_NULL_THUNK_DATA_DLN+0x31a
0013f568  00000000
0013f56c  00000000
0013f570  0000007e

Inserting those values into the DelayLoadInfo declaration from MSDN gives:

struct DelayLoadInfo {
    DWORD           cb == 0x24;         // size of structure
    PCImgDelayDescr pidd == 0x28c57c4;       // raw form of data (everything is there)
    FARPROC *       ppfn == 0x28f5374;       // points to address of function to load
    LPCSTR          szDll == 0x28b1850;      // name of dll
    DelayLoadProc   dlp {
        BOOL fImportByName == 0x1;
        union {
            LPCSTR          szProcName == 0x28c5dae;
            DWORD           dwOrdinal;
        }
    }
    HMODULE         hmodCur == 0x0;    // the hInstance of the library we have loaded
    FARPROC         pfnCur == 0x0;     // the actual function that will be called
    DWORD           dwLastError == 0x7e; // error received (if an error notification)
}

We can confirm we've interpreted this correctly by looking at some of the strings involved:

0:000> da 028b1850
028b1850  "QTMovieWin.dll"
0:000> da 028c5dae
028c5dae  "?initializeQuickTime at QTMovie@@SA"
028c5dce  "_NXZ"

So we're trying to load QTMovieWin.dll and get the address of ?initializeQuickTime at QTMovie@@SA_NXZ. Looks like we've got it right.

The interesting thing here is dwLastError. Hopefully that will tell us what went wrong:

0:000> !error 7e
Error code: (Win32) 0x7e (126) - The specified module could not be found.

Oh. Great. We already knew that. But at least now we are more confident!

After going through all of this, I realized that the error code is right there in the exception code c06d007e. (See [1] for how that value is constructed.) And we also could have gotten it much more easily right from the start:

0:000> !gle
LastErrorValue: (Win32) 0x7e (126) - The specified module could not be found.
LastStatusValue: (NTSTATUS) 0xc0000135 - {Unable To Locate Component}  This application has failed to start because %hs was not found. Re-installing the application may fix this problem.

I'll choose to view this as a character-building experience. And I got to learn a little more about WinDbg, exceptions, and the delay-load mechanism!

1. http://msdn.microsoft.com/en-us/library/1c9e046h(v=VS.80).aspx
2. http://msdn.microsoft.com/en-us/library/ms680552(v=vs.85).aspx
3. http://msdn.microsoft.com/en-us/library/aa363082(v=vs.85).aspx
4. http://msdn.microsoft.com/en-us/library/16b2dyk5(v=vs.80).aspx

-- 
Configure bugmail: https://bugs.webkit.org/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are the assignee for the bug.


More information about the webkit-unassigned mailing list