{"id":1114,"date":"2013-03-20T17:48:21","date_gmt":"2013-03-20T07:48:21","guid":{"rendered":"http:\/\/brnz.org\/hbr\/?p=1114"},"modified":"2013-03-26T15:42:57","modified_gmt":"2013-03-26T05:42:57","slug":"bugs-of-the-day-2013-03-19","status":"publish","type":"post","link":"https:\/\/brnz.org\/hbr\/?p=1114","title":{"rendered":"Bugs of the day,  Tuesday 2013-03-19"},"content":{"rendered":"<h2>Changed virtual function prototype results in correct function not being called<\/h2>\n<p>This one wasn&#8217;t a bug that landed immediately from my change, but happened when a subsequent code branch was integrated. I&#8217;m going to claim this as my bug as it could have been prevented (or at least made more obvious) with some extra though.<\/p>\n<h3>The problem:<\/h3>\n<p>We have a virtual function, something like<\/p>\n<pre escaped=\"true\" lang=\"c++\">class Base {\r\npublic:\r\n\u00a0 virtual void Foo(int some_param) \u00a0{ \u00a0}\r\n};<\/pre>\n<p>Which I modified a few weeks back by adding an extra parameter, so foo() became<\/p>\n<pre escaped=\"true\" lang=\"c++\">  virtual void foo(int some_param, WhatsitType some_other_param) { }<\/pre>\n<p>and I added the same parameter to every one of the classes that inherited from class Base. There were quite a few.<\/p>\n<p>Sometime later, \u00a0code was integrated from another branch where the old prototype was still in use, including something like this:<\/p>\n<pre escaped=\"true\" lang=\"c++\">class NewInheritor : public Base {\r\npublic:\r\n  virtual void Foo(int some_param) { \/\/ oh noes - it's the old prototype!\r\n    DoAmazingThings();\r\n  }\r\n};<\/pre>\n<p>The new code compiled without warning, but at runtime, <strong>NewInheritor::Foo()<\/strong> wasn&#8217;t being called, so the amazing things were failing to be done. Debugging this was somewhat inefficient &#8212; the process for calling <strong>Foo()<\/strong> methods includes a number of steps, and I failed to notice the missing parameter for quite a while.<\/p>\n<h3>The fix:<\/h3>\n<p>Update <strong>NewInheritor::Foo()<\/strong> to match the parent class.<\/p>\n<h3>Preventing these in future:<\/h3>\n<p>Remember that virtual inheritance is a horribly fragile beast.<\/p>\n<p>One thing that may have worked is to make <strong>Foo()<\/strong> pure (compile error) &#8212; or undefined (link error) &#8212; in the base class (i.e. <strong>void\u00a0Foo() = 0;<\/strong>). This isn&#8217;t a great match in this case as inheriting classes don&#8217;t need to have their own implementation of <strong>Foo()<\/strong> to be valid, and requiring it makes for some additional tedious boilerplate code in every inheritor (of which there are many).<\/p>\n<p>The <strong>override<\/strong> keyword will help detect this at compile time, but it relies on the implementer of <strong>NewInheritor<\/strong> to have used it :\\ The action here is to recommend that people use <strong>override<\/strong> on every virtual function override.<\/p>\n<p>In this case, what I do know about this code is that it is never valid to call <strong>Foo()<\/strong> on a class that doesn&#8217;t have its own implementation. We can put an <strong>assert()<\/strong> in <strong>Base::Foo()<\/strong> and let the writers of inheriting types (or me when next I get to debug one of these) have a more obvious clue about what&#8217;s happening. Adequately functional.<\/p>\n<h2><strong>memcpy()<\/strong> into an uninitialized pointer variable<\/h2>\n<h3>The problem:<\/h3>\n<p>I had changed the type of a variable from being a static array to being a pointer, to match a change I&#8217;d made to a particular function. What I hadn&#8217;t paid attention to was that this array was being used as the destination address for a call to <strong>memcpy()<\/strong>. An uninitialized pointer on the stack is not a good place to try to copy things.<\/p>\n<p>The call to <strong>memcpy()<\/strong> did not cause the program to crash. The program did crash shortly thereafter, though, which distracted me for a short while from the cause.<\/p>\n<h3>The fix:<\/h3>\n<p>Explicitly allocate some space for the copy.<\/p>\n<h3>Preventing in the future:<\/h3>\n<p>The pointer on the stack had not been set. A null pointer would have caused the crash to happen at the call to <strong>memcpy()<\/strong>, making the cause more obvious.<\/p>\n<h2>Bad loop counting<\/h2>\n<h3>The problem:<\/h3>\n<pre escaped=\"true\" lang=\"c++\">int max = m_Max;\r\nint i = 0;\r\nfor( ; i &lt; max; ++max )\r\n\u00a0 if( a[i] == bar )\r\n    break;<\/pre>\n<p>++max? Yeesh.<\/p>\n<p>m_Max is initialized to zero, which means that this was a no-op rather than an infinite loop.<\/p>\n<h3>The fix:<\/h3>\n<p>Increment the counter, not the upper bound.<\/p>\n<h3>Preventing in the future:<\/h3>\n<p>Don&#8217;t be a goose.<\/p>\n<h2>Failing to store updated state<\/h2>\n<h3>The problem:<\/h3>\n<p>Immediately following the code above, in the case where we failed to find the desired <strong>bar<\/strong> in the array, increase the size of the array. And then fail to store the new max size into m_Max.<\/p>\n<p>I even got this wrong twice: my first attempt was to replace a use of\u00a0<strong>max+1<\/strong> with <strong>++max<\/strong>.<\/p>\n<h3>The fix:<\/h3>\n<p>Write the necessary state back to the object: <strong>++m_Max.<\/strong><\/p>\n<h3>Preventing in the future:<\/h3>\n<p>Pay attention to where the state should go. Don&#8217;t be a goose.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Changed virtual function prototype results in correct function not being called This one wasn&#8217;t a bug that landed immediately from my change, but happened when a subsequent code branch was integrated. I&#8217;m going to claim this as my bug as it could have been prevented (or at least made more obvious) with some extra though. &hellip; <a href=\"https:\/\/brnz.org\/hbr\/?p=1114\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Bugs of the day,  Tuesday 2013-03-19&#8221;<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[26],"tags":[],"_links":{"self":[{"href":"https:\/\/brnz.org\/hbr\/index.php?rest_route=\/wp\/v2\/posts\/1114"}],"collection":[{"href":"https:\/\/brnz.org\/hbr\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/brnz.org\/hbr\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/brnz.org\/hbr\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/brnz.org\/hbr\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1114"}],"version-history":[{"count":6,"href":"https:\/\/brnz.org\/hbr\/index.php?rest_route=\/wp\/v2\/posts\/1114\/revisions"}],"predecessor-version":[{"id":1121,"href":"https:\/\/brnz.org\/hbr\/index.php?rest_route=\/wp\/v2\/posts\/1114\/revisions\/1121"}],"wp:attachment":[{"href":"https:\/\/brnz.org\/hbr\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1114"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/brnz.org\/hbr\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1114"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/brnz.org\/hbr\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1114"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}