{"id":24523,"date":"2007-11-14T10:00:00","date_gmt":"2007-11-14T10:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2007\/11\/14\/psychic-debugging-ip-on-heap\/"},"modified":"2007-11-14T10:00:00","modified_gmt":"2007-11-14T10:00:00","slug":"psychic-debugging-ip-on-heap","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20071114-00\/?p=24523","title":{"rendered":"Psychic debugging: IP on heap"},"content":{"rendered":"<p>\nSomebody asked the shell team to look at this crash in a\ncontext menu shell extension.\n<\/p>\n<pre>\nIP_ON_HEAP:  003996d0\nChildEBP RetAddr\n00b2e1d8 68f79ca6 0x3996d0\n00b2e1f4 7713a7bd ATL::CWindowImplBaseT&lt;\n                           ATL::CWindow,ATL::CWinTraits&lt;2147483648,0&gt; &gt;\n                     ::StartWindowProc+0x43\n00b2e220 77134be0 USER32!InternalCallWinProc+0x23\n00b2e298 7713a967 USER32!UserCallWinProcCheckWow+0xe0\n...\neax=68f79c63 ebx=00000000 ecx=00cade10 edx=7770df14 esi=002796d0 edi=000603cc\neip=002796d0 esp=00cade4c ebp=00cade90 iopl=0         nv up ei pl nz na pe nc\ncs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010206\n002796d0 c744240444bafb68 mov     dword ptr [esp+4],68fbba44\n<\/pre>\n<p>\nYou should be able to determine the cause instantly.\n<\/p>\n<p>\nI replied,\n<\/p>\n<blockquote CLASS=\"m\"><p>\nThis shell extension is using a non-DEP-aware version of ATL.\nThey need to upgrade to ATL&nbsp;8 or disable DEP.\n<\/p><\/blockquote>\n<p>\nThis was totally obvious to me, but the person who asked the\nquestion met it with stunned amazement.\nI guess the person forgot that older versions of\nATL are notorious DEP violators.\nYou see a DEP violation, you see that it&#8217;s coming from ATL,\nand bingo, you have your answer.\nWhen DEP was first introduced, the base team sent out mail\nto the entire Windows division saying,\n&#8220;Okay, folks, we&#8217;re turning it on.\nYou&#8217;re going to see a lot of application compatibility problems,\nespecially this ATL one.&#8221;\n<\/p>\n<p>\nPsychic powers sometimes just means having a good memory.\n<\/p>\n<p>\nEven if you forgot that information, it&#8217;s still totally obvious\nonce you look at the scenario and understand what it&#8217;s trying to do.\n<\/p>\n<p>\nThe fault is <code>IP_ON_HEAP<\/code> which is precisely\nwhat DEP protects against.\nThe next question is why IP ended up on the heap.\nWas it a mistake or intentional?\n<\/p>\n<p>\nLook at the circumstances surrounding the faulting instruction again.\nThe faulting instruction is the window procedure for a window,\nand the action is storing a constant into the stack.\nThe symbols of the caller tell us that it&#8217;s some code in ATL,\nand you can even go look up the source code yourself:\n<\/p>\n<pre>\ntemplate &lt;class TBase, class TWinTraits&gt;\nLRESULT CALLBACK CWindowImplBaseT&lt; TBase, TWinTraits &gt;\n  ::StartWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {\n    CWindowImplBaseT&lt; TBase, TWinTraits &gt;* pThis =\n              (CWindowImplBaseT&lt; TBase, TWinTraits &gt;*)\n                  _AtlWinModule.ExtractCreateWndData();\n    pThis-&gt;m_hWnd = hWnd;\n    pThis-&gt;m_thunk.Init(pThis-&gt;GetWindowProc(), pThis);\n    WNDPROC pProc = pThis-&gt;m_thunk.GetWNDPROC();\n    ::SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)pProc);\n    return pProc(hWnd, uMsg, wParam, lParam);\n}\n<\/pre>\n<p>\nIs <code>pProc<\/code> corrupted and we&#8217;re jumping to a random\naddress on the heap?\nOr was this intentional?<\/p>\n<p><p>\nATL is clearly generating code on the fly (the window procedure\nthunk), and it is in execution of the thunk that we encounter\nthe DEP exception.\n<\/p>\n<p>\nNow, you didn&#8217;t need to have the ATL source code to realize that\nthis is what&#8217;s going on.\nIt is a very common pattern in framework libraries to put\na C++ wrapper around window procedures.\nSince C++ functions have a hidden <code>this<\/code> parameter,\nthe wrappers need to sneak that parameter in somehow,\nand one common technique is to generate some code on the fly\nthat sets up the hidden <code>this<\/code> parameter before\ncalling the C++ function.\nThe value at <code>[esp+4]<\/code> is the window handle,\nsomething that can be recovered from the <code>this<\/code>\npointer, so it&#8217;s a handly thing to replace with <code>this<\/code>\nbefore jumping to the real C++ function.\n<\/p>\n<p>\nThe address being stored as the <code>this<\/code> parameter is\n<code>68fbba44<\/code>,\nwhich is inside the DLL in question.\n(You can tell this because the return address,\nwhich points to the ATL thunk code, is at\n<code>68f79ca6<\/code> which is in the same neighborhood\nas the mystery pointer.)\nTherefore, this is almost certainly an ATL thunk for a static C++ object.\n<\/p>\n<p>\nIn other words, this is extremely unlikely be a jump to a random address.\nThe code at the address looks too good.\nIt&#8217;s probably jumping there intentionally,\nand the fact that it&#8217;s coming from a window procedure thunk\nconfirms it.\n<\/p>\n<p>\nBut our tale is not over yet.\nThe plot thickens.\nWe&#8217;ll continue next time.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Somebody asked the shell team to look at this crash in a context menu shell extension. IP_ON_HEAP: 003996d0 ChildEBP RetAddr 00b2e1d8 68f79ca6 0x3996d0 00b2e1f4 7713a7bd ATL::CWindowImplBaseT&lt; ATL::CWindow,ATL::CWinTraits&lt;2147483648,0&gt; &gt; ::StartWindowProc+0x43 00b2e220 77134be0 USER32!InternalCallWinProc+0x23 00b2e298 7713a967 USER32!UserCallWinProcCheckWow+0xe0 &#8230; eax=68f79c63 ebx=00000000 ecx=00cade10 edx=7770df14 esi=002796d0 edi=000603cc eip=002796d0 esp=00cade4c ebp=00cade90 iopl=0 nv up ei pl nz na pe nc cs=001b [&hellip;]<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[26],"class_list":["post-24523","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-other"],"acf":[],"blog_post_summary":"<p>Somebody asked the shell team to look at this crash in a context menu shell extension. IP_ON_HEAP: 003996d0 ChildEBP RetAddr 00b2e1d8 68f79ca6 0x3996d0 00b2e1f4 7713a7bd ATL::CWindowImplBaseT&lt; ATL::CWindow,ATL::CWinTraits&lt;2147483648,0&gt; &gt; ::StartWindowProc+0x43 00b2e220 77134be0 USER32!InternalCallWinProc+0x23 00b2e298 7713a967 USER32!UserCallWinProcCheckWow+0xe0 &#8230; eax=68f79c63 ebx=00000000 ecx=00cade10 edx=7770df14 esi=002796d0 edi=000603cc eip=002796d0 esp=00cade4c ebp=00cade90 iopl=0 nv up ei pl nz na pe nc cs=001b [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/24523","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=24523"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/24523\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=24523"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=24523"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=24523"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}