{"id":41043,"date":"2004-01-15T07:00:00","date_gmt":"2004-01-15T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2004\/01\/15\/what-can-go-wrong-when-you-mismatch-the-calling-convention\/"},"modified":"2004-01-15T07:00:00","modified_gmt":"2004-01-15T07:00:00","slug":"what-can-go-wrong-when-you-mismatch-the-calling-convention","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20040115-00\/?p=41043","title":{"rendered":"What can go wrong when you mismatch the calling convention?"},"content":{"rendered":"<p>Believe it or not, calling conventions is one of the things that\nprograms frequently get wrong. The compiler yells at you when\nyou mismatch a calling convention, but lazy programmers will just\nstick a cast in there to get the compiler to &#8220;shut up already&#8221;.<\/p>\n<p>\nAnd then Windows is stuck having to support your buggy code forever.\n<\/p>\n<dl>\n<dt>The window procedure<\/dt>\n<dd>\n<p>\nSo many people misdeclare their window procedures (usually by\ndeclaring them as __cdecl instead of __stdcall),\nthat the function that dispatches messages to window procedures\ncontains extra protection\nto detect incorrectly-declared window procedures and perform the\nappropriate fixup.  This is the source of the mysterious 0xdcbaabcd\non the stack.  The function that dispatches messages to window\nprocedures checks whether this value is on the stack in the correct\nplace. If not, then it checks whether the window procedure popped\none dword too much off the stack (if so, it fixes up the stack;\nI have no idea how this messed up a window procedure could have existed),\nor whether the window procedure was mistakenly declared as __cdecl\ninstead of __stdcall (if so, it pops the parameters off the stack that\nthe window procedure was supposed to do).\n<\/p>\n<\/dd>\n<dt>DirectX callbacks<\/dt>\n<dd>\n<p>\nMany DirectX functions use callbacks, and people once again misdeclared\ntheir callbacks as __cdecl instead of __stdcall, so the DirectX\nenumerators have to do special stack cleanup for those bad functions.\n<\/p>\n<\/dd>\n<dt>IShellFolder::CreateViewObject<\/dt>\n<dd>\n<p>\nI remember there was one program that decided to declare their\nCreateViewWindow function incorrectly, and somehow they managed\nto trick the compiler into accepting it!\n<\/p>\n<pre>\nclass BuggyFolder : public IShellFolder ... {\n ...\n \/\/ wrong function signature!\n HRESULT CreateViewObject(HWND hwnd) { return S_OK; }\n}\n<\/pre>\n<p>\nNot only did they get the function signature wrong, they\nreturned S_OK even though they failed to do anything!\nI had to add extra code to clean up the stack after calling this\nfunction, as well as verify that the return value wasn&#8217;t a lie.\n<\/p>\n<dt>Rundll32.exe entry points<\/dt>\n<dd>\n<p>\n<a HREF=\"http:\/\/support.microsoft.com\/support\/kb\/articles\/q164\/7\/87.asp\">\nThe function signature required for functions called by rundll32.exe\nis documented in this Knowledge Base article<\/a>.\nThat hasn&#8217;t stopped people from using rundll32 to call random functions\nthat weren&#8217;t designed to be called by rundll32,\n<a HREF=\"http:\/\/weblogs.asp.net\/bdesmond\/archive\/2003\/12\/11\/43016.aspx\">\nlike user32 LockWorkStation<\/a> or\n<a HREF=\"http:\/\/is-it-true.org\/nt\/nt2000\/utips\/utips47.shtml\">\nuser32 ExitWindowsEx<\/a>.\n<\/p>\n<p>\nLet&#8217;s walk through what happens when you try to use rundll32.exe\nto call a function like ExitWindowsEx:\n<\/p>\n<p>\nThe rundll32.exe program parses its command line and calls the\nExitWindowsEx function on the assumption that the function is written\nlike this:<\/p>\n<pre>\nvoid CALLBACK ExitWindowsEx(HWND hwnd, HINSTANCE hinst,\n       LPSTR pszCmdLine, int nCmdShow);\n<\/pre>\n<p>But it isn&#8217;t. The actual function signature for ExitWindowsEx is<\/p>\n<pre>\nBOOL WINAPI ExitWindowsEx(UINT uFlags, DWORD dwReserved);\n<\/pre>\n<p>What happens? Well, on entry to ExitWindowsEx, the stack\nlooks like this:\n<\/p>\n<table BORDER=\"0\">\n<col ALIGN=\"center\">\n<tr>\n<td STYLE=\"border: solid 1px buttonshadow\">.. rest of stack ..<\/td>\n<td><\/td>\n<\/tr>\n<tr>\n<td STYLE=\"border: solid 1px buttonshadow\">nCmdShow<\/td>\n<td><\/td>\n<\/tr>\n<tr>\n<td STYLE=\"border: solid 1px buttonshadow\">pszCmdLine<\/td>\n<td><\/td>\n<\/tr>\n<tr>\n<td STYLE=\"border: solid 1px buttonshadow\">hinst<\/td>\n<td><\/td>\n<\/tr>\n<tr>\n<td STYLE=\"border: solid 1px buttonshadow\">hwnd<\/td>\n<td><\/td>\n<\/tr>\n<tr>\n<td STYLE=\"border: solid 1px buttonshadow\">return address<\/td>\n<td>&lt;- ESP<\/td>\n<\/tr>\n<\/table>\n<p>\nHowever, the function is expecting to see<\/p>\n<table BORDER=\"0\">\n<col ALIGN=\"center\">\n<tr>\n<td STYLE=\"border: solid 1px buttonshadow\">.. rest of stack ..<\/td>\n<td><\/td>\n<\/tr>\n<tr>\n<td STYLE=\"border: solid 1px buttonshadow\">dwReserved<\/td>\n<td><\/td>\n<\/tr>\n<tr>\n<td STYLE=\"border: solid 1px buttonshadow\">uFlags<\/td>\n<td><\/td>\n<\/tr>\n<tr>\n<td STYLE=\"border: solid 1px buttonshadow\">return address<\/td>\n<td>&lt;- ESP<\/td>\n<\/tr>\n<\/table>\n<p>\nWhat happens? The hwnd passed by rundll32.exe gets misinterpreted\nas uFlags and the hinst gets misinterpreted as dwReserved.\nSince window handles are pseudorandom, you end up passing random\nflags to ExitWindowsEx.  Maybe today it&#8217;s EWX_LOGOFF, tomorrow it&#8217;s\nEWX_FORCE, the next time it might be EWX_POWEROFF.\n<\/p>\n<p>\nNow suppose that the function manages to return. (For example,\nthe exit fails.)  The ExitWindowsEx function cleans two parameters\noff the stack, unaware that it was passed four. The resulting stack\nis<\/p>\n<table BORDER=\"0\">\n<col ALIGN=\"center\">\n<tr>\n<td STYLE=\"border: solid 1px buttonshadow\">.. rest of stack ..<\/td>\n<td><\/td>\n<\/tr>\n<tr>\n<td STYLE=\"border: solid 1px buttonshadow\">nCmdShow<\/td>\n<td>(garbage not cleaned up)<\/td>\n<\/tr>\n<tr>\n<td STYLE=\"border: solid 1px buttonshadow\">pszCmdLine<\/td>\n<td>&lt;- ESP (garbage not cleaned up)<\/td>\n<\/tr>\n<\/table>\n<p>Now the stack is corrupted and really fun things happen.\nFor example, suppose the thing at &#8220;.. rest of the stack ..&#8221; is\na return address.  Well, the original code is going to execute\na &#8220;return&#8221; instruction to return through that return address,\nbut with this corrupted stack, the &#8220;return&#8221; instruction will\ninstead return to a command line and attempt to execute it as if\nit were code.\n<\/p>\n<\/dd>\n<dt>Random custom functions<\/dt>\n<dd>\n<a HREF=\"http:\/\/weblogs.asp.net\/oldnewthing\/archive\/2004\/01\/08\/48616.aspx#58017\">\nAn anonymous commenter exported a function as __cdecl but treated it as if\nit were __stdcall<\/a>.  This will seem to work, but on return, the stack\nwill be corrupted (because the caller is expecting a __stdcall function\nthat cleans the stack, but what it gets is a __cdecl funcion that doesn&#8217;t),\nand bad things will happen as a result.\n<\/dd>\n<\/dl>\n<p>\nOkay, enough with the examples; I think you get the point.\nHere are some questions I&#8217;m sure you&#8217;re asking:\n<\/p>\n<dl>\n<dt>Why doesn&#8217;t the compiler catch all these errors?<\/dt>\n<dd>\n<p>\nIt does. (Well, not the rundll32 one.)\nBut people have gotten into the habit of just inserting the\nfunction cast to get the compiler to shut up.\n<\/p>\n<p>\n<a HREF=\"http:\/\/www.functionx.com\/win32\/ScrollBars.htm\">Here&#8217;s\na random example I found<\/a>:<\/p>\n<pre>\nLRESULT CALLBACK DlgProc(HWND hWnd, UINT Msg,\n   WPARAM wParam, LPARAM lParam);\n<\/pre>\n<p>\nThis is the incorrect function signature for a dialog procedure.\n<a HREF=\"http:\/\/msdn.microsoft.com\/library\/en-us\/winui\/WinUI\/WindowsUserInterface\/Windowing\/DialogBoxes\/DialogBoxReference\/DialogBoxFunctions\/DialogProc.asp\">The\ncorrect signature<\/a> is<\/p>\n<pre>\nINT_PTR CALLBACK DialogProc(HWND hwndDlg, UINT uMsg,\n    WPARAM wParam, LPARAM lParam);\n<\/pre>\n<\/p>\n<p>\nYou start with<\/p>\n<pre>\nDialogBox(hInst, MAKEINTRESOURCE(IDD_CONTROLS_DLG),\n          hWnd, DlgProc);\n<\/pre>\n<p>but the compiler rightly spits out the error message<\/p>\n<pre>\nerror C2664: 'DialogBoxParamA' : cannot convert parameter 4\nfrom 'LRESULT (HWND,UINT,WPARAM,LPARAM)' to 'DLGPROC'\n<\/pre>\n<p>so you fix it by slapping a cast in to make the compiler\nshut up:<\/p>\n<pre>\nDialogBox(hInst, MAKEINTRESOURCE(IDD_CONTROLS_DLG),\n          hWnd, <font COLOR=\"red\">reinterpret_cast&lt;DLGPROC&gt;<\/font>(DlgProc));\n<\/pre>\n<\/p>\n<p>\n&#8220;Aw, come on, who would be so stupid as to insert a cast to\nmake an error go away without actually fixing the error?&#8221;\n<\/p>\n<p>\nApparently everyone.\n<\/p>\n<p>\nI stumbled across\n<a HREF=\"http:\/\/www.computing.net\/programming\/wwwboard\/forum\/8629.html\">\nthis page that does exactly the same\nthing<\/a>,\n<a HREF=\"http:\/\/www.willemer.de\/informatik\/windows\/windial.htm\">\nand this one in German which gets not only the return value wrong,\nbut also misdeclares the third and fourth parameters<\/a>,\n<a HREF=\"http:\/\/www.kumei.ne.jp\/c_lang\/sdk\/sdk_13.htm\">\nand this one in Japanese<\/a>.\n<a HREF=\"http:\/\/www.codeguru.com\/mfc\/comments\/29324.shtml\">\nIt&#8217;s as easy to fix (incorrectly) as 1-2-3<\/a>.\n<\/p>\n<\/dd>\n<dt>How did programs with these bugs ever work at all?\nCertainly these programs worked to some degree or people would have\nnoticed and fixed the bug.\nHow can the program survive a corrupted stack?<\/dt>\n<dd>\n<p>\nI&#8217;ll answer this question tomorrow.\n<\/dd>\n<\/dl>\n","protected":false},"excerpt":{"rendered":"<p>Believe it or not, calling conventions is one of the things that programs frequently get wrong. The compiler yells at you when you mismatch a calling convention, but lazy programmers will just stick a cast in there to get the compiler to &#8220;shut up already&#8221;. And then Windows is stuck having to support your buggy [&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":[25],"class_list":["post-41043","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Believe it or not, calling conventions is one of the things that programs frequently get wrong. The compiler yells at you when you mismatch a calling convention, but lazy programmers will just stick a cast in there to get the compiler to &#8220;shut up already&#8221;. And then Windows is stuck having to support your buggy [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/41043","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=41043"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/41043\/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=41043"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=41043"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=41043"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}