记一次Windows Embedded CE应用程序崩溃的摸索
2010-05-17 18:55 王克伟 阅读(2550) 评论(0) 编辑 收藏 举报一次很难忘的Bug Fix,记录一下以便以后归纳总结一下。对于应用程序、系统关键进程Crash等Bug相信会比较让人头痛,这次就让我头疼了1个星期,
一方面因为代码规模较大,另一方面对这样的Bug没有什么经验。
Bug Description
打开一个Word文档,“另存为”操作时弹出“没有足够的内存保存文档”,并抛出异常:
297006 PID:a6b00fe TID:a6c00fe Exception 'Access Violation' (14): Thread-Id=0a6c00fe(pth=8d88c000), Proc-Id=0a6b00fe(pprc=868f38e4) 'pword.exe', VM-active=0a6b00fe(pprc=868f38e4) 'pword.exe' 297006 PID:a6b00fe TID:a6c00fe PC=4006dea9(coredll.dll+0x0004dea9) RA=40042ebc(coredll.dll+0x00022ebc) SP=0005d918, BVA=00449000
解决过程
初步定位到问题代码是:
传递到private\winceos\coreos\core\locale\utf.c L256函数中的cchWideChar参数为0xffffffff(-1)
int UnicodeToUTF( UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar, LPSTR lpMultiByteStr, int cbMultiByte, LPCSTR lpDefaultChar, LPBOOL lpUsedDefaultChar)
此时的Callstack为:
COREDLL!UnicodeToUTF(unsigned int 0x0000fde9, unsigned long 0x00000000, const wchar_t * 0x00449820, int 0xffffffff, char * 0x00000000, int 0x00000000, const char * 0x00000000, int * 0x00000000) utf.c line 288 + 3 bytes COREDLL!WideCharToMultiByte(unsigned int 0x0000fde9, unsigned long 0x00000000, const wchar_t * 0x00449820, int 0xffffffff, char * 0x00000000, int 0x00000000, const char * 0x00000000, int * 0x00000000) codepage.cpp line 2609 + 27 bytes OSSVCS!UnicodeToMB(const wchar_t * 0x00449820, unsigned int 0x0000fde9, char * * 0x0005da0c, unsigned long * 0x0005da10) helpers.cpp line 1483 OSSVCS!DecodeBase64W(const wchar_t * 0x00449820, unsigned char * * 0x0005da94, unsigned long * 0x0005da98, tagBASE64_OPTIONS BASE64_OPTION_IGNOREINVALIDCHARACTER) base64.cpp line 463 + 19 bytes PWWIFF!OnEndFldData(PDSItem * 0x00000000, PDSItem * 0x00449720, RDPItemData * 0x0005daac) cdwhelpers.cpp line 11259 + 23 bytes PWWIFF!CRDParser::EndElement() rdparser.cpp line 375 + 8 bytes PWORD!SendSAXEndElement(ISAXContentHandler * 0x003e02e4, const wchar_t * const 0x0005db28, unsigned long 0x0000000a) saxutilcmn.cpp line 93 + 33 bytes PWORD!CRosettaReader::SendEndElement(const wchar_t * const 0x0005db28, unsigned long 0x0000000a) crosettareader.cpp line 70 + 14 bytes PWORD!CRosettaReader::DoTreetoXML(void * 0x003dba20) crosettareader.cpp line 392 PWORD!CRosettaReader::DoTreetoXML(void * 0x003db8a0) crosettareader.cpp line 368 + 13 bytes PWORD!CRosettaReader::DoTreetoXML(void * 0x003db860) crosettareader.cpp line 368 + 13 bytes PWORD!CRosettaReader::DoTreetoXML(void * 0x003db820) crosettareader.cpp line 368 + 13 bytes PWORD!CRosettaReader::parse(tagVARIANT {...}) crosettareader.cpp line 233 PWORD!CAFWrite::SendSubTreeToDF(void * 0x003db820) convwrite.cpp line 699 + 30 bytes PWORD!CAFWrite::UpdateState() convwrite.cpp line 600 + 10 bytes PWORD!CAFWrite::EndBodyChildCore(unsigned int 0x00000000, long 0x003db820) convwrite.cpp line 559 + 7 bytes PWORD!AFWriteWndProc(HWND__ * 0x70055220, unsigned int 0x00000468, unsigned int 0x00000000, long 0x003db820) convwrite.cpp line 760 GWES!WindowProcCallback(void * 0x0a6b00fe, long (HWND__ *, unsigned int, unsigned int, long)* 0x000381ab, CWindow * 0x70055220, unsigned int 0x00000468, unsigned int 0x00000000, long 0x003db820, bool * 0xd7f6f18f) wbase.cpp line 3198 + 18 bytes GWES!CWindow::CallWindowProcW_I(CePtr_t<long (__cdecl*)(HWND__ *,unsigned int,unsigned int,long)> {...}, HWND__ * 0x000381ab, unsigned int 0x00000468, unsigned int 0x00000000, long 0x003db820, SendMsgEntry_t * 0x00000000) wbase.cpp line 3403 + 21 bytes GWES!MsgQueue::SendMessageWithOptions(HWND__ * 0x70055220, unsigned int 0x00000468, unsigned int 0x00000000, long 0x003db820, unsigned int 0x00000000) msgque.cpp line 4110 + 29 bytes GWES!MsgQueue::SendMessageW_I(HWND__ * 0x70055220, unsigned int 0x00000468, unsigned int 0x00000000, long 0x003db820) msgque.cpp line 5437 + 22 bytes GWES!MsgQueue::SendMessageW_E(HWND__ * 0x70055220, unsigned int 0x00000468, unsigned int 0x00000000, long 0x003db820) msgque.cpp line 5372 + 17 bytes GWES!PixelDoubled_t::SendMessageW_I(HWND__ * 0x70055220, unsigned int 0x00000468, unsigned int 0x00000000, long 0x003db820) pixeldouble.cpp line 1928 + 18 bytes PWORD!CRosettaContentHandler::DispatchAppFilterMessage(CTreeElement<DConvNode> * 0x003d8520, unsigned int 0x00000468) rosettacontenthandler.cpp line 318 + 5 bytes PWORD!CRosettaContentHandler::endElement(const wchar_t * 0x43a93adc, int 0x00000000, const wchar_t * 0x43a9ab34, int 0x00000002, const wchar_t * 0x43a9ab30, int 0x00000004) rosettacontenthandler.cpp line 884 PWWIFF!SendSAXEndElement(ISAXContentHandler * 0x0015bda0, const wchar_t * const 0x43a9ab30, unsigned long 0x00000004) saxutilcmn.cpp line 93 + 33 bytes PWWIFF!CDocReader::SendEndElement(const wchar_t * const 0x43a9ab30, unsigned long 0x00000004) cdocreader.cpp line 804 + 14 bytes PWWIFF!CDocReader::EndWaitableWrapper(CDocReader::XMLRunState XRS_Paragraph) cdocreader.cpp line 8815 + 13 bytes PWWIFF!CDocReader::RenderParagraph(PlxInfo * 0x003e1e28, unsigned char * 0x003e2b50, unsigned long 0x00000006, unsigned short 0x0000, int 0x00000000, long 0x00000000, PropStatusObj * 0x0005ec38) cdocreader.cpp line 5468 + 24 bytes PWWIFF!CDocReader::RenderCurrentPapxFkp(PlxInfo * 0x003e1e28, int 0x00000000, long 0x00000000, PropStatusObj * 0x0005ec38) cdocreader.cpp line 5907 + 28 bytes PWWIFF!CDocReader::GetNextPap(PlxInfo * 0x003e1e28, PropStatusObj * 0x0005ec38, long * 0x00000b8a, long * 0x0005ea54, int * 0x0005ea38) cdocreader.cpp line 6334 + 15 bytes PWWIFF!CDocReader::XMLEmitMainBody() cdocreader.cpp line 9036 + 42 bytes PWWIFF!CDocReader::DoXMLConversion() cdocreader.cpp line 2659 + 7 bytes PWORD!BuildDConvTree(const wchar_t * 0x0005f3d4, ISequentialStream * 0x00000000, ISAXXMLReader * 0x003e13e0) dconv.cpp line 408 + 13 bytes PWORD!DConvHandleFile(const wchar_t * 0x0005f3d4, HWND__ * 0x70055220, void * * 0x0005f24c, DCONV_FILEOP DCONV_WRITE, _GUID {...}) dconv.cpp line 636 + 10 bytes PWORD!DConvCreateFile(const wchar_t * 0x0005f3d4, PWRD_FILE_TYPE PWRD_CONVERTFILE_TYPE_DOC, HWND__ * 0x70055220, void * * 0x0005f24c, DCONV_FILEOP DCONV_WRITE) dconv.cpp line 681 + 23 bytes PWORD!AFWrite(const wchar_t * 0x0005f3d4, PWRD_FILE_TYPE PWRD_CONVERTFILE_TYPE_DOC, IDocFilter * 0x003e02e0, CRosettaReader * 0x003d02a0, ISAXContentHandler * 0x003e02e4, long 0x00000000, unsigned long 0x000003f7, PWRD_XML_VERSION PW_XML_VER_O11) convwrite.cpp line 94 + 18 bytes PWORD!DConvWriteFile(const wchar_t * 0x0005f3d4, PWRD_FILE_TYPE PWRD_CONVERTFILE_TYPE_DOC, PWRD_XML_VERSION PW_XML_VER_O11, const wchar_t * 0x0006dbae, PWRD_FILE_TYPE PWRD_CONVERTFILE_TYPE_DOC, long 0x00000000, unsigned long 0x000003f7) dconv.cpp line 846 + 29 bytes PWORD!SaveDOCorXMLFile(tagINKW * 0x00010002, const wchar_t * 0x0005f3d4, const wchar_t * 0x0006dbae) appfilter.cpp line 405 + 29 bytes PWORD!PureREDisplayToDocFile(const wchar_t * 0x0006dbae) appfilter.cpp line 310 + 10 bytes PWORD!REDisplayToDocFile(tagINKW * 0x0006d960, const wchar_t * 0x0005f3d4, const wchar_t * 0x0006dbae, PWRD_FILE_TYPE PWRD_CONVERTFILE_TYPE_DOC) appfilter.cpp line 230 + 18 bytes PWORD!CreateOrOpenFile(tagINKW * 0x0006d960, int * 0x00000000, int 0x00000000, int * 0x0005f3c0, wchar_t * 0x0005f3d4) doc2.cpp line 2382 + 17 bytes PWORD!SaveDoc(tagINKW * 0x0006d960, SD_SAVEAS SAVEDOC_SAVEAS, int * 0x00000000, SD_LOWMEM SAVEDOC_NOT_LOWMEM, SD_WAITCURSOR SAVEDOC_WAITCURSOR, SD_AUTOSAVE SAVEDOC_NOT_AUTOSAVE, SD_PROMPT SAVEDOC_PROMPT_DONTPROMPT) doc2.cpp line 3126 + 32 bytes PWORD!HandleCommand(tagINKW * 0x0006d960, unsigned int 0x000063a1, long 0x70053d40) commands.cpp line 979 + 15 bytes PWORD!InkWWndProc(HWND__ * 0x70052340, unsigned int 0x00000111, unsigned int 0x000063a1, long 0x70053d40) msghdlr.cpp line 2234 + 12 bytes GWES!WindowProcCallback(void * 0x0a6b00fe, long (HWND__ *, unsigned int, unsigned int, long)* 0x0001ea4f, CWindow * 0x70052340, unsigned int 0x00000111, unsigned int 0x000063a1, long 0x70053d40, bool * 0xd7f6f407) wbase.cpp line 3198 + 18 bytes GWES!CWindow::CallWindowProcW_I(CePtr_t<long (__cdecl*)(HWND__ *,unsigned int,unsigned int,long)> {...}, HWND__ * 0x0001ea4f, unsigned int 0x00000111, unsigned int 0x000063a1, long 0x70053d40, SendMsgEntry_t * 0x00000000) wbase.cpp line 3403 + 21 bytes GWES!MsgQueue::SendMessageWithOptions(HWND__ * 0x70052340, unsigned int 0x00000111, unsigned int 0x000063a1, long 0x70053d40, unsigned int 0x00000000) msgque.cpp line 4110 + 29 bytes GWES!MsgQueue::SendMessageW_I(HWND__ * 0x70052340, unsigned int 0x00000111, unsigned int 0x000063a1, long 0x70053d40) msgque.cpp line 5437 + 22 bytes GWES!MsgQueue::SendMessageW_E(HWND__ * 0x70052340, unsigned int 0x00000111, unsigned int 0x000063a1, long 0x70053d40) msgque.cpp line 5372 + 17 bytes GWES!PixelDoubled_t::SendMessageW_I(HWND__ * 0x70052340, unsigned int 0x00000111, unsigned int 0x000063a1, long 0x70053d40) pixeldouble.cpp line 1928 + 18 bytes PWORD!WorkerHandleCommand(HWND__ * 0x700539a0, tagINKW * 0x0006d960, unsigned int 0x000063a1, long 0x70053d40) workwin.cpp line 334 + 18 bytes PWORD!WorkerWndProc(HWND__ * 0x700539a0, unsigned int 0x00000111, unsigned int 0x000063a1, long 0x70053d40) workwin.cpp line 721 GWES!WindowProcCallback(void * 0x0a6b00fe, long (HWND__ *, unsigned int, unsigned int, long)* 0x0001d205, CWindow * 0x700539a0, unsigned int 0x00000111, unsigned int 0x000063a1, long 0x70053d40, bool * 0xd7f6f67f) wbase.cpp line 3198 + 18 bytes GWES!CWindow::CallWindowProcW_I(CePtr_t<long (__cdecl*)(HWND__ *,unsigned int,unsigned int,long)> {...}, HWND__ * 0x0001d205, unsigned int 0x00000111, unsigned int 0x000063a1, long 0x70053d40, SendMsgEntry_t * 0x00000000) wbase.cpp line 3403 + 21 bytes GWES!MsgQueue::SendMessageWithOptions(HWND__ * 0x700539a0, unsigned int 0x00000111, unsigned int 0x000063a1, long 0x70053d40, unsigned int 0x00000000) msgque.cpp line 4110 + 29 bytes GWES!MsgQueue::SendMessageW_I(HWND__ * 0x700539a0, unsigned int 0x00000111, unsigned int 0x000063a1, long 0x70053d40) msgque.cpp line 5437 + 22 bytes GWES!MsgQueue::SendMessageW_E(HWND__ * 0x700539a0, unsigned int 0x00000111, unsigned int 0x000063a1, long 0x70053d40) msgque.cpp line 5372 + 17 bytes GWES!PixelDoubled_t::SendMessageW_I(HWND__ * 0x700539a0, unsigned int 0x00000111, unsigned int 0x000063a1, long 0x70053d40) pixeldouble.cpp line 1928 + 18 bytes AYGSHELL!MenuWndProc(HWND__ * 0x70053c20, unsigned int 0x00000111, unsigned int 0x000063a1, long 0x70053d40) menus.cpp line 1701 + 15 bytes GWES!WindowProcCallback(void * 0x0a6b00fe, long (HWND__ *, unsigned int, unsigned int, long)* 0x40da4e3d, CWindow * 0x70053c20, unsigned int 0x00000111, unsigned int 0x000063a1, long 0x70053d40, bool * 0xd7f6f8f7) wbase.cpp line 3198 + 18 bytes GWES!CWindow::CallWindowProcW_I(CePtr_t<long (__cdecl*)(HWND__ *,unsigned int,unsigned int,long)> {...}, HWND__ * 0x40da4e3d, unsigned int 0x00000111, unsigned int 0x000063a1, long 0x70053d40, SendMsgEntry_t * 0x00000000) wbase.cpp line 3403 + 21 bytes GWES!MsgQueue::SendMessageWithOptions(HWND__ * 0x70053c20, unsigned int 0x00000111, unsigned int 0x000063a1, long 0x70053d40, unsigned int 0x00000000) msgque.cpp line 4110 + 29 bytes GWES!MsgQueue::SendMessageW_I(HWND__ * 0x70053c20, unsigned int 0x00000111, unsigned int 0x000063a1, long 0x70053d40) msgque.cpp line 5437 + 22 bytes GWES!MsgQueue::SendMessageW_E(HWND__ * 0x70053c20, unsigned int 0x00000111, unsigned int 0x000063a1, long 0x70053d40) msgque.cpp line 5372 + 17 bytes GWES!PixelDoubled_t::SendMessageW_I(HWND__ * 0x70053c20, unsigned int 0x00000111, unsigned int 0x000063a1, long 0x70053d40) pixeldouble.cpp line 1928 + 18 bytes AYGSHELL!BubbleBarProc(HWND__ * 0x70053d40, unsigned int 0x00000111, unsigned int 0x000063a1, long 0x70053d40) menus_p.cpp line 1678 + 13 bytes GWES!WindowProcCallback(void * 0x0a6b00fe, long (HWND__ *, unsigned int, unsigned int, long)* 0x40da1be2, CWindow * 0x70053d40, unsigned int 0x00000111, unsigned int 0x000063a1, long 0x70053d40, bool * 0xd7f6fb6f) wbase.cpp line 3198 + 18 bytes GWES!CWindow::CallWindowProcW_I(CePtr_t<long (__cdecl*)(HWND__ *,unsigned int,unsigned int,long)> {...}, HWND__ * 0x40da1be2, unsigned int 0x00000111, unsigned int 0x000063a1, long 0x70053d40, SendMsgEntry_t * 0x00000000) wbase.cpp line 3403 + 21 bytes GWES!MsgQueue::DispatchMessageW_I(const tagMSG * 0x0005facc) msgque.cpp line 4967 + 32 bytes GWES!PixelDoubled_t::DispatchMessageW_I(const tagMSG * 0x0005facc) pixeldouble.cpp line 2083 + 9 bytes COREDLL!DispatchMessageW(const tagMSG * 0x0005facc) twinuser.cpp line 2947 + 9 bytes PWORD!WinMain(HINSTANCE__ * 0x0a6b00fe, HINSTANCE__ * 0x00000000, wchar_t * 0x0005fc20, int 0x00000005) inkword.cpp line 850 + 9 bytes PWORD!WinMainCRTStartupHelper(HINSTANCE__ * 0x0a6b00fe, HINSTANCE__ * 0x00000000, unsigned short * 0x0005fc20, int 0x00000005) pegwmain.c line 71 + 17 bytes PWORD!WinMainCRTStartup(HINSTANCE__ * 0x0a6b00fe, HINSTANCE__ * 0x00000000, unsigned short * 0x0005fc20, int 0x00000005) pegwmain.c line 104 + 17 bytes COREDLL!MainThreadBaseFunc(void * 0x0001becd, const wchar_t * 0x0005fc0
分析private\apps\woffice\word\main\doc2.cpp L2902的SaveDoc函数:
private\winceos\coreos\core\locale\utf.c L308的字符串指针lpWideCharStr没有结束符是造成Access Violation异常:
if (cchWideChar <= -1) { cchWideChar = wcslen(lpWideCharStr) + 1; }
对应的X86汇编代码(我对汇编不熟,这些只是看一下关键的部分,我们调试Release版本的Code时因为编译器优化的原因经常发现Visual Studio“闹鬼”了,
这时可以借助x86和ARM汇编,也可以直接用RETAILMSG打出Log):
306: if (cchWideChar <= -1) 4006DE9E cmp edx,0FFFFFFFFh 4006DEA1 jg UnicodeToUTF+77h (4006debb) 307: { 308: cchWideChar = wcslen(lpWideCharStr) + 1; 4006DEA3 mov ecx,edi 4006DEA5 push esi 4006DEA6 lea esi,[ecx+2] 4006DEA9 mov dx,word ptr [ecx] 4006DEAC inc ecx 4006DEAD inc ecx 4006DEAE cmp dx,ax 4006DEB1 jne UnicodeToUTF+65h (4006dea9) 4006DEB3 sub ecx,esi 4006DEB5 sar ecx,1 4006DEB7 lea edx,[ecx+1] 4006DEBA pop esi 309: }
那么谁传递的没有结束符的字符串,搞的大爷崩溃了?
突破口:
1.private\apps\woffice\word\filters\rosetta\crosettareader.cpp L351:
if(!(wcscmp(k_szCharacters, szName))) { //then we have to read the child and emit the characters //We do not emit the start and end element tags here CHRA(DoCharacters(hRoot)); } else { CHRA(SendStartElementFromHandle(hRoot)); CHRA(DConvGetChildHandle(hRoot, nIndex, &hChild)); //DConvGetChildHandle returns NULL when there are no more children. while(hChild) { // Process the children depth first // NOTE: this is a recursive call CHRA(DoTreetoXML(hChild)); //Get the next child here //But before you do that, free the current child handle, //to avoid memory leaks VERIFY(SUCCEEDED(DConvCloseHandle(&hChild))); //If for whatever reason the close handle did not succeed, //we will go over the previous tag again. //So watch out if the Verify on the previous call fires an assert. //We may then need to error check the closehandle call and //increment nChild in that case. CHRA(DConvGetChildHandle(hRoot, ++nIndex, &hChild)); } //At this point the heirarchy of this element is done, //so send the end element tag CHRA(SendEndElement(szName, cchName)); }
2.private\apps\woffice\word\filters\pwwiff\cdwhelpers.cpp L2318:
ulmemcpy(prt->pwcText + prt->cchText, wzText, cchText * sizeof(*wzText));
3.private\winceos\coreos\core\locale\utf.c L306:
if (cchWideChar <= -1) { cchWideChar = wcslen(lpWideCharStr) + 1; }
设置这3个断点,然后分析流程到底怎样,为什么lpWideCharStr指向的数据是:
A.N.D.J.6.n.n.5.u.s .4.R.j.I.I.A.q.g.B. L.q.Q.s.C.A.A.A.A.F .w.A.A.A.B.Y.A.A.A. B.o.A.H.Q.A.d.A.B.w .A.D.o.A.L.w.A.v.A. G.g.A.e.Q.B.w.A.G.U .A.c.g.B.s.A.G.k.A.
时就出现问题,这些数据到底代表什么?
摸索中…
经验证这是经常出现的数据,可能是标志位,标志图片或者链接之类的,它是0x4C个Unicode字符,占0x98字节:
004AE560 41 00 4E 00 44 00 4A 00 36 00 6E 00 6E 00 35 00 75 00 73 A.N.D.J.6.n.n.5.u.s 004AE573 00 34 00 52 00 6A 00 49 00 49 00 41 00 71 00 67 00 42 00 .4.R.j.I.I.A.q.g.B. 004AE586 4C 00 71 00 51 00 73 00 43 00 41 00 41 00 41 00 41 00 46 L.q.Q.s.C.A.A.A.A.F 004AE599 00 77 00 41 00 41 00 41 00 42 00 59 00 41 00 41 00 41 00 .w.A.A.A.B.Y.A.A.A. 004AE5AC 42 00 6F 00 41 00 48 00 51 00 41 00 64 00 41 00 42 00 77 B.o.A.H.Q.A.d.A.B.w 004AE5BF 00 41 00 44 00 6F 00 41 00 4C 00 77 00 41 00 76 00 41 00 .A.D.o.A.L.w.A.v.A. 004AE5D2 47 00 67 00 41 00 65 00 51 00 42 00 77 00 41 00 47 00 55 G.g.A.e.Q.B.w.A.G.U 004AE5E5 00 41 00 63 00 67 00 42 00 73 00 41 00 47 00 6B 00 41 00 .A.c.g.B.s.A.G.k.A. 004AE5F8 00 00
出现问题时的内存区,可以看到字符串结束符没有了:
0498020 41 00 4E 00 44 00 4A 00 36 00 6E 00 6E 00 35 00 75 00 73 A.N.D.J.6.n.n.5.u.s 00498033 00 34 00 52 00 6A 00 49 00 49 00 41 00 71 00 67 00 42 00 .4.R.j.I.I.A.q.g.B. 00498046 4C 00 71 00 51 00 73 00 43 00 41 00 41 00 41 00 41 00 46 L.q.Q.s.C.A.A.A.A.F 00498059 00 77 00 41 00 41 00 41 00 42 00 59 00 41 00 41 00 41 00 .w.A.A.A.B.Y.A.A.A. 0049806C 42 00 6F 00 41 00 48 00 51 00 41 00 64 00 41 00 42 00 77 B.o.A.H.Q.A.d.A.B.w 0049807F 00 41 00 44 00 6F 00 41 00 4C 00 77 00 41 00 76 00 41 00 .A.D.o.A.L.w.A.v.A. 00498092 47 00 67 00 41 00 65 00 51 00 42 00 77 00 41 00 47 00 55 G.g.A.e.Q.B.w.A.G.U 004980A5 00 41 00 63 00 67 00 42 00 73 00 41 00 47 00 6B 00 41 00 .A.c.g.B.s.A.G.k.A. 004980B8 62 00 67 00 42 00 72 00 41 00 44 00 45 00 41 00 4C 00 67 b.g.B.r.A.D.E.A.L.g 004980CB 00 42 00 6A 00 41 00 47 00 38 00 41 00 62 00 51 00 41 00 .B.j.A.G.8.A.b.Q.A. 004980DE 41 00 41 00 4F 00 44 00 4A 00 36 00 6E 00 6E 00 35 00 75 A.A.O.D.J.6.n.n.5.u 004980F1 00 73 00 34 00 52 00 6A 00 49 00 49 00 41 00 71 00 67 00 .s.4.R.j.I.I.A.q.g. 00498104 42 00 4C 00 71 00 51 00 73 00 75 00 41 00 41 00 41 00 41 B.L.q.Q.s.u.A.A.A.A 00498117 00 61 00 41 00 42 00 30 00 41 00 48 00 51 00 41 00 63 00 .a.A.B.0.A.H.Q.A.c. 0049812A 41 00 41 00 36 00 41 00 43 00 38 00 41 00 4C 00 77 00 42 A.A.6.A.C.8.A.L.w.B 0049813D 00 6F 00 41 00 48 00 6B 00 41 00 63 00 41 00 42 00 6C 00 .o.A.H.k.A.c.A.B.l. 00498150 41 00 48 00 49 00 41 00 62 00 41 00 42 00 70 00 41 00 47 A.H.I.A.b.A.B.p.A.G 00498163 00 34 00 41 00 61 00 77 00 41 00 78 00 41 00 43 00 34 00 .4.A.a.w.A.x.A.C.4. 00498176 41 00 59 00 77 00 42 00 76 00 41 00 47 00 30 00 41 00 4C A.Y.w.B.v.A.G.0.A.L 00498189 00 77 00 41 00 41 00 41 00 41 00 3D 00 3D 00 A5 A6 A7 A8 .w.A.A.A.A.=.=.....
下一步采用不同文档进一步排除和缩小范围,使用更简单的文档来分析:
即使保存空的文档也还是有Exception抛出,但是没有内存不足的提示,这个异常跟内存不足错误是否有关系?
635630 PID:2700002 TID:85e0002 Exception 'Access Violation' (14): Thread-Id=085e0002(pth=85b52ad0), Proc-Id=02700002(pprc=8f91c7f4) 'udevice.exe', VM-active=02700002(pprc=8f91c7f4) 'udevice.exe' 635644 PID:2700002 TID:85e0002 PC=4002f680(coredll.dll+0x0000f680) RA=40031450(coredll.dll+0x00011450) SP=001bf7a8, BVA=011c1e44 635662 PID:7790092 TID:b9a00ca Exception 'Access Violation' (14): Thread-Id=0b9a00ca(pth=850f7980), Proc-Id=07790092(pprc=8ba28de4) 'pword.exe', VM-active=07790092(pprc=8ba28de4) 'pword.exe' 635712 PID:7790092 TID:b9a00ca PC=4002f680(coredll.dll+0x0000f680) RA=4002f6bf(coredll.dll+0x0000f6bf) SP=0005eb78, BVA=011c1e44
看来Word代码本身就有问题。
A.Word文档里面连续存在4个(有时3个)带链接的和回车的文字比如:
http://hyperlink2.com mailto:hyperlink3.com http://hyperlink1.com http://hyperlink1.com
或者B.内容较多时只要有3个以上带链接的的文字
“另存为”时就会出现内存不够保存文档,并且NK.exe报错。
首先分析A情况:
PWWIFF!AddTextToRdpText(RdpText * 0x004497c0, const wchar_t * const 0x0043a8a0, const unsigned long 0x0000004c, CInternalHeap * 0xcccccccc) cdwhelpers.cpp line 2319 PWWIFF!OnCharactersT(const wchar_t * const 0x0043a8a0, const unsigned long 0x0000004c, PDSItem * 0x004494e0, RDPItemData * 0x0005d864) cdwhelpers.cpp line 5796 + 22 bytes PWWIFF!CRDParser::Characters(const wchar_t * 0x0043a8a0, unsigned long 0x0000004c) rdparser.cpp line 476 + 62 bytes PWWIFF!CDocWriter::CDWContentHandler::characters(const wchar_t * 0x0043a8a0, int 0x0000004c) cdocwriter.cpp line 6819 PWORD!SendSAXCharacters(ISAXContentHandler * 0x003e02e4, const wchar_t * 0x0043a8a0, unsigned long 0x0000004c) saxutilcmn.cpp line 113 + 12 bytes PWORD!CRosettaReader::SendCharacters(const wchar_t * 0x0043a8a0, unsigned long 0x0000004c) crosettareader.cpp line 77 + 14 bytes PWORD!CRosettaReader::DoCharacters(void * 0x0043a860) crosettareader.cpp line 314 + 13 bytes PWORD!CRosettaReader::DoTreetoXML(void * 0x0043a860) crosettareader.cpp line 357 PWORD!CRosettaReader::DoTreetoXML(void * 0x0043a820) crosettareader.cpp line 368 + 13 bytes PWORD!CRosettaReader::DoTreetoXML(void * 0x0043a720) crosettareader.cpp line 368 + 13 bytes PWORD!CRosettaReader::DoTreetoXML(void * 0x0043a6e0) crosettareader.cpp line 368 + 13 bytes PWORD!CRosettaReader::DoTreetoXML(void * 0x0043a6a0) crosettareader.cpp line 368 + 13 bytes PWORD!CRosettaReader::parse(tagVARIANT {...}) crosettareader.cpp line 233 PWORD!CAFWrite::SendSubTreeToDF(void * 0x0043a6a0) convwrite.cpp line 699 + 30 bytes PWORD!CAFWrite::UpdateState() convwrite.cpp line 600 + 10 bytes PWORD!CAFWrite::EndBodyChildCore(unsigned int 0x00000000, long 0x0043a6a0) convwrite.cpp line 559 + 7 bytes PWORD!AFWriteWndProc(HWND__ * 0x70055380, unsigned int 0x00000468, unsigned int 0x00000000, long 0x0043a6a0) convwrite.cpp line 760
问题点很可能在AddTextToRdpText,在以下代码执行之前:
ulmemcpy(prt->pwcText + prt->cchText, wzText, cchText * sizeof(*wzText)); prt->cchText += cchText;
wzText的值为0x0043a8a0 "bgBrADMALgBjAG8AbQAAAODJ6nn5us4RjIIAqgBLqQssAAAAbQBhAGkAbAB0AG8AOgBoAHkAcABl"
prt->pwcText的值为0x00449800 "ANDJ6nn5us4RjIIAqgBLqQsCAAAAFwAAABYAAABtAGEAaQBsAHQAbwA6AGgAeQBwAGUAcgBsAGkA
而执行之后
prt->pwcText的值变为0x00449800 "ANDJ6nn5us4RjIIAqgBLqQsCAAAAFwAAABYAAABtAGEAaQBsAHQAbwA6AGgAeQBwAGUAcgBsAGkAbgBrADMALgBjAG8AbQAAAODJ6nn5us4RjIIAqgBLqQssAAAAbQBhAGkAbAB0AG8AOgBoAHkAcABl 再一次prt->pwcText的值变为0x00449800 "ANDJ6nn5us4RjIIAqgBLqQsCAAAAFwAAABYAAABtAGEAaQBsAHQAbwA6AGgAeQBwAGUAcgBsAGkAbgBrADMALgBjAG8AbQAAAODJ6nn5us4RjIIAqgBLqQssAAAAbQBhAGkAbAB0AG8AOgBoAHkAcABlAHIAbABpAG4AawAzAC4AYwBvAG0AAAA= 然后进入private\winceos\coreos\core\locale\utf.c中的UnicodeToUTF函数L306:
if (cchWideChar <= -1) { cchWideChar = wcslen(lpWideCharStr) + 1;//此处因为字符串没有结束符出现问题 }
此时lpWideCharStr的值跟prt->pwcText一样,且都没有结束符。
进一步分析:
private\apps\woffice\word\filters\pwwiff\cdwhelpers.cpp第11255行传进去的字符串指针prtElt->pwcText指向的字符串没有结束符,
而DecodeBase64W函数(在private\ossvcs\services\misc\base64.cpp中)假设字符串是有结束符的:
// Decode the input CHRA(DecodeBase64W(prtElt->pwcText, (LPBYTE *)&szDecoded, &cchDecoded, BASE64_OPTION_IGNOREINVALIDCHARACTER));
在这之前加如下代码:
*((prtElt->pwcText)+(prtElt->cchText)) = L'\0';
可以正常运行的更久一点,但是稍后抛出了一个堆异常。
用CeDebugX工具查看一下,发现应该是分配堆得时候分配小了一点,直接这样修改内存:
*((prtElt->pwcText)+(prtElt->cchText)) = L'\0';
破坏了堆的标记所以事后抛出了堆错误异常:
+++++++++++++ PROBLEMS DETECTED +++++++++++++ id Confidence Severity Description =========================================================================================== 1 Certain Application fatal Heap corruption 'Bad item tail signature' detected in pword.exe 2 Certain Application fatal Heap corruption 'Bad item tail signature' detected in pword.exe 3 Certain Application fatal Heap corruption 'Bad item tail signature' detected in pword.exe 4 Certain Application fatal Heap corruption 'Bad item tail signature' detected in pword.exe 5 Certain Application fatal Unknown Exception caused by pword.exe 6 Certain Application fatal Deadlock in NK.EXE 7 Certain Application fatal Deadlock in NK.EXE 8 Certain Application fatal Deadlock in NK.EXE 9 Possible System fatal CPU Starvation may be generated by servicesd.exe thread (CTEpDispatchThread) Windows CE>!diagnose 1 ======================================================= | | Heap corruption 'Bad item tail signature' detected in pword.exe | ======================================================= Heap allocations are aligned to a heap block size of 16 bytes. When heap sentinels are enabled the difference between the requested allocation size and the 16 byte block boundary is filled with a tail signature. The tail signature of the following item appears to be corrupt. The most likely cause is a heap item over-run, i.e. an app has written to memory beyond the requested heap item size. addr value ========================== header ========================== 0x00470980 : 0xa9e4b608 Signature (expect 0xa9e4b620) 0x00470984 : 0x00000178 Data size (bytes) 0x00470988 : 0x43a9d83b pwwiff.dll ! CInternalHeap::InternalReAlloc + 0x7f 0x0047098c : 0x43a9d887 pwwiff.dll ! _InternalHeapReAlloc + 0x16 0x00470990 : 0x43ab23b9 pwwiff.dll ! AddTextToRdpText + 0x30 0x00470994 : 0x43ab2b61 pwwiff.dll ! OnCharactersT + 0x19 0x00470998 : 0x43abef93 pwwiff.dll ! CRDParser::Characters + 0x69 0x0047099c : 0x43aaeb26 pwwiff.dll ! CDocWriter::CDWContentHandler::characters + 0x14 Tags for bug matcher: +DEFECT:CRASH:HEAP_CORRUPTION:pword.exe:|Type=Bad item tail signature;
将private\apps\woffice\word\filters\pwwiff\cdwhelpers.cpp中的L2308从:
// We already ahve something. We need to realloc. szText = (LPWSTR) InternalHeapReAlloc( prt->pwcText, LMEM_MOVEABLE, (prt->cchText+cchText)*sizeof(*wzText));
修改为(多留16字节保持Unicode字符串结束符):
// We already ahve something. We need to realloc. szText = (LPWSTR) InternalHeapReAlloc( prt->pwcText, LMEM_MOVEABLE, (prt->cchText+cchText+1)*sizeof(*wzText));
问题解决了。
简单总结
1.Word在处理字符串时不是采用结束符标记的,而是直接记录字符串的长度,但是调用System的API时要记得添加上这些结束符。
2.解决问题需要很强的对知识综合应用的能力,Bug Fixing占项目中很长的时间,而且直接影响着软件质量。
出处: http://wangkewei.cnblogs.com/
版权声明: 本文的版权归作者与博客园共有。转载时须注明本文的详细链接,否则作者将保留追究其法律责任的权利。
您可以从这里更方便的找到我的文章。