{"id":880,"date":"2011-07-23T18:16:09","date_gmt":"2011-07-23T16:16:09","guid":{"rendered":"http:\/\/blog.m-ri.de\/?p=880"},"modified":"2011-07-22T22:36:31","modified_gmt":"2011-07-22T20:36:31","slug":"auflosung-des-getbuffer-und-getalloclength-rastels","status":"publish","type":"post","link":"http:\/\/blog.m-ri.de\/index.php\/2011\/07\/23\/auflosung-des-getbuffer-und-getalloclength-rastels\/","title":{"rendered":"Aufl\u00f6sung des GetBuffer und GetAllocLength R\u00e4stels"},"content":{"rendered":"<p>Dann will ich mal das Problem l\u00fcften, dass sich mit diesem Code ergibt, dein ich meinem <a href=\"http:\/\/blog.m-ri.de\/index.php\/2011\/07\/17\/zur-abwechslung-mal-ein-kleines-quiz-was-ist-das-problem-mit-diesem-template\/\">letzten Artikel<\/a> vorgestellt habe:<\/p>\n<pre lang=\"cpp\">template &lt;class T&gt;\r\nvoid SecureClearString(T &amp;strText)\r\n{\r\n  ::SecureZeroMemory(strText.GetBuffer(0),strText.GetAllocLength());\r\n  strText.Empty();\r\n}<\/pre>\n<p>Zuerst einmal liegt es nicht daran, dass es hier Template verwendet wurde.<br \/>\nEin Template wurde verwendet, weil in dem Code nicht nur <em>CString<\/em>, sondern implizit <em>CStringA<\/em> und <em>CStringW<\/em> verwendet wurde. Der Code sollte also mit beiden Typen funktionieren.<\/p>\n<p>Und damit sind wir bei Problem 1, das auch gel\u00f6st wurde:<br \/>\nWenn ein <em>CStringW<\/em> verwendet wird, dann wird nur die H\u00e4lfte des Strings gel\u00f6scht, und nicht alles.<\/p>\n<p>Das Szenario, dass zu einem miesen Crash f\u00fchren kann, will ich nun in den einzelnen Schritten schildern (es wurde ja vermutet, dass es mit GetBuffer zusammenh\u00e4ngt und die Vermutung ist richtig):<\/p>\n<ol>\n<li>Der <em>CString<\/em> der mit diesem template behandelt wurde enthielt einen gr\u00f6\u00dferen <em>CString<\/em> und anschlie\u00dfend wurde ein k\u00fcrzerer <em>CString<\/em> zugewiesen. Damit ist <em>GetAllocLength<\/em>&gt;<em>GetLength<\/em>.<\/li>\n<li>Dieser <em>CString<\/em> wird nun an eine weitere Variable zugewiesen. Durch die Referenzz\u00e4hlung wird keine volle Kopie erzeugt.<\/li>\n<li>Nun kommt unsere sch\u00f6ne Funktion ins Spiel und einer der beiden Strings wird mit dieser Template Funktion behandelt.<\/li>\n<li>Die Funktion hat zwei Argumente, die von rechts nach links berechnet und auf den Stack geschoben werden.<\/li>\n<li>D.h. Zuerst wird <em>GetAllocLength<\/em> ausgef\u00fchrt. Und dies ergibt einen Wert f\u00fcr die L\u00e4nge, der urspr\u00fcnglich einmal in diese Variable passte.<\/li>\n<li>Als zweites erfolgt nun der Aufruf von <em>GetBuffer<\/em>. Da wir aber einen <em>CString<\/em> haben, der mehrfach benutzt wird, muss nun ein Copy on Write erfolgen. D..h. der String wird kopiert und mit der jetzt ben\u00f6tigten L\u00e4nge neu alloziert und der Zeiger auf diesen Speicher wird zur\u00fcckgegeben, dieser ist aber eben k\u00fcrzer als der urspr\u00fcngliche Puffer.<\/li>\n<li>Und nun erfolgt der <em>memset<\/em>, auf einen Speicher der nur noch so gro\u00df ist wie der kurze String. Folgerichtig wird der Heap zerst\u00f6rt, weil der Speicher hinter dem String \u00fcberschrieben wird.<\/li>\n<li>Peng \u2757 Wir haben hier einen ganz miesen Seiteneffekt.<\/li>\n<\/ol>\n<p>Hier der Code, mit dem man den Crash gezielt nachbauen kann:<\/p>\n<pre lang=\"cpp\">void Crash()\r\n{\r\n  CString str1 = _T(\"12345678901234567890\");\r\n  str1 = _T(\"123\");\r\n  CString str2 = str1;\r\n  SecureClearString(str1); \/\/ Crash\r\n  SecureClearString(str2);\r\n}<\/pre>\n<p>Der Vollst\u00e4ndigkeit halber will ich aber auch noch ein St\u00fcck Code zegen, der es richtig macht:<\/p>\n<pre lang=\"cpp\">template &lt;class T&gt;\r\nvoid SecureClearString(T &amp;strText)\r\n{\r\n  \/\/ We need this only if there is a private buffer\r\n  if (strText.GetAllocLength()!=0)\r\n  {\r\n    \/\/ Execute GetBuffer first. This might cause a fork and may change\r\n    \/\/ GetAllocLength.\r\n    T::XCHAR *pBuffer = strText.GetBuffer(0);\r\n    size_t iLen =strText.GetAllocLength();\r\n    ::SecureZeroMemory(pBuffer,iLen*sizeof(T::XCHAR));\r\n  }\r\n  strText.Empty();\r\n}<\/pre>\n<p lang=\"cpp\">PS: Der Leser kann sich\u00a0denken, dass mich dieser Bug und die entsprechende Reproduktion einige Nerven gekostet\u00a0haben. \u00a0Denn es war nicht einfach die Vorbedingung (erst langer String, dann kurzer String, dann Zuweisung) zu ermitteln. Und wie es oft so ist f\u00fchren Heap-Fehler erst sehr verz\u00f6gert zu einem Problem.<br \/>\nWen es genau interessiert: Ich habe ca\u00a07 Stunden an dem Fall geknobelt und hatte 3 verschiedene Crashdumps zur Verf\u00fcgung. Selbst konnte ich\u00a0diesen Fehler\u00a0in unserem Testfeld zuvor nicht erzeugen, weil eben nie alle Bedingungen erf\u00fcllt waren.\u00a0Erst als mir klar war wo das Problem lag, gelang es mir nat\u00fcrlich auch sofort Eingaben zu erzeugen, die den Crash reproduzierten.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Dann will ich mal das Problem l\u00fcften, dass sich mit diesem Code ergibt, dein ich meinem letzten Artikel vorgestellt habe: template &lt;class T&gt; void SecureClearString(T &amp;strText) { ::SecureZeroMemory(strText.GetBuffer(0),strText.GetAllocLength()); strText.Empty(); } Zuerst einmal liegt es nicht daran, dass es hier Template verwendet wurde. Ein Template wurde verwendet, weil in dem Code nicht nur CString, sondern implizit &hellip; <a href=\"http:\/\/blog.m-ri.de\/index.php\/2011\/07\/23\/auflosung-des-getbuffer-und-getalloclength-rastels\/\" class=\"more-link\"><span class=\"screen-reader-text\">\u201eAufl\u00f6sung des GetBuffer und GetAllocLength R\u00e4stels\u201c <\/span>weiterlesen<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_post_was_ever_published":false},"categories":[30,11,4,3],"tags":[99,370,352,136],"class_list":["post-880","post","type-post","status-publish","format-standard","hentry","category-c","category-debugging","category-mfc","category-programmieren","tag-bug","tag-c","tag-mfc","tag-qualitaetssicherung"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/posts\/880","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/comments?post=880"}],"version-history":[{"count":1,"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/posts\/880\/revisions"}],"predecessor-version":[{"id":881,"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/posts\/880\/revisions\/881"}],"wp:attachment":[{"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/media?parent=880"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/categories?post=880"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/tags?post=880"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}