{"id":2337,"date":"2015-06-07T15:00:26","date_gmt":"2015-06-07T03:00:26","guid":{"rendered":"https:\/\/www.deltics.co.nz\/blog\/?p=2337"},"modified":"2015-06-08T09:24:39","modified_gmt":"2015-06-07T21:24:39","slug":"a-silent-danger","status":"publish","type":"post","link":"https:\/\/www.deltics.co.nz\/blog\/posts\/2337\/","title":{"rendered":"A Silent Danger&#8230;"},"content":{"rendered":"<span class=\"rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">[Estimated Reading Time: <\/span> <span class=\"rt-time\">3<\/span> <span class=\"rt-label rt-postfix\">minutes]<\/span><\/span><p>A brief post on a long standing omission in type checking in Pascal and the limitations of Range Checking as applied to the problem.<\/p>\n<p><!--more--><\/p>\n<p>Consider this contrived example of a simple function:<\/p>\n<pre class=\"brush: delphi; title: ; notranslate\" title=\"\">\r\n  function IsLessThan64K(aValue: Integer): Boolean;\r\n  begin\r\n    result := aValue &lt; Word($ffff);\r\n  end;\r\n<\/pre>\n<p>This very simple function accepts an explicitly <em>32-bit<\/em> <strong>Integer<\/strong> parameter and simply returns <strong>TRUE<\/strong> if the value passed is less than 64K (65536).  Worth noting at this point is that <strong>Integer<\/strong> is 32-bit regardless of whether you are compiling for 32-bit or 64-bit platforms.<\/p>\n<p>Now consider two <strong>Int64<\/strong> variables, declared and initialised as follows:<\/p>\n<pre class=\"brush: delphi; title: ; notranslate\" title=\"\">\r\n  a, b: Int64;\r\n\r\n  a := $7fff;                \/\/ 32767\r\n  b := $7fffffffffffffff;    \/\/ 9223372036854775807\r\n<\/pre>\n<p>Now consider the results of the following calls to that <em>IsLessThan64K()<\/em> function, involving <strong>a<\/strong> and <strong>b<\/strong>:<\/p>\n<pre class=\"brush: delphi; title: ; notranslate\" title=\"\">\r\n  IsLessThan64K( a );\r\n  IsLessThan64K( b );\r\n  IsLessThan64K( b - a );\r\n<\/pre>\n<p>Somewhat surprisingly, given the dramatic discrepancy between the types of the variables and the type of the function parameter, these all compile without grumbling.  But Pascal is strongly typed, so if the compiler is happy then all must be right with the world, surely ?<\/p>\n<p>Well, let&#8217;s look at the results of these calls:<\/p>\n<pre class=\"brush: delphi; title: ; notranslate\" title=\"\">\r\n  IsLessThan64K( a );       \/\/ Returns TRUE - so far so good\r\n  IsLessThan64K( b );       \/\/ Returns TRUE ... um, what ?\r\n  IsLessThan64K( b - a );   \/\/ Also returns TRUE ... OMG THE COMPILER IS BROKEN!\r\n<\/pre>\n<p>That last comment is wrong.  The compiler isn&#8217;t broken, it has just not being very helpful in this particular case.<\/p>\n<p>Using the debugger, if we step into the last of these three calls we can see what value the function thinks it has been passed, and we find that this value is <strong>-32768<\/strong> when the correct result of <strong>a &#8211; b<\/strong> should be <strong>9223372036854743040<\/strong>.  <\/p>\n<p>Hmmm, maybe the compiler is broken after all ?<\/p>\n<p>No.  So what&#8217;s going on ?<\/p>\n<p>If we examine these values in their hexadecimal notation, things become a little clearer:<\/p>\n<pre class=\"brush: delphi; title: ; notranslate\" title=\"\">\r\n  a       $0000000000007fff                     32767\r\n  b       $7fffffffffffffff       9223372036854775807\r\n\r\n  b - a   $7fffffffffff8000       9223372036854743040\r\n                  $ffff8000                    -32768\r\n<\/pre>\n<p>The 64-bit value passed to that function has been simply <em>truncated<\/em> to 32-bits, to fit into that value.  As a result, the internal representation results in that massively large positive number being interpreted as a much smaller, negative number.  Precisely the sort of problem that a strongly typed language is supposed to prevent, surely ?<\/p>\n<p>So it may come as a surprise to some that <em>all three<\/em> of those calls will compile without any indication that the wrong type has been passed.<\/p>\n<p>There is no warning or even so much as a hint about the inappropriate attempt to pass a 64-bit value in that 32-bit parameter.<\/p>\n<h2>Range Checking: An Incomplete Solution<\/h2>\n<p>There is a compiler setting that can help in these circumstances:  <strong>Range Checking<\/strong>.<\/p>\n<p>First of all, be aware that this option is not on by default.  Not even in debug builds.  You ideally do not have it enabled in release builds in order to avoid the performance overhead involved, but in debug builds it perhaps makes sense.<\/p>\n<p>This is necessary because as suggested by the fact that this compiler option is grouped under &#8220;<strong>Runtime Errors<\/strong>&#8220;, this does not affect <em>compilation<\/em> of code.  Rather it introduces additional checks at runtime to ensure that values are within the required ranges of the types involved.<\/p>\n<p>This point bears emphasis:  <strong>Range Checking<\/strong> applies to <strong>value<\/strong>, not to <em>types<\/em>.<\/p>\n<p>So, for example, even with <strong>Range Checking<\/strong> enabled, the call involving <strong>a<\/strong> both compiles <em>and runs<\/em> without any problem what-so-ever:<\/p>\n<pre class=\"brush: delphi; title: ; notranslate\" title=\"\">\r\n  IsLessThan64K( a );\r\n<\/pre>\n<p>The range checking introduced by the compiler does not care that <strong>a<\/strong> is the wrong type.  It merely checks the <em>value<\/em>, finds that it is in the range required for a 32-bit Integer and waves it through.  In this contrived example of course <strong>a<\/strong> always has a value in the required range, but in a real-world scenario it may have any number of different values at different times in the execution of the code, only some of which may trigger a range check exception.<\/p>\n<p>What you really want &#8211; and perhaps expect &#8211; from a strongly typed language, is for the compiler to tell you that the potential error exists in the first place.<\/p>\n<p>Caveat Developor:  <strong>It doesn&#8217;t<\/strong>.<\/p>\n<h2>Not Just an Int(64) Problem<\/h2>\n<p>This isn&#8217;t limited only to 32\/64-bit integer types.  Exactly the same issue also affects other ordinal types.  e.g. Passing a <strong>Word<\/strong> in a <strong>Byte<\/strong> parameter, an <strong>Integer<\/strong> in a <strong>Word<\/strong>, etc.<\/p>\n<h2>Also, Not Just a Delphi Problem<\/h2>\n<p>Having quickly investigated in other variants of Pascal this appears to be a consistent behaviour, suggesting that perhaps it is some sort of hang-over from legacy Pascal compiler days.<\/p>\n<p>Neither Oxygene (at least when compiling for .net) nor FreePascal complain about this sort of thing either.  In the case of FreePascal this is particularly odd since this compiler supports a warning which seems aimed at precisely this situation: <strong>Type size mismatch, possible loss of data \/ range check error<\/strong>.<\/p>\n<p>For Oxygene\/Delphi the question is why does no such warning exist ?<\/p>\n<p>For FreePascal the question is if this code does not trigger that warning, what would ?<\/p>\n","protected":false},"excerpt":{"rendered":"<p><span class=\"rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">[Estimated Reading Time: <\/span> <span class=\"rt-time\">3<\/span> <span class=\"rt-label rt-postfix\">minutes]<\/span><\/span> A brief post on a long standing omission in type checking in Pascal and the limitations of Range Checking as applied to the problem.<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"jetpack_publicize_message":"","jetpack_is_tweetstorm":false,"jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":[]},"categories":[4],"tags":[13,127,173,288],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p1TKYv-BH","jetpack_sharing_enabled":true,"jetpack-related-posts":[{"id":2624,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/2624\/","url_meta":{"origin":2337,"position":0},"title":"Expressive If and Case &#8230;","date":"25 Apr 2017","format":false,"excerpt":"A quick post on a small but hugely useful little language feature in Oxygene... if expressions. Many people will be familiar with the so-called ternary operator. Delphi developers will also be aware that there is no direct equivalent in Delphi. In 'C' and other languages we can write a statement\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":2344,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/2344\/","url_meta":{"origin":2337,"position":1},"title":"A Deeper Dive into Range Checking","date":"08 Jun 2015","format":false,"excerpt":"Yesterday I posted about an issue with type checking in Delphi (and other Pascal) compilers. As mentioned in that post, range checking is fundamentally flawed as a supposed solution to the problem for reasons that are explored further in this post. To recap: Range checking does not test the types\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":2095,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/2095\/","url_meta":{"origin":2337,"position":2},"title":"Extending Smoketest (Part 1) &#8211; An Inspector Calls","date":"05 Nov 2013","format":false,"excerpt":"In the soon to be released Smoketest framework it is sometimes useful to create new test types to supplement the tests built-in to the framework. In this and the next post I will walk through the process of implementing and registering a custom test with the Smoketest framework. In a\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":254,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/254\/","url_meta":{"origin":2337,"position":3},"title":"An Exchange() For All","date":"26 Aug 2008","format":false,"excerpt":"Following on from yesterday's post, Barry Kelly (CodeGear engineer) kindly clarified a few points, one of which was that Generics support in Delphi 2009 won't extent to unit procedures, only class methods, so speculation about a possible generic implementation of a Swap()\/Exchange() routine was rendered largely academic. Not to be\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":706,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/706\/","url_meta":{"origin":2337,"position":4},"title":"Making a case for Strings, the sane way","date":"02 Dec 2010","format":false,"excerpt":"Lars Fosdal responded to my previous post suggesting a way of implementing string support in a case-like construct (but not actually a case statement) using generics and anonymous methods. All very clever, but way, way too complicated and - if you don't mind me saying so - as ugly as\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1207,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/1207\/","url_meta":{"origin":2337,"position":5},"title":"Adventures in Syntax: Something Old, Something New etc&#8230;","date":"20 Sep 2012","format":false,"excerpt":"As the post title says, this will be a brief detour through some features of the Pascal language and a presentation of some (theoretical) alternatives that could have been introduced instead. That is, some are real but little known syntax, others are what I think might be preferable to the\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]}],"_links":{"self":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/2337"}],"collection":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/comments?post=2337"}],"version-history":[{"count":6,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/2337\/revisions"}],"predecessor-version":[{"id":2343,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/2337\/revisions\/2343"}],"wp:attachment":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/media?parent=2337"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/categories?post=2337"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/tags?post=2337"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}