diff --git a/_includes/headers.html b/_includes/headers.html index e381ec5e02aabdd60f146e0fcfbceebb9aef377f..aadd4f2c8c472c5648cdc048d47a338f9928851f 100755 --- a/_includes/headers.html +++ b/_includes/headers.html @@ -1,36 +1,32 @@ <header class="siteHeader" id="site_header"> <div id="header_iv_point" class="inviewTop"></div> <span class="brandLogo"><a href="/index.html" rel="home" title= - "Frama-C"><img src="/assets/img/framac.gif" alt=""><span>Frama-C</span></a></span><a role="button" id= - "menu_toggle" class="menuToggle"><span class="open" onclick="openMenu()"><i></i><i></i><i></i></span><span class="close" onclick="closeMenu()"><i></i><i></i></span></a> + "Frama-C"><img src="/assets/img/framac.gif" alt=""><span>Frama-C</span></a></span> + <input class="burger-check" id="burger-check" type="checkbox"><label for="burger-check" class="burger"></label> <nav id="menu" role="navigation"> - <div class="menu-primary-meny-container"> - <ul id="menu-primary-meny" class="menu"> + <div> + <ul class="menu"> {% for item in site.data.nav %} {% if item.id == include.header %} - <li class="menu-item menu-item-type-post_type menu-item-object-page current-menu-item page_item current_page_item"> + <li class="menu-item current-menu-item"> {% else %} - <li class="menu-item menu-item-type-post_type menu-item-object-page"> + <li class="menu-item"> {% endif %} <a href="{{ item.link }}">{{ item.name }}</a> </li> {% endfor %} + {% if include.header == "download" %} + <li class="menu-item current-menu-item download"> + {% else %} + <li class="menu-item download"> + {% endif %} + <a href="/html/get-frama-c.html">Download</a> + </li> </ul> </div> <a role="button" href="/html/get-frama-c.html" id="header_download_link" class="btnDownload"><span><i class= "icon icon-curly-left"></i><i class="icon icon-download-arrow"></i><i class="icon icon-curly-right"></i></span></a> </nav> + </header> - -<script> -function openMenu(){ - var x = document.getElementById("site_header"); - x.classList.add("menuOpen"); -} - -function closeMenu(){ - var x = document.getElementById("site_header"); - x.classList.remove("menuOpen"); -} -</script> \ No newline at end of file diff --git a/_posts/2010-09-30-Progress-of-the-value-analysis-tutorial.html b/_posts/2010-09-30-Progress-of-the-value-analysis-tutorial.html index baa25c70378d83fdfd451a21868b126c99949122..c387ca76d179c947d0fda49051ddd55b7f08d2f7 100644 --- a/_posts/2010-09-30-Progress-of-the-value-analysis-tutorial.html +++ b/_posts/2010-09-30-Progress-of-the-value-analysis-tutorial.html @@ -37,34 +37,5 @@ typedef unsigned int size_t; void* memcpy(void* region1 const void* region2 size_t n); void* memset (void* dest int val size_t len); </code></pre> -</blockquote> <p><a href="http://frama-c.com/download/value-analysis-Boron-20100401.pdf" hreflang="en">Boron's value analysis manual</a> has the beginning of a captivating tutorial and I figure that the suspense must be unbearable. I on the other hand already know how it ends. But I'm not telling yet. Neener-neener! Okay maybe later on this blog.</p> -<p>The new manual (with an expanded tutorial) will be released at the same time as Frama-C version Carbon which is not immediately for various technical reasons. The new version will have some amazing performance improvements but the Boron version is good enough for one of the steps that comes after the current tutorial ends:</p> -<blockquote><p><strong>Generalizing to arbitrary numbers of Update calls</strong></p> -<p> -As an exercise try to verify that there cannot be a run-time error -when hashing arbitrary contents by calling <code>Update(... 80)</code> an arbitrary number of times -between <code>Init</code> and <code>Final</code>. The general strategy -is to modify the C analysis context we have already written in a way -such that it is evident that it captures all such sequences of calls -and also in a way such that launched with adequate options -the value analysis does not emit any warning.</p> -<p> -The latter condition is harder than the former. -Observing results (with the GUI or observation functions -described in section 8.3) can help iterate towards -a solution. Be creative.</p> -</blockquote> -<p>Solution(s) in a few days.</p> -<p>Note: if you try the tutorial for the first time or on a new computer you may also appreciate this new paragraph in the documentation:</p> -<blockquote><p>Some compilation plaforms' headers define the names <code>memset</code> -and <code>memcpy</code> in a way that make it impossible to provide -your own implementation for these functions. If this happens for -yours you can try placing your own header in the analysis directory -under the name <code>string.h</code></p> -<pre><code> -typedef unsigned int size_t; -void* memcpy(void* region1 const void* region2 size_t n); -void* memset (void* dest int val size_t len); -</code></pre> </blockquote> {% endraw %} diff --git a/_posts/2010-10-06-Specification-of-loop-assigns.html b/_posts/2010-10-06-Specification-of-loop-assigns.html index be42395f53ec2f0eb610bea5e21d20d477380325..a95aaa14cf94c526f5016fc7894630117e05072f 100644 --- a/_posts/2010-10-06-Specification-of-loop-assigns.html +++ b/_posts/2010-10-06-Specification-of-loop-assigns.html @@ -64,62 +64,5 @@ bool fill(value_type* a size_type n const value_type x); return; } </pre> -<p>Hint: although strictly speaking this is not needed ghost code might be helpful.</p> - <h2>A simple example</h2> -<p>Broadly speaking, every location which is not mentioned in such a clause should have the same value when exiting the corresponding code as it when entering it. For instance, if we take the following declaration (extracted from <a href="http://first.fraunhofer.de/owx_download/acsl-by-example-5_1_0.pdf" hreflang="en">ACSL by Example</a>)</p> -<pre>/*@ assigns \ -othing; */ -bool equal(const value_type* a size_type n const value_type* b); -</pre> -<p>we claim that a call to <code>equal</code> won't modify the global state of the program. Note that a complete specification of the function would need some <code>requires</code> clause about the validity of pointers but we'll ignore that in this post to concentrate on <code>assigns</code>.</p> -<p>Now the implementation of equal would be the following:</p> -<pre>bool equal(const value_type* a size_type n const value_type* b) -{ - /*@ loop assigns i; */ - for (size_type i = 0; i < n; i++) - if (a[i] != b[i]) - return 0; - return 1; -} -</pre> -<p>This time we can not claim that the loop does not assign anything. More specifically it modifies the index <code>i</code>. Note that there is no contradiction with the fact that <code>equal</code> does not modify the global state of the program as <code>i</code> is only a local variable. One might argue that the scope of <code>i</code> being exactly the <code>for</code> loop it shouldn't be needed to have it mentioned in the <code>loop assigns</code>. However the ACSL manual explicitely says that in the case of a <code>for</code> loop loop annotations are evaluated after initialization takes place. In addition the other kind of loop annotations (<code>loop variant</code> and <code>loop invariant</code>) usually will refer to <code>i</code> and thus it wouldn't be coherent to have</p> -<pre>/*@ loop assigns \ -othing; - loop variant n - i; -*/ -for (size_type i = 0; i < n; i++) ... -</pre> -<p>If nothing is modified by the loop it'd be difficult for the variant to strictly decrease at each step. In other words if you have a "normal" <code>for</code> loop (<em>i.e.</em> not something like <code>for(;;)</code>) the index must be part of the <code>loop assigns</code>.</p> -<h2>When the modified zone grows at each step</h2> -<p>Not all loops modify only their index. Writing <code>loop assigns</code> for loops that modify different locations at each step is a bit trickier than the <code>equal</code> example. If we now look at a function which fills a block of code we would have the following prototype:</p> -<pre>/*@ assigns a[0..n-1]; */ -bool fill(value_type* a size_type n const value_type x); -</pre> -<p>meaning that we will modify the first <code>n</code> elements of the block pointed to by <code>a</code>.</p> -<p>When looking at the implementation a possible specification for the loop would be like this:</p> -<pre>void fill(value_type* a size_type n value_type x) { - /*@ loop assigns i a[0..(n-1)]; */ - for (size_type i = 0; i < n; i++) - a[i] = x; - return; -} -</pre> -<p>It is correct (at each loop steps the modified locations are included in the ones mentioned in the <code>loop assigns</code>) but this is an over-approximation. Let's see how we can refine it. The ACSL manual says that <code>loop assigns</code> are a special form of <em>inductive</em> invariants that is something which</p> -<ol> -<li>must be true when entering the loop</li> -<li>if supposed to be true at the beginning of a loop step still holds at the end of the same step.</li> -</ol> -<p>For a clause <code>loop assigns P;</code> this means that we have to prove that <code>\at(P end_loop_step)</code> contains both the sets of locations written by the current loop step and <code>\at(P begin_loop_step)</code> the set of locations written by the preceding steps. Coming back to our example at the end of the <code>i</code>-th step elements <code>0</code> to <code>i-1</code> have been modified (we have already incremented <code>i</code> at the point where we evaluate the locations) so that the correct and minimal clause is</p> -<pre>//@ loop assigns i a[0..(i-1)]; -</pre> -<p>Note that for the code after the loop this does not change anything: when exiting the loop <code>i</code> is equal to <code>n</code> and thus we know that all elements up to <code>n-1</code> may have been modified. However when proving something (<em>e.g.</em> a <code>loop invariant</code>) inside the loop the latter <code>loop assigns</code> says that all elements between <code>i</code> and <code>n-1</code> are unchanged from their value at the very beginning of the loop while the former does provide any information on the values of these elements.</p> -<h2>A little exercise</h2> -<p>In order to keep up with the tradition of this blog here is a little exercise: what would be the most precise <code>loop assigns</code> of the following loop?</p> -<pre>void fill(char* a char x) { - for(;*a;a++) - *a = x; - return; -} -</pre> <p>Hint: although strictly speaking this is not needed ghost code might be helpful.</p> {% endraw %} diff --git a/_posts/2010-10-07-Value-analysis-tutorial-part-2.html b/_posts/2010-10-07-Value-analysis-tutorial-part-2.html index a371eef8ce152e2bcd895fed30de3e2a393da2a9..8bca335a6b48c746d76504dda2bbd17aa5970aa1 100644 --- a/_posts/2010-10-07-Value-analysis-tutorial-part-2.html +++ b/_posts/2010-10-07-Value-analysis-tutorial-part-2.html @@ -138,136 +138,5 @@ lib.c:18:[kernel] warning: out of bounds write. assert \valid(tmp); <pre>lib.c:18:[kernel] warning: out of bounds write. assert \valid(tmp); </pre> <p>Quiz 2: how should we get rid of the last alarm (that occurs in our file lib.c at line 10 function <code>memcpy</code> although it is caused by imprecision in the callers of that function)?</p> -<p>The files in their state at the end of this blog post are available <a href="/assets/img/blog/imported-posts/skein_verification.zip">here</a>. To rewind to earlier stages of the verification process simply erase <code>main.c</code> which is the only file we have modified so far.</p> - <p>In order to create a tradition of providing solutions to previous quizzes, this post is a partial answer to the question in <a href="/skein/value/2010/09/30/Progress-of-the-value-analysis-tutorial2" hreflang="en">this one about Frama-C's value analysis</a>.</p> -<p>To recap: at the end of the Boron tutorial we arrive at the <code>main</code> function below. This function is useful as an analysis context for the verification of hashing a 80-char message with Skein-256:</p> -<pre>#include "skein.h" -#define HASHLEN (32) -u08b_t msg[80]; -void main(void) -{ - int i; - u08b_t hash[HASHLEN]; - for (i=0; i<80; i++) - msg[i] = Frama_C_interval(0 255); - Skein_256_Ctxt_t skein_context; - Skein_256_Init(&skein_context HASHLEN * 8); - Skein_256_Update(&skein_context msg 80); - Skein_256_Final( &skein_context hash); -} -</pre> -<p>The context analysis above allocates as a global array and initializes a message <code>msg</code> with arbitrary contents. It also allocates a structure <code>skein_context</code> as a local variable to be used by the library for ongoing computations.</p> -<p>Our goal is now to generalize the analysis to arbitrary numbers of <code>Skein_256_Update</code> calls. Let us replace the single <code>Skein_256_Update</code> call in the above context by the loop below. This loop uses <code>Frama_C_interval(0 1)</code> as its condition. The value analysis is guaranteed to take into account the possible results 0 and 1 for all these calls. This ensures that the results of the analysis apply to all the different execution paths we are now interested in although these paths differ in length.</p> -<pre> while (Frama_C_interval(0 1)) - { - for (i=0; i<80; i++) - msg[i] = Frama_C_interval(0 255); - Skein_256_Update(&skein_context msg 80); - } -</pre> -<p>Using the same command-line as in the tutorial generates warnings about possible undefined behaviors:</p> -<p><code>frama-c -val -slevel 100 *.c .../share/builtin.c > log</code></p> -<pre>grep ssert log -lib.c:10:[kernel] warning: out of bounds write. assert \valid(tmp); -skein.c:53:[kernel] warning: accessing uninitialized left-value *(src + n): assert(TODO) -skein.c:53:[kernel] warning: accessing uninitialized left-value *(src + (n + (size_t_0 )1)): assert(TODO) -skein.c:53:[kernel] warning: accessing uninitialized left-value *(src + (n + (size_t_0 )2)): assert(TODO) -skein.c:53:[kernel] warning: accessing uninitialized left-value *(src + (n + (size_t_0 )3)): assert(TODO) -skein.c:53:[kernel] warning: accessing uninitialized left-value *(src + (n + (size_t_0 )4)): assert(TODO) -skein.c:53:[kernel] warning: accessing uninitialized left-value *(src + (n + (size_t_0 )5)): assert(TODO) -skein.c:53:[kernel] warning: accessing uninitialized left-value *(src + (n + (size_t_0 )6)): assert(TODO) -skein.c:53:[kernel] warning: accessing uninitialized left-value *(src + (n + (size_t_0 )7)): assert(TODO) -</pre> -<p>It is possible to increase the argument of option <code>-slevel</code> in order to unroll more iterations and postpone the moment in the analysis when precision is lost and alarms occur. However since the <code>while</code> loop is infinite there is no value for <code>-slevel</code> that lets this loop be analyzed with precision to its end.</p> -<p>In fact we do not want this <code>while</code> loop unrolled. We want the value analysis to do standard value analysis magic and extract properties that are true at all iterations of the loop without studying each iteration individually. In other words we want the value analysis not to unroll the while loop (but to continue unrolling the other finite loops so as to remain as precise as it was for the single <code>Skein_256_Update</code> call).</p> -<p>One way to obtain this result is to move the <code>for</code> loop outside function <code>main</code> so that the <code>while</code> loop is the only one that remains in <code>main</code> and to use the option <code>-slevel-function</code> introduced in Frama-C Boron. This option allows "semantic unrolling" to be tuned function by function. Here we can use it to tell the value analysis to unroll loops except inside <code>main</code>.</p> -<p>The complete analysis context becomes:</p> -<pre>#include "skein.h" -#define HASHLEN (32) -u08b_t msg[80]; -void arbitrarize_msg(void) -{ - for (int i=0; i<80; i++) msg[i]=Frama_C_interval(0 255); -} -u08b_t hash[HASHLEN]; -void main(void) -{ - int i; - u08b_t hash[HASHLEN]; - Skein_256_Ctxt_t skein_context; - Skein_256_Init(&skein_context HASHLEN * 8); - while (Frama_C_interval(0 1)) - { - arbitrarize_msg(); - Skein_256_Update(&skein_context msg 80); - } - Skein_256_Final( &skein_context hash); -} -</pre> -<p>The new command-line to use is:</p> -<p><code>frama-c -val -slevel 100 -slevel-function main:0 *.c > log</code></p> -<p>The analysis takes a minute or so.</p> -<pre>grep ssert log -skein.c:53:[kernel] warning: accessing uninitialized left-value *(src + n): assert(TODO) -skein.c:53:[kernel] warning: accessing uninitialized left-value *(src + (n + (size_t )1)): assert(TODO) -skein.c:53:[kernel] warning: accessing uninitialized left-value *(src + (n + (size_t )2)): assert(TODO) -skein.c:53:[kernel] warning: accessing uninitialized left-value *(src + (n + (size_t )3)): assert(TODO) -skein.c:53:[kernel] warning: accessing uninitialized left-value *(src + (n + (size_t )4)): assert(TODO) -skein.c:53:[kernel] warning: accessing uninitialized left-value *(src + (n + (size_t )5)): assert(TODO) -skein.c:53:[kernel] warning: accessing uninitialized left-value *(src + (n + (size_t )6)): assert(TODO) -skein.c:53:[kernel] warning: accessing uninitialized left-value *(src + (n + (size_t )7)): assert(TODO) -lib.c:10:[kernel] warning: out of bounds write. assert \valid(tmp); -lib.c:18:[kernel] warning: out of bounds write. assert \valid(tmp); -</pre> -<p>The warnings from the previous attempt are still there and they have a surprise guest at lib.c line 18 (in function <code>memset</code>). But since the only thing we have changed since the last attempt is to prevent a loop from being unrolled this was to be expected (you may have noticed that the analysis was a little bit faster also as a result of not unrolling the <code>while</code> loop).</p> -<p>Now let us try to get rid of these warnings for good. For this purpose we need information about what is causing them. Plunging in the code with <code>frama-c-gui</code> is a good way to obtain some of that but this approach lacks the ability to display values of variables for different calls to <code>Skein_256_Update</code> separately. Purely as an experiment in order to have a place to click to see the state at the first second ... fifth iteration let us change the <code>while</code> loop to:</p> -<pre> arbitrarize_msg(); - Skein_256_Update(&skein_context msg 80); - arbitrarize_msg(); - Skein_256_Update(&skein_context msg 80); - arbitrarize_msg(); - Skein_256_Update(&skein_context msg 80); - arbitrarize_msg(); - Skein_256_Update(&skein_context msg 80); - arbitrarize_msg(); - Skein_256_Update(&skein_context msg 80); - while (Frama_C_interval(0 1)) - { - arbitrarize_msg(); - Skein_256_Update(&skein_context msg 80); - } -</pre> -<p>Using the command-line <code>frama-c-gui -val -slevel 100 -slevel-function main:0 *.c</code> the first surprise is that we have accidentally eliminated most of the alarms by hand-unrolling the <code>while</code> loop. Indeed only the following now remains:</p> -<pre>lib.c:10:[kernel] warning: out of bounds write. assert \valid(tmp); -</pre> -<p>We can stick to the initial plan and observe the states after each of the first five iterations to understand what happened. This is no time to celebrate victory yet. For starters the verification is not done until all alarms have been eliminated. Also our investigative instrumentation has eliminated some execution paths — the executions paths with less than five iterations — that would still need to be studied separately before the verification can be called finished.</p> -<p>Here are the contents of variable <code>skein_context</code> before the first second and third calls:</p> -<pre>skein_context.h.hashBitLen ∈ {256; } - .h{.bCnt; .T[0]; } ∈ {0; } - .h.T[1] ∈ {8070450532247928832; } - .X[0] ∈ {4072681676153946182; } - .X[1] ∈ {5436642852965252865; } - .X[2] ∈ {2889783295839482789; } - .X[3] ∈ {6109786322067550404; } - .b[0..31] ∈ UNINITIALIZED -</pre> -<pre>skein_context.h.hashBitLen ∈ {256; } - .h.bCnt ∈ {16; } - .h.T[0] ∈ {64; } - .h.T[1] ∈ {3458764513820540928; } - {.X[0..3]; .b[0..15]; } ∈ [--..--] - .b[16..31] ∈ UNINITIALIZED -</pre> -<pre>skein_context.h.hashBitLen ∈ {256; } - .h.bCnt ∈ {32; } - .h.T[0] ∈ {128; } - .h.T[1] ∈ {3458764513820540928; } - {.X[0..3]; .b[0..31]; } ∈ [--..--] -</pre> -<p>Based on this information it is now clear where the "accessing uninitialized left-value" warnings came from: there is inside the structure <code>skein_context</code> a buffer that only becomes initialized after the first two calls to <code>Skein_256_Update</code>. And these alarms are now gone because these iterations when the buffer is not yet completely initialized are handled separately from the latter iterations when the buffer is initialized and presumably read from at some point.</p> -<p>Quiz 1: continuing the study of the first five calls to <code>Skein_256_Update</code> what used to cause the warning below and what made it disappear?</p> -<pre>lib.c:18:[kernel] warning: out of bounds write. assert \valid(tmp); -</pre> -<p>Quiz 2: how should we get rid of the last alarm (that occurs in our file lib.c at line 10 function <code>memcpy</code> although it is caused by imprecision in the callers of that function)?</p> <p>The files in their state at the end of this blog post are available <a href="/assets/img/blog/imported-posts/skein_verification.zip">here</a>. To rewind to earlier stages of the verification process simply erase <code>main.c</code> which is the only file we have modified so far.</p> {% endraw %} diff --git a/_posts/2010-10-15-Value-analysis-tutorial-part-3-answering-one-quiz.html b/_posts/2010-10-15-Value-analysis-tutorial-part-3-answering-one-quiz.html index 73c4411b7b7690d4dd0232b78a2f6ea3f4677ecd..cdc326b8c833e0f2f49b845125e8153be34f0c8f 100644 --- a/_posts/2010-10-15-Value-analysis-tutorial-part-3-answering-one-quiz.html +++ b/_posts/2010-10-15-Value-analysis-tutorial-part-3-answering-one-quiz.html @@ -38,36 +38,5 @@ lib.c:18:[kernel] warning: out of bounds write. assert \valid(tmp); <p>If you still have the <code>frama-c-gui</code> with the results for the main with unrolling lying around you can check that in that case the values for <code>ctx->h.bCnt</code> are {16; 32; } at the <code>if</code> and { 16; } at the call.</p> <p>This leads us to the following conclusion: the imprecision that leads to the false alarm at lib.c:18 is caused by analyzing the call to <code>memset</code> with imprecise arguments in function <code>Sein_256_Final</code>. By unrolling the first few calls to <code>Skein_256_Update</code> we also forced these calls to happen systematically and that made the analysis conditions for <code>Skein_256_Final</code> simpler. When completing the verification with separate analyses of the omitted cases the arguments to <code>memset</code> are precise again (and complementary) so the false alarm is omitted again.</p> <p>In fact if we kept investigating in the same fashion we would find that the case <code>ctx->h.bCnt==0</code> corresponds to the absence of any call to <code>Skein_256_Update</code>. This case is indeed covered by the <code>while</code> loop in the <code>main</code> analysis context without unrolling. The alarm we obtained when analyzing that loop does not mean there is a problem with the sequence <code>Skein_256_Init(...); Skein_256_Final(...);</code> only that some peculiar values happen in this case and that analyzing this case together with the others leads to false alarms. When verifying software that has already been tested and that its authors take pride on it makes sense to heuristically assume that alarms are false alarms when investigating them. One should however remain honest and continue to investigate until the alarm is understood—ideally until the value analysis can confirm that there was no alarm after all.</p> -<p>Next time the answer to the other quiz.</p> - <p>This is another episode in the advanced value analysis tutorial. The first episode was <a href="/skein/value/2010/09/30/Progress-of-the-value-analysis-tutorial2" hreflang="en">here</a> and the second one <a href="/index.php?post/2010/10/07/Value-analysis-tutorial%2C-part-2" hreflang="en">here</a>.</p> -<p>There were a couple of questions left unanswered at the break. This post answers the first one.</p> -<blockquote><p>Quiz 1: continuing the study of the first five calls to <code>Skein_256_Update</code> what used to cause the warning below and what made it disappear?</p> -<p><code>lib.c:18:<a href="kernel" title="kernel">kernel</a> warning: out of bounds write. assert \valid(tmp);</code></p> -</blockquote> -<p>Value analysis messages in the log are output in order. To understand what the analysis was doing when an alarm was emitted it is recommended to look at the surrounding entries in the log. Using the command-line <code>frama-c -val -slevel 100 -slevel-function main:0 *.c > log</code> on the version of <code>main</code> without unrolling we get the following information about the circumstances that cause the value analysis to worry about line lib.c:18 in function <code>memset</code>:</p> -<pre>... -[value] Done for function Skein_256_Update -[value] computing for function Skein_256_Final <-main. -Called from main.c:44. -[value] computing for function memset <-Skein_256_Final <-main. -Called from skein.c:212. -lib.c:18:[kernel] warning: out of bounds write. assert \valid(tmp); -[value] Recording results for memset -[value] Done for function memset -...</pre> -<p>Using <code>frama-c-gui</code> to observe the value of the troublesome pointer inside <code>memset</code> we see for the <code>main</code> with unrolling:</p> -<p><code>tmp ∈ {{ &skein_context + [24..87] ; &cfg + [0..31] ;}}</code></p> -<p>Repeating the procedure for the <code>main</code> without unrolling we see:</p> -<p><code>tmp ∈ {{ &skein_context + [24..88] ; &cfg + [0..31] ;}}</code></p> -<p>It seems that the pointer causing the problem is at an offset of 88 bytes inside <code>skein_context</code>. To confirm this still while in <code>frama-c-gui</code> we can select any statement of the function <code>main</code> and use "Evaluate expression" in the contextual menu to evaluate the expression <code>sizeof(skein_context)</code>. The result is as follows:</p> -<pre>[...] all the values taken by the expression sizeof(skein_context) are contained in {88; }</pre> -<p>Note: not all C expressions can be evaluated this way but expressions of the form <code>sizeof(v)</code> can at a statement where the variable <code>v</code> is in scope. This is often useful to make sense of the offsets in bytes displayed by the value analysis.</p> -<p>So the problem is indeed that the value analysis thinks that the pointer may refer to offset 88 of <code>skein_context</code> when dereferenced inside <code>memset</code>. This address is out of range. According to the log snippet above this happens when <code>memset</code> is called from <code>Skein_256_Final</code>. The log points us to line 212 in file skein.c that is the first call in that function. This call is guarded by the following conditional and comment:</p> -<code><p>if (ctx->h.bCnt < SKEIN_256_BLOCK_BYTES) /* zero pad b[] if necessary */</p> -<p> memset(&ctx->b[ctx->h.bCnt] 0 SKEIN_256_BLOCK_BYTES - ctx->h.bCnt);</p> -</code><p>In that call the pointer argument is <code>& ctx->b[ctx->h.bCnt]</code> and the values recorded at the <code>if</code> for <code>ctx->h.bCnt</code> are {0; 16; 32; } whereas the values at the call are {0; 16; } (the analysis knows that in the case of 32 the call is not executed because the condition <code>ctx->h.bCnt < SKEIN_256_BLOCK_BYTES</code> is false).</p> -<p>If you still have the <code>frama-c-gui</code> with the results for the main with unrolling lying around you can check that in that case the values for <code>ctx->h.bCnt</code> are {16; 32; } at the <code>if</code> and { 16; } at the call.</p> -<p>This leads us to the following conclusion: the imprecision that leads to the false alarm at lib.c:18 is caused by analyzing the call to <code>memset</code> with imprecise arguments in function <code>Sein_256_Final</code>. By unrolling the first few calls to <code>Skein_256_Update</code> we also forced these calls to happen systematically and that made the analysis conditions for <code>Skein_256_Final</code> simpler. When completing the verification with separate analyses of the omitted cases the arguments to <code>memset</code> are precise again (and complementary) so the false alarm is omitted again.</p> -<p>In fact if we kept investigating in the same fashion we would find that the case <code>ctx->h.bCnt==0</code> corresponds to the absence of any call to <code>Skein_256_Update</code>. This case is indeed covered by the <code>while</code> loop in the <code>main</code> analysis context without unrolling. The alarm we obtained when analyzing that loop does not mean there is a problem with the sequence <code>Skein_256_Init(...); Skein_256_Final(...);</code> only that some peculiar values happen in this case and that analyzing this case together with the others leads to false alarms. When verifying software that has already been tested and that its authors take pride on it makes sense to heuristically assume that alarms are false alarms when investigating them. One should however remain honest and continue to investigate until the alarm is understood—ideally until the value analysis can confirm that there was no alarm after all.</p> <p>Next time the answer to the other quiz.</p> {% endraw %} diff --git a/_posts/2010-10-15-loop-assigns-part-2.html b/_posts/2010-10-15-loop-assigns-part-2.html index 9b67d32fe4a8ebc189bac9df0beb2bc3761e09b8..77e6b44239b1172d8e2b129624f41b8432c29f9c 100644 --- a/_posts/2010-10-15-loop-assigns-part-2.html +++ b/_posts/2010-10-15-loop-assigns-part-2.html @@ -38,35 +38,5 @@ summary: <p>This post shows various ways to specify the <code>loop assigns</code <p>This time Jessie accepts to generate the proof obligation<sup>[<a href="#pnote-8-1" id="rev-pnote-8-1">1</a>]</sup> but the automated theorem provers seem unable to handle it. In fact This annotation alone is not provable even if we assume that all pointer accesses are valid and no arithmetic overflow occurs. Why is that? Well I guess this will be the subject of the quizz for next post.</p> <div class="footnotes"><h4>Notes</h4> <p>[<a href="#rev-pnote-8-1" id="pnote-8-1">1</a>] The analyses have been made with Frama-C Boron and Why 2.27</p> -</div> <h2>Context</h2> -<p><a href="/acsl/2010/10/06/Specification-of-loop-assigns">Last week's post</a> asked how to express a loop assigns for the following code:</p> -<pre>void fill(char* a char x) { - for(;*a;a++) - *a = x; - return; -} -</pre> -<p>The difficulty here is that the pointer <code>a</code> is modified at each step of the loop and that we must take this fact into account when writing the <code>loop assigns</code></p> -<h2>Very broad (but correct) annotations</h2> -<p>Remember that (<code>loop</code>) <code>assigns</code> clauses are an overapproximation of the locations that are actually written. Thus a first possibility is to say that each step can potentially modify any byte from the block pointed to by <code>a</code> (and a itself of course).</p> -<pre>loop assigns a a[..]; -</pre> -<p>Since we do not specify any of the bounds in the range we really mean that each step is allowed to modify any location reachable from (the current value of) a in any direction. In fact it is not too difficult to be slightly more precise: <code>a</code> is the upper bound of the locations that have been written to so far so that the following clause is also correct:</p> -<pre>loop assigns a a[..(-1)]; -</pre> -<p>However this assignment is too broad: if we call <code>fill</code> with a parameter that points to the middle of a block the <code>loop assigns</code> tells that the beginning of the block can be modified too. Let's see if we can do better.</p> -<h2>Precise annotations</h2> -<p>In fact we want to say that before entering the current loop step we have modified the set of locations that are between the initial (which is denoted as <code>\at(a Pre)</code> in ACSL's terms) and the current value of <code>a</code> the latter exlcuded. This can be done in ACSL by defining the set in comprehension: the ACSL expression below is literally the translation of the previous sentence.</p> -<pre>loop assigns a *{ p | char* p; \at(a Pre) <= p < a }; -</pre> -<p>Unfortunately such definition is not handled by the Jessie plugin yet and we can not use Frama-C to verify that it is indeed correct (at least it is accepted by the parser but that only means that this is a well-typed expression). In fact Jessie is more comfortable with ranges of location and we can try to use that starting either from <code>a</code> and going backward or from <code>\at(a Pre)</code> and going forward:</p> -<pre>loop assigns a a[(\at(a Pre)-a)..(-1)]; -</pre> -<p>Alternative annotation starting from the initial value of <code>a</code>:</p> -<pre>loop assigns a \at(a Pre)[0..(a-\at(a Pre)-1)]; -</pre> -<p>This time Jessie accepts to generate the proof obligation<sup>[<a href="#pnote-8-1" id="rev-pnote-8-1">1</a>]</sup> but the automated theorem provers seem unable to handle it. In fact This annotation alone is not provable even if we assume that all pointer accesses are valid and no arithmetic overflow occurs. Why is that? Well I guess this will be the subject of the quizz for next post.</p> -<div class="footnotes"><h4>Notes</h4> -<p>[<a href="#rev-pnote-8-1" id="pnote-8-1">1</a>] The analyses have been made with Frama-C Boron and Why 2.27</p> -</div> +</div> {% endraw %} diff --git a/_posts/2010-10-17-Unspecified-behaviors-and-derived-analyses.html b/_posts/2010-10-17-Unspecified-behaviors-and-derived-analyses.html index d1afc2d7988b667e69417552ff67c4fb3165fa1a..c669cd6b06ca9dedc22da99d956e22c117354326 100644 --- a/_posts/2010-10-17-Unspecified-behaviors-and-derived-analyses.html +++ b/_posts/2010-10-17-Unspecified-behaviors-and-derived-analyses.html @@ -24,22 +24,5 @@ undefined behaviors. Fast alias analyses intended to scale to millions of lines <h2>What is a well-defined execution?</h2> <p>The value analysis is more precise and more aggressive than the typical large-scale alias analysis in its handling of what look like possible quirks in the analyzed program. The reason the <code>-val-signed-overflow-alarms</code> option mentioned above is not enabled by default is that several test programs became meaningless. The analysis was in effect saying "look this program is sure to produce an overflow here at the third line there is no point in going further until this has been resolved" and refused to analyze the rest of the program. The typical large-scale context-insensitive path-insensitive alias analysis does not have this problem but that's only because it is too imprecise to have it. It is still making assumptions such that you do not access <code>p</code> when you read or write from <code>*(&q+1)</code>.</p> <p>So does this mean that all high-level analyses of C programs are meaningless unless the absence of undefined behaviors in target program is also verified(1)? In the style of Dan Simmons' Hyperion cycle we are going to leave this crucial question for another volume that is a future blog post.</p> -<p>(1) which it rarely is in practice. As pointed out earlier most of them do not even tell you whether you should worry and what to worry about.</p> - <h2>Prologue</h2> -<p><strong>The C standard(s) specifies a minimum of things</strong> that all C compilers must agree on. For the sake of efficiency, many syntactically correct constructs are left without an unambiguous meaning.</p> -<p>The worst way for a construct not to have an unambiguous meaning is to be <em>undefined behavior</em>. An example of undefined behavior is invalid pointer access. Not all platforms have the required MMU, and even when they do, the MMU does not catch all invalid memory uses. Accessing an invalid pointer is not guaranteed to crash the program cleanly. A program that does so may \crash cleanly" or continue executing in an inconsistent state. The program may crash a little bit later because of the inconsistency or it may appear to work fine and return a wrong result or it may reformat your harddrive. All these behaviors and others are encompassed by "undefined behavior".</p> -<h2>Compilers and compilation-platform-specific static analysis</h2> -<p>Recently C compilers have started to take advantage of undefinedness in the C99 standard for the sake of aggressive optimization. They apply program transformations that are <strong>only valid in the case of defined behaviors</strong> and leave the program doing strange unpredictable things in other cases. John Regehr has a very good explanation of C's undefined behaviors that spans <a href="http://blog.regehr.org/archives/213" hreflang="en">three blog posts</a>.</p> -<p>There are other more benign ways for a construct not to have an unambiguous meaning though. <em>Implementation-defined behaviors</em> must be documented and consistent for a given compiler. In the case of <em>unspecified behaviors</em> one of several plausible alternatives must happen. In Frama-C we have reclassified some unspecified and even some undefined behaviors as implementation-defined. For instance the value analysis assumes by default that signed arithmetic overflows have been put there on purpose by the programmer and that he intended 2's complement modulo results. In this default configuration the value analysis does not warn about these overflows and propagate 2's complement modulo results. John Regehr convinced us however that this was not satisfactory so there is now an option <code>-val-signed-overflow-alarms</code> for when the programmer is not supposed to rely on this behavior (signed arithmetic overflows are technically undefined behavior). The Jessie plug-in allows roughly the same distinction with the defaults reversed (by default you get alarms for integer overflows). -In short a Frama-C analysis session is parameterized by a <strong>description of the compilation platform</strong> that includes genuine or reclassified implementation-defined choices.</p> -<p>That still leaves of course some unspecified and undefined behaviors that the value analysis or Jessie plug-ins do indeed warn about and prove the absence of when they do not warn about them. Each construct that may cause some kind of unspecifiedness or undefinedness is the object of a warning containing the word <code>assert</code> in the value analysis log. Terms and conditions apply.</p> -<p>This post is about the one use case where the user does not have to worry about the alarms So if you were tired of the ongoing thread about the verification of Skein-256 good news! This is something else.</p> -<h2>Derived analyses</h2> -<p>Well I say "one" use case but it's really a family of use cases. I am talking about all the <strong>analyses that are helping the user to comprehend the code</strong> and that can therefore not mandate that all the alarms have been eliminated through the kind of laborious inspection and refinement illustrated in the Skein verification thread. Instead the values and therefore the results of the analysis that relies on them are guaranteed to apply to well-defined executions only (executions that do not falsify any of the assertions that have been emitted). As long as this is kept in mind it may even not be necessary to look at these alarms. In fact it is standard for high-level analyzers of C programs to <strong>assume the absence of undefined behaviors</strong> or apply only to executions without -undefined behaviors. Fast alias analyses intended to scale to millions of lines of C for instance assume that you do not transmit an address to pointer <code>p</code> by writing it in <code>*(&q+1)</code> where <code>q</code> is the address below <code>p</code> in memory. These analyses and any other analyses that rely on the first ones do not tell you whether you should have reasons to worry about this happening. If you should worry they do not give you a list of dangerous constructs in the target program. The value analysis provides such a list of alarms but you can ignore it if you wish and then you get results with similar caveats.</p> -<p>Well almost. We are finally arriving to the core of the problem.</p> -<h2>What is a well-defined execution?</h2> -<p>The value analysis is more precise and more aggressive than the typical large-scale alias analysis in its handling of what look like possible quirks in the analyzed program. The reason the <code>-val-signed-overflow-alarms</code> option mentioned above is not enabled by default is that several test programs became meaningless. The analysis was in effect saying "look this program is sure to produce an overflow here at the third line there is no point in going further until this has been resolved" and refused to analyze the rest of the program. The typical large-scale context-insensitive path-insensitive alias analysis does not have this problem but that's only because it is too imprecise to have it. It is still making assumptions such that you do not access <code>p</code> when you read or write from <code>*(&q+1)</code>.</p> -<p>So does this mean that all high-level analyses of C programs are meaningless unless the absence of undefined behaviors in target program is also verified(1)? In the style of Dan Simmons' Hyperion cycle we are going to leave this crucial question for another volume that is a future blog post.</p> <p>(1) which it rarely is in practice. As pointed out earlier most of them do not even tell you whether you should worry and what to worry about.</p> {% endraw %} diff --git a/_posts/2010-10-27-Loop-assigns-part-3-On-the-importance-of-loop-invariants.html b/_posts/2010-10-27-Loop-assigns-part-3-On-the-importance-of-loop-invariants.html index 6adc01a60a6ed00ea6fa57d0e7263d9c513e4e64..0b5d410c883b0e564bac537ba234f66df3423e27 100644 --- a/_posts/2010-10-27-Loop-assigns-part-3-On-the-importance-of-loop-invariants.html +++ b/_posts/2010-10-27-Loop-assigns-part-3-On-the-importance-of-loop-invariants.html @@ -8,45 +8,7 @@ title: "Loop assigns, part 3: On the importance of loop invariants" summary: This post is the third of a serie dealing with loop assigns. The first can be found\r\n[here|/acsl/2010/10/06/Specification-of-loop-assigns] and the second [here|/index.php?post/2010/10/15/loop-assigns%2C-part-2]. --- {% raw %} -!!!! Context -Last week's post mentioned that it is not possible to prove the following @@loop assigns@@ with Jessie: -/// -void fill(char* a, char x) { -//@ loop assigns a, \at(a,Pre)[0..(a-\at(a,Pre)-1)]; - for(;*a;a++) - *a = x; - return; -} -/// -and in fact this annotation is not provable. An hint to where the issue lies is given by the title of this post: we don't provide enough context on what the loop steps are doing. -!!!! Loop invariants -One (perhaps the most) important thing to remember when doing deductive verification is that one has to provide sufficiently strong @@loop invariant@@ for each loop of the program. Formally, @@loop invariant@@ is a property which must hold before entering the loop and is preserved by a loop step (''i.e.'' if it holds before a step, it must also hold after the step has been executed). Another way to look at this is to say that the invariant abstracts away what has been done by the first @@k@@ steps (for an arbitrary @@k@@). In this view, the loop invariant is __the only thing which is known about the state of the program__ after an arbitrary number of loop steps, and thus we must provide the right amount of information to be able to prove -# our property of interest (here @@loop assigns@@, which is a special case of invariant) -# the loop invariant itself (otherwise we just exchange an unprovable goal against another, which is not that useful regarding the correctness of the whole function). -In our case, the missing invariant is simply that @@a@@ is increasing: if we don't mention that, then for all what Jessie knows @@a-\at(a,Pre)-1@@ could well be negative (since @@a@@ itself has been modified, but we don't say anything about its new value), and thus our assigned interval be empty, whereas it should at least include @@a-1@@. Thus a sufficient loop invariant would be: -/// -loop invariant \at(a,Pre) - a <= 0; -/// -and this time, the @@loop assigns@@ can be discharged on the whole program: -/// -void fill(char* a, char x) { -/*@ loop assigns a, a[(\at(a,Pre)-a)..(-1)]; - loop invariant \at(a,Pre) - a <= 0; -*/ - for(;*a;a++) - *a = x; - return; -} -/// -As said in the previous, we are not interested for the moment in safety issues (\i.e." we assume that all pointer accesses are valid for now). We thus instruct Jessie not to generate the proof obligations corresponding to potential run-time errors with a particular @@-jessie-behavior@@ option: -/// -frama-c -jessie -jessie-behavior default -jessie-atp alt-ergo -/// -Unfortunately alt-ergo is still not able to discharge the proof and neither can Simplify nor z3. It seems like the proof obligation generated by jessie is too complicated for automated theorem provers. However the specification is correct as the attached coq file that discharge all proof obligations generated by -/// -frama-c -jessie -jessie-behavior default -jessie-atp coq -/// -shows." <h2>Context</h2> +<h2>Context</h2> <p>Last week's post mentioned that it is not possible to prove the following <code>loop assigns</code> with Jessie:</p> <pre> void fill(char* a, char x) { diff --git a/_posts/2010-11-20-IEEE-754-single-precision-numbers-in-Frama-C.html b/_posts/2010-11-20-IEEE-754-single-precision-numbers-in-Frama-C.html index ef9a5ef279e94cd46da2f876ef0bb63b1cc36462..e926187ec1cbd7713523c5776074a6fd4574e655 100644 --- a/_posts/2010-11-20-IEEE-754-single-precision-numbers-in-Frama-C.html +++ b/_posts/2010-11-20-IEEE-754-single-precision-numbers-in-Frama-C.html @@ -19,17 +19,5 @@ summary: <p>So far so good. If there is a <code>10.0</code> literal in the program it stands for the double 10.0. If there is a <code>0.1</code> in the program it stands for one of representable numbers no further than 1ulp from the real 0.1. This is slightly annoying because the representable number chosen by CIL may not be the same as the representable number chosen by your actual C compiler but in all likelihood both will round the number from the source code to the nearest double-precision floating-point number. Thus the AST analyzed in Frama-C accurately represents the compiled program and all is well.</p> <p>The picture gets muddied a little if the target program contains a literal such as <code>3.14f</code>. This is supposed to represent a single-precision floating-point literal in C. I'm willing to bet without really looking that CIL represents that literal in the AST with the double-precision number nearest to the real number written in decimal in the target program. If you are a Frama-C plug-in author willing to do the right thing you may think of rounding this double-precision number to the nearest single-precision number yourself but that doesn't work: the double rounding can make your final result different from the compiler's which will round only once from real to single-precision. To be correct you have to go back to the string representation that has been saved from the source code.</p> <p>In fact Frama-C's front-end should be doing this for all plug-ins of course. When the literal is single-precision it should represent it in the AST as an OCaml float containing the single-precision number meant by the programmer (all single-precision numbers can be represented as double-precision numbers). Probably this will be done soon now that the problem is identified. This was just an example of how far support for single-precision numbers in Frama-C is.</p> -<p>Full disclosure: I said I was betting without looking but I wouldn't take the bet if I were you. I do not just risk public humiliation like that without strong presumptions. First I was just working on something related and visible effects of this subtlety came up as one annoying unforeseen issue. Secondly there is no function in OCaml to parse a number as single-precision. There are some OCaml functions to parse double-precision numbers and this task is enough of a bother that these are defined by calling the C function <code>strtod()</code>. The way to fix the front-end is probably to replicate this OCaml-C interface for <code>strtof()</code>. So my bet is in fact that CIL's authors neither implemented a single-precision parsing function in OCaml nor interfaced it from C.</p> - <p>Every once in a while, someone asks about single-precision floating-point support in Frama-C. Until recently it was often in the context of the value analysis, but actually, thanks to a lot of interesting new results obtained in the context of <a href="http://hisseo.saclay.inria.fr/index.html" hreflang="en">this project</a> people working on deductive verification within Frama-C can now look forward to being harassed too.</p> -<p>We are not nearly home and dry yet though. Frama-C's front-end is <a href="http://www.cs.berkeley.edu/~necula/cil/" hreflang="en">CIL</a> (no relation to something from Microsoft with a similar acronym). CIL is written in <a href="http://caml.inria.fr/" hreflang="en">OCaml</a> (the rest of Frama-C is written in OCaml too but never mind that). OCaml has a single floating-point type which corresponds to <a href="http://en.wikipedia.org/wiki/IEEE_754-2008" hreflang="en">IEEE 754</a> double precision.</p> -<p>So guess how floating-point literal constants are represented in the abstract syntax tree built by CIL...</p> -<p>If you guessed "as an IEEE 754 double-precision number" you are partly right. Yay! But also as a string. CIL's authors did think about this especially since one of CIL's first use was for source-to-source transformation. Specifically you have all the information in this constructor defined in file frama-c/cil/src/cil_types.mli:</p> -<pre>| CReal of float * fkind * string option - (** Floating point constant. Give the fkind (see ISO 6.4.4.2) and also - * the textual representation if available. *)</pre> -<p>The above is OCaml code and the type <code>float</code> means double-precision floating-point number.</p> -<p>So far so good. If there is a <code>10.0</code> literal in the program it stands for the double 10.0. If there is a <code>0.1</code> in the program it stands for one of representable numbers no further than 1ulp from the real 0.1. This is slightly annoying because the representable number chosen by CIL may not be the same as the representable number chosen by your actual C compiler but in all likelihood both will round the number from the source code to the nearest double-precision floating-point number. Thus the AST analyzed in Frama-C accurately represents the compiled program and all is well.</p> -<p>The picture gets muddied a little if the target program contains a literal such as <code>3.14f</code>. This is supposed to represent a single-precision floating-point literal in C. I'm willing to bet without really looking that CIL represents that literal in the AST with the double-precision number nearest to the real number written in decimal in the target program. If you are a Frama-C plug-in author willing to do the right thing you may think of rounding this double-precision number to the nearest single-precision number yourself but that doesn't work: the double rounding can make your final result different from the compiler's which will round only once from real to single-precision. To be correct you have to go back to the string representation that has been saved from the source code.</p> -<p>In fact Frama-C's front-end should be doing this for all plug-ins of course. When the literal is single-precision it should represent it in the AST as an OCaml float containing the single-precision number meant by the programmer (all single-precision numbers can be represented as double-precision numbers). Probably this will be done soon now that the problem is identified. This was just an example of how far support for single-precision numbers in Frama-C is.</p> <p>Full disclosure: I said I was betting without looking but I wouldn't take the bet if I were you. I do not just risk public humiliation like that without strong presumptions. First I was just working on something related and visible effects of this subtlety came up as one annoying unforeseen issue. Secondly there is no function in OCaml to parse a number as single-precision. There are some OCaml functions to parse double-precision numbers and this task is enough of a bother that these are defined by calling the C function <code>strtod()</code>. The way to fix the front-end is probably to replicate this OCaml-C interface for <code>strtof()</code>. So my bet is in fact that CIL's authors neither implemented a single-precision parsing function in OCaml nor interfaced it from C.</p> {% endraw %} diff --git a/_posts/2010-11-21-Value-analysis-tutorial-part-4-one-solution-to-second-quiz.html b/_posts/2010-11-21-Value-analysis-tutorial-part-4-one-solution-to-second-quiz.html index c949365dc27b2faba9904eebc69118275dc19a10..cd4ce3b257530def6193b0ebf4be289598076490 100644 --- a/_posts/2010-11-21-Value-analysis-tutorial-part-4-one-solution-to-second-quiz.html +++ b/_posts/2010-11-21-Value-analysis-tutorial-part-4-one-solution-to-second-quiz.html @@ -79,77 +79,5 @@ skein_context.h.bCnt ∈ {16; 32; }</pre> } </pre> <p>With the command-line <code>frama-c -val -slevel 100 -slevel-function main:0 *.c</code> the value analysis does not emit any alarm for this <code>main()</code>. The case of one call was already handled in the tutorial chapter of the value analysis documentation. The separate cases of 0 calls and of an odd number of calls larger than three are left to the reader and this time there will not be any further refinement of this solution in a future blog post. Ask on the <a href="http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/frama-c-discuss" hreflang="en">mailing list</a> if you encounter a problem finishing the verification from here.</p> -<p>In the next episode an alternative and more generalizable solution to the same problem. Or maybe a meta-discussion about the verification methodology being sketched out in this thread.</p> - <p>This post offers one answer to the second quiz from <a href="/index.php?post/2010/10/07/Value-analysis-tutorial%2C-part-2" hreflang="en">part 2</a>. For context here are links to <a href="/skein/value/2010/09/30/Progress-of-the-value-analysis-tutorial2" hreflang="en">part 1</a> and <a href="/index.php?post/2010/10/15/Value-analysis-tutorial%2C-part-3" hreflang="en">part 3</a>.</p> -<p>The question was: how should we get rid of the last alarm below and conclude that Skein-256 is indeed safe from run-time errors when used in the conditions previously described?</p> -<pre>lib.c:10:[kernel] warning: out of bounds write. assert \valid(tmp); -</pre> -<p>The alarm appears when using the command-line:</p> -<pre>frama-c-gui -val -slevel 100 -slevel-function main:0 *.c</pre> -<p>Inspecting values inside function <code>memcpy</code> we can see that the problematic address is again at offset 88 inside structure <code>skein_context</code>. Following the same procedure as in <a href="/index.php?post/2010/10/15/Value-analysis-tutorial%2C-part-3" hreflang="en">part 3</a> we identify this context for the alarm inside the analysis log:</p> -<pre>... -[value] computing for function Skein_256_Update <-main. - Called from main.c:40. -[value] computing for function memcpy <-Skein_256_Update <-main. - Called from skein.c:171. -lib.c:10:[kernel] warning: out of bounds write. assert \valid(tmp); -[value] Recording results for memcpy -[value] Done for function memcpy -... -</pre> -<p>Several remarks:</p> -<ol> -<li>the problematic <code>Skein_256_Update</code> call is the call inside the <code>while</code> loop (at line main.c:40). This is completely unsurprising.</li> -<li>Function <code>memcpy</code> is called several times from <code>Skein_256_Update</code> but the call that results in an alarm is the call at skein.c:171.</li> -</ol> -<p>Inspecting the incriminated call site in the GUI the address argument to <code>memcpy</code> is <code>&ctx->b[ctx->h.bCnt]</code> and the values that the analysis thinks are taken by <code>ctx->h.bCnt</code> at this point are 16 and 32. The length argument <code>n</code> is always 16. Since the array <code>b</code> inside struct <code>skein_context</code> is only 32 bytes it is normal to get an alarm inside <code>memcpy</code> with such arguments.</p> -<p>Now the reason we originally unrolled a few calls to <code>Skein_256_Update</code> was in order to reverse-engineer what the function was doing much as if we had inserted calls to <code>printf</code> inside the source code except without the need to choose in advance the values to inspect. So let us use the GUI to check the values of <code>skein_context.h.bCnt</code> for the first few calls.</p> -<p>Using "Evaluate expression" on the first call to <code>Skein_256_Update</code>:</p> -<pre>Before statement: -skein_context.h.bCnt ∈ {0; } -At next statement: -skein_context.h.bCnt ∈ {16; }</pre> -<p>On the second call:</p> -<pre>Before statement: -skein_context.h.bCnt ∈ {16; } -At next statement: -skein_context.h.bCnt ∈ {32; }</pre> -<p>On the third call:</p> -<pre>Before statement: -skein_context.h.bCnt ∈ {32; } -At next statement: -skein_context.h.bCnt ∈ {16; }</pre> -<p>On the fourth call:</p> -<pre>Before statement: -skein_context.h.bCnt ∈ {16; } -At next statement: -skein_context.h.bCnt ∈ {32; }</pre> -<p>On the fifth and last call before entering the loop:</p> -<pre>Before statement: -skein_context.h.bCnt ∈ {32; } -At next statement: -skein_context.h.bCnt ∈ {16; 32; }</pre> -<p>Do not let yourself be distracted by the last "At next statement:" information: this one is imprecise because the "next statement" is inside the <code>while</code> loop. Apart from that it is rather clear what is happening: each call after the first one changes the <code>bCnt</code> field from 16 to 32 or conversely. Inside the <code>while</code> loop the two values end up amalgamated together. That makes it look like there may be a problem with the <code>memcpy</code> call. To make it clear there is no problem we probably just need to group the calls by two. That leads us for instance to write the following <code>main</code> function to verify the safety of all sequences of an even number of calls to <code>Skein_256_Update</code>.</p> -<pre>void main(void) -{ - int i; - u08b_t hash[HASHLEN]; - Skein_256_Ctxt_t skein_context; - Skein_256_Init(&skein_context HASHLEN * 8); - arbitrarize_msg(); - Skein_256_Update(&skein_context msg 80); - arbitrarize_msg(); - Skein_256_Update(&skein_context msg 80); - while (Frama_C_interval(0 1)) - { - arbitrarize_msg(); - Skein_256_Update(&skein_context msg 80); - arbitrarize_msg(); - Skein_256_Update(&skein_context msg 80); - } - Skein_256_Final( &skein_context hash); -} -</pre> -<p>With the command-line <code>frama-c -val -slevel 100 -slevel-function main:0 *.c</code> the value analysis does not emit any alarm for this <code>main()</code>. The case of one call was already handled in the tutorial chapter of the value analysis documentation. The separate cases of 0 calls and of an odd number of calls larger than three are left to the reader and this time there will not be any further refinement of this solution in a future blog post. Ask on the <a href="http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/frama-c-discuss" hreflang="en">mailing list</a> if you encounter a problem finishing the verification from here.</p> <p>In the next episode an alternative and more generalizable solution to the same problem. Or maybe a meta-discussion about the verification methodology being sketched out in this thread.</p> {% endraw %} diff --git a/_posts/2010-11-22-Value-analysis-tutorial-part-5-jumping-to-conclusions.html b/_posts/2010-11-22-Value-analysis-tutorial-part-5-jumping-to-conclusions.html index 7977c23f7baa3fee83389de18e4234b3b846be95..f09b3e949d3b6034c219cd481b755ffce0c29804 100644 --- a/_posts/2010-11-22-Value-analysis-tutorial-part-5-jumping-to-conclusions.html +++ b/_posts/2010-11-22-Value-analysis-tutorial-part-5-jumping-to-conclusions.html @@ -50,48 +50,5 @@ while(Frama_C_interval(0 1)) <p>Using local variables as in the above C code snippet the possibility of such a breach can be eliminated: we cannot prevent function <code>Update</code> to keep trace of a previous input buffer in its state but if it then accessed it or even just compared it to another address this would be detected as an operation on a dangling pointer and an alarm would be emitted.</p> <blockquote><p>Digression: actually we can also prevent function <code>Update</code> to keep trace of a previous input buffer thanks to secondary analyses derived from the value analysis. One of them computes the set of locations written to by a C function. With this analysis we can list the entire set of memory locations that <code>Update</code> uses as state and check that only information that should be kept is. <a href="/derived/analysis/skein/value/2011/01/10/Value-analysis-assisted-verification-of-output-variables-and-information-flow">Here is a future blog post on this topic</a>.</p> </blockquote> -<p>With the future Frama-C release the verification takes about 5h and 150MiB of memory on a computer that was near top-of-the-line in 2006 (Intel Xeon 5150). Since we are speaking of performance this analysis is single-threaded. With the memory footprint that it now has there is hope that it will get a bit faster in time as a larger and larger proportion of the working set fits in lower and lower levels of memory cache. A parallel value analysis applicable to some verification plans (but untried for this one) is also at the proof-of-concept stage. Where applicable this parallel analysis will allow to take advantage of multicore processors and computation farms.</p> - <p>This post is in two parts, both of them independently good fits for the title, and still not completely without relation to each other, but that's probably a coincidence.</p> -<h2>Methodology</h2> -<p>In this thread, we aim at the verification of low-level properties for the functions in Skein. In the last post, I closed one line of reasoning as if the objective had been reached. But someone might object. \How do you know you can trust the verifier?" ey might say. "What have you really proved?". And "are you asking me to believe that all cases are covered with separate analyses for 0 1 even numbers greater than 2 and odd numbers greater than 3?".</p> -<p>Answers in reverse order:</p> -<ol> -<li>yes. In C you cannot call a function a negative number of times so I am asking you to believe that this partition covers the "calling Update(... 80) an arbitrary number of times" part of the informal specification we settled on <a href="/skein/value/2010/09/30/Progress-of-the-value-analysis-tutorial2" hreflang="en">from the beginning</a>.</li> -<li>The middle question refers to the fact that there is a translation of sorts from the informal requirement or specification to the formal one. This is not unlike the translation in traditional verification from the informal requirement to executable test (or code review) plans. Yes there are dangers here but the dangers are not new. Both with testing or with more formal verification as we have been outlining you can make unjustified assumptions or forget a critical case. That weakness does not prevent replacing some tests and code reviews with formal methods since all these techniques have the weakness. If anything formal specifications that are slightly more expressive than individual test cases or review objectives are slightly closer to informal speech and could be argued to have a slightly lower and therefore slightly less risky translation step.</li> -<li>The first question is even less original than the middle one. We gain confidence in the verifier with tests and code reviews. They didn't suddenly stop working you know.</li> -</ol> -<h2>Jumping ahead to the conclusion of the Skein-256 verification</h2> -<p>All the techniques to deploy have not been exposed yet in this blog but now that the thread gives a good idea of how absence of run-time errors can be verified in very general circumstances using the value analysis I thought I would hint at the final results. One of the techniques to deploy is (as of November 2010) the next Frama-C release which contains many optimizations and performance improvements so there is no hurry for me to go into the details (yet).</p> -<p>Following roughly the same method we have verified in-house that there wasn't any alarm when calling <code>Skein_256_Update</code> an arbitrary number of times between <code>Skein_256_Init</code> and <code>Skein_256_Final</code> using for each call to <code>Skein_256_Update</code> a value <code>n</code> for the length and an input buffer of length exactly <code>n</code> with for each call an arbitrary independent <code>n</code> between 1 and 128.</p> -<p>The question of what has been proved is even more acute than previously. The above informal specification could have several interpretations. Let us just say that one part of the <code>main</code> function used for the verification looks like this:</p> -<pre>... -while(Frama_C_interval(0 1)) - { - { - int c = Frama_C_interval(0 1); - if (c) - { - u08b_t msg[1]; - arbitrarize_msg(msg 1); - Skein_256_Update( &skein_context msg 1); - continue; - } - } - { - int c = Frama_C_interval(0 1); - if (c) - { - u08b_t msg[2]; - arbitrarize_msg(msg 2); - Skein_256_Update( &skein_context msg 2); - continue; - } - } - ... -</pre> -<p>In the verification described in detail until now we re-use the same buffer for each call to <code>Skein_256_Update</code>. This is a small weakness in the verification plan: there could be a bug that happens only with two calls with two different buffers. For instance <code>Skein_256_Update</code> could memorize the address of the buffer passed the first time and access it on the second call when the buffer may no longer exist. It goes to show that there is some validity to the question "what have you really proved?" but in this example as often the problem is with the ambiguous informal specification and not with the formal method itself.</p> -<p>Using local variables as in the above C code snippet the possibility of such a breach can be eliminated: we cannot prevent function <code>Update</code> to keep trace of a previous input buffer in its state but if it then accessed it or even just compared it to another address this would be detected as an operation on a dangling pointer and an alarm would be emitted.</p> -<blockquote><p>Digression: actually we can also prevent function <code>Update</code> to keep trace of a previous input buffer thanks to secondary analyses derived from the value analysis. One of them computes the set of locations written to by a C function. With this analysis we can list the entire set of memory locations that <code>Update</code> uses as state and check that only information that should be kept is. <a href="/derived/analysis/skein/value/2011/01/10/Value-analysis-assisted-verification-of-output-variables-and-information-flow">Here is a future blog post on this topic</a>.</p> -</blockquote> <p>With the future Frama-C release the verification takes about 5h and 150MiB of memory on a computer that was near top-of-the-line in 2006 (Intel Xeon 5150). Since we are speaking of performance this analysis is single-threaded. With the memory footprint that it now has there is hope that it will get a bit faster in time as a larger and larger proportion of the working set fits in lower and lower levels of memory cache. A parallel value analysis applicable to some verification plans (but untried for this one) is also at the proof-of-concept stage. Where applicable this parallel analysis will allow to take advantage of multicore processors and computation farms.</p> {% endraw %} diff --git a/_posts/2010-12-04-Unspecified-behaviors-and-derived-analyses-part-2.html b/_posts/2010-12-04-Unspecified-behaviors-and-derived-analyses-part-2.html index f84d574d905f5f7568834de36309c03002c5169e..e377b6bbd9b557fba15e03c9be39b5bf89e2a1b5 100644 --- a/_posts/2010-12-04-Unspecified-behaviors-and-derived-analyses-part-2.html +++ b/_posts/2010-12-04-Unspecified-behaviors-and-derived-analyses-part-2.html @@ -59,57 +59,5 @@ is also an assumption. Still as implementation progresses and the value analysi becomes able to extract more information from the alarms it emits one or several options to configure it either not to emit some alarms or not to make the corresponding -assumptions will certainly become necessary.</p> - <h2>Context</h2> -<p>This post is a sequel and conclusion to <a href="/derived/analysis/unspecified/behavior/value/2010/10/17/Unspecified-behaviors-and-derived-analyses" hreflang="en">this remark</a>.</p> -<h2>Example of derived analysis: slicing</h2> -<p>When writing a Frama-C plug-in to assist in -reverse-engineering source code it does not really make sense to expect -the user to check the alarms that are emitted by the value analysis. -Consider for instance Frama-C's slicing plug-in. This plug-in produces -a simplified version of a program. It is often applied to large unfamiliar -codebases; if the user is at the point where he needs a slicer to make -sense of the codebase it's probably a bad time to require -him to check alarms on the original unsliced version.</p> -<p>The slicer and other code comprehension plug-ins work around this problem -by defining the results they provide as ``valid for well-defined executions''. -In the case of the slicer this is really the only definition that makes -sense. Consider the following code snippet:</p> -<pre> x = a; - y = *p; - x = x+1; - // slice for the value of x here. -</pre> -<p>This piece of program is begging for its second line to be removed but -if <code>p</code> can be the <code>NULL</code> pointer the sliced -program behaves differently from the original: the original program -exits abruptly on most architectures whereas the sliced version -computes the value of <code>x</code>.</p> -<p>It is fine to ignore alarms in this context -but the user of a code comprehension plug-in based on the value analysis -should study the categorization of alarms in the value analysis' reference manual with particular care. -Because the value analysis is more aggressive -in trying to extract precise information from the program than other -analyses the user is more likely to observe incorrect results if there -is a misunderstanding between him and the tool about what assumptions -should be made.</p> -<h2>Example of benign alarm: testing <code>p<=q</code></h2> -<p>Everybody agrees that accessing an invalid pointer is an unwanted behavior -but what about comparing two pointers with <code><=</code> in an undefined manner or -assuming that a signed overflow wraps around in 2's complement -representation? Function <code>memmove</code> for instance typically does the -former when applied to two addresses with different bases.</p> -<p>Currently if there appears to be an undefined pointer comparison the -value analysis propagates a state that contains all possible results -for the comparison and for the pointers. This blog post was just trying -to scare you. It is possible to take advantage of the value analysis -for program comprehension and all existing program comprehension -tools need to make assumptions about undefined behaviors. Most tools -do not tell you if they had to make assumptions or not. The value analysis -does: each alarm in general -is also an assumption. Still as implementation progresses and the value analysis -becomes able to extract more information from the alarms it emits -one or several options -to configure it either not to emit some alarms or not to make the corresponding assumptions will certainly become necessary.</p> {% endraw %} diff --git a/_posts/2010-12-10-Documentation.html b/_posts/2010-12-10-Documentation.html index deaa72434c0ab4f8075605d6cafb381451687ce3..1934b155d832b2e3078955f81e18a66879418eb6 100644 --- a/_posts/2010-12-10-Documentation.html +++ b/_posts/2010-12-10-Documentation.html @@ -10,8 +10,5 @@ summary: {% raw %} <p>So it may seem that I have a pretty good job for having nothing more important to worry about —that may or may not be accurate— but I worry about the state of the Frama-C documentation in general and of the value analysis in particular.</p> <p>I hate noticing that it's all so poorly organized that <a href="http://lists.gforge.inria.fr/pipermail/frama-c-discuss/2010-November/002356.html" hreflang="en">people use an undocumented -users option for the side-effect it has of initiating the value analysis</a>. The feeling is the irritation of a compulsive optimizer faced with a stubbornly suboptimal system. You may or may not be familiar with the condition.</p> -<p>Being a compulsive optimizer does not mean that you have to be good at it. And there are quite a few of us who are trying to improve access to Frama-C information. Apparently documentation is significantly different from programming which we modestly are demigods at.</p> - <p>So it may seem that I have a pretty good job for having nothing more important to worry about —that may or may not be accurate— but I worry about the state of the Frama-C documentation in general and of the value analysis in particular.</p> -<p>I hate noticing that it's all so poorly organized that <a href="http://lists.gforge.inria.fr/pipermail/frama-c-discuss/2010-November/002356.html" hreflang="en">people use an undocumented -users option for the side-effect it has of initiating the value analysis</a>. The feeling is the irritation of a compulsive optimizer faced with a stubbornly suboptimal system. You may or may not be familiar with the condition.</p> <p>Being a compulsive optimizer does not mean that you have to be good at it. And there are quite a few of us who are trying to improve access to Frama-C information. Apparently documentation is significantly different from programming which we modestly are demigods at.</p> {% endraw %} diff --git a/_posts/2011-01-10-Value-analysis-assisted-verification-of-output-variables-and-information-flow.html b/_posts/2011-01-10-Value-analysis-assisted-verification-of-output-variables-and-information-flow.html index 0c64f15697c29470daec2d3abf58de50652c5727..b99b2452de94abc9ca9d391d8eb9885cd9056dd4 100644 --- a/_posts/2011-01-10-Value-analysis-assisted-verification-of-output-variables-and-information-flow.html +++ b/_posts/2011-01-10-Value-analysis-assisted-verification-of-output-variables-and-information-flow.html @@ -16,14 +16,5 @@ summary: <p>One example use of these computations is provided as part of the tutorial in the <a href="http://frama-c.com/download/value-analysis-Carbon-20101202-beta2.pdf" hreflang="en">Carbon version of the value analysis manual</a> (it's section 2.5.2 there).</p> <p>Rather than repeating here this addition to the tutorial I want to reiterate on the notion of derived analysis. Although the outputs and dependencies computations rely on the results of the value analysis they do not require you to check each of the alarms generated by the value analysis.</p> <p>When a sequence of function calls has dependencies (as computed by option <code>-deps</code>) of <code>hash[0..7] FROM msg[0..79]; ONE[bits 0 to 7] (and SELF)</code> it means that if all goes well array <code>hash</code> after the calls has been computed from array <code>msg</code> and variable <code>ONE</code>. Computing and taking advantage of this information is orthogonal to the verification that all always goes well during the execution of these function calls (which is done by making sure that the value analysis emits no alarm or by checking the emitted alarms with alternative techniques).</p> -<p>In more difficult cases the latter may require a combination of human reflexion and of hours of computer time. But functional dependencies can be useful even when based on the results of a simpler faster value analysis.</p> - <p>A previous post in the value analysis thread in this blog contained this digression:</p> -<blockquote><p>Actually, we can also prevent function Update to keep trace of a previous input buffer, thanks to secondary analyses derived from the value analysis. One of them computes the set of locations written to by a C function. With this analysis, we can list the entire set of memory locations that Update uses as state, and check that only information that should be kept is. Perhaps there will be a blog post on this topic.</p> -</blockquote> -<p>Before the Carbon release, I wasn't in a hurry to talk about this. The value-analysis assisted computations of output variables and information flow are part of the many improvements in Carbon. In the Boron release and before, when applied on the Skein codebase, they gave results that were too approximated to be useful.</p> -<p>Now, they just work.</p> -<p>One example use of these computations is provided as part of the tutorial in the <a href="http://frama-c.com/download/value-analysis-Carbon-20101202-beta2.pdf" hreflang="en">Carbon version of the value analysis manual</a> (it's section 2.5.2 there).</p> -<p>Rather than repeating here this addition to the tutorial I want to reiterate on the notion of derived analysis. Although the outputs and dependencies computations rely on the results of the value analysis they do not require you to check each of the alarms generated by the value analysis.</p> -<p>When a sequence of function calls has dependencies (as computed by option <code>-deps</code>) of <code>hash[0..7] FROM msg[0..79]; ONE[bits 0 to 7] (and SELF)</code> it means that if all goes well array <code>hash</code> after the calls has been computed from array <code>msg</code> and variable <code>ONE</code>. Computing and taking advantage of this information is orthogonal to the verification that all always goes well during the execution of these function calls (which is done by making sure that the value analysis emits no alarm or by checking the emitted alarms with alternative techniques).</p> <p>In more difficult cases the latter may require a combination of human reflexion and of hours of computer time. But functional dependencies can be useful even when based on the results of a simpler faster value analysis.</p> {% endraw %} diff --git a/_posts/2011-01-11-Seven-errors-game.html b/_posts/2011-01-11-Seven-errors-game.html index 1565eb804efc347b883915005435ac60197f2654..88aa429542fe32e5a3a5931511da0858c46d0bd3 100644 --- a/_posts/2011-01-11-Seven-errors-game.html +++ b/_posts/2011-01-11-Seven-errors-game.html @@ -37,35 +37,5 @@ summary: <p>Behold the new graphical user interface that Boris and I have spent the afternoon on (pay attention: the difference is subtle):</p> <p><br /> </p> -<p><img src="/assets/img/blog/imported-posts/after.png" alt="After" title="After janv. 2011" /></p> - <p>If you have seen the basic presentation of the value analysis, you may remember the following function.</p> -<p><br /> -</p> -<pre>void abs(int y) -{ - if (y >= 0) - { - r = y; - return; - } - else - { - r = -y; - return; - } -} -</pre> -<p><br /> -</p> -<p>\Why the two ugly <code>return;</code> statements in a function that needs none?" I almost hear you ask. Here is why: without these spurious <code>return;</code> statements you may need to explain where the <code>{2; 3; }</code> set comes from in the screenshot below.</p> -<p><br /> -</p> -<p><img src="/assets/img/blog/imported-posts/before.png" alt="Before" title="Before janv. 2011" /></p> -<p><br /> -</p> -<p>In the screenshot the user has clicked on variable <code>r</code> in the then branch of the if. The bottom panel displays information about the value of <code>r</code> before the assignment and also the possible values of <code>r</code> at the beginning of the successor of the assignment. The intention is to let the user see the effect the statement has on <code>x</code> but in this case this only produces confusion.</p> -<p>Behold the new graphical user interface that Boris and I have spent the afternoon on (pay attention: the difference is subtle):</p> -<p><br /> -</p> <p><img src="/assets/img/blog/imported-posts/after.png" alt="After" title="After janv. 2011" /></p> {% endraw %} diff --git a/_posts/2011-01-13-Why-dont-you-verify-the-entire-Internet-.html b/_posts/2011-01-13-Why-dont-you-verify-the-entire-Internet-.html index cc718c8074141d14c8b669bd1a1bce48e0f994a8..db334425759b0374f6d86abab9378526878e75bc 100644 --- a/_posts/2011-01-13-Why-dont-you-verify-the-entire-Internet-.html +++ b/_posts/2011-01-13-Why-dont-you-verify-the-entire-Internet-.html @@ -15,13 +15,5 @@ summary: </blockquote> <p>Surprisingly often though the reason I do not start a new experiment is not that Frama-C's value analysis couldn't handle the source code but that I couldn't. Functional C code is often ugly — for reasons that given the language and the objectives are unavoidable. The program tries to work as a shared library; it want to compile on 1995's version of DJGPP for MS-DOS; ...</p> <p>Yesterday at 17:00 I was discovering another gem of simple and efficient code comparable in cleanliness to Skein. And not to boast or anything simply as a measure of how efficient one can be when equipped with the right tool today at the same time I was reporting a tiny flaw in said library that has since been semi-acknowledged by its author.</p> -<p>I'd start a new thread but I haven't finished presenting the analysis of Skein.</p> - <p>... or at least the C codebase available on there, anyway?</p> -<p>Don't be fooled by the positive examples presented here and there. Verifying arbitrary programs is still arbitrarily difficult. There is some cherry-picking going on in the results we, and others, present.</p> -<p>In the case of Frama-C's value analysis, dynamic allocation is one issue. This analysis was never intended to analyze programs that use it. I wonder if it would be possible to get interesting results by modelizing the heap as a single large array whose contents are voluntarily kept imprecise. But I never tried, if that tells you how optimistic I am.</p> -<blockquote><p>Aside: this is purely a limitation of the value analysis plug-in, not of the framework. See for instance <a href="http://www.liafa.jussieu.fr/~sighirea/celia/examples.html" hreflang="en">this plug-in</a> for an attempt that we are eager to hear more about to handle C programs with dynamic allocation.</p> -</blockquote> -<p>Surprisingly often though the reason I do not start a new experiment is not that Frama-C's value analysis couldn't handle the source code but that I couldn't. Functional C code is often ugly — for reasons that given the language and the objectives are unavoidable. The program tries to work as a shared library; it want to compile on 1995's version of DJGPP for MS-DOS; ...</p> -<p>Yesterday at 17:00 I was discovering another gem of simple and efficient code comparable in cleanliness to Skein. And not to boast or anything simply as a measure of how efficient one can be when equipped with the right tool today at the same time I was reporting a tiny flaw in said library that has since been semi-acknowledged by its author.</p> <p>I'd start a new thread but I haven't finished presenting the analysis of Skein.</p> {% endraw %} diff --git a/_posts/2011-01-22-Verifying-numerical-precision-with-Frama-Cs-value-analysis.html b/_posts/2011-01-22-Verifying-numerical-precision-with-Frama-Cs-value-analysis.html index 1884eda13f36d47bb2dfb7a10e8f38457c27f56d..797ffd539eb062b828518be4f2764b32a271fe77 100644 --- a/_posts/2011-01-22-Verifying-numerical-precision-with-Frama-Cs-value-analysis.html +++ b/_posts/2011-01-22-Verifying-numerical-precision-with-Frama-Cs-value-analysis.html @@ -130,128 +130,5 @@ This part of the input interval is the best case. Looking at the worst case:</p> </pre> <p>It is less regular than previously and being hand-written (well copy-pasted) the risk of an error in the annotation is especially high. But one of the very important lines in the output is "cos_taylor.c:4:[value] Assertion got status valid". This means that the intervals I wrote for <code>rad</code> when taken together cover completely the input interval specified by the <code>requires</code> clause. So if I mistyped and did not divide exactly as I intended it does not matter: the reasoning is still correct.</p> <p>The other important result is of course that this new sub-division shows that no double result is further than <code>0.0492</code> from its corresponding real result. In fact the generated log contains the input interval and could be used to check the double result directly against a reference function. If the reference function is known to be decreasing on [0 .. Ï€] the image of each input sub-interval through the reference function can be computed and a bound can be given on the difference between the reference function and the C function as approximated and computed using floating-point.</p> -<p>One last hint: interpreting ACSL formulas is a difficult exercise for the value analysis. If you omit the first and last bounds that is if you write <code>rad <= 1. / 16. || ...</code> instead of <code>0.0 <= rad <= 1. / 16. || ...</code> you make it easier for the analyzer to recognize that the sub-intervals cover completely the input interval from the pre-condition. Otherwise it may fail. It fails for instance if the bound is 0.0 for good reasons that are difficult to circumvent: the neighborhood of zero in floating-point is to use an expression made popular a couple of years ago a bag of hurt.</p> - <p>Frama-C's value analysis wasn't aimed at verifying numerical precision of C functions when it was conceived. There already was <a href="http://www-list.cea.fr/labos/gb/LSL/fluctuat/index.html" hreflang="en">a specialized project for this purpose</a>.</p> -<p>However the value analysis needed to handle floating-point computations <strong>correctly</strong> (that is without omitting any of the possible behaviors the function can have at run-time) in order to be generally correct. Some industrial users at the same time wanted floating-point values to be handled more precisely than the "always unknown" placeholder used in very early versions. Floating-point computations are notoriously underspecified in C so "handling floating-point computations correctly" became something of a journey with gradual improvements in each release since Beryllium. The goal was only reached in the last release (missing support for the single-precision <code>float</code> type was the last known limitation and that was removed in Carbon).</p> -<p>Besides in the value analysis the primary solution to work around issues is <strong>case analysis</strong>. Again the underlying algorithms were there from the start but they have been continuously refined until the Carbon release. For a numerical function case analysis typically means subdividing the definition domain of the function in small sub-intervals on which interval arithmetic is as precise as the sub-interval is narrow.</p> -<p>Interestingly the combination of these different elements means that the value analysis can be used to verify the numerical precision of a C program in a context where the required precision is not too high but it's absolutely vital that it is uniformly reached on the entire definition interval of the program.</p> -<p>Enough chit-chat. Here is a C function:</p> -<pre>/*@ requires 0.0 <= rad <= 1.58 ; */ -double cos_taylor(double rad) -{ - double sq = rad * rad; - double r = 1. + sq * (sq * (sq * (-1. / 720.) + (1. / 24.)) - 0.5 ); - return r; -} -</pre> -<p>This C function is part of an application that needs at some point to compute a cosine. The designer decided that a Taylor development was the best way to implement this cosine and determined that the function x ↦ 1 - x^2/2 + x^4/4! - x^6/6! was a good enough approximation for an algorithm that can be implemented with only 4 multiplications.</p> -<p>One important detail is that the aforementioned study was about a mathematical function mapping reals to reals through use of real operations. The C implementation on the other hand uses <code>double</code> variables and <code>double</code> operations. -Verifying that the result computed by <code>cos_taylor</code> is never far from the result that would have been computed by the same program using real numbers can be one link in the chain of trust between conceived and realized system.</p> -<p>The usual mathematical methods for studying functions do not work well on the floating-point version. For instance the C function <code>cos_taylor</code> <strong>may</strong> be decreasing on [0 .. 1.58] but it's absolutely not obvious that it is. Floating-point computations <a href="http://www.johndcook.com/blog/2009/04/06/numbers-are-a-leaky-abstraction/" hreflang="en">sometimes behave strangely</a> and it is not easy for the non-specialist to tell whether this happens for this particular function.</p> -<p>Analyzing the above function as-is does not tell us much:</p> -<pre>frama-c -val cos_taylor.c -main cos_taylor -... -[value] Values for function cos_taylor: - sq ∈ [-0. .. 2.4964] - r ∈ [-0.2482 .. 1.] -</pre> -<p>The option <code>-all-rounding-modes</code> makes the analyzer take into account all compilations and executions allowed by the C standard (whereas without this option assumptions are made about the architecture and FPU rounding mode). For a small function like this the option can be expected to have limited influence:</p> -<pre>frama-c -val cos_taylor.c -main cos_taylor -all-rounding-modes -... -[value] Values for function cos_taylor: - sq ∈ [-0. .. 2.4964] - r ∈ [-0.2482 .. 1.] -</pre> -<p>The results the program would give <strong>using real numbers instead of floating-point ones</strong> are also guaranteed to be in the variation intervals computed with option -all-rounding-modes. We can use this guarantee to our advantage: to verify that the one is close to the other let us just make sure that they are both inside the same narrow interval the interval computed by option -all-rounding-modes.</p> -<p>If we were to use only the above results in our reasoning it would go like this: on the input interval [0.0..1.58] the result computed by function <code>cos_taylor</code> using real numbers always is within [-0.2482 .. 1.] whereas the result computed with floating-point is always within [-0.2482 .. 1.]. The absolute error between the two is therefore never more than 1.2482. -For a cosine function implementation this is an unsatisfying precision result.</p> -<p>However we can make the analysis more precise by splitting the input interval in small sub-intervals:</p> -<pre>/*@ requires 0.0 <= rad <= 1.58 ; */ -double cos_taylor(double rad) -{ - /*@ assert rad <= 1. / 16. || - 1. / 16. <= rad <= 2. / 16. || - 2. / 16. <= rad <= 3. / 16. || - 3. / 16. <= rad <= 4. / 16. || - 4. / 16. <= rad <= 5. / 16. || - 5. / 16. <= rad <= 6. / 16. || - 6. / 16. <= rad <= 7. / 16. || - 7. / 16. <= rad <= 8. / 16. || - 8. / 16. <= rad <= 9. / 16. || - 9. / 16. <= rad <= 10. / 16. || - 10. / 16. <= rad <= 11. / 16. || - 11. / 16. <= rad <= 12. / 16. || - 12. / 16. <= rad <= 13. / 16. || - 13. / 16. <= rad <= 14. / 16. || - 14. / 16. <= rad <= 15. / 16. || - 15. / 16. <= rad <= 16. / 16. || - 16. / 16. <= rad <= 17. / 16. || - 17. / 16. <= rad <= 18. / 16. || - 18. / 16. <= rad <= 19. / 16. || - 19. / 16. <= rad <= 20. / 16. || - 20. / 16. <= rad <= 21. / 16. || - 21. / 16. <= rad <= 22. / 16. || - 22. / 16. <= rad <= 23. / 16. || - 23. / 16. <= rad <= 24. / 16. || - 24. / 16. <= rad <= 25. / 16. || - 25. / 16. <= rad <= 26. / 16. || - 26. / 16. <= rad ; */ - double sq = rad * rad; - double r = 1. + sq * (sq * (sq * (-1. / 720.) + (1. / 24.)) - 0.5 ); - return r; -} -</pre> -<pre>frama-c -val cos_taylor.c -main cos_taylor -all-rounding-modes -slevel 100 -... -[value] Values for function cos_taylor: - sq ∈ [-0. .. 2.4964] - r ∈ [-0.0153848312717 .. 1.] -</pre> -<p>The result interval for <code>r</code> is slightly improved but the previous reasoning still isn't satisfactory even with the improved interval. -The synthetic results displayed at the end of the analysis hide the information that would be useful to us that is how close real and double results are in each of the small 1/16th-width intervals.</p> -<p>We can make the value analysis display these intermediate results by inserting the following line in the code between the computation of <code>r</code> and the <code>return</code> statement.</p> -<pre>Frama_C_show_each_r(rad r); -</pre> -<p>Here is one line of the generated information:</p> -<pre>[value] Called Frama_C_show_each_r([-0. .. 0.0625] [0.998046875 .. 1.]) -</pre> -<p>Now we're talking! This line means that for the input interval [-0. .. 0.0625] both the real and the double results are in [0.998046875 .. 1.] and therefore the absolute difference between the two can never be more than 0.002. -This part of the input interval is the best case. Looking at the worst case:</p> -<pre>[value] Called Frama_C_show_each_r([1.5 .. 1.5625] - [-0.0104477405548 .. 0.0867156982422]) -</pre> -<p>The bound on the difference between real and double results we can deduce in the interval [1.5 .. 1.5625] is slightly less than 0.1. That's better than before but probably still not satisfactory.</p> -<p>We can and will refine the division to improve this bound. But before that here is my chance to document two convenient options I never had had the chance to talk about.</p> -<p>The first useful option is <code>-float-relative</code> which changes the format for displaying intervals of floating-point values. Instead of lower and upper bound this option displays lower bound and width which is very convenient when the width is the only thing we are interested in. When this option is set the aforementioned intervals for <code>r</code> become <code>[0.998046875 ++ 0.001953125]</code> and <code>[-0.0104477405548 ++ 0.097163438797]</code> directly giving us the bounds 0.001953125 and 0.097163438797.</p> -<p>There are some expressions for which naive interval propagation naturally introduces approximation. The simplest example is the statement <code>y = x*x;</code> where <code>x</code> is known to be in the interval [-10. .. 10.]. Naive interval propagation computes the interval [-100. .. 100.] for <code>y</code> when <code>y</code> could have been inferred to be positive with only the available information. The function <code>cos_taylor</code> exhibits the same behavior: this is why the computed synthetic interval for <code>r</code> was improved when we used option <code>-slevel</code> together with an annotation to split the input interval.</p> -<p>The second previously undocumented option automatically detects expressions that look like they could benefit from subdivisions and applies the subdivisions without need for user annotations. It is compatible with option <code>-slevel</code>: the effects of the two options combine for even greater precision. Because the subdivisions are limited to the scope of the expression this option does not cause combinatorial explosion the way <code>-slevel</code> can. The precision gains are limited but should be considered as a bonus obtained only at the cost of CPU time. This option's name is <code>-subdivide-float-var</code> and it takes an integer argument that represents how much additional CPU time you are willing to spend trying to improve precision. Like what happens for <code>-slevel</code> the CPU time is not consumed if the circumstances in which it looks like it could be used usefully do not occur.</p> -<p>Let's try it:</p> -<pre>frama-c -val cos_taylor.c -main cos_taylor -all-rounding-modes -slevel 100 -float-relative -subdivide-float-var 50 -... -[value] Called Frama_C_show_each_r([-0. ++ 0.0625] - [0.9980475107 ++ 0.00195248929991]) -... -[value] Called Frama_C_show_each_r([1.5 ++ 0.0625] - [0.0074385681914 ++ 0.0626786193086]) -... -</pre> -<p>Here we are lucky and the effect of this option is most sensitive where it matters: the width of the worst case result sub-interval is diminished by more than 33%.</p> -<p>Let us pretend for the sake of the argument that a difference of 0.05 between real and double computations is acceptable: we only need to make sub-divisions narrower for the intervals that do not reach this objective. I tried it and ended up with the assertion below.</p> -<pre> /*@ assert rad <= 1. / 16. || - 1. / 16. <= rad <= 2. / 16. || - 2. / 16. <= rad <= 3. / 16. || - ... - 13. / 16. <= rad <= 14. / 16. || - 14. / 16. <= rad <= 15. / 16. || - 30. / 32. <= rad <= 31. / 32. || - 31. / 32. <= rad <= 32. / 32. || - 32. / 32. <= rad <= 33. / 32. || - ... - 50. / 32. <= rad <= 51. / 32. || - 51. / 32. <= rad <= 52. / 32. || - 26. / 16. <= rad ; */ -</pre> -<p>It is less regular than previously and being hand-written (well copy-pasted) the risk of an error in the annotation is especially high. But one of the very important lines in the output is "cos_taylor.c:4:[value] Assertion got status valid". This means that the intervals I wrote for <code>rad</code> when taken together cover completely the input interval specified by the <code>requires</code> clause. So if I mistyped and did not divide exactly as I intended it does not matter: the reasoning is still correct.</p> -<p>The other important result is of course that this new sub-division shows that no double result is further than <code>0.0492</code> from its corresponding real result. In fact the generated log contains the input interval and could be used to check the double result directly against a reference function. If the reference function is known to be decreasing on [0 .. Ï€] the image of each input sub-interval through the reference function can be computed and a bound can be given on the difference between the reference function and the C function as approximated and computed using floating-point.</p> <p>One last hint: interpreting ACSL formulas is a difficult exercise for the value analysis. If you omit the first and last bounds that is if you write <code>rad <= 1. / 16. || ...</code> instead of <code>0.0 <= rad <= 1. / 16. || ...</code> you make it easier for the analyzer to recognize that the sub-intervals cover completely the input interval from the pre-condition. Otherwise it may fail. It fails for instance if the bound is 0.0 for good reasons that are difficult to circumvent: the neighborhood of zero in floating-point is to use an expression made popular a couple of years ago a bag of hurt.</p> {% endraw %} diff --git a/_posts/2011-01-27-On-memcpy-part-1-the-source-code-approach.html b/_posts/2011-01-27-On-memcpy-part-1-the-source-code-approach.html index 37e974fe67c51f334ed26404143439fa45b7080d..d6b4c3f93dcdbd754aadda767ba809c4f6300d9e 100644 --- a/_posts/2011-01-27-On-memcpy-part-1-the-source-code-approach.html +++ b/_posts/2011-01-27-On-memcpy-part-1-the-source-code-approach.html @@ -187,185 +187,5 @@ memcpy(void *dst void *src size_t length) d ∈ {{ garbled mix of &{a; b; } (origin: Merge {mfast.c:32; }) }} or UNINITIALIZED </pre> -<p>In short the modified <code>memcpy</code> voluntarily loses information so that finding the loop's fixpoint becomes straightforward. The analysis of the original <code>memcpy</code> has to discover the fixpoint by gradually losing information and seeing what values stick. In fact the process of discovering the fixpoint may overshoot and end up <strong>less</strong> precise as well as slower than the improved <code>memcpy</code>. For imprecise analyses of programs that use <code>memcpy</code> when the user is interested in the verification of the program itself rather than <code>memcpy</code> it is recommended to use the replacement version.</p> - <p><code>memcpy()</code> is one of the few functions standardized as part of C itself instead of an additional API. But that's not what makes it interesting from a static analysis point of view. I think what makes it interesting is that it is used often, and often for tasks that can be described in high-level terms, whereas its implementations range <strong>from the low-level to the horribly low-level</strong>.</p> -<p>Here is a typical <code>memcpy</code> implementation:</p> -<pre>void * -memcpy(void *dst, void *src, size_t length) -{ - int i; - unsigned char *dp = dst; - unsigned char *sp = src; - for (i=0; i<length; i++) - *dp++ = *sp++; - return dst; -} -</pre> -<p>And here are snippets of an analysis context that uses it (download <a href="/assets/img/blog/imported-posts/m.c">the entire file</a>):</p> -<pre>struct S { int *p; int *q; int i; double d; int j; }; -... - struct S s d; - s.p = &a; - s.q = Frama_C_nondet_ptr(&a &b); - s.i = Frama_C_interval(17 42); - s.j = 456; - s.d = Frama_C_double_interval(3.0 7.0); - memcpy(&d &s sizeof(struct S)); -</pre> -<p>Analyzing with <code>frama-c -val .../builtin.c m.c</code> produces the following information about the contents of <code>s</code> which is exactly what we could have expected:</p> -<pre> s.p ∈ {{ &a ;}} - .q ∈ {{ &a ; &b ;}} - .i ∈ [17..42] - .d ∈ [3. .. 7.] - .j ∈ {456; } -</pre> -<p>On the other hand the information for <code>d</code> is much less precise:</p> -<pre> d ∈ {{ garbled mix of &{a; b; } (origin: Misaligned {m.c:11; }) }} or UNINITIALIZED -</pre> -<p>Each field of <code>d</code> is only guaranteed to contain a value that was not computed from base addresses other than <code>&a</code> and <code>&b</code>. The fields of <code>d</code> are not even guaranteed to have been initialized. An ideally precise analysis would tell us that <code>d</code> contains the same values as those displayed for <code>s</code>.</p> -<p>Side remark: if you do run the analysis at home you can ignore the messages about imprecise values for the moment. These are not alarms to act upon but simply informational messages to help trace when the value analysis is imprecise on large programs where the imprecision starts.</p> -<p>If you have been reading this blog from the beginning perhaps as a continuation from the <a href="http://frama-c.com/download/frama-c-value-analysis.pdf" hreflang="en">tutorial</a> you may have noticed by now that whenever the value analysis is not precise enough the first thing to try is option <code>-slevel</code>.</p> -<p><code>frama-c -val .../builtin.c m.c -slevel 100</code></p> -<pre> s.p ∈ {{ &a ;}} - .q ∈ {{ &a ; &b ;}} - .i ∈ [17..42] - .d ∈ [3. .. 7.] - .j ∈ {456; } - d.p ∈ {{ &a ;}} - .q[bits 0 to 7]# ∈ {{ &a ; &b ;}} misaligned 0%32 - .q[bits 8 to 15]# ∈ {{ &a ; &b ;}} misaligned 0%32 - .q[bits 16 to 23]# ∈ {{ &a ; &b ;}} misaligned 0%32 - .q[bits 24 to 31]# ∈ {{ &a ; &b ;}} misaligned 0%32 - .i[bits 0 to 7]# ∈ [17..42] misaligned 0%32 - .i[bits 8 to 15]# ∈ [17..42] misaligned 0%32 - .i[bits 16 to 23]# ∈ [17..42] misaligned 0%32 - .i[bits 24 to 31]# ∈ [17..42] misaligned 0%32 - .d[bits 0 to 7]# ∈ [3. .. 7.] misaligned 32%64 - .d[bits 8 to 15]# ∈ [3. .. 7.] misaligned 32%64 - .d[bits 16 to 23]# ∈ [3. .. 7.] misaligned 32%64 - .d[bits 24 to 31]# ∈ [3. .. 7.] misaligned 32%64 - .d[bits 32 to 39]# ∈ [3. .. 7.] misaligned 32%64 - .d[bits 40 to 47]# ∈ [3. .. 7.] misaligned 32%64 - .d[bits 48 to 55]# ∈ [3. .. 7.] misaligned 32%64 - .d[bits 56 to 63]# ∈ [3. .. 7.] misaligned 32%64 - .j ∈ {456; } -</pre> -<p>Good news: all fields of <code>d</code> are now guaranteed to be initialized. -In addition the information available for each field is more precise than before. -The information about fields <code>.j</code> and <code>.p</code> has been perfectly preserved during the <code>memcpy</code> from <code>s</code> to <code>d</code> whereas fields <code>.q</code> <code>.i</code> and <code>.d</code> are only known to contain several 8-bit slices of values. This is what the "misaligned ..." part of each line mean.</p> -<p>For instance line ".i[bits 0 to 7]# ∈ [17..42] misaligned 0%32" uses this mention in order to avoid giving the impression that bits 0 to 7 of field <code>.i</code> contain [17..42]. Instead there was a 32-bit value [17..42] somewhere in memory and a 8-bit slice of that value was copied to the first 8 bits or <code>.i</code>.</p> -<p>The fact that all 4 (respectively 8) slices of each field are followed by the same "misaligned" mention with the same numerical values mean that all slices for that field <strong>could</strong> come from the same value and have been copied in order with the first source slice going to the first destination slice ... However the value analysis is not able to guarantee that this is what happened. It has lost the information that bits 0 to 7 and bits 8 to 15 of <code>.i</code> come from the same value which is why the contents of <code>.i</code> are printed thus instead of just displaying that <code>.i</code> is [17..42].</p> -<p>It is important not to stitch together say bit 0 to 7 of <code>{{ &a ; &b ;}} misaligned 0%32</code> and bit 8 to 31 of <code>{{ &a ; &b ;}} misaligned 0%32</code> into <code>{{ &a ; &b ;}}</code> when you do not know that they come from the same value. Consider the example below:</p> -<pre> int a b; - int *p = Frama_C_nondet_ptr(&a &b); - int *q = Frama_C_nondet_ptr(&a &b); - *(char*)&p = *(char*)&q; -</pre> -<p>After analyzing this piece of code the value analysis predicts for <code>p</code>:</p> -<pre> p[bits 0 to 7]# ∈ {{ &a ; &b ;}} misaligned 0%32 - [bits 8 to 31]# ∈ {{ &a ; &b ;}} misaligned 0%32 -</pre> -<p>It would be incorrect to predict that <code>p</code> contains {{ &a ; &b ;}} here because the first call to <code>Frama_C_nondet_ptr</code> may return <code>&a</code> while the second one returns <code>&b</code>. Without the information that the two slices originate from the same value it is incorrect to stitch them together as if they did.</p> -<p>The value analysis does better when there is only one possible concrete value inside the set at hand. Fields <code>.p</code> and <code>.j</code> in the original program although they were copied char by char could be reconstituted because the value analysis knows that there is only one possible way to be {{ &a ; }} (or { 456; }) which implies that properly ordered slices when put side by side can only rebuild &a.</p> -<p>This <code>memcpy</code> if it is called with large values of <code>length</code> in the program and the program is analyzed with the <code>-slevel</code> option may occupy a large fraction of the analysis time. This is because although the analyzer does not keep the information that the small bites of values come from the same value which it could use it keeps the information that there exist plenty of equalities between source and destination chars — and does not use them. This should be considered a known issue with an open-ended fix date.</p> -<p>And this performance issue naturally brings up another performance issue with which it is suitable to conclude this first part of the <code>memcpy</code> discussion. At the other end of the spectrum what if the user finds the analysis of <code>memcpy</code> <strong>too slow</strong> even without <code>-slevel</code> (or with <code>-slevel-function memcpy:0</code> to force a rough analysis of <code>memcpy</code>)?</p> -<p>To this user we say: replace your <code>memcpy</code> function by the one below.</p> -<pre>void * -memcpy(void *dst void *src size_t length) -{ - unsigned char *dp = dst; - unsigned char *sp = src; - for (;Frama_C_interval(0 1);) - { - dp[Frama_C_interval(0 length-1)] = sp[Frama_C_interval(0 length-1)]; - } - return dst; -} -</pre> -<p>While it it may not be immediately clear why one would want to replace the original executable <code>memcpy</code> with this non-executable one we can at least notice that all the executions of the original <code>memcpy</code> are captured by this one. At each iteration of the original <code>memcpy</code> the condition is either 0 or 1 and one of the characters <code>sp[Frama_C_interval(0 length-1)]</code> is copied to <code>dp[Frama_C_interval(0 length-1)]</code>.</p> -<p>Now to investigate why analyzing this function is faster let us look at the states propagated by the analyzer when analyzing the <code>for</code> loop of the original <code>memcpy</code>. It starts the loop with:</p> -<pre> i ∈ {0; } - dp ∈ {{ &d ;}} - sp ∈ {{ &s ;}} - d completely uninitialized -</pre> -<p>Here is the sequence of states at the point after another char has been copied before <code>dp</code> <code>sp</code> and <code>i</code> are incremented:</p> -<pre> i ∈ {0; } - dp ∈ {{ &d ;}} - sp ∈ {{ &s ;}} - d.p[bits 0 to 7]# ∈ {{ &a ;}} misaligned 0%32 - {.p[bits 8 to 31]; .q; .i; .d; .j; } ∈ UNINITIALIZED - i ∈ {0; 1; } - dp ∈ {{ &d + {0; 1; } ;}} - sp ∈ {{ &s + {0; 1; } ;}} - d.p[bits 0 to 15] ∈ - {{ garbled mix of &{a; } (origin: Merge {m.c:12; }) }} or UNINITIALIZED - {.p[bits 16 to 31]; .q; .i; .d; .j; } ∈ UNINITIALIZED - i ∈ {0; 1; 2; } - dp ∈ {{ &d + {0; 1; 2; } ;}} - sp ∈ {{ &s + {0; 1; 2; } ;}} - d.p[bits 0 to 23] ∈ - {{ garbled mix of &{a; } (origin: Merge {m.c:12; }) }} or UNINITIALIZED - {.p[bits 24 to 31]; .q; .i; .d; .j; } ∈ UNINITIALIZED - i ∈ {0; 1; 2; 3; } - dp ∈ {{ &d + {0; 1; 2; 3; } ;}} - sp ∈ {{ &s + {0; 1; 2; 3; } ;}} - d.p ∈ - {{ garbled mix of &{a; } (origin: Merge {m.c:12; }) }} or UNINITIALIZED - {.q; .i; .d; .j; } ∈ UNINITIALIZED - i ∈ {0; 1; 2; 3; 4; } - dp ∈ {{ &d + {0; 1; 2; 3; 4; } ;}} - sp ∈ {{ &s + {0; 1; 2; 3; 4; } ;}} - d{.p; .q[bits 0 to 7]; } ∈ - {{ garbled mix of &{a; b; } (origin: Merge {m.c:12; }) }} or UNINITIALIZED - {.q[bits 8 to 31]; .i; .d; .j; } ∈ UNINITIALIZED - i ∈ [0..15] - dp ∈ {{ &d + {0; 1; 2; 3; 4; 5; } ;}} - sp ∈ {{ &s + {0; 1; 2; 3; 4; 5; } ;}} - d{.p; .q[bits 0 to 15]; } ∈ - {{ garbled mix of &{a; b; } (origin: Merge {m.c:12; }) }} or UNINITIALIZED - {.q[bits 16 to 31]; .i; .d; .j; } ∈ UNINITIALIZED - i ∈ [0..16] - dp ∈ {{ &d + {0; 1; 2; 3; 4; 5; 6; } ;}} - sp ∈ {{ &s + {0; 1; 2; 3; 4; 5; 6; } ;}} - d{.p; .q[bits 0 to 23]; } ∈ - {{ garbled mix of &{a; b; } (origin: Merge {m.c:12; }) }} or UNINITIALIZED - {.q[bits 24 to 31]; .i; .d; .j; } ∈ UNINITIALIZED - i ∈ [0..23] - dp ∈ {{ &d + [0..7] ;}} - sp ∈ {{ &s + [0..7] ;}} - d{.p; .q; } ∈ - {{ garbled mix of &{a; b; } (origin: Merge {m.c:12; }) }} or UNINITIALIZED - {.i; .d; .j; } ∈ UNINITIALIZED - i ∈ [0..23] - dp ∈ {{ &d + [0..8] ;}} - sp ∈ {{ &s + [0..8] ;}} - d{.p; .q; .i[bits 0 to 7]; } ∈ - {{ garbled mix of &{a; b; } (origin: Merge {m.c:12; }) }} or UNINITIALIZED - {.i[bits 8 to 31]; .d; .j; } ∈ UNINITIALIZED - i ∈ [0..23] - dp ∈ {{ &d + [0..15] ;}} - sp ∈ {{ &s + [0..15] ;}} - d{.p; .q; .i; .d[bits 0 to 31]; } ∈ - {{ garbled mix of &{a; b; } (origin: Merge {m.c:12; }) }} or UNINITIALIZED - {.d[bits 32 to 63]; .j; } ∈ UNINITIALIZED - i ∈ [0..23] - dp ∈ {{ &d + [0..16] ;}} - sp ∈ {{ &s + [0..16] ;}} - d{.p; .q; .i; .d[bits 0 to 39]; } ∈ - {{ garbled mix of &{a; b; } (origin: Merge {m.c:12; }) }} or UNINITIALIZED - {.d[bits 40 to 63]; .j; } ∈ UNINITIALIZED - i ∈ [0..23] - dp ∈ {{ &d + [0..23] ;}} - sp ∈ {{ &s + [0..23] ;}} - d ∈ - {{ garbled mix of &{a; b; } (origin: Merge {m.c:12; }) }} or UNINITIALIZED -</pre> -<p>In contrast with this long sequence of abstract states going through the same point of the <code>for</code> loop until a fixpoint is finally found the analysis of the modified <code>memcpy</code> reaches the same abstract state in one iteration realizes that it is a fixpoint and goes on with its life:</p> -<pre> dp ∈ {{ &d ;}} - sp ∈ {{ &s ;}} - d ∈ - {{ garbled mix of &{a; b; } (origin: Merge {mfast.c:32; }) }} or UNINITIALIZED -</pre> <p>In short the modified <code>memcpy</code> voluntarily loses information so that finding the loop's fixpoint becomes straightforward. The analysis of the original <code>memcpy</code> has to discover the fixpoint by gradually losing information and seeing what values stick. In fact the process of discovering the fixpoint may overshoot and end up <strong>less</strong> precise as well as slower than the improved <code>memcpy</code>. For imprecise analyses of programs that use <code>memcpy</code> when the user is interested in the verification of the program itself rather than <code>memcpy</code> it is recommended to use the replacement version.</p> {% endraw %} diff --git a/_posts/2011-01-31-On-memcpy-part-2-the-OCaml-source-code-approach.html b/_posts/2011-01-31-On-memcpy-part-2-the-OCaml-source-code-approach.html index e7e4c51b1ae212cb235f856e2ee45eb895ae8f8b..eb7cc73a348669730095df39012fd721e6f97e96 100644 --- a/_posts/2011-01-31-On-memcpy-part-2-the-OCaml-source-code-approach.html +++ b/_posts/2011-01-31-On-memcpy-part-2-the-OCaml-source-code-approach.html @@ -62,60 +62,5 @@ user 0m0.402s <blockquote><p>Note: if the 78800-bit number explanation seems terribly complicated do not worry there will be a better explanation for this issue in a future post. We just need another new feature in order to be able to show you.</p> </blockquote> <p>In conclusion not everyone may want a Formula One car. But <code>Frama_C_memcpy</code> should at least work for completely unrolled deterministic programs where it can speed up analysis quite a bit compared to the interpretation of a C memcpy.</p> -<p>Thanks to Julien for help with motorsports metaphors and to Boris for help in improving <code>Frama_C_memcpy</code> (it used to be worse).</p> - <p>When picking up the title for <a href="/index.php?post/2011/01/27/On-memcpy-1" hreflang="en">the previous post on function memcpy</a> I anticipated this second part would describe the <code>Frama_C_memcpy</code> built-in function. The subtitle "part 1: the source code approach" seemed a good idea since the first part was about using C source code to tell the analyzer what this function <code>memcpy</code> it often encounters is.</p> -<p>I did not think further and did not realize that I would spend this sequel post explaining that a built-in function is <strong>an OCaml function that directly transforms an abstract state into another abstract state</strong> without going through the tedious instruction-by-instruction interpretation of C code. So this second post is still about source code.</p> -<p>It is not source code that it is recommended or even documented how to write yourself. But it is a convenient way for value analysis experts to introduce certain new features.</p> -<p><strong>What new features?</strong> Smoking hot blazing fast new features.</p> -<p>Also features that work completely right neither the first nor the second time. The <strong>Formula One</strong> of features if you will. In fact you could be forgiven for calling them Virgin Racing features although I prefer to think of them as Ferrari features.</p> -<p>As just stated builtins are about using OCaml functions to describe the effect of an unavailable C function. For instance calls to <code>Frama_C_memcpy(d s l)</code> are interpreted with an OCaml function that in a single step copies a slice of memory of length <code>l*8</code> bits from <code>s</code> to <code>d</code>. And it is fast. Behold:</p> -<pre>char s[10000] d[10000]; -main() -{ - // Make problem representative - for (int i=0; i<100; i++) - s[100*i] = i; - // Time one or the other - // c_memcpy(d s 10000); - Frama_C_memcpy(d s 10000); - // Check that d contains the right thing - Frama_C_dump_each(); - return 0; -} -</pre> -<p><a href="/assets/img/blog/imported-posts/memcpytest.c">(download the entire program)</a></p> -<p>Using the C version of <code>memcpy</code> and sufficient unrolling you get the expected contents for <code>d</code>:</p> -<pre>$ time bin/toplevel.opt -val -slevel 20000 memcpytest.c -no-results -... - d[0..99] ∈ {0; } - [100] ∈ {1; } - [101..199] ∈ {0; } - [200] ∈ {2; } - ... -user 0m23.155s -</pre> -<p>Using the <code>Frama_C_memcpy</code> built-in you get the same precise result for <code>d</code>:</p> -<pre>$ time bin/toplevel.opt -val -slevel 20000 memcpytest.c -no-results -... - d[0..99] ∈ {0; } - [100] ∈ {1; } - [101..199] ∈ {0; } - [200] ∈ {2; } - ... -user 0m0.402s -</pre> -<p>You also get nearly 23 seconds of your life back.</p> -<p>So what are the things that can go wrong with a builtin replacement function?</p> -<ol> -<li>If the C code that is not analyzed would have caused an alarm to be emitted the built-in should emit that alarm too or at the very least be provided with a header file that offers an ACSL pre-condition along with a prototype for the builtin. Both alternatives work but it is easy to forget to do either.</li> -<li>All cases of imprecise arguments should be handled. Support for an imprecise length was added recently. Very imprecise source or destination pointers may still cause the analysis to abort (it is being done and I am not sure where we were the last time we were working on this).</li> -<li>The builtin function calls the value analysis' internal functions in contexts that differ from the usual well tested circumstances occurring during the analysis of normal C programs. Strange behaviors or bugs may be uncovered by the user. As an example I was just preparing the next section of this post where I would have shown how imprecise lengths were now handled. I was going to suggest modifying the above test program thus:</li> -</ol> -<pre> Frama_C_memcpy(d s Frama_C_nondet(150 10000)); -</pre> -<p>This brought up the following two remarks: first there is an internal function for moving slices of the abstract state around that is slower than it should be and it shows on this test. Secondly the value analysis in Carbon will tell you that bits 1200 to 79999 of <code>d</code> contain either <code>0</code> or a very large number a number with about 23400 decimal digits that start with <code>2164197</code> and end with <code>85824</code>. The value analysis is right of course. If the length argument to <code>Frama_C_memcpy</code> was <code>150</code> then that slice of memory contains zero. If the length was <code>10000</code> the numbers in <code>d</code> that were copied from <code>s</code> can be interpreted as representing exactly that 78800-bit number. This is the value analysis' way of telling you that it's either one or the other: either the length was <code>150</code> or it was <code>10000</code>. This is more informative than telling you cell by cell that the cell contains zero or another number because then you wouldn't see that it's either all one or all the other. The value analysis is rather cute that way.</p> -<blockquote><p>Note: if the 78800-bit number explanation seems terribly complicated do not worry there will be a better explanation for this issue in a future post. We just need another new feature in order to be able to show you.</p> -</blockquote> -<p>In conclusion not everyone may want a Formula One car. But <code>Frama_C_memcpy</code> should at least work for completely unrolled deterministic programs where it can speed up analysis quite a bit compared to the interpretation of a C memcpy.</p> <p>Thanks to Julien for help with motorsports metaphors and to Boris for help in improving <code>Frama_C_memcpy</code> (it used to be worse).</p> {% endraw %} diff --git a/_posts/2011-02-10-Verifying-numerical-precision-with-Frama-Cs-value-analysis---part-2.html b/_posts/2011-02-10-Verifying-numerical-precision-with-Frama-Cs-value-analysis---part-2.html index f194abdee8d48d5e92f407c72a23d309084b4500..a6ee8898208b00c4bcce7f23a360fa114217e4bd 100644 --- a/_posts/2011-02-10-Verifying-numerical-precision-with-Frama-Cs-value-analysis---part-2.html +++ b/_posts/2011-02-10-Verifying-numerical-precision-with-Frama-Cs-value-analysis---part-2.html @@ -155,153 +155,5 @@ double interp_sin(double degrees) <p>Unfortunately option <code>-all-rounding-modes</code> brings back the imprecision that we had just found a way around. Indeed by instructing the analyzer to take into account the possibility that the compiler might be using 80-bit extended doubles for representing variables typed as doubles in the program we are preventing it from reasoning its way from <code>degrees < 4.0</code> to <code>degrees <= 0x1.fffffffffffffp1</code>.</p> <p>There is no convenient way around this limitation. You can write <code>degrees <= 0x1.fffffffffffffp1</code> in the assertion instead of <code>degrees < 4.0</code> but then the assertion will not be provable with option <code>-all-rounding-modes</code> for exactly the same reason. With extended doubles or for that matter reals there exists numbers between 0x1.fffffffffffffp1 and 4.0.</p> <p>There remains the possibility to compare each input output interval pair to a reference function known to be increasing on [0.0 .. 90.0]. Since this post is getting long I will leave this as an optional exercise as well as actually finishing to sub-divide the interval [4.25 .. 90.0]. Spam forces us to limit the possibility to comment on this blog but should these exercises lead to any remarks they will always be welcome on <a href="http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/frama-c-discuss" hreflang="en">the mailing list</a>. One most welcome remark from someone familiar with Emacs Lisp would be a ready-made macro to generate subdivision assertions very quickly in the Emacs text editor.</p> -<p>Many thanks to Zaynah Dargaye and David Delmas for their remarks.</p> - <p>In this sequel to <a href="/index.php?post/2011/01/22/Verifying-numerical-precision-with-Frama-C-s-value-analysis" hreflang="en">a previous post about numerical precision and the value analysis</a> we tackle another extremely common implementation technique the linear interpolation table. In an attempt to make things less boring the approximated function this time is a sine and takes as its argument a double representing an angle in degrees. The interpolation table contains values for each integral angle between 0 and 90.</p> -<p>As before we are focusing on verification so the code already exists and probably works fine too. Our goal here is to double-check that it works. We make up the specification as we go along which is the main difference with real life where the specification would have been defined before the function was written.</p> -<pre>double table_sin[91] = - { 0.000000 /* 0 */ - 0.017452 /* 1 */ - 0.034899 /* 2 */ - 0.052336 /* 3 */ - ... - 0.998630 /* 87 */ - 0.999391 /* 88 */ - 0.999848 /* 89 */ - 1.000000 /* 90 */ } ; -/*@ requires 0.0 <= degrees <= 90.0 ; */ -double interp_sin(double degrees) -{ - int i = (int) degrees; - double r = degrees - i; - double result = table_sin[i] * (1-r) + table_sin[i+1] * r; - return result; -} -</pre> -<p>You can also <a href="/assets/img/blog/imported-posts/sin1.c">download sin1.c</a></p> -<p>The tools we have are the same as last time. The first step is to run a basic value analysis with command <code>frama-c -val sin1.c -main interp_sin</code>. Precision should not be expected from this first run:</p> -<pre>[value] Values for function interp_sin: - i ∈ [0..90] - r ∈ [-90. .. 90.] - result ∈ [-179. .. 181.] -</pre> -<p>But let us pay attention to another important piece of information in the log:</p> -<pre>sin1.c:99:[kernel] warning: accessing out of bounds index. assert (0 ≤ (int )(i+1)) ∧ - ((int )(i+1) < 91); -</pre> -<p>The index <code>i</code> is computed from the argument <code>degrees</code> and the value analysis was able to take advantage of the precondition limiting the value of <code>degrees</code> to 90.0 but the function actually accesses <code>table_sin[i+1]</code>. So we have found a bug which was not our initial goal. Since this was an honest mistake I made when preparing this post I thought I would leave it in. Do not complain for I did spare you the previous mistake I made (I initially wrote <code>double table_sin[90] = ...</code>).</p> -<blockquote><p>Digression: for the mistake in declaring the size of <code>table_sin</code> as 90 any serious compiler would have been able to spot that something was wrong because initial values were provided for 91 cells (e.g. <code>sin_interp.c:92: warning: excess elements in array initializer</code>). Frama-C does not make any effort to duplicate work that has already been done many times over in compilers so you should not necessarily expect it to warn about local inconsistencies such as this one. If you want the best of both worlds <strong>use the value analysis in addition to your compiler's warnings</strong>. Frama-C's value analysis would still warn about accessing a <code>table_sin</code> of size 90 out of bounds though.</p> -</blockquote> -<p>Since <code>interp_sin</code>'s contract is that it is called with argument <code>degrees</code> at most 90.0 one simple fix is to add one element in <code>table_sin</code>:</p> -<pre>double table_sin[92] = - ... - 0.999848 /* 89 */ - 1.000000 /* 90 */ - 1.000000 /* work around overflow at i+1 for degrees=90.0 */ } ; -</pre> -<p>This does not make the value analysis any more precise but at least the alarm disappears.</p> -<p>The next step is to gain precision by sub-dividing input intervals. We subdivide the first few degrees in quarter-degree intervals and for clarity leave the largest part of the input range ([4.25 .. 90.0]) undivided.</p> -<pre>/*@ requires 0.0 <= degrees <= 90.0 ; */ -double interp_sin(double degrees) -{ - /*@ assert - degrees <= 0.25 || - 0.25 <= degrees <= 0.5 || - 0.5 <= degrees <= 0.75 || - ... - 3.75 <= degrees <= 4.0 || - 4.0 <= degrees <= 4.25 || - 4.25 <= degrees ; */ - int i = (int) degrees; - double r = degrees - i; - double result = table_sin[i] * (1-r) + table_sin[i+1] * r; - Frama_C_show_each_d(degrees i r result); - return result; -} -</pre> -<p><a href="/assets/img/blog/imported-posts/sin2.c">Download sin2.c</a></p> -<p>This function also contains computations that can benefit from option <code>-subdivide-float-var</code>. This option <a href="/index.php?post/2011/01/22/Verifying-numerical-precision-with-Frama-C-s-value-analysis" hreflang="en">described in last post</a> automatically refines the precision of the analysis without requiring any annotations. The command-line thus grows to:</p> -<pre>frama-c -main interp_sin sin2.c -slevel 100 -val -subdivide-float-var 50 -float-relative -</pre> -<p>It is normal for the result corresponding to the large undivided range from 4.25 to 90.0 to be imprecise:</p> -<pre>[value] Called Frama_C_show_each_d([4.25 ++ 85.75] [4..90] [-85.75 ++ 171.75] - [-79.698667 ++ 159.769407]) -</pre> -<p>The interesting part is what happens for the other intervals:</p> -<pre>degrees i r result -[4. ++ 0.25] {4; } [0. ++ 0.25] [0.06975478125 ++ 0.00435161819458] -[3.75 ++ 0.25] {3; 4; } [-0.25 ++ 1.25] [0.043630998695 ++ 0.0435276801381] -[3.5 ++ 0.25] {3; } [0.5 ++ 0.25] [0.0610458515625 ++ 0.004355198349] -[3.25 ++ 0.25] {3; } [0.25 ++ 0.25] [0.0566908515625 ++ 0.004355198349] -[3. ++ 0.25] {3; } [0. ++ 0.25] [0.0523358515625 ++ 0.004355198349] -[2.75 ++ 0.25] {2; 3; } [-0.25 ++ 1.25] [0.0261847499594 ++ 0.0435715837503] -[2.5 ++ 0.25] {2; } [0.5 ++ 0.25] [0.0436174958397 ++ 0.0043592552011] -[2.25 ++ 0.25] {2; } [0.25 ++ 0.25] [0.0392582458397 ++ 0.0043592552011] -[2. ++ 0.25] {2; } [0. ++ 0.25] [0.0348989958397 ++ 0.0043592552011] -[1.75 ++ 0.25] {1; 2; } [-0.25 ++ 1.25] [0.008731 ++ 0.0436050104082] -[1.5 ++ 0.25] {1; } [0.5 ++ 0.25] [0.026175499998 ++ 0.00436175000263] -[1.25 ++ 0.25] {1; } [0.25 ++ 0.25] [0.021813749998 ++ 0.00436175000263] -[1. ++ 0.25] {1; } [0. ++ 0.25] [0.017451999998 ++ 0.00436175000263] -[0.75 ++ 0.25] {0; 1; } [-0.25 ++ 1.25] [-0.00872475 ++ 0.0436237500051] -[0.5 ++ 0.25] {0; } [0.5 ++ 0.25] [0.008726 ++ 0.004363] -[0.25 ++ 0.25] {0; } [0.25 ++ 0.25] [0.004363 ++ 0.004363] -[-0. ++ 0.25] {0; } [-0. ++ 0.25] [0. ++ 0.004363] -</pre> -<p>Every few input intervals the result interval is ten times wider than usual. This could become a problem. Indeed if you try further to reduce the width of of one of the problematic input intervals you will notice that there always remains one output interval that refuses to get slimmer.</p> -<p>Analyzing this issue it turns out the reason for the irreducible imprecision is that an input interval such as [2.75 .. 3.0] for <code>degrees</code> means that <code>i</code> can be either 2 or 3 which means that <code>r</code> gets approximated. Interval arithmetics cannot see that <code>r</code> computed as <code>degrees - i</code> is always positive. The solution is to <strong>subdivide smarter</strong> so that all the values inside one same interval for <code>degrees</code> produce the same value for <code>i</code>:</p> -<pre> /*@ assert - degrees < 0.25 || - 0.25 <= degrees < 0.5 || - 0.5 <= degrees < 0.75 || - ... - 3.75 <= degrees < 4.0 || - 4.0 <= degrees < 4.25 || - 4.25 <= degrees ; */ -</pre> -<p>If you are using <strong>version 20110201 or later</strong> the value analysis is able to guarantee that just as before the assertion is always true and thus that using it does not incur any additional proof obligation:</p> -<pre>sin3.c:98:[value] Assertion got status valid. -</pre> -<p>With the new assertion all the result intervals are uniformly narrow with a width less than 0.005 for all the few intervals we are currently looking at:</p> -<pre>[value] Called Frama_C_show_each_d([4. ++ 0.25] {4; } [0. ++ 0.25] - [0.06975478125 ++ 0.00435161819458]) -[value] Called Frama_C_show_each_d([3.75 ++ 0.25] {3; } [0.75 ++ 0.25] - [0.0654008515625 ++ 0.004355198349]) -[value] Called Frama_C_show_each_d([3.5 ++ 0.25] {3; } [0.5 ++ 0.25] - [0.0610458515625 ++ 0.004355198349]) -... -[value] Called Frama_C_show_each_d([0.25 ++ 0.25] {0; } [0.25 ++ 0.25] - [0.004363 ++ 0.004363]) -[value] Called Frama_C_show_each_d([-0. ++ 0.25] {0; } [-0. ++ 0.25] - [0. ++ 0.004363]) -</pre> -<p>The input sub-intervals appear the same as before in the log but they are subtly different. The best way to see the difference is to request floating-point intervals to be displayed exactly to the bit with option <code>-float-hex</code>. It takes some time getting used to hexadecimal floating-point numbers; if you wish do not worry about it and skip to the part about Emacs Lisp at the end of the post.</p> -<pre>frama-c -main interp_sin sin3.c -slevel 100 -val -subdivide-float-var 50 -float-hex -... -[value] Called Frama_C_show_each_d([0x1.0000000000000p2 .. 0x1.0ffffffffffffp2] - {4; } - [0x0.0000000000000p-1022 .. 0x1.fffffffffffe0p-3] - [0x1.1db73083558a7p-4 .. 0x1.2f8a31209edbep-4]) -[value] Called Frama_C_show_each_d([0x1.e000000000000p1 .. 0x1.fffffffffffffp1] - {3; } - [0x1.8000000000000p-1 .. 0x1.ffffffffffffcp-1] - [0x1.0be1c36976bc2p-4 .. 0x1.1db8851116a8bp-4]) -[value] Called Frama_C_show_each_d([0x1.c000000000000p1 .. 0x1.dffffffffffffp1] - {3; } - [0x1.0000000000000p-1 .. 0x1.7fffffffffffcp-1] - [0x1.f4166e008e9b4p-5 .. 0x1.0be1f8a7e73a3p-4]) -[value] Called Frama_C_show_each_d([0x1.a000000000000p1 .. 0x1.bffffffffffffp1] - {3; } - [0x1.0000000000000p-2 .. 0x1.ffffffffffff8p-2] - [0x1.d069552e2fbe3p-5 .. 0x1.f416d87d6f976p-5]) -</pre> -<p>The first of these input intervals is when displayed exactly [0x1.0p2 .. 0x1.0ffffffffffffp2]. With the assertion used in sin2.c the corresponding interval was [0x1.0p2 .. 0x1.10p2] or in decimal [4. .. 4.25]. The number 0x1.0ffffffffffffp2 is the first <code>double</code> immediately below 4.25. Similarly and more importantly 0x1.fffffffffffffp1 is the first <code>double</code> immediately below 4.0 and the value analysis knows that the truncation to <code>int</code> of this number as that of any number in [0x1.e0p1 .. 0x1.fffffffffffffp1] (in decimal [3.75 .. 4.0]) is 3.</p> -<p>The next step in reproducing the method from <a href="/index.php?post/2011/01/22/Verifying-numerical-precision-with-Frama-C-s-value-analysis" hreflang="en">part 1</a> is to use option <code>-all-rounding-modes</code> to capture all possible FPU rounding modes extra precision introduced by the compiler for temporary results and incidentally to get result intervals that capture what the program would have computed if it had used reals instead of doubles:</p> -<pre>frama-c -main interp_sin sin3.c -slevel 100 -val -subdivide-float-var 50 -all-rounding-modes -float-relative -... -[value] Called Frama_C_show_each_d([3.75 ++ 0.25] {3; 4; } [-0.25 ++ 1.25] - [0.043630998695 ++ 0.0435276801381]) -</pre> -<p>Unfortunately option <code>-all-rounding-modes</code> brings back the imprecision that we had just found a way around. Indeed by instructing the analyzer to take into account the possibility that the compiler might be using 80-bit extended doubles for representing variables typed as doubles in the program we are preventing it from reasoning its way from <code>degrees < 4.0</code> to <code>degrees <= 0x1.fffffffffffffp1</code>.</p> -<p>There is no convenient way around this limitation. You can write <code>degrees <= 0x1.fffffffffffffp1</code> in the assertion instead of <code>degrees < 4.0</code> but then the assertion will not be provable with option <code>-all-rounding-modes</code> for exactly the same reason. With extended doubles or for that matter reals there exists numbers between 0x1.fffffffffffffp1 and 4.0.</p> -<p>There remains the possibility to compare each input output interval pair to a reference function known to be increasing on [0.0 .. 90.0]. Since this post is getting long I will leave this as an optional exercise as well as actually finishing to sub-divide the interval [4.25 .. 90.0]. Spam forces us to limit the possibility to comment on this blog but should these exercises lead to any remarks they will always be welcome on <a href="http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/frama-c-discuss" hreflang="en">the mailing list</a>. One most welcome remark from someone familiar with Emacs Lisp would be a ready-made macro to generate subdivision assertions very quickly in the Emacs text editor.</p> <p>Many thanks to Zaynah Dargaye and David Delmas for their remarks.</p> {% endraw %} diff --git a/_posts/2011-02-25-Numerical-functions-are-not-merely-twisted.html b/_posts/2011-02-25-Numerical-functions-are-not-merely-twisted.html index d9ae189466ecbc592462197d7e7745df7ba060ea..de68d132381bea158b472be5626d68ef28da63c4 100644 --- a/_posts/2011-02-25-Numerical-functions-are-not-merely-twisted.html +++ b/_posts/2011-02-25-Numerical-functions-are-not-merely-twisted.html @@ -42,40 +42,5 @@ __kernel_cos(double x double y) <li>This code accesses bits of the <code>double</code> argument <code>x</code> with 32-bit integers and this is mostly for purposes of speed (only "mostly" here. In other functions from the same library the same trick is used and the only justification is speed). This made sense at a time but on a modern architecture with a sensible ABI this is very much misguided. Argument <code>x</code> would be passed in a floating-point register and would stay there for the duration of the function if this pessimization did not force it to be written to memory. Worse I am pretty sure that with some of the architectures implementing SSE the program is penalized by long stalls for accessing with general registers memory that has been written from SSE registers.</li> <li>You may wonder if it's necessary to think about the difference between <code>doubles</code> and reals. Look at it this way: if you did not have to think about this difference the whole mess with <code>qx</code> would not be part of this function because with reals it doesn't have any effect to subtract the same quantity from two arguments of the same subtraction. And yes this correction is only there to obtain precision at a scale much smaller than we were <a href="/index.php?post/2011/01/22/Verifying-numerical-precision-with-Frama-C-s-value-analysis" hreflang="en">verifying using the value analysis</a>. The problem is this modification makes the code more complex for everyone. If you only need a precision of one thousandth but you absolutely must be sure that you have it otherwise the plane/nuclear power plant/satellite may crash it is now less certain that you have this precision because the increased complexity makes it less obvious the function works properly. We even found a bug although that was only in a comment. You'd better verify it carefully if that's the function you have decided to use.</li> </ol> -<p>To be fair regarding the last point I chose a cosine implementation on purpose because its result gets closer to zero (making it easier to observe a possible imprecision) when its argument gets farther from zero (meaning less precision available for computations if you are not careful). The <code>qx</code> trick actually serves to get computations closer to zero where more precision is (in absolute terms) available. <a href="http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libm/src/k_sin.c?rev=1.3;content-type=text%2Fplain">The sine implementation</a> does not need such a trick.</p> - <p>In <a href="/index.php?post/2011/01/22/Verifying-numerical-precision-with-Frama-C-s-value-analysis" hreflang="en">a previous post</a> there was a cosine function that I made up for the purpose of blogging about it. Let us now look at <a href="http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libm/src/k_cos.c?rev=1.3;content-type=text%2Fplain">a real cosine function (OpenBSD's libm derived from widespread code written at Sun in the 1990s)</a> to get a feeling how far off we were:</p> -<pre>double -__kernel_cos(double x double y) -{ - double a hz z r qx; - int32_t ix; - GET_HIGH_WORD(ix x); - ix &= 0x7fffffff; /* ix = |x|'s high word*/ - if(ix<0x3e400000) { /* if x < 2**27 */ - if(((int)x)==0) return one; /* generate inexact */ - } - z = x*x; - r = z*(C1+z*(C2+z*(C3+z*(C4+z*(C5+z*C6))))); - if(ix < 0x3FD33333) /* if |x| < 0.3 */ - return one - (0.5*z - (z*r - x*y)); - else { - if(ix > 0x3fe90000) { /* x > 0.78125 */ - qx = 0.28125; - } else { - INSERT_WORDS(qx ix-0x00200000 0); /* x/4 */ - } - hz = 0.5*z-qx; - a = one-qx; - return a - (hz - (z*r-x*y)); - } -} -</pre> -<p>Some remarks in decreasing order of obviousness:</p> -<ol> -<li>the line <code>if(ix<0x3e400000) { /* if x < 2**27 */</code> contains a clear bug: the comment should undoubtedly be "if x < 2**-27".</li> -<li>The function computes the cosine of <code>x+y</code>. Argument <code>y</code> is the "tail" of <code>x</code> and since <code>x</code> is a <code>double</code> in the range -Ï€/4 .. Ï€/4 <code>y</code> is really small and only needs to be taken into account in the lower-order terms of the polynomial approximation.</li> -<li>This code accesses bits of the <code>double</code> argument <code>x</code> with 32-bit integers and this is mostly for purposes of speed (only "mostly" here. In other functions from the same library the same trick is used and the only justification is speed). This made sense at a time but on a modern architecture with a sensible ABI this is very much misguided. Argument <code>x</code> would be passed in a floating-point register and would stay there for the duration of the function if this pessimization did not force it to be written to memory. Worse I am pretty sure that with some of the architectures implementing SSE the program is penalized by long stalls for accessing with general registers memory that has been written from SSE registers.</li> -<li>You may wonder if it's necessary to think about the difference between <code>doubles</code> and reals. Look at it this way: if you did not have to think about this difference the whole mess with <code>qx</code> would not be part of this function because with reals it doesn't have any effect to subtract the same quantity from two arguments of the same subtraction. And yes this correction is only there to obtain precision at a scale much smaller than we were <a href="/index.php?post/2011/01/22/Verifying-numerical-precision-with-Frama-C-s-value-analysis" hreflang="en">verifying using the value analysis</a>. The problem is this modification makes the code more complex for everyone. If you only need a precision of one thousandth but you absolutely must be sure that you have it otherwise the plane/nuclear power plant/satellite may crash it is now less certain that you have this precision because the increased complexity makes it less obvious the function works properly. We even found a bug although that was only in a comment. You'd better verify it carefully if that's the function you have decided to use.</li> -</ol> <p>To be fair regarding the last point I chose a cosine implementation on purpose because its result gets closer to zero (making it easier to observe a possible imprecision) when its argument gets farther from zero (meaning less precision available for computations if you are not careful). The <code>qx</code> trick actually serves to get computations closer to zero where more precision is (in absolute terms) available. <a href="http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libm/src/k_sin.c?rev=1.3;content-type=text%2Fplain">The sine implementation</a> does not need such a trick.</p> {% endraw %} diff --git a/_posts/2011-02-28-On-switch-statements.html b/_posts/2011-02-28-On-switch-statements.html index d4965370f429a740c798ec33f6bac569533d10ea..999f920579c6969f91dfc597d20eca8f2dc5009a 100644 --- a/_posts/2011-02-28-On-switch-statements.html +++ b/_posts/2011-02-28-On-switch-statements.html @@ -161,159 +161,5 @@ main(int argc char **argv){ } </pre> <p>As you can see on this example from the next release onwards option <code>-simplify-cfg</code> is no longer necessary to get precise results with the value analysis. This means better slicing of programs that use the <code>switch</code> construct — and one option that you may now forget about.</p> -<p>Many thanks to Boris Taker of our Own Value Analysis Medicine extraordinaire for implementing the new feature described in this post and to Miguel Ferreira for providing expertise in English idioms.</p> - <p>In Carbon 20110201 and earlier versions of Frama-C, if you do not use precautions when analyzing a program with <code>switch</code> statements, you get imprecise results. Consider the example program below.</p> -<pre>main(int argc, char **argv){ - switch(argc){ - case 1: - Frama_C_show_each_no_args(argc); - break; - case 2: - Frama_C_show_each_exactly_2(argc); - /* fall through */ - case 3: - Frama_C_show_each_2_or_3(argc); - break; - default: - Frama_C_show_each_else(argc); - break; - } - return argc; -} -</pre> -<pre>$ frama-c -val sw.c -... -[value] Called Frama_C_show_each_exactly_2([-2147483648..2147483647]) -[value] Called Frama_C_show_each_no_args([-2147483648..2147483647]) -[value] Called Frama_C_show_each_else([-2147483648..2147483647]) -[value] Called Frama_C_show_each_2_or_3([-2147483648..2147483647]) -... -</pre> -<p>This is correct, but disappointingly imprecise. -Frama-C (the framework) can normalize the code to a large extent so that its plug-ins (here, the value analysis) do not need to handle redundant constructs. A <code>switch</code> construct can be encoded using <code>if</code> and <code>goto</code>. Frama-C option <code>-simplify-cfg</code> does exactly that, for the convenience of plug-in authors. As long as they have already programmed a precise analysis for these constructions, they can always get a precise result by requiring the program to be transformed thus.</p> -<blockquote><p>Crediting where credit is due, the C code normalization philosophy is inherited from <a href="http://www.cs.berkeley.edu/~necula/cil/" hreflang="en">CIL</a> which provided the basis of Frama-C's front-end.</p> -</blockquote> -<p>The transformed program looks like this:</p> -<pre>$ frama-c -simplify-cfg -print sw.c -... - if (! (argc == 1)) { - if (argc == 2) { goto switch_0_2; } - else { - if (argc == 3) { goto switch_0_3; } - else { goto switch_0_default; goto switch_0_break; } - } - } - switch_0_1: /* internal */ Frama_C_show_each_no_args(argc); - goto switch_0_break; - switch_0_2: /* internal */ Frama_C_show_each_exactly_2(argc); - switch_0_3: /* internal */ Frama_C_show_each_2_or_3(argc); - goto switch_0_break; - switch_0_default: /* internal */ ; - Frama_C_show_each_else(argc); - goto switch_0_break; - switch_0_break: /* internal */ ; - return (argc); -... -</pre> -<p>I did not say the transformed code looked good. But usually you do not need to look at the generated code; the analysis results are what you are interested in:</p> -<pre>$ frama-c -simplify-cfg -val sw.c -... -[value] Called Frama_C_show_each_no_args({1; }) -[value] Called Frama_C_show_each_exactly_2({2; }) -[value] Called Frama_C_show_each_2_or_3({2; 3; }) -[value] Called Frama_C_show_each_else([-2147483648..2147483647]) -... -</pre> -<p>This time the value analysis' results show that each time the program point at which we placed the <code>Frama_C_show_each_no_args</code> call is traversed the value of <code>argc</code> is exactly 1. The program point with the call to <code>Frama_C_show_each_exactly_2</code> is only traversed with <code>argc==2</code> and so on. These are the expected results.</p> -<p>Sometimes however the value analysis is used as a means to a different end and option <code>-simplify-cfg</code> can conflict with the final objective. Let's say the example program is modified slightly:</p> -<pre>int x t[4]; -main(int argc char **argv){ - t[0] = 10; - t[1] = 11; - t[2] = 12; - t[3] = 13; - switch(argc){ - case 1: - Frama_C_show_each_no_args(argc); - break; - case 2: - Frama_C_show_each_exactly_2(argc); - /* fall through */ - case 3: - Frama_C_show_each_2_or_3(argc); - x = t[argc]; - break; - default: - Frama_C_show_each_else(argc); - break; - } - return x; -} -</pre> -<p>If the task we are actually interested in is obtaining a subset of the statements of the above program so that this subset when compiled and executed returns the same value as the original program option <code>-simplify-cfg</code> gets in the way. The options to instruct the slicing plug-in to compute this subset are <code>-slice-return main -slice-print</code>. We face the following dilemma:</p> -<ol> -<li>not use option <code>-simplify-cfg</code> give the slicing plug-in access to an unmodified abstract syntax tree but let it rely on imprecise values; or</li> -<li>use option <code>-simplify-cfg</code> get precise values but have the slicing plug-in work on an abstract syntax tree representing a mangled version of the original program.</li> -</ol> -<p>In the first case we get the sliced program below which is shaped like the original but retains several statements that could have been removed:</p> -<pre>$ frama-c sw.c -slice-return main -slice-print -... -{ - t[0] = 10; - t[1] = 11; - t[2] = 12; - t[3] = 13; - switch (argc) { - case 1: ; - break; - case 2: ; - case 3: ; - /*@ assert (0 ≤ argc) ∧ (argc < 4); - // synthesized - */ - x = t[argc]; - break; - default: ; - } - return (x); -} -</pre> -<p>In the second case some useless initializations are removed but the transformation makes the sliced program harder to follow:</p> -<pre>$ frama-c sw.c -slice-return main -slice-print -simplify-cfg -... -{ - t[2] = 12; - t[3] = 13; - if (! (argc == 1)) { - if (argc == 2) { goto switch_0_2; } - else { if (argc == 3) { goto switch_0_3; } } - } - goto switch_0_break; - switch_0_2: /* internal */ ; - switch_0_3: /* internal */ ; - x = t[argc]; - switch_0_break: /* internal */ ; - return (x); -} -</pre> -<p>Or... you can use the next version of Frama-C:</p> -<pre>$ bin/toplevel.opt sw.c -slice-return main -slice-print -... -{ - t[2] = 12; - t[3] = 13; - switch (argc) { - case 1: ; - break; - case 2: ; - case 3: ; - x = t[argc]; - break; - default: ; - } - return (x); -} -</pre> -<p>As you can see on this example from the next release onwards option <code>-simplify-cfg</code> is no longer necessary to get precise results with the value analysis. This means better slicing of programs that use the <code>switch</code> construct — and one option that you may now forget about.</p> <p>Many thanks to Boris Taker of our Own Value Analysis Medicine extraordinaire for implementing the new feature described in this post and to Miguel Ferreira for providing expertise in English idioms.</p> {% endraw %} diff --git a/_posts/2011-03-01-Analyzing-unit-tests-and-interpretation-speed.html b/_posts/2011-03-01-Analyzing-unit-tests-and-interpretation-speed.html index 78a66c9587eae267b5d309fc9ff81966428dec5d..a4986c99daf49f1759e565f9a9dcb3ef0b7815eb 100644 --- a/_posts/2011-03-01-Analyzing-unit-tests-and-interpretation-speed.html +++ b/_posts/2011-03-01-Analyzing-unit-tests-and-interpretation-speed.html @@ -19,17 +19,5 @@ summary: <p>So in the race between execution and completely unrolled analysis execution triumphs for program <code>unsigned int i; main() { while(++i); }</code>. It has an advantage for program <code>unsigned short i; main() { while(++i); }</code> —did we say we were including compilation time again? And finally positions are reversed for program <code>unsigned short i=17; main(){ while (i+=42); }</code> where execution literally takes forever whereas when completely unrolled the value analysis quickly diagnoses the program as non-terminating.</p> <p>One handicap which is also an advantage for the value analysis is that it records previously seen states. It can therefore detect when <code>i</code> becomes <code>17</code> that this variable has been <code>17</code> before and it knows what happens then: a lot of computations take place and then <code>i</code> is 17 again. Recording values also mean that it's possible to inspect values in the graphical user interface. And one last advantage of the value analysis over execution is that it can target about any architecture regardless of the architecture it is running on. It can analyze a program for a 64-bit big-endian architecture on a 32-bit little-endian one.</p> <p>A factor of up to 100000 may seem so expensive as to be impractical but you should <strong>try Carbon on examples of increasing sizes</strong> before altogether dismissing it as unrealistic. The value analysis' algorithms for efficient use of time and memory have become rather sophisticated over time. 100000 is not that bad: we have very fast desktop computers nowadays but some of the C programs we are interested in are still small either because they have no particular reason to grow and fill the computation time available or because they must run on power-limited mobile devices.</p> -<p>Lastly fully unrolling deterministic programs is nice because in this mode there never are any false positives that waste human time without revealing bugs. But the value analysis can be useful even when it is not completely unrolled. For instance it also concludes that the earlier program with <code>while (i+=42);</code> does not terminate without being unrolled.</p> - <p>I once claimed in a comment that with the value analysis, when the source code is fully available, you can analyze many executable C programs with maximum precision. For this to work, all inputs must have been decided in advance and be provided. It can therefore be likened to running a deterministic unit or integration test. In fact, <strong>existing unit and integration tests</strong> are choice candidates for this kind of analysis.</p> -<p>One of the ideas to remember from <a href="/index.php?post/2011/01/27/On-memcpy-1" hreflang="en">this post on function memcpy</a> is that even horribly <strong>low-level code can be analyzed precisely</strong> as long as you have precise inputs —for instance code that copies a pointer one char at a time. There are some known situations where the analysis may start losing precision without the program doing anything too arguably wrong. Tell us about it if you find one —some of the known precision-loss situations are remediable it's all just a question of priorities.</p> -<p>Such a maximally precise analysis provides better guarantees than merely executing the program with the inputs you have crafted: it detects all undefined behaviors in the sense of the value analysis. This is more systematic and reliable than letting executions chance on issues in the code even assisted by dynamic tools such as <a href="http://valgrind.org/" hreflang="en">Valgrind</a>.</p> -<p>Still in order to get a maximally precise analysis you need to unroll all loops by passing a sufficiently large argument to option <code>-slevel</code>. If you have ever tried it you may have noticed that it can be slow. But how slow? While writing the beginning of the Skein tutorial the first meaningful analysis was taking 10s on the computer I had then (note that the 10 seconds were for analyzing a complete useful program not a unit test). I had no idea how much time executing the same code took because it was too fast. I assumed the difference was something between a factor of 1000 and a factor of 10000 for "normal" programs such as that one.</p> -<blockquote><p>Note: if you wanted to make the comparison fairer you could compare the time taken by the value analysis to the time taken by compilation plus execution. But this is not the point I am interested in here.</p> -</blockquote> -<p>I have been running and analyzing more of these deterministic programs recently so I had a chance to improve my estimate: it's more like a factor between 10000 and 100000. It depends very much on the shape of the analyzed program: the value analysis remembers the value of all variables for each traversed statement so each additional global variable makes the analysis marginally slower on all statements even when it is not accessed. And this is only one of the fundamental differences between the two.</p> -<p>A good rule of thumb is that a program that enumerates all values of a 32-bit variable —say because of a bug— may take a few minutes to execute if it's not too many instructions that are executed 2^32 times. It's about the same for complete unrolling of the value analysis except that the cut-off size for the variable is 16-bit instead.</p> -<p>So in the race between execution and completely unrolled analysis execution triumphs for program <code>unsigned int i; main() { while(++i); }</code>. It has an advantage for program <code>unsigned short i; main() { while(++i); }</code> —did we say we were including compilation time again? And finally positions are reversed for program <code>unsigned short i=17; main(){ while (i+=42); }</code> where execution literally takes forever whereas when completely unrolled the value analysis quickly diagnoses the program as non-terminating.</p> -<p>One handicap which is also an advantage for the value analysis is that it records previously seen states. It can therefore detect when <code>i</code> becomes <code>17</code> that this variable has been <code>17</code> before and it knows what happens then: a lot of computations take place and then <code>i</code> is 17 again. Recording values also mean that it's possible to inspect values in the graphical user interface. And one last advantage of the value analysis over execution is that it can target about any architecture regardless of the architecture it is running on. It can analyze a program for a 64-bit big-endian architecture on a 32-bit little-endian one.</p> -<p>A factor of up to 100000 may seem so expensive as to be impractical but you should <strong>try Carbon on examples of increasing sizes</strong> before altogether dismissing it as unrealistic. The value analysis' algorithms for efficient use of time and memory have become rather sophisticated over time. 100000 is not that bad: we have very fast desktop computers nowadays but some of the C programs we are interested in are still small either because they have no particular reason to grow and fill the computation time available or because they must run on power-limited mobile devices.</p> <p>Lastly fully unrolling deterministic programs is nice because in this mode there never are any false positives that waste human time without revealing bugs. But the value analysis can be useful even when it is not completely unrolled. For instance it also concludes that the earlier program with <code>while (i+=42);</code> does not terminate without being unrolled.</p> {% endraw %} diff --git a/_posts/2011-03-03-This-time-for-real-verifying-function-cosine.html b/_posts/2011-03-03-This-time-for-real-verifying-function-cosine.html index 109bf0064379138f638e7d164999064cff6a0fe4..ec8324261668e7811324ab381161f4d463ca8129 100644 --- a/_posts/2011-03-03-This-time-for-real-verifying-function-cosine.html +++ b/_posts/2011-03-03-This-time-for-real-verifying-function-cosine.html @@ -32,30 +32,5 @@ The value analysis was configured with the <code>-all-rounding-modes</code> opti <p>From the fact that the builtin did not complain for any sub-interval we can conclude that on the interval 0..Ï€/4 <strong>the proposed implementation for cosine is never farther than 2^-21 (half a millionth) from the real function cosine</strong>.</p> <blockquote><p>According to the aforementioned billion tests I made the implementation seems to be much more precise than above (to about 2^-52 times its argument). The key difference is that I am quite sure it is precise to half a millionth and that I have observed that it seems to be precise to about 2^-52 times its argument.</p> </blockquote> -<p>Guillaume Melquiond provided irreplaceable floating-point expertise in the preparation of this post.</p> - <p>This post follows <a href="/floating-point/2011/02/25/Numerical-functions-are-not-merely-twisted" hreflang="en">that post where a typical double-precision implementation for a cosine function is shown</a>. That implementation is not a correctly rounded implementation but its <code>double</code> result is precise to a level close to what the double-precision floating-point representation allows. It uses low-level tricks that make it faster on nineties computers.</p> -<p>In this post I offer a slightly simplified version of the same function (<a href="/assets/img/blog/imported-posts/mcos.c">download</a>). This function does not compute exactly the same results but according to a few billion tests I ran it does not seem more wrong than the original. I expect the simplified version is actually faster than the original on tens computers but this is not why I modified it. I needed to make changes because the value analysis does not yet precisely handle all the low-level conversions in the original (accessing the 32 most significant bits of a <code>double</code>). Although the value analysis does not say anything false it is only possible to analyze the function precisely if this idiom is handled precisely.</p> -<blockquote><p>If it was important to analyze as-is code that uses this low-level idiom implementation of this treatment could be prioritized according to the results of the experiment in this post. Results on the original function can be expected to be the same after the new feature is implemented as the results for the modified function described here.</p> -</blockquote> -<p>I implemented <a href="/assets/img/blog/imported-posts/compare_cos.ml">a quick-and-dirty value analysis builtin</a> for the purpose of this verification. It is not provided so much for being re-used as for possible comments: it is large enough that a bug in it could invalidate the verification. This builtin checks that its second argument is close enough to the cosine of its first argument (it uses its third argument as allowable distance). The builtin displays a log line for each call so that you can check that it was properly called.</p> -<blockquote><p>Demonstrating how easy it is to write an unsafe builtin this implementation assumes without verification that it is called in a range where function cosine is decreasing.</p> -</blockquote> -<p>I then wrote the following lines of C:</p> -<pre> x = Frama_C_double_interval(... ...); - m = mcos(x); - Frama_C_compare_cos(x m 0x1.0p-21); -</pre> -<p>Next I arranged to have the value analysis repeatedly analyze these lines with bounds passed to <code>Frama_C_double_interval</code> that taken together cover entirely the range from 0 to Ï€/4. I will not say how I did because it is not very interesting. Besides the method I used is convenient enough to discourage someone from writing an Emacs Lisp macro to generate sub-division assertions. That would be an unwanted side-effect: it in fact has complementary advantages with the would-be assertion generation macro that I recommend someone look into.</p> -<p>The verification used a few hours of CPU time (I did not try very hard to make it fast). One thing I did was adapt the input sub-interval width to the part of the curve that was being verified from two millionths for inputs near zero to a quarter of a millionth for inputs near Ï€/4.</p> -<p>During this experiment I actually used the cosine implementation from <a href="http://lipforge.ens-lyon.fr/www/crlibm/" hreflang="en">CRlibm</a> as reference function. This library incidentally developed at my alma mater provides a number of fast <strong>and</strong> correctly rounded implementations for mathematical functions. -The value analysis was configured with the <code>-all-rounding-modes</code> option so the results are guaranteed for arbitrary rounding modes and are guaranteed even if the compiler uses supplemental precision for intermediate results (e.g. if the compiler uses the infamous 80-bit historial floating-point unit of Intel processors).</p> -<p>Here are the logs I obtained (warning: I did not make any file of that level of boringness publicly available since my PhD plus these are really big even after compression. Handle with care): <a href="/assets/img/blog/imported-posts/log1.gz">log1.gz</a> <a href="/assets/img/blog/imported-posts/log2.gz">log2.gz</a> <a href="/assets/img/blog/imported-posts/log3.gz">log3.gz</a> <a href="/assets/img/blog/imported-posts/log4.gz">log4.gz</a> <a href="/assets/img/blog/imported-posts/log5.gz">log5.gz</a> <a href="/assets/img/blog/imported-posts/log6.gz">log6.gz</a> <a href="/assets/img/blog/imported-posts/log7.gz">log7.gz</a> <a href="/assets/img/blog/imported-posts/log8.gz">log8.gz</a> <a href="/assets/img/blog/imported-posts/log9.gz">log9.gz</a> <a href="/assets/img/blog/imported-posts/log10.gz">log10.gz</a> <a href="/assets/img/blog/imported-posts/log11.gz">log11.gz</a> <a href="/assets/img/blog/imported-posts/log12.gz">log12.gz</a> <a href="/assets/img/blog/imported-posts/log13.gz">log13.gz</a> <a href="/assets/img/blog/imported-posts/log14.gz">log14.gz</a> <a href="/assets/img/blog/imported-posts/log15.gz">log15.gz</a>. To save you the bother of downloading even the first file here is what the first three lines look like.</p> -<pre>[value] CC -0.0000000000000000 0.0000019073486328 0.9999999999981809 1.0000000000000002 0.9999999999981810 1.0000000000000000 OK -[value] CC 0.0000019073486328 0.0000038146972656 0.9999999999927240 0.9999999999981811 0.9999999999927240 0.9999999999981811 OK -[value] CC 0.0000038146972656 0.0000057220458984 0.9999999999836291 0.9999999999927242 0.9999999999836291 0.9999999999927242 OK -</pre> -<p>From the fact that the builtin did not complain for any sub-interval we can conclude that on the interval 0..Ï€/4 <strong>the proposed implementation for cosine is never farther than 2^-21 (half a millionth) from the real function cosine</strong>.</p> -<blockquote><p>According to the aforementioned billion tests I made the implementation seems to be much more precise than above (to about 2^-52 times its argument). The key difference is that I am quite sure it is precise to half a millionth and that I have observed that it seems to be precise to about 2^-52 times its argument.</p> -</blockquote> <p>Guillaume Melquiond provided irreplaceable floating-point expertise in the preparation of this post.</p> {% endraw %} diff --git a/_posts/2011-03-06-The-level-to-analyze.html b/_posts/2011-03-06-The-level-to-analyze.html index 48de7e1e0ad7e3805e154447b3a61a00e44aeede..d3d91e78edd2d91ef247bf2a56223061d24e0986 100644 --- a/_posts/2011-03-06-The-level-to-analyze.html +++ b/_posts/2011-03-06-The-level-to-analyze.html @@ -9,5 +9,4 @@ summary: --- {% raw %} <p><a href="http://stackoverflow.com/q/5189239/139746" hreflang="en">This sort of question</a> (here about the trade-offs involved in the choice of the level of intermediate language to statically analyze) is the reason I still visit StackOverflow despite everything that is wrong with it.</p> - <p><a href="http://stackoverflow.com/q/5189239/139746" hreflang="en">This sort of question</a> (here about the trade-offs involved in the choice of the level of intermediate language to statically analyze) is the reason I still visit StackOverflow despite everything that is wrong with it.</p> {% endraw %} diff --git a/_posts/2011-03-23-Helping-the-value-analysis---part-1.html b/_posts/2011-03-23-Helping-the-value-analysis---part-1.html index 7fc60462733dde5f2ebe510eb16b8f4148b052b4..9aa18af1d5199a529906162f50c62b0d2528a769 100644 --- a/_posts/2011-03-23-Helping-the-value-analysis---part-1.html +++ b/_posts/2011-03-23-Helping-the-value-analysis---part-1.html @@ -107,105 +107,5 @@ we made to reach the conclusion that the division was safe is informal and there could be a mistake in it. In a next post we will try to make the analysis say that the division is safe which will be more satisfying. <a href="/assets/img/blog/imported-posts/interp.c">Here is the file</a> in case you wish to try it at home. Another possible exercise if to complete the contract of <code>choose_segment</code> and/or implement it. If you do both you can check your implementation against your specification with a deductive verification plug-in.</p> -<p>This post is co-authored by Kerstin Hartig.</p> - <h2>Introduction</h2> -<p>This post introduces a new series about the -art of helping the value analysis to be more precise. -Until now, in the numerical precision series of this blog, -this was easy enough. -There was a single input variable and the obvious way to get -more precise output values was to subdivide the range for that -input variable. Sometimes, it is more complicated.</p> -<h2>The example</h2> -<p>The example we are going to look at in this series -is an interpolation function. It is similar to <a href="index.php?post/2011/02/10/Verifying-numerical-precision-part-2" hreflang="en">the sine example seen previously</a> but here the divisions of the function's -definition interval are not uniform. The sub-intervals on which the -function is implemented as a linear interpolation have been carefully -chosen by the designers to minimize the occupied memory while providing -appropriate precision.</p> -<pre>struct point { double x; double y; }; -struct point t[] = - { 0. 1. - 0.125 1.00782267782571089 - 0.25 1.03141309987957319 - 0.5 1.1276259652063807 - 1. 1.54308063481524371 - 2. 3.76219569108363139 - 5. 74.2099485247878476 - 10. 11013.2329201033244 }; -</pre> -<p>The interpolation function calls function <code>choose_segment</code> to get an index <code>i</code> indicating the segment to use. It then computes its result by interpolation -of <code>x</code> between the points <code>t[i]</code> and <code>t[i+1]</code>.</p> -<pre>/*@ requires 0. <= x <= 10. ; */ -double interp(double x) -{ - double x0 x1 y0 y1; - int i; - i = choose_segment(x); - x0 = t[i].x; - y0 = t[i].y; - x1 = t[i+1].x; - y1 = t[i+1].y; - return (y1 * (x - x0) + y0 * (x1 - x)) / (x1 - x0); -} -</pre> -<p>We are supposed to verify that function <code>interp</code> above is <strong>free of run-time errors</strong> but auxiliary function <code>choose_segment</code> -is not yet available for some reason. All we have is the specification it -is supposed to satisfy.</p> -<p>Part of the specification has been formally written in ACSL:</p> -<pre>/*@ - requires 0. <= x <= 10. ; - assigns \ -othing ; - ensures 0 <= \esult <= 6 ; */ -int choose_segment(double x); -</pre> -<p>Of course this ACSL specification of <code>choose_segment</code> is partial: it -does not completely caracterize what the function is supposed to do (the function is supposed to -select the right segment not just any segment which is what the -ACSL contract says). -Nevertheless if we can verify the safety of function <code>interp</code> using -only this contract for function <code>choose_segment</code> it will be a -feather in our cap and we will only need to check that -<code>choose_segment</code> statisfies its own specification when it finally -arrives.</p> -<h2>First analysis</h2> -<p>The first step is always to launch an imprecise analysis to gauge the -situation:</p> -<pre>frama-c -val -main interp interp.c -</pre> -<p>Four messages in the log are related to the verification process:</p> -<pre>interp.c:20:[value] Function interp: precondition got status unknown -</pre> -<p>This is the pre-condition for the function we are verifying. It is normal for this property not to be verified: it is <code>interp</code>'s callers' job to make sure that the condition expressed here is met.</p> -<pre>interp.c:24:[value] Function choose_segment: precondition got status valid -</pre> -<p>The value analysis has verified that auxiliary function <code>choose_segment</code> was called in the conditions defined by its contract.</p> -<pre>interp.c:24:[value] Function choose_segment: postcondition got status unknown -</pre> -<p>Again it is normal for the annotation here not to be verified: it is supposed to be ensured by <code>choose_segment</code>'s body which is not available.</p> -<pre>interp.c:28:[kernel] warning: float operation: assert \is_finite((double )((double )((double )(y1*(double )(x-x0))+(double ) (y0*(double )(x1-x)))/(double ) (x1-x0))); -</pre> -<p>Because of subtle differences between ACSL and C a lot of casts have been -inserted but this assertion means the analyzer is worried that the value -computed by the function to be returned might be an infinite or NaN.</p> -<p>Inspecting the toplevel operation in the formula (which is the -problematic one: the value analysis would warn individually about -sub-expressions if it thought one contained an additional problem) we -see it is a division by <code>x1 - x0</code>. An issue would be if this -expression was zero or unreasonably close to zero. Further inspection -shows that <code>x0 = t[i].x</code> and <code>x1 = t[i+1].x</code>. From this we deduce -that <code>x1</code> is always strictly greater than <code>x0</code> and more -specifically that <code>x1 - x0 >= 0.125</code> which should preclude any possibility -of overflow considering that the values for variables <code>y0</code> and <code>y1</code> cannot be unreasonably large themselves.</p> -<h2>What next?</h2> -<p>We could stop here if we wished: there was a single place the value analysis -was worried about and we have used a code review to check that the -dangerous-looking operation was indeed safe. This is a standard way -of proceeding especially for non-critical code. However the reasoning -we made to reach the conclusion that the division was safe is informal -and there could be a mistake in it. In a next post we will try to make the -analysis say that the division is safe which will be more satisfying. -<a href="/assets/img/blog/imported-posts/interp.c">Here is the file</a> in case you wish to try it at home. Another possible exercise if to complete the contract of <code>choose_segment</code> and/or implement it. If you do both you can check your implementation against your specification with a deductive verification plug-in.</p> <p>This post is co-authored by Kerstin Hartig.</p> {% endraw %} diff --git a/_posts/2011-03-26-Helping-the-value-analysis---part-2.html b/_posts/2011-03-26-Helping-the-value-analysis---part-2.html index 900608033d0444ec2277f1c7d95128318506062e..2a7a1fa5330e6dfccbc665bf5ef767b1a88ec38e 100644 --- a/_posts/2011-03-26-Helping-the-value-analysis---part-2.html +++ b/_posts/2011-03-26-Helping-the-value-analysis---part-2.html @@ -212,210 +212,5 @@ analyzer has no chance to prove that the cases offered cover all the possibilities. And it shouldn't be inserted too early lest the information be lost again the number of combinations become too big or the analyzer waste resources on irrelevant parts of the target program.</p> -<p>This post is co-authored by Kerstin Hartig.</p> - <h2>How it started</h2> -<p>In the <a href="index.php?post/2011/03/23/Helping-the-value-analysis-1" hreflang="en">last post</a> -we started a new series about helping the value analysis be more precise. We introduced an <a href="/assets/img/blog/imported-posts/interp.c">interpolation function</a> with the goal of verifying that it is free of run-time errors. -Having launched a first value analysis we got one alarm we need to take care of.</p> -<pre>interp.c:28:[kernel] warning: float operation: assert \is_finite((double )((double )((double )(y1*(double )(x-x0))+(double ) (y0*(double )(x1-x)))/(double ) (x1-x0))); -</pre> -<p>This alarm is emitted because the analyzer is unsure that the value computed by the function is not an infinite or NaN. The suspicion originates from the division by <code>x1 - x0</code>. Furthermore we informally deduced from <code>x0 = t[i].x</code> and <code>x1 = t[i+1].x</code> that <code>x1</code> is always strictly greater than <code>x0</code> and more specifically that <code>x1 - x0 >= 0.125</code>.</p> -<p>In this post we show how to eliminate the alarm formally. For a change of style -we start with a few attempts that are natural but do not work.</p> -<h2>Getting more precise</h2> -<p>From the Value Analysis manual and former posts we know already that using the option <code>-slevel</code> with an adequate argument may (in some cases) help the analyzer already in being more precise. This is the first thing to try:</p> -<pre>frama-c -val -slevel 10 -main interp interp.c -</pre> -<p>We obtain the same results as before. The alarm does not disappear. The analyzer still does not know if the variables of <code>x1</code> and <code>x0</code> may contain the same value or (as they are <code>double</code> variables) if they may be very close to each other which would mean the subtraction <code>x1 - x0</code> may be very close to zero.</p> -<p>We further investigate the output of the analysis:</p> -<pre>[value] Values for function interp: - x0 ∈ [0. .. 5.] - x1 ∈ [0.125 .. 10.] - y0 ∈ [1. .. 74.2099485248] - y1 ∈ [1.00782267783 .. 11013.2329201] - i ∈ {0; 1; 2; 3; 4; 5; 6; } - __retres ∈ [-1.79769313486e+308 .. 1.79769313486e+308] -</pre> -<p>We can see that the expected minimum and maximum return values are very large -occupying the entire range allowed by a double. This is consistent with the fact -that the value analysis is unable to guarantee there is no overflow in the -computation of this result.</p> -<p>A natural first thought could be to write an assertion containing -what we deduced already from looking at the code namely <code>x1 - x0 >= 0.125</code>. -In fact let's modify the program so:</p> -<pre> y1 = ...; - //@ assert x1 - x0 >= 0.125; - Frama_C_show_each_diff(x1 - x0); - return (y1 * (x - x0) + y0 * (x1 - x)) / (x1 - x0); -} -</pre> -<p>Inserting this assertion could be useful in two ways: -the analyzer could tell us that it is true which would be reassuring; -and it could take advantage of the information it contains to improve -the precision of its results. The call to <code>Frama_C_show_each...</code> only -helps to observe the improvements.</p> -<pre>frama-c -val -slevel 10 -main interp interp.c -... -interp_try.c:29:[value] Assertion got status unknown. -[value] Called Frama_C_show_each_diff([-4.875 .. 10.]) -</pre> -<p>Here neither of the two ways work: the analyzer cannot decide -if this assertion is correct and it is -also unable to take advantage of the provided information to eliminate the -alarm or for that matter to improve its prediction of the value of -<code>x1 - x0</code> which still contains zero and values close to zero.</p> -<p>But why? The states propagated by the value analysis assign values to individual -variables such as <code>x0</code> and <code>x1</code>. Looking again at the final values we see that <code>x0</code> and <code>x1</code> are both interpreted as the -following floating-point ranges:</p> -<pre>x0 ∈ [0. .. 5.] -x1 ∈ [0.125 .. 10.] -</pre> -<p>Providing information about <code>x1 - x0</code> -when <code>x0</code> and <code>x1</code> are already imprecise has the following drawbacks:</p> -<ul> -<li>the analyzer cannot tell whether the assertion is true or false because it is already manipulating imprecise values for <code>x0</code> and <code>x1</code> that could make the formula true or false.</li> -<li>Even assuming it was strong at symbolic manipulations and able to transform <code>x1 - x0 >= 0.125</code> into <code>x1 >= x0 + 0.125</code> (or a similar formula that is actually a correct transformation in double-precision floating-point arithmetics) to improve the value of <code>x1</code> it would be impaired by the fact that <code>x0</code> is already imprecise so that the formula doesn't tell it anything new about the value of <code>x1</code>. And similarly when trying to take advantage of the formula to improve the value of <code>x0</code>.</li> -</ul> -<p>The value analysis does not represent information about the -relationship the values of <code>x0</code> and <code>x1</code> may have. Therefore it -considers possibilities here that do not exist in a real execution. -Since the states propagated by the analysis assign values to -variables only the best way to provide information is to write assertions -that directly tell about the values of variables:</p> -<pre> x0 = t[i].x; -/*@ assert x0 == 0. || x0 == 0.125 || x0 == 0.25 || x0 == 0.5 || - x0 == 1. || x0 == 2. || x0 == 5. ; */ - y0 = t[i].y; - x1 = t[i+1].x; -/*@ assert x1 == 0.125 || x1 == 0.25 || x1 == 0.5 || x1 == 1. || - x1 == 2. || x1 == 5. || x1 == 10. ; */ - y1 = t[i+1].y; - Frama_C_show_each_diff(x1 - x0); - return (y1 * (x - x0) + y0 * (x1 - x)) / (x1 - x0); -} -</pre> -<p>We augment the option <code>-slevel</code> since the two assertions multiply the number -of possibilities:</p> -<pre>frama-c -val -slevel 100 -main interp interp.c -... -[value] Called Frama_C_show_each_diff(-4.875) -[value] Called Frama_C_show_each_diff(-4.75) -[value] Called Frama_C_show_each_diff(-4.5) -... -[value] Called Frama_C_show_each_diff({0; }) -... -[value] Called Frama_C_show_each_diff(5.) -[value] Called Frama_C_show_each_diff(10.) -... -interp_try.c:36:[kernel] warning: float operation: assert \is_finite((double )((double )((double )(y1*(double )(x-x0))+(double ) (y0*(double )(x1-x)))/(double ) (x1-x0))); -</pre> -<p>The alarm remains. This was to be expected because -the analyzer does not know that certain combinations of values for the pair -<code>(x0 x1)</code> are impossible which include the cases where <code>x0 == x1</code>. To remove these cases we can instead provide an assertion about the possible pairs of <code>x0</code> and <code>x1</code>:</p> -<pre>/*@ assert x0 == 0. && x1 == 0.125 || - x0 == 0.125 && x1 == 0.25 || - x0 == 0.25 && x1 == 0.5 || - x0 == 0.5 && x1 == 1. || - x0 == 1. && x1 == 2. || - x0 == 2. && x1 == 5. || - x0 == 5. && x1 == 10. ; -*/ -</pre> -<p>Looking at the output again we notice that the alarm has disappeared. -The values displayed for <code>x1 - x0</code> show that the assertion was taken into account. Finally the return value is in a more acceptable range now.</p> -<pre>[value] Called Frama_C_show_each_diff(5.) -[value] Called Frama_C_show_each_diff(3.) -[value] Called Frama_C_show_each_diff(1.) -[value] Called Frama_C_show_each_diff(0.5) -[value] Called Frama_C_show_each_diff(0.25) -[value] Called Frama_C_show_each_diff(0.125) -[value] Called Frama_C_show_each_diff(0.125) -... -[value] Values for function interp: -... - __retres ∈ [-16801.608905 .. 881132.843557] -</pre> -<p>Still one problem remains. The assertion can not be verified by the value analysis:</p> -<pre>interp_try.c:29:[value] Assertion got status unknown. -</pre> -<p>The alarm is gone but only under the assumption that the information provided in the above assertion is correct. -And as far as the analyzer is concerned -it is unfortunately not guaranteed.</p> -<p>This attempt is only half-successful because we are trying to reduce -and divide the propagated state too late at a point where the -values for <code>x0</code> and <code>x1</code> have already been computed and the information -about their relationship already lost. Ideally we would like to nudge -the analyzer into finding out about the relationship by itself. Being -non-relational it cannot -represent the relationship inside a single state but it can represent -it virtually by using several states. This is in fact what we have -been forcing it to do with the last assertion.</p> -<h2>How to improve the provided hint?</h2> -<p>The computation of the formula as investigated so far is -dependent on the possible values of <code>x0 x1 y0</code> and <code>y1</code>. -Looking again at the function we can see that the respective -computations of <code>x0 x1 y0</code> and <code>y1</code> are dependent on the value of <code>i</code> immediately before. -Due to the postcondition of the <code>choose_segment</code> function we know that only integer values between <code>0</code> and <code>6</code> might be assigned to <code>i</code>. This post-condition is taken into account by the value analysis and the information -restituted in the final values displayed for <code>interp</code>:</p> -<pre>i ∈ {0; 1; 2; 3; 4; 5; 6; } -</pre> -<p>Depending on the value of <code>i</code> there are actually only seven possible cases.</p> -<pre>x0 == 0. && x1 == 0.125 && y0 == 1. && y1 == 1.00782267782571089 || -x0 == 0.125 && x1 == 0.25 && y0 == 1.00782267782571089 && y1 == 1.03141309987957319 || -x0 == 0.25 && x1 == 0.5 && y0 == 1.03141309987957319 && y1 == 1.1276259652063807 || -x0 == 0.5 && x1 == 1. && y0 == 1.1276259652063807 && y1 == 1.54308063481524371 || -x0 == 1. && x1 == 2. && y0 == 1.54308063481524371 && y1 == 3.76219569108363139 || -x0 == 2. && x1 == 5. && y0 == 3.76219569108363139 && y1 == 74.2099485247878476 || -x0 == 5. && x1 == 10. && y0 == 74.2099485247878476 && y1 == 11013.2329201033244 -</pre> -<p>Now we want to perform a case analysis to make the analyzer propagate only those 7 specific cases. -A new appoach could be to formulate an assertion to make the analysis -be split before the computation of the four variables by using information the analyzer already has the range of values for <code>i</code>. -The function could now look like this:</p> -<pre>/*@ requires 0. <= x <= 10. ; */ -double interp(double x) -{ - double x0 x1 y0 y1; - int i; - i = choose_segment(x); - //@ assert i == 0 || i == 1 || i == 2 || i == 3 || i == 4 || i == 5 || i == 6 ; - x0 = t[i].x; - y0 = t[i].y; - x1 = t[i+1].x; - y1 = t[i+1].y; - Frama_C_show_each_x0_x1(x0 x1); - return (y1 * (x - x0) + y0 * (x1 - x)) / (x1 - x0); -} -</pre> -<p>Running Frama-C this time we achieve success. The alarm is gone and the hint assertion can at the same time be verified. -The call to <code>Frama_C_show_each_x0_x1(x0 x1)</code> confirms the absence of any case in which <code>x0</code> and <code>x1</code> contain the same value. Thereby it is possible to show that the divisor is not zero or a value too close to zero.</p> -<pre>frama-c -val -slevel 100 -main interp interp.c -... -interp.c:25:[value] Assertion got status valid. -[value] Called Frama_C_show_each_x0_x1(5. 10.) -[value] Called Frama_C_show_each_x0_x1(2. 5.) -[value] Called Frama_C_show_each_x0_x1(1. 2.) -[value] Called Frama_C_show_each_x0_x1(0.5 1.) -[value] Called Frama_C_show_each_x0_x1(0.25 0.5) -[value] Called Frama_C_show_each_x0_x1(0.125 0.25) -[value] Called Frama_C_show_each_x0_x1({0; } 0.125) -... -[value] Values for function interp: -... - __retres ∈ [-11013.2329201 .. 11161.6528172] -</pre> -<p>Regarding the return value again we obtain a result in an acceptable range. -The difference with the previous approach is that this time -the analyzer is able to verify the assertion. -Therefore this last approach is not only less verbose but also -safer than the former.</p> -<p>In conclusion case analysis is a powerful tool to help Frama-C's value analysis -especially when the information required to reach the verification -goal is relational in nature. When this technique works the assertion -to split the different cases shouldn't be inserted too late when the -analyzer has no chance to prove that the cases offered cover all the -possibilities. And it shouldn't be inserted too early lest the information -be lost again the number of combinations become too big or the -analyzer waste resources on irrelevant parts of the target program.</p> <p>This post is co-authored by Kerstin Hartig.</p> {% endraw %} diff --git a/_posts/2011-04-05-Verifying-the-Compression-Library-QuickLZ.html b/_posts/2011-04-05-Verifying-the-Compression-Library-QuickLZ.html index 2bd4fca708ec4ccc314527e6cc9b21982e0c73f1..959fd00ce9d26af8671cbf8ed7a0a1946c5075b4 100644 --- a/_posts/2011-04-05-Verifying-the-Compression-Library-QuickLZ.html +++ b/_posts/2011-04-05-Verifying-the-Compression-Library-QuickLZ.html @@ -404,402 +404,5 @@ The next step now that we have established a base camp is to remove as many as <blockquote><p>Incidentally once the fix is applied no alarms at all are emitted because with our assumptions the safety test causes the library to return before the <code>memcpy()</code>. This shows the necessity at the very least to verify the library using other values for compressed and decompressed sizes.</p> </blockquote> <p>This post is co-authored by Kerstin Hartig and benefited of suggestions from Lasse Reinhold. Apologies to any reader confused by Douglas Adams references.</p> -<p>Note: this work was done with the development version of the value analysis at the time. Recent released versions of Frama-C detect another innocuous issue where an uninitialized variable is used in order to silence compiler warnings: <code>{ int i; i;…</code>. In order to replay the analysis with such a recent version the uninitialized access to <code>i</code> should be removed.</p> - <p>This new series is dedicated to the verification of the C version of Open Source compression library <a href="http://www.quicklz.com/">QuickLZ</a> version 1.5.0 using Frama-C's Value Analysis. The source code can be downloaded from the web site.</p> -<p>QuickLZ offers compression and decompression routines using the Lempel-Ziv (LZ) algorithm. Various options are provided at compile-time. One noteworthy setting is the <code>QLZ_MEMORY_SAFE</code> compilation mode; this option guarantees that the -decompression routine will terminate safely if fed corrupted data without illegal memory accesses.</p> -<p>In this post we focus on the analysis of the decompression routines using <code>QLZ_COMPRESSION_LEVEL == 1</code> with the option <code>QLZ_MEMORY_SAFE</code> enabled.</p> -<h2>Analysis Context</h2> -<p>The <code>QLZ_MEMORY_SAFE</code> guarantee is interesting to verify formally and a good fit for the value analysis. -Still with the Skein tutorial under our belt we do not expect to immediately -get this kind of general result. Let us start with the decompression of -a 20-char compressed buffer inside a 40-char destination buffer. -If we succeed at verifying that we can come back to these choices and -see what is needed to make the verification more general.</p> -<p>We need to define a variable <code>state_decompress</code> used -by the library for temporary storage during decompression:</p> -<pre>#include "quicklz.h" -qlz_state_decompress state_decompress; -</pre> -<p>We define the destination array as a global variable. This means the value analysis assumes it is initialized to zero. If we succeed we may later improve the verification -by using an uninitialized local array for the destination buffer. If we are able to analyze that program without alarms it will confirm -that the decompression routine does not -use any contents of the destination buffer it has not already written there -which will be another interesting property. For now let us concentrate -on memory safety:</p> -<pre>unsigned char file_data[20]; -unsigned char decompressed[40]; -</pre> -<p>The program we write for the purpose of this analysis fills <code>file_data</code> with arbitrary contents by calling -an unknown function <code>u()</code>. -Then the decompression function <code>qlz_decompress()</code> reads from <code>file_data</code> decompresses using <code>state_decompress</code> and writes the decompressed data to array <code>decompressed</code> returning the decompressed size:</p> -<pre>int main(int argc char* argv[]) -{ - size_t d; - int i; - for (i=0; i<20; i++) - file_data[i] = u(); - d = qlz_decompress(file_data decompressed &state_decompress); - return 0; -} -</pre> -<p>Get the files: <a href="/assets/img/blog/imported-posts/QuickLZ/decompress.c">decompress.c</a> <a href="/assets/img/blog/imported-posts/QuickLZ/quicklz_0.c">quicklz.c</a> <a href="/assets/img/blog/imported-posts/QuickLZ/quicklz.h">quicklz.h</a>.</p> -<p>The QuickLZ library calls in two places the function <code>memcpy()</code> -which is expected to be in a system library. -A list of missing functions can be printed with the command:</p> -<pre>$ frama-c -metrics quicklz.c -... -Undefined functions (1): - memcpy (2 calls); -... -</pre> -<p>The value analysis needs source code to work accurately. As explained in the <a href="http://frama-c.com/download/value-analysis-Carbon-20110201.pdf">Frama-C Value Analysis manual</a> the best way to handle missing functions like <code>memset()</code> or <code>memcpy()</code> is to provide source code for them. In the same fashion as in the <a href="http://blog.frama-c.com/index.php?q=Skein">analysis of the Skein library</a> we provide our own implementation of <code>memcpy()</code> and place it in a file <a href="/assets/img/blog/imported-posts/QuickLZ/libc.c">libc.c</a> with the other source files.</p> -<h2>Step by Step Analysis</h2> -<p>We first launch an imprecise analysis:</p> -<pre>$ frama-c -val decompress.c quicklz.c libc.c > log -$ grep assert log -quicklz.c:209:[kernel] warning: out of bounds read. assert \valid(src); -quicklz.c:668:[kernel] warning: pointer comparison: assert \pointer_comparable(offset2 (dst-2)-1); -quicklz.c:209:[kernel] warning: out of bounds write. assert \valid(dst); -quicklz.c:106:[kernel] warning: out of bounds read. assert \valid(p+3); -quicklz.c:112:[kernel] warning: out of bounds read. assert \valid(p); -quicklz.c:110:[kernel] warning: out of bounds read. assert \valid(p); -quicklz.c:110:[kernel] warning: out of bounds read. assert \valid(p+1); -quicklz.c:108:[kernel] warning: out of bounds read. assert \valid(p); -quicklz.c:108:[kernel] warning: out of bounds read. assert \valid(p+1); -quicklz.c:108:[kernel] warning: out of bounds read. assert \valid(p+2); -quicklz.c:106:[kernel] warning: out of bounds read. assert \valid(p); -quicklz.c:106:[kernel] warning: out of bounds read. assert \valid(p+1); -quicklz.c:106:[kernel] warning: out of bounds read. assert \valid(p+2); -quicklz.c:607:[kernel] warning: out of bounds read. assert \valid(src+2); -quicklz.c:713:[kernel] warning: out of bounds read. assert \valid(src); -quicklz.c:713:[kernel] warning: out of bounds write. assert \valid(dst); -libc.c:9:[kernel] warning: out of bounds read. assert \valid(tmp_0); -libc.c:9:[kernel] warning: out of bounds write. assert \valid(tmp); -</pre> -<p>18 alarms are emitted. As there are large arrays used in the source code we try to improve this result by passing a very large argument to the <code>-slevel</code> option.</p> -<pre>$ frama-c -val decompress.c quicklz.c libc.c -slevel 6000 > log -$ grep assert log -quicklz.c:106:[kernel] warning: out of bounds read. assert \valid(p+3); -quicklz.c:106:[kernel] warning: out of bounds read. assert \valid(p); -quicklz.c:106:[kernel] warning: out of bounds read. assert \valid(p+1); -quicklz.c:106:[kernel] warning: out of bounds read. assert \valid(p+2); -quicklz.c:209:[kernel] warning: out of bounds read. assert \valid(src); -quicklz.c:607:[kernel] warning: out of bounds read. assert \valid(src+2); -quicklz.c:209:[kernel] warning: out of bounds write. assert \valid(dst); -quicklz.c:108:[kernel] warning: out of bounds read. assert \valid(p+2); -quicklz.c:108:[kernel] warning: out of bounds read. assert \valid(p+1); -quicklz.c:108:[kernel] warning: out of bounds read. assert \valid(p); -quicklz.c:713:[kernel] warning: out of bounds read. assert \valid(src); -quicklz.c:713:[kernel] warning: out of bounds write. assert \valid(dst); -libc.c:9:[kernel] warning: out of bounds read. assert \valid(tmp_0); -libc.c:9:[kernel] warning: out of bounds write. assert \valid(tmp); -</pre> -<p>The analyzer still emits 14 alarms. We now try to eliminate these. -The process is a routine of picking -an alarm investigating where it comes from displaying values of variables -to comprehend the situation -in order to eventually resolve it by helping the analyzer.</p> -<p>Let us have a look at the first alarm:</p> -<pre>[value] computing for function fast_read <-qlz_decompress_core <-qlz_decompress <-main. - Called from quicklz.c:578. -quicklz.c:106:[kernel] warning: out of bounds read. assert \valid(p+3); -</pre> -<p>We have a look at line 106 in the source code. It refers to the access to <code>p+3</code> in <code>case 4</code> of the <code>switch</code> construct in the function <code>fast_read()</code>.</p> -<pre>static __inline ui32 fast_read(void const *src ui32 bytes) -{ -... - unsigned char *p = (unsigned char*)src; - switch (bytes) - { - case 4: - return(*p | *(p + 1) << 8 | *(p + 2) << 16 | *(p + 3) << 24); - case 3: - return(*p | *(p + 1) << 8 | *(p + 2) << 16); - case 2: - return(*p | *(p + 1) << 8); - case 1: - return(*p); - } -... -} -</pre> -<p><code>fast_read()</code> is unlikely to be at fault here. Instead if there -is a bug it is likely to be in <code>fast_read()</code>'s caller and if this is -a false alarm the imprecision again is to be found in the -analysis of <code>fast_read()</code>'s caller.</p> -<p>The log indicates that <code>fast_read()</code> was called from line 578 when the -alarm appeared. -Going to line 578 we indeed find the function call:</p> -<pre> cword_val = fast_read(src CWORD_LEN); -</pre> -<p><code>CWORD_LEN</code> is defined to be <code>4</code> at the top of the quicklz.c file. Here we want to inspect the values of variable <code>src</code>. Therefore we insert a call to -a <code>Frama_C_show_each...()</code> function immediately before the call to <code>fast_read()</code>:</p> -<pre> Frama_C_show_each_src_at_beginning(src); - cword_val = fast_read(src CWORD_LEN); -</pre> -<blockquote><p>Regarding the time taken by the analysis: the analyzer may need some time to finish the analysis especially when unrolling with very large arguments or when the analyzer is made to inspect a large number of cases separately. You do not have to wait for the end of the analysis to look at the log file. We decided to start with the first alarms. Inserting assertions or logging functions <code>Frama_C_show_each...()</code> to get more information we expect the corresponding output to appear early in the log even while the analysis is still running.</p> -</blockquote> -<p>Although only logging some values with a <code>Frama_C_show_each...()</code> function -does not change what the program does -it may change a bit the order in which values are propagated so we -get a different first alarm this time. The new first alarm is still -very close to the previous one and obviously related: it takes place -in the same function at the same line but for the next call to this -function in the caller a few lines below. -Let us study this new alarm as if it was the one -we were after from the beginning. The log says:</p> -<pre>[value] Called Frama_C_show_each_src_at_beginning({{ &file_data + [7..17] ;}}) -[value] computing for function fast_read <-qlz_decompress_core <-qlz_decompress <-main. - Called from quicklz.c:588. -quicklz.c:106:[kernel] warning: out of bounds read. assert \valid(p+3); -</pre> -<p>This time the alarm refers to a call to <code>fast_read()</code> a few lines below at 588:</p> -<pre> fetch = fast_read(src 4); -</pre> -<p>Inspecting the output we can see that <code>src</code> may be in the range <code>{{&file_data + [7..17];}}</code>. As <code>file_data</code> is an array of size 20 it is indeed illegal to read 4 bytes starting from <code>{{&file_data + 17}}</code>. -When compiling with the <code>QLZ_MEMORY_SAFE</code> option we expect this to be prevented by -the safety test above. Again we display the values of <code>src</code> and -<code>last_source_byte</code> in the beginning of the <code>QLZ_MEMORY_SAFE</code> block to obtain more information.</p> -<pre>#ifdef QLZ_MEMORY_SAFE - Frama_C_show_each_src_last(src last_source_byte); - if(src + CWORD_LEN - 1 > last_source_byte) - return 0; -#endif -</pre> -<p>The corresponding output looks like this:</p> -<pre>[value] Called Frama_C_show_each_src_last({{ &file_data + [7..17] ;}} - {{ &file_data + [10..4294967294] ;}})) -</pre> -<p>The pointer <code>last_source_byte</code> seems to possibly contain very large offsets of <code>file_data</code>. We inspect the source to determine where these come from. The last assignment to this pointer can be found within this function a few lines above.</p> -<pre>last_source_byte = source + qlz_size_compressed((const char *)source) - 1; -</pre> -<p>It is the address of the last element in the compressed array. -The auxiliary function <code>qlz_size_compressed()</code> is called to determine the size of the compressed array. -Studying function <code>qlz_size_compressed()</code> we find that the information is read from the header of the compressed array. Specifically the compressed size is read from either 1 or 4 bytes starting at the second byte in the source array. -This explains why the <code>last_source_byte</code> values are so imprecise. As the source array is filled with arbitrary values the header is filled arbitrarily as well. But in the analysis context we set the size for our compressed array to be 20. To be consistent let us make sure the analysis uses the same size by placing an assertion within function <code>qlz_size_compressed()</code>.</p> -<pre>size_t qlz_size_compressed(const char *source) -{ - ui32 n r; - n = (((*source) & 2) == 2) ? 4 : 1; - r = fast_read(source + 1 n); - r = r & (0xffffffff >> ((4 - n)*8)); - //@ assert r == 20; - return r; -} -</pre> -<p>Once the analysis is launched again -the log near the first alarm looks like:</p> -<pre>[value] Called Frama_C_show_each_src_last({{ &file_data + [7..17] ;}} - {{ &file_data + {19; } ;}}) -[value] computing for function fast_read <-qlz_decompress_core <-qlz_decompress <-main. - Called from quicklz.c:590. -quicklz.c:106:[kernel] warning: out of bounds read. assert \valid(p+3); -[value] Called Frama_C_show_each_src_at_beginning({{ &file_data + [7..17] ;}}) -</pre> -<p>Thinking about it for ourselves the condition <code>src + 4 - 1 > last_source_byte</code> -is true if <code>src</code> is <code>{{&file_data + 17}}</code> and it is false when <code>src</code> is in <code>{{&file_data + [7..16]}}</code>. Still the output of <code>Frama_C_show_each_src_at_beginning()</code> claims that <code>src</code> might be <code>{{&file_data + [7..17]}}</code>.</p> -<p>Obviously the analyzer is not taking full advantage of the available -information although in this case -the reduced value for <code>src</code> would be representable. This is because computing the values that -make the condition false amounts to solving an equation. The analyzer -cannot expect to solve all possible equations (The C language allows to write some -fiendishly difficult quadratic ones). It could be expected to solve this one -but obviously it doesn't. We could report this issue as a feature wish -but no one ever listens.</p> -<p>Determining which subsets of values for <code>src</code> make the condition -true or false is a difficult problem but finding out that the condition is -true or false for user-provided subsets is easier. -Let's help the analyzer by adding an assertion that divides <code>src</code>'s values into those that respectively lead to a true condition and to a false one that is <code>{{&file_data + 17}}</code> and <code>{{&file_data + [7..16]}}</code>. Note that simple interval arithmetics allow to see that in the first case <code>src + 4 - 1 > last_source_byte</code> is true and that in the second case it is false for all values of <code>src</code>. The analyzer once told to separate these subsets of value naturally propagates only the latter after the <code>if</code>.</p> -<p>Note that we place our annotations before the problematic call to <code>fast_read()</code> and that we do not try to make assumptions within function <code>fast_read()</code> itself in line 106 where the alarm occurs. Intuitively this is a way of -saying that the problem (or imprecision) is not with <code>fast_read</code> but with -its caller. It is a matter of placing the annotation in just the right place as in <a href="/index.php?post/2011/03/26/Helping-the-value-analysis-2" hreflang="en">this previous example</a>.</p> -<p>Or looking at this situation from another angle the function <code>fast_read()</code> is called nine times in the library. Placing an assertion inside the function means the assertion applies for every function call. If placed before the function call it only applies to this specific call. An assertion to help the analyzer which might be valid for one call may be false for another call to the same function.</p> -<pre>#ifdef QLZ_MEMORY_SAFE - //@ assert src <= source + 16 || src > source + 16; - if(src + 4 - 1 > last_source_byte) - return 0; -#endif -</pre> -<p>After adding this assertion and analyzing again the output is slightly different.</p> -<pre> Called from quicklz.c:581. -quicklz.c:106:[kernel] warning: out of bounds read. assert \valid(p+3); -</pre> -<p>The same problem re-appears in line 581 which contains the first call to <code>fast_read</code>. It is normal to see this alarm come back to first position now that we have eliminated its close competitor. In the safety test above line 581 we find the same precision issue we just handled. We again divide the state into values that make the condition true and values that make it false in order to circumvent the analyzer's limitations.</p> -<pre>#ifdef QLZ_MEMORY_SAFE - Frama_C_show_each_src_last(src last_source_byte); - //@ assert src <= source + 16 || src > source + 16; - if(src + CWORD_LEN - 1 > last_source_byte) - return 0; -#endif -</pre> -<p>Launching Frama-C again we discover that the alarm has disappeared thanks to the hint we provided. -Some alarms remain. Let us have a look at the next one.</p> -<pre>[value] computing for function memcpy_up <-qlz_decompress_core <-qlz_decompress <-main. - Called from quicklz.c:680. -quicklz.c:210:[kernel] warning: out of bounds write. assert \valid(dst); -</pre> -<p>We inspect line 210 in the function <code>memcpy_up()</code>.</p> -<pre>static __inline void memcpy_up(unsigned char *dst const unsigned char *src ui32 n) -{ -... - unsigned char *end = dst + n; - while(dst < end) - { - *dst = *src; - dst++; - src++; - } -... -} -</pre> -<p>The analyzer warns us of a possible out of bounds write in <code>*dst = *src;</code>. The pointer <code>dst</code> is passed to the function as an argument. Guided by the log we find the function call at line 680. Again we start by displaying the values before the function call to understand where the problem comes from.</p> -<pre> Frama_C_show_each_memcpy(dst offset2 matchlen); - memcpy_up(dst offset2 matchlen); -</pre> -<p>The result is:</p> -<pre>[value] Called Frama_C_show_each_memcpy({{ &decompressed + {3; 4; } ;}} - {{ &decompressed + {0; 1; } ;}} [0..255]) -[value] Called Frama_C_show_each_src_last({{ &file_data + [7..20] ;}} - {{ &file_data + {19; } ;}}) -[value] computing for function memcpy_up <-qlz_decompress_core <-qlz_decompress <-main. - Called from quicklz.c:680. -quicklz.c:210:[kernel] warning: out of bounds write. assert \valid(dst); -</pre> -<p>Seeing the <code>#ifdef QLZ_MEMORY_SAFE</code> guard above the call and inserting some more -<code>Frama_C_show_each...()</code> calls we find that the first issue is that <code>last_destination_byte</code> is imprecise. It seems the problem is that the input buffer -having been filled arbitrarily a nondeterministic value is read -from the header to use as the decompressed size. -In our analysis context we set the size of the decompressed array to 40. -Remember that earlier we have assumed that the compressed size indicated by the header was 20. We should write another assertion that similarly sets the decompressed size to be the same as in the analysis context.</p> -<pre>size_t qlz_size_decompressed(const char *source) -{ - ui32 n r; - n = (((*source) & 2) == 2) ? 4 : 1; - r = fast_read(source + 1 + n n); - r = r & (0xffffffff >> ((4 - n)*8)); - //@ assert r == 40; - return r; -} -</pre> -<p>Next:</p> -<pre>[value] Called Frama_C_show_each_memcpy({{ &decompressed + [0..8] ;}} - {{ &decompressed + {0; 1; 2; 3; 4; 5; } ;}} - [0..36]) -[value] Called Frama_C_show_each_src_last({{ &file_data + [7..20] ;}} - {{ &file_data + {19; } ;}}) -[value] computing for function memcpy_up <-qlz_decompress_core <-qlz_decompress <-main. - Called from quicklz.c:681. -quicklz.c:211:[kernel] warning: out of bounds write. assert \valid(dst); -quicklz.c:211:[kernel] warning: out of bounds read. assert \valid(src); -</pre> -<p>The output has changed slightly but the value analysis is still emitting alarms. Assuming the decompressed array is of size 40 we can safely write or read <code>&decompressed + 39</code>. The result of <code>Frama_C_show_each_memcpy()</code> states that at the point we are considering up to 36 bytes might be read from <code>&decompressed + 5</code> and might be written to <code>&decompressed + 8</code> to just mention one example. This would be indeed out of bounds.</p> -<p>We assume this to be a false alarm because there should not be any illegal memory access in the <code>QLZ_MEMORY_SAFE</code> mode. Let us have a look at the <code>QLZ_MEMORY_SAFE</code> block just above the problematic call to <code>memcpy_up</code> and obtain more information about the values. -<code>MINOFFSET</code> is defined to be <code>2</code> and <code>UNCOMPRESSED</code> is defined to be <code>4</code> in quicklz.c.</p> -<pre>#ifdef QLZ_MEMORY_SAFE - Frama_C_show_each_all(offset2 history dst matchlen); - if(offset2 < history || offset2 > dst - MINOFFSET - 1) - return 0; - Frama_C_show_each_bound(matchlen last_destination_byte dst (last_destination_byte - dst - 4 + 1)); - if(matchlen > (ui32)(last_destination_byte - dst - UNCOMPRESSED_END + 1)) - return 0; -#endif -</pre> -<p>We search the log for the last calls to <code>Frama_C_show_each_all()</code> and <code>Frama_C_show_each_bound()</code> before the alarm occurs and get this result:</p> -<pre>[value] Called Frama_C_show_each_all({{ &NULL ; &decompressed + {0; 1; 2; 3; 4; 5; } ;}} - {{ &decompressed ;}} - {{ &decompressed + [0..8] ;}} [0..255]) -[value] Called Frama_C_show_each_bound([0..255] {{ &decompressed + {39; } ;}} - {{ &decompressed + [0..8] ;}} [28..36]) -</pre> -<p>For the sake of memory safety the <code>QLZ_MEMORY_SAFE</code> block has to make sure nothing bad happens. The suspicion here is that by abstract interpretation the possible values of <code>dst</code> <code>offset2</code> and <code>matchlen</code> are summarized in such a way that at the call to <code>memcpy_up</code> combinations of values are considered to be possible that actually are not. -We help the analyzer by providing the hint that each value of <code>dst</code> -should be considered separately. For each single value of <code>dst</code> the -analysis can then compute the precise values of <code>offset2</code> (and <code>matchlen</code>) that are -eliminated by the safety test <code>if(offset2 < history || offset2 > dst - MINOFFSET - 1) return 0;</code> (and the other test).</p> -<pre>#ifdef QLZ_MEMORY_SAFE - Frama_C_show_each_all(offset2 history dst matchlen); - /*@ assert - dst == decompressed || dst == decompressed + 1 || - dst == decompressed + 2 || dst == decompressed + 3 || - dst == decompressed + 4 || dst == decompressed + 5 || - dst == decompressed + 6 || dst == decompressed + 7 || - dst == decompressed + 8 || dst == decompressed + 9 || - dst == decompressed + 10 || dst == decompressed + 11 || - dst == decompressed + 12 || dst == decompressed + 13 || - dst == decompressed + 14 || dst == decompressed + 15 || - dst == decompressed + 16 || dst == decompressed + 17 || - dst == decompressed + 18 || dst == decompressed + 19 || - dst == decompressed + 20 || dst == decompressed + 21 || - dst == decompressed + 22 || dst == decompressed + 23 || - dst == decompressed + 24 || dst == decompressed + 25 || - dst == decompressed + 26 || dst == decompressed + 27 || - dst == decompressed + 28 || dst == decompressed + 29 || - dst == decompressed + 30 || dst == decompressed + 31 || - dst == decompressed + 32 || dst == decompressed + 33 || - dst == decompressed + 34 || dst == decompressed + 35 || - dst == decompressed + 36 || dst == decompressed + 37 || - dst == decompressed + 38 || dst == decompressed + 39; */ - if(offset2 < history || offset2 > dst - MINOFFSET - 1) - return 0; - Frama_C_show_each_bound(matchlen last_destination_byte dst (last_destination_byte - dst - 4 + 1)); - if(matchlen > (ui32)(last_destination_byte - dst - UNCOMPRESSED_END + 1)) - return 0; -#endif -</pre> -<p>Running the analysis again only the following two alarms remain:</p> -<pre>[value] computing for function memcpy <-qlz_decompress <-main. - Called from quicklz.c:854. -libc.c:9:[kernel] warning: using size of 'void' -libc.c:9:[kernel] warning: out of bounds read. assert \valid(tmp_0); -libc.c:9:[kernel] warning: out of bounds write. assert \valid(tmp); -</pre> -<h2>Tackling the last alarms</h2> -<p>In line 854 the function <code>memcpy()</code> is called from inside function <code>qlz_decompress()</code>.</p> -<pre>size_t dsiz = qlz_size_decompressed(source); -... - if((*source & 1) == 1) - { - reset_table_decompress(state); - dsiz = qlz_decompress_core((const unsigned char *)source (unsigned char *)destination dsiz state (const unsigned char *)destination); - } - else - { - Frama_C_show_each_dsiz(destination source qlz_size_header(source) dsiz); - memcpy(destination source + qlz_size_header(source) dsiz); - } -</pre> -<p>The condition <code>if((*source & 1) == 1)</code> checks if the last bit of the first header byte of the compressed data equals <code>1</code>. By doing some research in the source code we find this bit indicates whether the data was compressible or if it was copied verbatim. If compression was used the bit contains the value <code>1</code>. If not the bit's value is <code>0</code>. In the then-branch (when the data is indeed compressed by the algorithm) the reverse decompression algorithm is applied. In the else-branch knowing that the incompressible data was copied verbatim at compress-time the data from the source buffer is copied to the decompressed array omitting the header. In this case the compressed array is supposed to be exactly of the size of the decompressed header plus the size of the header. -Let us display the possible values at this point.</p> -<pre>[value] Called Frama_C_show_each_dsiz({{ &decompressed ;}} {{ &file_data ;}} - {3; 9; } {40; }) -</pre> -<p>The decompressed size <code>dsiz</code> is read from the header by the function <code>qlz_size_decompressed()</code> and then passed to <code>memcpy()</code>. We forced this size to be <code>40</code> so this is what the analyzer prints for <code>dsiz</code>. In this call to <code>memcpy()</code> <code>40</code> bytes will be read starting from either <code>&file_data + 3</code> or <code>&file_data + 9</code>. But as we fixed the compressed size to 20 there definitely will be an illegal access.</p> -<p>The problem is that this program point can be reached with a -corrupted header. -Since the source and destination buffers can be assumed to have been -allocated with sizes read from the header when copying the -entire contents from one to the other -there should be a guard that checks the compressed size to be equal to the decompressed size plus the size of the header</p> -<p>This bug was reported and is fixed in version 1.5.1 beta of QuickLZ. The fix consists in adding the guard below before the call to <code>memcpy()</code>.</p> -<pre>if(qlz_size_compressed(source) != qlz_size_decompressed(source) + qlz_size_header(source)) - return 0; -</pre> -<h2>Verification is not finished.</h2> -<p>There were several assumptions made during verification: we were checking only <code>QLZ_COMPRESSION_LEVEL 1</code> and -assumed that the compressed and decompressed sizes were fixed in order to help the analyzer. Additionally the decompressed array is defined globally and therefore initialized before the first use which represents a weaker property than using an uninitialized local declaration for the analysis.</p> -<p>The manually added assertions are shown to be valid by the analyzer except for the two assertions that define the compressed and decompressed sizes.</p> -<pre>quicklz.c:185:[value] Assertion got status unknown. -quicklz.c:195:[value] Assertion got status unknown. -quicklz.c:580:[value] Assertion got status valid. -quicklz.c:590:[value] Assertion got status valid. -quicklz.c:677:[value] Assertion got status valid. -</pre> -<p>After investigating the decompression routines this call to <code>memcpy()</code> contained the last remaining alarms. -This means that under the assumptions we made so far the decompression routines are safe from any other undefined behavior. -The next step now that we have established a base camp is to remove as many assumptions are possible to get the most general verification result.</p> -<blockquote><p>Incidentally once the fix is applied no alarms at all are emitted because with our assumptions the safety test causes the library to return before the <code>memcpy()</code>. This shows the necessity at the very least to verify the library using other values for compressed and decompressed sizes.</p> -</blockquote> -<p>This post is co-authored by Kerstin Hartig and benefited of suggestions from Lasse Reinhold. Apologies to any reader confused by Douglas Adams references.</p> <p>Note: this work was done with the development version of the value analysis at the time. Recent released versions of Frama-C detect another innocuous issue where an uninitialized variable is used in order to silence compiler warnings: <code>{ int i; i;…</code>. In order to replay the analysis with such a recent version the uninitialized access to <code>i</code> should be removed.</p> {% endraw %} diff --git a/_posts/2011-04-11-C99-promotion-rules-what-.html b/_posts/2011-04-11-C99-promotion-rules-what-.html index 3db33877a474f8639036ff5f902c25224096093f..8bde7949acbbf8b535e58a9a937e0e1340b50768 100644 --- a/_posts/2011-04-11-C99-promotion-rules-what-.html +++ b/_posts/2011-04-11-C99-promotion-rules-what-.html @@ -25,23 +25,5 @@ summary: <li>"Otherwise both operands are converted to the unsigned integer type corresponding to the type of the operand with signed integer type."</li> </ol> <p>There is a philosophy hidden in there. The philosophy seems to be "favor unsigned types unless the signed type makes more sense". Even a signed type of higher hank may see its values converted to the unsigned version of the same type changing the meaning of half of them. The rank matters only when it confirms that the unsigned type should be favored. You may be forgiven for wondering why we bother with ranks at all.</p> -<p>In conclusion both <code>0x090E7AF82577C8A6LL</code> and <code>x9[1][0]</code> should be promoted to <code>unsigned long long</code> which shall also be the type of the result. This is not what Carbon does.</p> - <p>I reported <a href="http://bts.frama-c.com/view.php?id=785" hreflang="en">bug 785</a> after getting three-quarters sure that the problem was in Frama-C (I used two different versions of GCC as oracles).</p> -<p>I still cannot believe how twisted integer promotion rules are in <a href="http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf" hreflang="en">C99</a>. I had read them before but I had not followed the precise path I followed today in the various cases of 6.3.1.8.</p> -<p>The fun starts earlier in 6.3.1.3 with the definition of conversion rank.</p> -<p>rank(long long int) > rank(long int) even when these two types have the same size. But:</p> -<blockquote><p>The rank of any standard integer type shall be greater than the rank of any extended integer type with the same width.</p> -</blockquote> -<p>So if a compiler defines an extended <code>long long long</code> type programs that use them will become differently typed the day <code>long long long</code> becomes a standard type. Until it is standardized it has lower rank than a standardized type of the same size. When it becomes standardized it will probably get a higher rank than other standardized types of the same size.</p> -<p>Well never mind this: it is unclear whether this can have any effect on the computations in practice (it matters only when types have exactly the same size). Let's see what in 6.3.1.8 applies to bug 785 starting with the promotions applicable to <code>0x090E7AF82577C8A6LL | x9[1][0]</code>.</p> -<p>We have a `long long` on the left-hand side an `unsigned long` on the right-hand side. Oh and in this platform description `long` and `long long` are both the same size 64-bit.</p> -<ol> -<li>blah blah "If both operands have the same type" <strong>nope</strong></li> -<li>"if both operands have signed integer types or both have unsigned integer types" <strong>nope</strong></li> -<li>"if the operand that has unsigned integer type has rank greater or equal to the rank of the type of the other operand" <strong>nope</strong></li> -<li>"if the type of the operand with signed integer type can represent all of the values of the type of the operand with unsigned integer type" <strong>nope</strong> it's missing half of them.</li> -<li>"Otherwise both operands are converted to the unsigned integer type corresponding to the type of the operand with signed integer type."</li> -</ol> -<p>There is a philosophy hidden in there. The philosophy seems to be "favor unsigned types unless the signed type makes more sense". Even a signed type of higher hank may see its values converted to the unsigned version of the same type changing the meaning of half of them. The rank matters only when it confirms that the unsigned type should be favored. You may be forgiven for wondering why we bother with ranks at all.</p> <p>In conclusion both <code>0x090E7AF82577C8A6LL</code> and <code>x9[1][0]</code> should be promoted to <code>unsigned long long</code> which shall also be the type of the result. This is not what Carbon does.</p> {% endraw %} diff --git a/_posts/2011-04-14-When-is-it-valid-to-compare-two-pointers-in-C.html b/_posts/2011-04-14-When-is-it-valid-to-compare-two-pointers-in-C.html index a66b669a536a6826796d00d3d4d8608d350191af..6955aa358e7b317661c63b58a66d5f978036b218 100644 --- a/_posts/2011-04-14-When-is-it-valid-to-compare-two-pointers-in-C.html +++ b/_posts/2011-04-14-When-is-it-valid-to-compare-two-pointers-in-C.html @@ -71,69 +71,5 @@ evaluate to <code>1</code>.</p> </pre> <p>In this context <code>s4 == t + 6</code> is harmless because although <code>s4</code> points to the string <code>"hello"</code> the compiler was contrained by the requirement to place "oh " before it and could not place it at <code>t + 6</code>. This comparison always return <code>0</code>. The comparison <code>s4 == t</code> on the other hand is dangerous because the compiler could have factored the tail of <code>s</code> with the head of <code>t</code>.</p> <h2>State of value analysis implementation</h2> -<p>The rules described in this post are only implemented approximately in Carbon. They will work exactly as described here in the next Frama-C release.</p> - <p>This post is about the circumstances in which the value analysis considers comparing pointers is safe, and those in which it considers the comparison is dangerous and emits an alarm. The alarm, an enigmatic <code>assert \pointer_comparable(…, …);</code>, uses an unaxiomatized ACSL predicate. If you use the value analysis regularly, you probably already encountered it (but perhaps only as a false alarm caused by earlier approximations). This posts informally describes the rules applied by the value analysis. It is by these rules false alarms should be sorted from true ones, although a specific programmer may wish the rules were either stricter or relaxed a bit.</p> -<p>If it were axiomatized, the predicate <code>\pointer_comparable</code> should capture all the conditions expressed in this post.</p> -<blockquote><p>Note: this discussion takes place in the usual working conditions of the value analysis: we know and assume a bit about the architecture: size of integer and pointer types, <code>NULL</code> is zero, …</p> -</blockquote> -<h2>Pointers</h2> -<p>The expression <code>&a < &b</code> is dangerous. It clearly can evaluate to <code>0</code> or <code>1</code> depending on compiler choices the programmer has no control over. I would have guessed that this constituted <strong>unspecified behavior</strong> (i.e. the expression evaluates to either 0 or 1). In fact, according to paragraph 6.5.8.5 in the C99 standard, it is <strong>undefined behavior</strong> (anything can happen, including a segmentation fault or the program displaying aberrant behavior from that point onwards).</p> -<p>Expression <code>&a + 1 == &b</code> is similarly dangerous: variable <code>b</code> may have been placed just after <code>a</code> in memory, or it may not. The comparison may just, in this case, be <strong>unspecified</strong>: this is my reading of paragraph 6.5.9.6.</p> -<h2>Pointers converted to integers</h2> -<p>The value analysis employs the same rule for comparisons between expressions that have pointer types and for comparison between expressions that have unsigned integer types but happen to contain addresses. Signed integer inequalities between values that happen to be addresses should be considered dangerous more often, since variables can be placed at will in memory by the compiler. Let me clarify what I mean with an example:</p> -<pre>int t[10]; -main(){ - return (unsigned int)t <= (unsigned int)(t+8); -} -</pre> -<p>In Frama-C's default target architecture, an `unsigned int` can contain a pointer to int. The comparison above is deemed safe, and always evaluates to <code>1</code> (true), same as the pointer comparison <code>t<=(t+8)</code>.</p> -<p>Compare to this slightly different example:</p> -<pre>int t[10]; -main(){ - return (int)t <= (int)(t+8); -} -</pre> -<p>The comparison above is dangerous and should be flagged as such by the value analysis, because the array <code>t</code> could have been placed by the compiler at address <code>0x7ffffffa</code>. That <code>t</code> could, by sheer bad luck, be placed at this address means that <code>(int)(t+8)</code> could be negative while <code>(int)t</code> is positive in the value analysis' permissive model of memory and values. The result of this comparison depending in this way on compiler choices is undesirable, hence the warning.</p> -<blockquote><p>You can force the value analysis to take into account the possibility that the dangerous comparison <code>(int)t <= (int)(t+8)</code> returns <code>0</code> (false) with option <code>-undefined-pointer-comparison-propagate-all</code>. This is exactly what this option is for.</p> -</blockquote> -<p>Let's move on from signed integer inequalities: you can really never do anything safe except <code>(int)&a <= (int)&a</code>. Here is another example:</p> -<pre>int t[10]; -main(){ - return 0 < (unsigned int)t; -} -</pre> -<p>In the value analysis modelization, this is a contrived way to test whether <code>t</code> is different from <code>NULL</code>, and is therefore always true. This comparison is considered safe.</p> -<pre>int t[10]; -main(){ - return t-1 <= t; -} -</pre> -<p>This comparison is dangerous: the address <code>0</code> is reserved for <code>NULL</code>, but nothing prevents the compiler from placing <code>t</code> at address <code>2</code>. Doing so means that the comparison, assumed to be implemented with the unsigned comparison assembly instruction, can return false. It returns true for most other allocations of <code>t</code>, and is therefore unsafe.</p> -<blockquote><p>Technically, computing <code>t - 1</code> is undefined behavior in C99. The value analysis waits until this value is used in a comparison before warning about it. This is only one of the various places where it is more lenient than the standard. The rationale is that the value analysis is intended for verification of existing programs. Existing programs do this (you wouldn't believe how often!). It would be very easy to warn at the slightest sign that the program is computing <code>t-1</code>, and this would in fact make a lof of things simpler (including this blog post). We are waiting for an industrial customer to ask for this specific feature, and we anticipate their asking, once it's done, how they can disable it locally.</p> -</blockquote> -<pre>int t[10]; -main(){ - return 2 <= (unsigned int)t; -} -</pre> -<p>The comparison above, and <code>2 == (unsigned int)t</code>, are both unsafe because, while they usually respectively return <code>1</code> and <code>0</code>, they might return <code>0</code> and <code>1</code> at run-time for some rare compilations.</p> -<h2>String literals</h2> -<p>The comparison <code>\tutu" == "tutu"</code> (or if you prefer the comparison <code>s == t</code> when <code>s</code> and <code>t</code> have been defined as -<code>char *s = "tutu"; char *t = "tutu";</code>) is dangerous: the compiler may -place the anonymous string constants anywhere in memory and factor them -at its option. Again in this case my reading of the -standard is that this comparison is only unspecified but the development -version of the value analysis emits an alarm for it nevertheless.</p> -<p><code>char *s = "tutu"; char *t = s; s == t</code> is not dangerous: it should always -evaluate to <code>1</code>.</p> -<p><code>"hello" == "world"</code> is not dangerous: the compiler has no opportunity to factor the chains and thus the comparison predictably evaluates to <code>0</code>. <code>"hello" == "hello world"</code> is not dangerous either: the compiler cannot factor the two strings because the first one must be zero-terminated. The terminating zero clashes with the space in the second string.</p> -<p><code>"hello" == "hello\000world"</code> is dangerous: the compiler <strong>can</strong> factor the strings making the comparison return <code>1</code>. It may also not factor them making the comparison return <code>0</code>.</p> -<p>Finaly consider the snippet below:</p> -<pre> char *s = "oh hello"; - char *s4 = s+4; - char *t = "hello\000hello"; -</pre> -<p>In this context <code>s4 == t + 6</code> is harmless because although <code>s4</code> points to the string <code>"hello"</code> the compiler was contrained by the requirement to place "oh " before it and could not place it at <code>t + 6</code>. This comparison always return <code>0</code>. The comparison <code>s4 == t</code> on the other hand is dangerous because the compiler could have factored the tail of <code>s</code> with the head of <code>t</code>.</p> -<h2>State of value analysis implementation</h2> <p>The rules described in this post are only implemented approximately in Carbon. They will work exactly as described here in the next Frama-C release.</p> {% endraw %} diff --git a/_posts/2011-04-21-List-of-the-ways-Frama_C_dump_each-is-better-than-printf.html b/_posts/2011-04-21-List-of-the-ways-Frama_C_dump_each-is-better-than-printf.html index b54227352de719db05c46f8092f910ca5eddddb0..fa9b6708342ed93a8476373eca5a30630c2fd165 100644 --- a/_posts/2011-04-21-List-of-the-ways-Frama_C_dump_each-is-better-than-printf.html +++ b/_posts/2011-04-21-List-of-the-ways-Frama_C_dump_each-is-better-than-printf.html @@ -57,55 +57,5 @@ main(){ <li>With <code>Frama_C_dump_each()</code> addresses are shown in a symbolic form such as <code>{{ &lblock2 ;}}</code> for variable <code>q</code> in the example instead of some arbitrary address where <code>lblock2</code> happens to be located.</li> <li>Contents of an union are shown using the type that was used to write there. In the example union <code>u</code> is shown as having received the floating-point value <code>1.5</code>. Using <code>printf()</code> we would have to choose between displaying <code>u.i</code> and <code>u.f</code> and if we chose the former the value would be hard to recognize for what it is.</li> </ul> -<p>The one disadvantage is that this only works for executions that the value analysis is able to capture precisely. This means no recursion and no bitwise xor on the values of pointers.</p> - <p>In <a href="/index.php?post/2011/03/01/Interpretation-speed" hreflang="en">an older post</a> I recommended that the value analysis be launched on existing unit and integration tests.</p> -<p>One advantage of using a completely unrolled analysis as compared to traditional compilation-execution is that the "execution" then takes place in an environment we have complete control of. Let us say there is a strange behavior in a large integration test that we are trying to investigate. First running the test inside the value analysis we can make sure the strange behavior is not caused by a buffer overflow or similar treat of the C language. In addition where we would insert calls to <code>printf()</code> in order to get a trace of the values of some variables as some well-chosen points in the program we can use <code>Frama_C_dump_each()</code>.</p> -<p>For instance in the program below something strange seems to be happening inside function <code>f()</code> so we insert a call to <code>Frama_C_dump_each()</code> in a strategic location there.</p> -<pre>int x a; -int y=2; -int *p *q; -union { int i ; float f ; } u; -void f(void) -{ - int lf = 5; - a = y + 2; - { - int lblock1 = 7; - p = &lblock1; - } - { - int lblock2; - q = &lblock2; - Frama_C_dump_each(); - } - return; -} -main(){ - int lmain = 3; - u.f = 1.5; - f(); - return 0; -} -</pre> -<p>Launching <code>frama-c -val -slevel 5000 t.c</code> we get:</p> -<pre>[value] DUMPING STATE of file t.c line 16 - x ∈ {0; } - a ∈ {4; } - y ∈ {2; } - p ∈ {{}} or ESCAPINGADDR - q ∈ {{ &lblock2 ;}} - u{.i; .f; } ∈ 1.5 - lf ∈ {5; } - lmain ∈ {3; } - =END OF DUMP== -</pre> -<p>Below is a list of advantages of <code>Frama_C_dump_each()</code> over <code>printf()</code>. Am I forgetting some? Does GDB provide comparable features where applicable? (I must admit I haven't used GDB in a long time)</p> -<ul> -<li>By inserting a single statement in the program you get a log of the entire state including variables that are out of scope for reason of being static to another compilation unit or for reason of being local variables of a caller. All the variables that can influence the remainder of the execution are shown.</li> -<li><code>Frama_C_dump_each()</code> does not show uninitialized variable as appearing to have a value. For instance <code>lblock2</code> above is not show as containing <code>7</code> which is what <code>printf()</code> might have shown. Or <code>982475</code>.</li> -<li>Similarly the value of dangling pointers (pointers to stack variables that have ceased to exist) is shown as <code>ESCAPINGADDR</code> not as the address of some other variable that happens to occupy the same place in the stack. In the example above <code>printf()</code> might have shown <code>p</code> as pointing to <code>lblock2</code> or some other seemingly valid location in the stack.</li> -<li>With <code>Frama_C_dump_each()</code> addresses are shown in a symbolic form such as <code>{{ &lblock2 ;}}</code> for variable <code>q</code> in the example instead of some arbitrary address where <code>lblock2</code> happens to be located.</li> -<li>Contents of an union are shown using the type that was used to write there. In the example union <code>u</code> is shown as having received the floating-point value <code>1.5</code>. Using <code>printf()</code> we would have to choose between displaying <code>u.i</code> and <code>u.f</code> and if we chose the former the value would be hard to recognize for what it is.</li> -</ul> <p>The one disadvantage is that this only works for executions that the value analysis is able to capture precisely. This means no recursion and no bitwise xor on the values of pointers.</p> {% endraw %} diff --git a/_posts/2011-05-11-One-of-these-situations-where-it-would-be-easy-to-misuse-the-word-ironic.html b/_posts/2011-05-11-One-of-these-situations-where-it-would-be-easy-to-misuse-the-word-ironic.html index 056b112b16c8d61c8387fe5cd5100647187fc0af..dded3c92a1f05469f2d688a5d9f66933746038ed 100644 --- a/_posts/2011-05-11-One-of-these-situations-where-it-would-be-easy-to-misuse-the-word-ironic.html +++ b/_posts/2011-05-11-One-of-these-situations-where-it-would-be-easy-to-misuse-the-word-ironic.html @@ -8,5 +8,5 @@ title: "One of these situations where it would be easy to misuse the word 'ironi summary: --- {% raw %} -<p>I just had to privately send someone a section from an article that, this same week, was rejected from the workshop it was submitted at.</p> <p>I just had to privately send someone a section from an article that, this same week, was rejected from the workshop it was submitted at.</p> +<p>I just had to privately send someone a section from an article that, this same week, was rejected from the workshop it was submitted at.</p> {% endraw %} diff --git a/_posts/2011-05-20-Fixing-robots-part-2.html b/_posts/2011-05-20-Fixing-robots-part-2.html index f796fc8f913a49ac0fca5ad2c940e02a2f3aa922..3d505f517b3a892461c3198f3924548810431ee9 100644 --- a/_posts/2011-05-20-Fixing-robots-part-2.html +++ b/_posts/2011-05-20-Fixing-robots-part-2.html @@ -406,404 +406,5 @@ what changes and causes <code>rampValue</code> to jump to 0. data->state = target; } </pre> -<p>This doesn't make sense. There is never any reason to jump directly to the target. We suppress these lines and the voltage jump around 66160 disappears.</p> - <p>This post follows <a href="/index.php?post/2011/06/06/Fixing-robots%2C-part-1">that post</a>.</p> -<p>For cases 2 and 3 in order to get more complete execution traces -we again take advantage of <code>Frama_C_dump_each()</code>. -Before launching the analysis we insert a call to this primitive right at the end of -<code>RoCo_process()</code> so that local variables of that function -will be displayed too.</p> -<pre>--- roco.c.orig 2011-05-16 13:53:57.000000000 +0200 -+++ roco.c 2011-05-16 13:55:18.000000000 +0200 -@@ -303 4 +303 5 @@ - else { - RoCo_engineVoltage = 0.0; - } -+ Frama_C_dump_each(); - } -</pre> -<p>The static analysis done by the previously provided shell script -(key command below) again -confirms that the execution does not run into any of the C99 undefined -behaviors that the value analysis detects (uninitialized access -use of a dangling pointer -overflows in signed integer arithmetics invalid memory access invalid -comparison of pointers division by zero -undefined logical shift overflows in conversions from -floating-point to integer infinite or NaN resulting from a -floating-point operation undefined side-effects in expressions). Yes I will -now give the full list every time. One year ago I stumbled on a -comparative study between PolySpace and Frama-C's value -analysis that gave the full list of alarms for PolySpace but listed only two types -of undefined behaviors for the value analysis. The author had -lazily copy-pasted a sentence from the documentation's -introduction but had crucially omitted the ellipsis. As a consequence -I will now inflict the full list on everyone every time. Bwa-ha-ha. -Also I plan to add three more categories of detected undefined -behaviors in the near future. Bwa-ha-ha-ha-ha.</p> -<pre>frama-c ${FILES} ${TESTCASE} -val -slevel 50000 -unspecified-access -val-signed-overflow-alarms -calldeps -save state$1 -</pre> -<h2>Case 2</h2> -<p>The trace corroborates the "does not stop jiggling when it hits the -target angle" diagnostic. We concentrate on relevant lines of the -log using the command:</p> -<pre>grep "\\(STATE\\|RoCo_legAngle \\|RoCo_engineVoltage\\|lastTime\\)" log2 -</pre> -<p>Here is the bit when the target for the first -command is reached:</p> -<pre>[value] DUMPING STATE of file roco.c line 306 - RoCo_legAngle ∈ -29.9791361754 - RoCo_engineVoltage ∈ -0.700730737571 - lastTime ∈ {66520} -[value] DUMPING STATE of file roco.c line 306 - RoCo_legAngle ∈ -30.0013178639 - RoCo_engineVoltage ∈ -0.573709804476 - lastTime ∈ {66540} -[value] DUMPING STATE of file roco.c line 306 - RoCo_legAngle ∈ -30.0235995355 - RoCo_engineVoltage ∈ -0.469713860267 - lastTime ∈ {66560} -[value] DUMPING STATE of file roco.c line 306 - RoCo_legAngle ∈ -30.0454486754 - RoCo_engineVoltage ∈ -0.384569182548 - lastTime ∈ {66580} -[value] DUMPING STATE of file roco.c line 306 - RoCo_legAngle ∈ -30.0664935071 - RoCo_engineVoltage ∈ -0.314858616438 - lastTime ∈ {66600} -[value] DUMPING STATE of file roco.c line 306 - RoCo_legAngle ∈ -30.0864858403 - RoCo_engineVoltage ∈ -0.257784432149 - lastTime ∈ {66620} -[value] DUMPING STATE of file roco.c line 306 - RoCo_legAngle ∈ -30.1052716542 - RoCo_engineVoltage ∈ 0.07897475281 - lastTime ∈ {66640} -[value] DUMPING STATE of file roco.c line 306 - RoCo_legAngle ∈ -30.1227678881 - RoCo_engineVoltage ∈ 0.354689853917 - lastTime ∈ {66660} -[value] DUMPING STATE of file roco.c line 306 - RoCo_legAngle ∈ -30.1389442061 - RoCo_engineVoltage ∈ 0.580426286282 - lastTime ∈ {66680} -[value] DUMPING STATE of file roco.c line 306 - RoCo_legAngle ∈ -30.1538087376 - RoCo_engineVoltage ∈ 0.765243645549 - lastTime ∈ {66700} -[value] DUMPING STATE of file roco.c line 306 - RoCo_legAngle ∈ -30.1673969897 - RoCo_engineVoltage ∈ 0.916559301284 - lastTime ∈ {66720} -[value] DUMPING STATE of file roco.c line 306 - RoCo_legAngle ∈ -30.1791116186 - RoCo_engineVoltage ∈ 1.04044608206 - lastTime ∈ {66740} -[value] DUMPING STATE of file roco.c line 306 - RoCo_legAngle ∈ -30.1885670036 - RoCo_engineVoltage ∈ 1.14187599937 - lastTime ∈ {66760} -[value] DUMPING STATE of file roco.c line 306 - RoCo_legAngle ∈ -30.195537956 - RoCo_engineVoltage ∈ 1.22491979196 - lastTime ∈ {66780} -[value] DUMPING STATE of file roco.c line 306 - RoCo_legAngle ∈ -30.1999193366 - RoCo_engineVoltage ∈ 1.29291029881 - lastTime ∈ {66800} -[value] DUMPING STATE of file roco.c line 306 - RoCo_legAngle ∈ -30.2016944051 - RoCo_engineVoltage ∈ 1.34857621768 - lastTime ∈ {66820} -[value] DUMPING STATE of file roco.c line 306 - RoCo_legAngle ∈ -30.2009101399 - RoCo_engineVoltage ∈ 1.39415161736 - lastTime ∈ {66840} -... -[value] DUMPING STATE of file roco.c line 306 - RoCo_legAngle ∈ -29.9951370606 - RoCo_engineVoltage ∈ 0.46939308602 - lastTime ∈ {67120} -... -[value] DUMPING STATE of file roco.c line 306 - RoCo_legAngle ∈ -29.8107877453 - RoCo_engineVoltage ∈ -1.35491972386 - lastTime ∈ {67400} -... -</pre> -<p>The voltage is still negative when the target angle of <code>-30</code> is -reached. The voltage becomes positive around the angle of <code>-30.1</code> -but the leg is still moving down at that time. We attribute this -phenomenon to inertia. The -angle reaches about <code>-30.2</code> before it finally stops decreasing and -starts increasing again.</p> -<p>Using the same method as in case 1 it is possible to identify some -variables that influence the choice of value for <code>Roco_Enginevoltage</code>. -This allows us to determine a number of independent changes that each -fix the problem.</p> -<p>The first possible change is to make the robot leg move back more slowly when it has -overshot its destination. This fixes the issue according to the -Python script provided to be used as an oracle.</p> -<pre>--- roco_config_testcase_2.h~ 2011-03-23 10:44:24.000000000 +0100 -+++ roco_config_testcase_2.h 2011-05-19 20:15:56.000000000 +0200 -@@ -35 7 +35 7 @@ - real64 RoCo_maxAngle_PARAM = 90.0; - real64 RoCo_minAngle_PARAM = -90.0; - real64 RoCo_shutdownTimeout_PARAM = 12.0; --real64 RoCo_stepSpeed_PARAM = 10.0; -+real64 RoCo_stepSpeed_PARAM = 5.0; - real64 RoCo_TempFltT_PARAM = 0.1; - real64 RoCo_TimeSlopeNeg_PARAM = 1.0; - real64 RoCo_TimeSlopePos_PARAM = 1.0; -</pre> -<p>Another possible fix is to make the robot accept a larger error margin -when deciding whether it is far enough of the intended angle to -justify moving back.</p> -<pre>--- roco_config_testcase_2.h~ 2011-03-23 10:44:24.000000000 +0100 -+++ roco_config_testcase_2.h 2011-05-19 20:18:12.000000000 +0200 -@@ -11 7 +11 7 @@ - real64 RoCo_angleAtMark_PARAM = 25.0; - real64 RoCo_angleReachedThreshold1_PARAM = 2.0; - real64 RoCo_angleReachedThreshold1Fast_PARAM = 4.0; --real64 RoCo_angleReachedThreshold2_PARAM = 0.1; -+real64 RoCo_angleReachedThreshold2_PARAM = 0.3; - real64 RoCo_batteryLowLimit_PARAM = 15.0; - real64 RoCo_batteryLowDelay_PARAM = 60.0; - boolean RoCo_checkBatteryVoltage_PARAM = TRUE; -</pre> -<p>Finally my two personal favorite fixes are below. They are (most -probably) completely wrong but they do fix the problem according to -the Python script oracle. The first makes the voltage filter so strong -that the oscillations become less visible to the script:</p> -<pre>--- roco_config_testcase_2.h~ 2011-03-23 10:44:24.000000000 +0100 -+++ roco_config_testcase_2.h 2011-05-19 20:19:10.000000000 +0200 -@@ -39 7 +39 7 @@ - real64 RoCo_TempFltT_PARAM = 0.1; - real64 RoCo_TimeSlopeNeg_PARAM = 1.0; - real64 RoCo_TimeSlopePos_PARAM = 1.0; --real64 RoCo_voltageFilter_PARAM = 0.1; -+real64 RoCo_voltageFilter_PARAM = 0.7; - real64 Engine_maxVoltage_PARAM = 18.0; - real64 Engine_minVoltage_PARAM = -18.0; -</pre> -<p>My other favorite fix makes the voltage filter so weak that -the motor no longer overshoots systematically when trying to correct its -position.</p> -<pre>--- roco_config_testcase_2.h~ 2011-03-23 10:44:24.000000000 +0100 -+++ roco_config_testcase_2.h 2011-05-19 20:20:35.000000000 +0200 -@@ -39 7 +39 7 @@ - real64 RoCo_TempFltT_PARAM = 0.1; - real64 RoCo_TimeSlopeNeg_PARAM = 1.0; - real64 RoCo_TimeSlopePos_PARAM = 1.0; --real64 RoCo_voltageFilter_PARAM = 0.1; -+real64 RoCo_voltageFilter_PARAM = 0.02; - real64 Engine_maxVoltage_PARAM = 18.0; - real64 Engine_minVoltage_PARAM = -18.0; -</pre> -<p>"Favorite" does not mean that I would recommend either of these two incompatible fixes. The first two seem more reasonable and less likely to break something else.</p> -<h2>Case 3</h2> -<p>According to the <a href="http://icpc2011.cs.usask.ca/conf_site/IndustrialTrack_files/industry-challenge.pdf">challenge description</a> -we should use our "tacit knowledge gained from several years of -employment at RobotControllers.com". Since we have not really been -employed at RobotControllers.com for several years it is only fair to -use the tacit knowledge encoded in the provided acceptance Python -script. This is probably what the organizers meant. Looking at the -script we see that the robot leg destruction is caused by a sudden -variation in the voltage applied to the motor. In practice the motor -when carried away by the inertia of the mechanism -it is supposed to set in motion -becomes a generator. The difference between the voltage this -generator provides and the voltage set by the environment should -never be too large. A well-designed modern power supply can take the -hit but a large voltage difference also means large -intensities going through the motors' coils. The motor turns into -a generator but it doesn't turn into a well-protected one.</p> -<p>The relevant part of the log is extracted as follows:</p> -<pre>grep "\\(STATE\\|RoCo_legAngle \\|RoCo_engineVoltage\\|lastTime\\)" log3 -... -[value] DUMPING STATE of file roco.c line 306 - RoCo_engineVoltage ∈ -6.93042056043 - lastTime ∈ {109960} - rampValue ∈ 0.998 -[value] DUMPING STATE of file roco.c line 306 - RoCo_engineVoltage ∈ -6.94303317304 - lastTime ∈ {109980} - rampValue ∈ 1. -[value] DUMPING STATE of file roco.c line 306 - RoCo_engineVoltage ∈ -4.41559004995 - lastTime ∈ {110000} - rampValue ∈ 1. -[value] DUMPING STATE of file roco.c line 306 - RoCo_engineVoltage ∈ -2.34629463843 - lastTime ∈ {110020} - rampValue ∈ 1. -[value] DUMPING STATE of file roco.c line 306 - RoCo_engineVoltage ∈ -0.652098847809 - lastTime ∈ {110040} - rampValue ∈ 1. -[value] DUMPING STATE of file roco.c line 306 - RoCo_engineVoltage ∈ 0.734991347706 - lastTime ∈ {110060} - rampValue ∈ 1. -[value] DUMPING STATE of file roco.c line 306 - RoCo_engineVoltage ∈ 1.87064474807 - lastTime ∈ {110080} -</pre> -<p>I have included variable <code>rampValue</code> above because as one can see by exploring the code in the GUI as for case 1 in addition to the voltage filter the program has a mechanism to make the voltage increase slowly when transitioning -from idle to active or from active to idle. -Slice for the statement that computes the value of -<code>rampValue</code> to see this mechanism more clearly for yourself: the command <code>frama-c-gui -load state3</code> can be used to load the values previously computed. In the statement's contextual menu first select "Enable slicing" and then "Slicing → Slice stmt".</p> -<p><a href="/assets/img/blog/imported-posts/ICPC11/slice_rampValue.png" title="slice_rampValue.png"><img src="/assets/img/blog/imported-posts/ICPC11/.slice_rampValue_m.jpg" alt="slice_rampValue.png" style="display:block; margin:0 auto;" title="slice_rampValue.png mai 2011" /></a></p> -<p>The log extract above shows that unfortunately this mechanism does not -smooth the voltage when a new order arrives in the middle of the execution -of the current order. Here the motor has just ramped out to -full speed (<code>rampValue==1.0</code>) when the command to move in the opposite -direction arrives at <code>lastTime==110000</code>. The value of <code>rampValue</code> remains -pegged at <code>1.0</code> during the transition. This could be considered to be the bug -that causes the voltage jump.</p> -<p>Apart from the sleazy way we obtain the numerical limit by -reverse-engineering the python script it is impossible to argue -against the inclusion of the patch below. Although it is written -without understanding the root cause of the problem it -exactly prevents a situation that is never desirable the destruction of the -robot.</p> -<pre>--- challenge/src/roco.c.orig 2011-05-16 13:53:57.000000000 +0200 -+++ ppc/tests/ICPC/src/roco_sol3.c 2011-05-02 16:35:52.000000000 +0200 -@@ -293 8 +293 17 @@ - desiredEngineVoltage Engine_maxVoltage_PARAM); - limitationActive = (Engine_maxVoltage_PARAM == desiredEngineVoltage) || - (Engine_minVoltage_PARAM == desiredEngineVoltage); -- RoCo_engineVoltage = PT1_Filter (&voltageFilter desiredEngineVoltage -- t13 dT); -+ -+ { real64 tentativeV = PT1_Filter (&voltageFilter desiredEngineVoltage -+ t13 dT); -+ if (tentativeV - RoCo_engineVoltage > 0.390625) -+ RoCo_engineVoltage += 0.390625; -+ else if (tentativeV - RoCo_engineVoltage < -0.390625) -+ RoCo_engineVoltage -= 0.390625; -+ else -+ RoCo_engineVoltage = tentativeV; -+ } -+ - wasInit = init; - wasActive = RoCo_isActive; - Timer_tick (&shutdownTimer dT); -</pre> -<p>Even if/when the root cause of the problem is fixed this -patch should remain in place for the sake of <strong>defensive programming</strong>. -It exactly prevents the voltage jumps that cause the destruction -of the motor and has almost no practical effects otherwise so -it does not hurt.</p> -<p>The best fix would perhaps be to do a ramp down followed by a ramp up -when receiving in the middle of the execution of an order another -order that causes a change in direction. This seems like a major change -to the logic of the program so we won't attempt it and we will instead -rely on the patch above to prevent destruction of the robot leg.</p> -<p>After applying the patch above we run and analyze testcase 3 again and we obtain -another complaint from the validation script <code>eval.py</code> provided by -the organizers:</p> -<pre>src $ make && ./roco_3.exe 2> trace3 && python ../eval.py 3 < trace3 -make: Nothing to be done for `all'. -149100: TOO SLOW / TARGET NOT REACHED! -found 1 error(s) -</pre> -<p>To look on the bright side of life the robot didn't explode.</p> -<p>The analysis log again conveniently provides all variables' values in -a single (if longish) step:</p> -<pre>$ grep "\\(RoCo_engineVoltage\\|lastTime\\|STATE\\|rampValue\\|legAngle \\)" log3 -[value] DUMPING STATE of file roco.c line 306 - RoCo_legAngle ∈ 19.970696807 - RoCo_engineVoltage ∈ 6.00755510873 - lastTime ∈ {115740} - rampValue ∈ 0.874 -[value] DUMPING STATE of file roco.c line 306 - RoCo_legAngle ∈ 20.0821939081 - RoCo_engineVoltage ∈ 5.99058545861 - lastTime ∈ {115760} - rampValue ∈ 0.872 -[value] DUMPING STATE of file roco.c line 306 - RoCo_legAngle ∈ 20.1933858392 - RoCo_engineVoltage ∈ 5.9736158 - lastTime ∈ {115780} - rampValue ∈ 0.87 -[value] DUMPING STATE of file roco.c line 306 - RoCo_legAngle ∈ 20.304272565 - RoCo_engineVoltage ∈ 5.95664613443 - lastTime ∈ {115800} - rampValue ∈ 0.868 -[value] DUMPING STATE of file roco.c line 306 - RoCo_legAngle ∈ 20.4148540546 - RoCo_engineVoltage ∈ 5.93967646317 - lastTime ∈ {115820} - rampValue ∈ 0.866 -[value] DUMPING STATE of file roco.c line 306 - RoCo_legAngle ∈ 20.5251302809 - RoCo_engineVoltage ∈ 5.92270678725 - lastTime ∈ {115840} - rampValue ∈ 0.864 -... -</pre> -<p>As illustrated in the log snippet above the robot leg overshoots the target position. This can be attributed to the value of variable <code>rampValue</code> being too high and specifically decreasing too slowly. Since there is now a piece of code to limit voltage jumps we can increase the speed at which this variable varies without fear of destroying the robot. In fact for all we know this variable was set to vary slowly in a misguided attempt to fix the explosion problem.</p> -<p>Since parameters <code>RoCo_TimeSlopePos_PARAM</code> and <code>RoCo_TimeSlopeNeg_PARAM</code> influence directly the computation of <code>rampValue</code> we decide to adjust these:</p> -<pre>--- roco_config_testcase_3.h 2011-03-23 11:07:48.000000000 +0100 -+++ roco_config_testcase_3_sol3.h 2011-05-02 16:35:52.000000000 +0200 -@@ -37 8 +37 8 @@ - real64 RoCo_shutdownTimeout_PARAM = 12.0; - real64 RoCo_stepSpeed_PARAM = 8.0; - real64 RoCo_TempFltT_PARAM = 0.15; --real64 RoCo_TimeSlopeNeg_PARAM = 0.1; --real64 RoCo_TimeSlopePos_PARAM = 0.1; -+real64 RoCo_TimeSlopeNeg_PARAM = 0.5; -+real64 RoCo_TimeSlopePos_PARAM = 0.5; - real64 RoCo_voltageFilter_PARAM = 0.1; - real64 Engine_maxVoltage_PARAM = 15.0; -</pre> -<pre>$ make && ./roco_3.exe 2> trace3 && python ../eval.py 3 < trace3 -... -found 0 error(s) -</pre> -<p>The ReadMe.txt reports that the field engineers also complained about voltage variations at time t=50. Since the voltage is perfectly stable around t=50s we can interpret this part of their report as caused by the hallucinogenic fumes famously released by burning electronics. Perhaps they mean t=66140ms when indeed the voltage can be seen to drop a bit sharply in the original execution trace. -The reason why it drops sharply is clear on this selection of variable values:</p> -<pre>[value] DUMPING STATE of file roco.c line 306 - RoCo_legAngle ∈ 12.3506194964 - RoCo_engineVoltage ∈ 4.50997019947 - lastTime ∈ {66120} - rampValue ∈ 0.614 -[value] DUMPING STATE of file roco.c line 306 - RoCo_legAngle ∈ 12.4293066254 - RoCo_engineVoltage ∈ 4.52254504977 - lastTime ∈ {66140} - rampValue ∈ 0.616 -[value] DUMPING STATE of file roco.c line 306 - RoCo_legAngle ∈ 12.5082201017 - RoCo_engineVoltage ∈ 3.90576827098 - lastTime ∈ {66160} - rampValue ∈ {0} -[value] DUMPING STATE of file roco.c line 306 - RoCo_legAngle ∈ 12.5873599253 - RoCo_engineVoltage ∈ 3.4007941544 - lastTime ∈ {66180} - rampValue ∈ {0} -</pre> -<p>Variable <code>rampValue</code> drops from <code>0.616</code> to <code>0.0</code> and this cannot even be excused by the arrival of an order at that instant. It seems the ramping up/down part of the program might as well be thrown away and re-written from scratch.</p> -<p>Looking at values for instants 66140 and 66160 side-by-side it becomes clear -what changes and causes <code>rampValue</code> to jump to 0. -<a href="/assets/img/blog/imported-posts/ICPC11/66140.png" title="66140.png"><img src="/assets/img/blog/imported-posts/ICPC11/.66140_m.jpg" alt="66140.png" style="display:block; margin:0 auto;" title="66140.png mai 2011" /></a></p> -<p>The variable <code>rampTarget</code> changes from <code>1.0</code> to <code>0.0</code>.</p> -<p>We could execute cycle 66160 in a debugger but that would be banal. Instead let us use a trick to observe that cycle on its own in Frama-C's GUI. We replace the line <code>RoCo_process();</code> in main_testcase_3.c with:</p> -<pre> if (lastTime==66160) RoCo_process_66160(); else RoCo_process(); -</pre> -<p>We then copy-paste the body of function <code>RoCo_process()</code> as the definition of an identical function <code>RoCo_process_66160()</code> and launch again the analysis. Yes this means waiting ten minutes again. You have to make sacrifices to be cool. This maneuver allows us to observe cycle 66160 in the GUI unmixed with the others with a lot more code displayed in orange (indicating that this code was not executed at that cycle and can be ignored) and values that are specific for that cycle.</p> -<p><a href="/assets/img/blog/imported-posts/ICPC11/gui_66160.png" title="gui_66160.png"><img src="/assets/img/blog/imported-posts/ICPC11/.gui_66160_m.jpg" alt="gui_66160.png" style="display:block; margin:0 auto;" title="gui_66160.png mai 2011" /></a></p> -<p>Listing the differences between this approach and using a debugger is left as an exercise for the reader. This inspection mostly confirms that the value <code>0.0</code> seems normal for variable <code>rampTarget</code> and that it should be function <code>Ramp_out()</code> that makes sure that <code>rampValue</code> varies slowly even when <code>rampTarget</code> jumps around. Note in passing that the duplication of function <code>RoCo_process()</code> does not help to see what happens inside function <code>Ramp_out()</code> at cycle 66160. But you are probably growing a little restless so I won't suggest to launch an analysis again. We can perfectly well infer what happens inside function <code>Ramp_out()</code> by reading the code. Doing that we notice the tests below.</p> -<pre> if (data->dir == -1) { - data->state = target; - } - ... - if (data->dir == 1) { - data->state = target; - } -</pre> <p>This doesn't make sense. There is never any reason to jump directly to the target. We suppress these lines and the voltage jump around 66160 disappears.</p> {% endraw %} diff --git a/_posts/2011-05-20-Frama-C-is-a-full-fledged-framework.html b/_posts/2011-05-20-Frama-C-is-a-full-fledged-framework.html index c9c60c7ff7bd383289413cf731f44c3fb5d20841..69340e9ce2db7faaa9263bfb7254a9554acb57dd 100644 --- a/_posts/2011-05-20-Frama-C-is-a-full-fledged-framework.html +++ b/_posts/2011-05-20-Frama-C-is-a-full-fledged-framework.html @@ -13,10 +13,4 @@ summary: what irks me is that researchers are supposed to be scientists. All the fictional quotes above are true and they are all false and they are generally so fuzzy as to be worthless. They remind me of example sentences that Richard Feynman would give when talking about the scientific method — and I don't mean "example" as in "good example".</p> <p>For each of the quotes above the author is clearly talking about some plug-in but the reader hearing about Frama-C for the first time gets a completely distorted view of what it is what it can do and what it is all about.</p> <p>And did I mention that the property attributed to it that will form the reader's first impression is usually both negative and unfair?</p> - <p>I wish researchers would stop calling the plug-in they are using \Frama-C". "Frama-C" is the framework. It has very few of the properties that are attributed to it. One plug-in or the other usually is to blame or praise.</p> -<p>This is not just because when researchers bring it up it is usually to say something bad about it: everyone has a bridge they want to sell you. A consequence is that you hear more often "Frama-C does not support recursion" "Frama-C does not handle pointer casts" or generally "this bridge is so much better than Frama-C" than "Frama-C is great: it can verify this binary search implementation and it finds the overflow that Google engineers pointed out" or "Frama-C found a subtle bug in QuickLZ that had escaped 'a year of beta testing regression testing code reviewing and static analysis tooling'". No -what irks me is that researchers are supposed to be scientists. All the fictional quotes above are true and they are all false and they are generally so fuzzy as to be worthless. They remind me of example sentences that Richard Feynman would give when talking about the scientific method — and I don't mean "example" as in "good example".</p> -<p>For each of the quotes above the author is clearly talking about some plug-in but the reader hearing about Frama-C for the first time gets a completely distorted view of what it is what it can do and what it is all about.</p> -<p>And did I mention that the property attributed to it that will form the reader's first impression is usually both negative and unfair?</p> - Kept the alliteration in 'f' of the title, but with a more politically correct tone -- Virgile {% endraw %} diff --git a/_posts/2011-05-21-Exploding-robots.html b/_posts/2011-05-21-Exploding-robots.html index b9d6ffd223334b8c3f236166fa7b487168e6af89..4b1981d13163b17ea26c6dab3ff3646d36170a83 100644 --- a/_posts/2011-05-21-Exploding-robots.html +++ b/_posts/2011-05-21-Exploding-robots.html @@ -9,5 +9,4 @@ summary: --- {% raw %} <p>I should have said this earlier — others might have wanted to join in the fun — but I will be sending an entry to participate in the International Conference on Program Comprehension's <a href="http://icpc2011.cs.usask.ca/conf_site/IndustrialTrack.html">Industrial Challenge</a>. My write-up will appear here shortly after the submission deadline.</p> - <p>I should have said this earlier — others might have wanted to join in the fun — but I will be sending an entry to participate in the International Conference on Program Comprehension's <a href="http://icpc2011.cs.usask.ca/conf_site/IndustrialTrack.html">Industrial Challenge</a>. My write-up will appear here shortly after the submission deadline.</p> {% endraw %} diff --git a/_posts/2011-05-31-Test-driving-static-analysis-tools.html b/_posts/2011-05-31-Test-driving-static-analysis-tools.html index 1866734883ae0cc3cbe4621b56fe9b7c9215874b..d67dd3437a066b95b6d46c4258c97aafdc1fc915 100644 --- a/_posts/2011-05-31-Test-driving-static-analysis-tools.html +++ b/_posts/2011-05-31-Test-driving-static-analysis-tools.html @@ -70,68 +70,5 @@ int main() return 1; } </pre> -<p>Finally I have already fixed some bugs thanks to this benchmark so if you try to reproduce these steps at home you may want to use <a href="/assets/img/blog/imported-posts/__fc_machdep.h">this file for __fc_machdep.h</a> and <a href="/assets/img/blog/imported-posts/limits.h">this one for limits.h</a> in directory libc in substitution for the files provided with Carbon.</p> - <p>I have recently added an article \Test driving static analysis tools in search of C code vulnerabilities" by George Chatzieleftheriou and Panagiotis Katsaros on the <a href="http://bts.frama-c.com/dokuwiki/doku.php?id=mantis:frama-c:publications">wiki page of publications relevant to Frama-C</a>. This article benchmarks a number of static analysis tools that it tests for precision (warning about real issues only) and recall (warning about all issues). Frama-C's value analysis is one of the static analysis tools. The article can be found in electronic form by googling for its title.</p> -<p>As the reader of this blog probably knows the value analysis when used properly is supposed to be sound. "Sound" is synonymous with 100% recall. Interestingly the article does not find that recall is the <em>forte</em> of the value analysis: in figure 3 the value analysis is the most precise of all tested tools but it does not have 100% recall. In fact the two commercial offerings in the benchmark have better recall than Frama-C's value analysis.</p> -<h2>So what about this recall then?</h2> -<p>I maintain my claim that the value analysis is supposed to be sound when used properly. The tested version is Beryllium released in 2009 which already had a strong implementation but may have been lacking in documentation. I don't think there was any Skein tutorial then let alone <a href="/index.php?post/2011/04/05/QuickLZ-1">a second tutorial using QuickLZ as an example</a>. However if we had made it clearer that the value analysis was primarily intended for the formal verification of embedded C code with neither dynamic allocation nor generally any calls to standard functions that are part of a desktop programming environment this might have discouraged the authors to include it in the comparison. So this is all for the best.</p> -<p>By the way I expect that many of the cases where the value analysis failed to identify an issue can be traced to the use of standard functions although I have not yet dug enough in the benchmark to be sure. Standard functions are natural suspects: the benchmark clearly uses them and although we provide several imperfect modelizations for <code>malloc()</code> they are so little documented that we can expect the authors of the benchmark used none. In this eventuality <code>malloc()</code> is treated by the analyzer like any unknown function that takes an integer and return a pointer. Now that there are tutorials you can see that they all start by listing the C functions that are missing from the analysis projects and by wondering for each how it can be provided.</p> -<h2>The human factor</h2> -<p>I was very happy to find this benchmark. I should explain: the 100% recall or "soundness" claim is utterly boring to test for. The value analysis was designed to be sound from the beginning (when used properly for its intended usage) and since its authors have only been fighting for precision. As a result and because they are only human there are a lot of what I would call positive tests (check that the value analysis succeeds at not warning about a complex but safe piece of code). There are not nearly enough negative tests (check that the value analysis does warn about an unsafe piece of code) because there is no progress to measure there. The value analysis implementors have been guilty of a basic very forgivable psychological error but even if we forgive them the situation must be fixed. This benchmark is a good start towards a collection of "negative tests" for the value analysis.</p> -<p>In fact I have started looking at the qualitative tests from <a href="http://mathind.csd.auth.gr/static_analysis_test_suite/">the benchmark</a> and it is rather simple to check the value analysis against expected results. Because I want to fix the lack of "negative tests" I focused on lines with the comment <code>DANGER</code> that the value analysis should find. Here is the test script I currently have:</p> -<pre> -#!/bin/sh -# export FRAMACLIBC=/usr/local/share/frama-c/libc -export FRAMACLIBC=/Users/pascal/ppc/share/libc -for F in general/division_zero/*.c -do - ~/ppc/bin/toplevel.opt -val -cpp-command "gcc -C -E -nostdinc -I. -I$FRAMACLIBC" $F | grep "division by zero" - grep -n DANGER $F /dev/null - echo -done -for F in integers/overflow/*.c -do - ~/ppc/bin/toplevel.opt -val -cpp-command "gcc -C -E -nostdinc -I. -I$FRAMACLIBC" -val-signed-overflow-alarms $F | grep "assert" - grep -n DANGER $F /dev/null - echo -done -for F in arrays/*/*.c -do - ~/ppc/bin/toplevel.opt -val -cpp-command "gcc -C -E -nostdinc -I. -I$FRAMACLIBC" -val-signed-overflow-alarms $F | grep "assert" - grep -n DANGER $F /dev/null - echo -done -</pre> -<p>It works rather well:</p> -<pre>general/division_zero/divisionzero1.c:11:[kernel] warning: division by zero: assert 0 ≢ 0; -general/division_zero/divisionzero1.c:11: d = 5 / 0; /* DANGER */ -general/division_zero/divisionzero1_alias1.c:21:[kernel] warning: division by zero: assert c2 ≢ 0; -general/division_zero/divisionzero1_alias1.c:21: d = 10 / c2; /* DANGER */ -general/division_zero/divisionzero1_alias2.c:23:[kernel] warning: division by zero: assert c2 ≢ 0; -general/division_zero/divisionzero1_alias2.c:23: d = 10 / c2; /* DANGER */ -</pre> -<p>In each of the two-line snippets above the first one is from grepping in the analysis results and the second one is from grepping for <code>DANGER</code> in the program itself.</p> -<p>But it is not so easy to compare expected and obtained results for what the authors of the benchmark call context-sensitive tests. This is more complex than it seems at first sight and I may need to dedicate an entire blog post to it:</p> -<pre>general/division_zero/divisionzero1_context1.c:7:[kernel] warning: division by zero: assert val ≢ 0; -general/division_zero/divisionzero1_context1.c:18: d = divide_values(c); /* DANGER */ -</pre> -<p>The file in question is:</p> -<pre>/* Division by zero error */ -/* Context sensitive example */ -/* Different functions */ -int divide_values(int val) -{ - return (10 / val); /* line 7 */ -} -int main() -{ - int d; - int b = 5; - int c = 0; - d = divide_values(b); /* OK */ - d = divide_values(c); /* DANGER */ /* line 18 */ - return 1; -} -</pre> <p>Finally I have already fixed some bugs thanks to this benchmark so if you try to reproduce these steps at home you may want to use <a href="/assets/img/blog/imported-posts/__fc_machdep.h">this file for __fc_machdep.h</a> and <a href="/assets/img/blog/imported-posts/limits.h">this one for limits.h</a> in directory libc in substitution for the files provided with Carbon.</p> {% endraw %} diff --git a/_posts/2011-05-31-The-Stupidest-Question-I-have-ever-heard-at-a-Computer-Science-presentation.html b/_posts/2011-05-31-The-Stupidest-Question-I-have-ever-heard-at-a-Computer-Science-presentation.html index f348f4a81787966eaaf77acfd67cda083a538fce..3326ac26f8f8aed8951d11741d875796bf68fb44 100644 --- a/_posts/2011-05-31-The-Stupidest-Question-I-have-ever-heard-at-a-Computer-Science-presentation.html +++ b/_posts/2011-05-31-The-Stupidest-Question-I-have-ever-heard-at-a-Computer-Science-presentation.html @@ -37,35 +37,5 @@ Adapted to the present context it would go like this:</p> <blockquote><p>It doesn't make sense to use Csmith find bugs in C compilers since it is itself compiled with a C (technically C++) compiler.</p> </blockquote> <p>Apparently as a physics student much earlier the asker had been chided for using a pendulum-based chronometer to verify the constancy of a pendulum's period.</p> -<p>So if I may be so bold as to impart my own wisdom to the world in the form of random remarks there are two lessons in this post. "Be careful of circular reasoning" is one but "software is not quite as similar to the physical world as you could expect" is another.</p> - <p>Some time back, I reported a Csmith bug against the last git version. -This is in no way a rant against <a href="http://embed.cs.utah.edu/csmith/">Csmith</a> a fine piece of engineering. -Csmith does something that I would not have thought possible if you had asked -me before I saw it: it generates random C programs that are both -free of undefined behavior and varied enough to uncover a ton -of bugs in the C-accepting program you pipe it into.</p> -<blockquote><p>Unless the C-accepting program is <a href="http://compcert.inria.fr/">CompCert</a> in which case you only uncover a couple of bugs apparently.</p> -</blockquote> -<p>Bugs in random programs have a funny way to find themselves. You don't need -to try many inputs as the random program explores these for you. -Even if you think you are being quite the conservative user -they pop up uninvited from time to time (although to be fair you can see -that they are being fixed because they pop up less and less frequently). -Anyway dangling pointers were being passed as arguments to functions that didn't -use them although I was not using the option that allows this behavior -in generated programs. This was my bug. It had been good company -but I didn't feel ready for a long-term relationship. It was time to let go.</p> -<p>Fast forward a few days and there is this <a href="https://github.com/csmith-project/csmith/commit/208de0fc9b42dd74b0a7bf93527a3378d03fad79">promising commit</a> on github. -I decide I may as well upgrade although the bug was only appearing from time to -time because I had fiddled with the parameters in a way that made it more likely to appear -and I had not seen it at all since I had fiddled with the parameters again.</p> -<p>Suddenly as I re-compile with GCC this program generator that finds bugs -in GCC I am reminded of the stupidest question I ever heard at the end of -a computer science presentation.</p> -<p>Like many bad questions this question was more a remark than a question. -Adapted to the present context it would go like this:</p> -<blockquote><p>It doesn't make sense to use Csmith find bugs in C compilers since it is itself compiled with a C (technically C++) compiler.</p> -</blockquote> -<p>Apparently as a physics student much earlier the asker had been chided for using a pendulum-based chronometer to verify the constancy of a pendulum's period.</p> <p>So if I may be so bold as to impart my own wisdom to the world in the form of random remarks there are two lessons in this post. "Be careful of circular reasoning" is one but "software is not quite as similar to the physical world as you could expect" is another.</p> {% endraw %} diff --git a/_posts/2011-06-02-Skein-tutorial-part-7-not-dead-but-resting.html b/_posts/2011-06-02-Skein-tutorial-part-7-not-dead-but-resting.html index 66f7f625f5eef163f2d2181d55aea757709a7189..1eb9566a7bad306362baea0b45d6f0d1bbe86bee 100644 --- a/_posts/2011-06-02-Skein-tutorial-part-7-not-dead-but-resting.html +++ b/_posts/2011-06-02-Skein-tutorial-part-7-not-dead-but-resting.html @@ -102,99 +102,5 @@ skein.c:162:[value] Assertion got status valid. ctx->h.bCnt == 28 || ctx->h.bCnt == 29 || ctx->h.bCnt == 30 || ctx->h.bCnt == 31 || ctx->h.bCnt == 32 ; */ -</pre>" <p>Do you remember the Skein tutorial? It went off to a good start (it started this blog) and then was never really completed. I blame <strong>laziness</strong>. Looking back at that first post, I notice that indeed, before Boron, we were shipping software without documentation (just think! Ahem). At the time, I also thought that the extended tutorial would be over in a couple of posts, a mistake I have learnt not to make any more. September 2010, those were the days…</p> -<h2>The story so far</h2> -<p>The solution provided in <a href="/index.php?post/2010/11/21/Value-analysis-tutorial%2C-part-4">this post</a> was one of two promised solutions. It was in fact my own solution. While conceiving it I was determined not to look at Skein's source code. I could claim that this was to make the verification method completely independent of the code which is obviously good. It allows for instance to swap in another implementation — say another entry in the NIST SHA3 contest — and hopefully to verify it just by relaunching the same script. The true reason I didn't want to look at the code is more likely written in bold at the top of this post.</p> -<p>Because I didn't want to look at Skein's source code my solution involved the meta-argument that you can cover all possible executions of the loop</p> -<pre> while (Frama_C_interval(0 1)) - { - arbitrarize_msg(); - Skein_256_Update(&skein_context msg 80); - } -</pre> -<p>by analyzing instead the two pieces of code below which between them do all the same things:</p> -<pre> while (Frama_C_interval(0 1)) - { - arbitrarize_msg(); - Skein_256_Update(&skein_context msg 80); - arbitrarize_msg(); - Skein_256_Update(&skein_context msg 80); - } -</pre> -<pre> arbitrarize_msg(); - Skein_256_Update(&skein_context msg 80); - while (Frama_C_interval(0 1)) - { - arbitrarize_msg(); - Skein_256_Update(&skein_context msg 80); - arbitrarize_msg(); - Skein_256_Update(&skein_context msg 80); - } -</pre> -<h2>The alternate solution</h2> -<p>In July 2010 I was teaching at <a href="http://flolac.iis.sinica.edu.tw/flolac10/en/start.html">the FLOLAC summer school</a> and I was lucky to have <a href="http://joshkos.blogspot.com/">Josh Ko</a> as my Teaching Assistant. He did not have my prejudices against looking at the code being verified. The alternate and better solution that follows is his.</p> -<p>We determined when we elaborated the solution based on pairing the calls to <code>Skein_256_Update()</code> that the issue was the field <code>skein_context.h.bCnt</code> -that contained <code>0</code> before the first iteration and alternately <code>16</code> or <code>32</code> after that. -Pairing the calls to <code>Skein_256_Update()</code> was one way to force similar calls to be analyzed together and prevent a loss of precision caused by not knowing whether <code>skein_context.h.bCnt</code> was <code>16</code> or <code>32</code>. Josh Ko's solution instead prevents the loss of precision by nudging the value analysis into studying these cases separately by way of an annotation inside <code>Skein_256_Update()</code>:</p> -<pre>--- skein.c.orig 2011-06-02 21:06:29.000000000 +0200 -+++ skein.c 2011-06-02 21:06:50.000000000 +0200 -@@ -159 6 +159 8 @@ - Skein_Assert(ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES SKEIN_FAIL); /* catch uninitialized context */ -+ /*@ assert ctx->h.bCnt == 0 || ctx->h.bCnt == 16 || ctx->h.bCnt == 32 ; */ -+ - /* process full blocks if any */ - if (msgByteCnt + ctx->h.bCnt > SKEIN_256_BLOCK_BYTES) - { -</pre> -<p>We have seen how to provide useful annotations in <a href="/index.php?post/2011/03/26/Helping-the-value-analysis-2">this post</a>. The above annotation is another example. With it we can use this <code>main()</code>:</p> -<pre>void main(void) -{ - int i; - u08b_t hash[HASHLEN]; - Skein_256_Ctxt_t skein_context; - Skein_256_Init(&skein_context HASHLEN * 8); - arbitrarize_msg(); - Skein_256_Update(&skein_context msg 80); - arbitrarize_msg(); - Skein_256_Update(&skein_context msg 80); - while (Frama_C_interval(0 1)) - { - arbitrarize_msg(); - Skein_256_Update(&skein_context msg 80); - } - Skein_256_Final( &skein_context hash); -} -</pre> -<pre>$ time frama-c -val -slevel 1000 -slevel-function main:0 *.c -cpp-command "gcc -m32 -C -E -I. " > log2 -real 1m48.218s -user 1m45.133s -sys 0m1.325s -</pre> -<p>This single <code>main()</code> cover all the programs with n>=2 calls to <code>Skein_256_Update(… 80)</code>:</p> -<pre>$ grep ssert log2 -skein.c:162:[value] Assertion got status valid. -</pre> -<p>And that's that: no alarm is emitted and the annotation that we provided for the value analysis is verified before being used (so it is not an assumption).</p> -<p>For the sake of completeness the cases of 0 and 1 calls to <code>Skein_256_Update(… 80)</code> should also be checked separately. We have done that before so there is no need to repeat it here.</p> -<h2>Generalizing</h2> -<p>The advantage of the method presented in this post over the previous one is that it can more easily be generalized to different buffer lengths passed to <code>Skein_256_Update()</code>. The more complete verification that I <a href="/index.php?post/2010/11/22/Value-analysis-tutorial%2C-part-5%3A-jumping-to-conclusions">last alluded to</a> uses among other annotations the assertion below.</p> -<pre> /*@ assert - ctx->h.bCnt == 0 || ctx->h.bCnt == 1 || - ctx->h.bCnt == 2 || ctx->h.bCnt == 3 || - ctx->h.bCnt == 4 || ctx->h.bCnt == 5 || - ctx->h.bCnt == 6 || ctx->h.bCnt == 7 || - ctx->h.bCnt == 8 || ctx->h.bCnt == 9 || - ctx->h.bCnt == 10 || ctx->h.bCnt == 11 || - ctx->h.bCnt == 12 || ctx->h.bCnt == 13 || - ctx->h.bCnt == 14 || ctx->h.bCnt == 15 || - ctx->h.bCnt == 16 || ctx->h.bCnt == 17 || - ctx->h.bCnt == 18 || ctx->h.bCnt == 19 || - ctx->h.bCnt == 20 || ctx->h.bCnt == 21 || - ctx->h.bCnt == 22 || ctx->h.bCnt == 23 || - ctx->h.bCnt == 24 || ctx->h.bCnt == 25 || - ctx->h.bCnt == 26 || ctx->h.bCnt == 27 || - ctx->h.bCnt == 28 || ctx->h.bCnt == 29 || - ctx->h.bCnt == 30 || ctx->h.bCnt == 31 || - ctx->h.bCnt == 32 ; */ -</pre>" +</pre> {% endraw %} diff --git a/_posts/2011-06-06-Fixing-robots-part-1.html b/_posts/2011-06-06-Fixing-robots-part-1.html index defc7bd589510649bdd0920bab46c4d86794bbcf..26248986420e4527a399c6f8fd9c415ecaf4e958 100644 --- a/_posts/2011-06-06-Fixing-robots-part-1.html +++ b/_posts/2011-06-06-Fixing-robots-part-1.html @@ -249,247 +249,5 @@ an impressive job of making this challenge interesting and indeed challenging. However I thought someone might want to look at these themselves now that I have shown how easy it is on task 1. The only difficult part is finding an <code>exp()</code> function.</p> -<p>To be continued...</p> - <p>This blog post is a revised version of part of my submission to the <a href="http://icpc2011.cs.usask.ca/conf_site/IndustrialTrack.html">ICPC 2011 Industry Challenge</a>. Please go ahead and read the challenge description. I could only paraphrase it without adding anything to it and so I won't.</p> -<p>The study was made with the April development version of Frama-C which -differs from the last released version in a number of bugfixes (<a href="http://bts.frama-c.com/" hreflang="en">list of reported issues</a>) and minor new -features. Specifically it uses the value analysis and dependencies -computations (documented in <a href="http://frama-c.com/download/frama-c-value-analysis.pdf" hreflang="en">this manual</a>) and -<a href="http://frama-c.com/scope.html" hreflang="en">code navigation features</a>. The latter reuse -building blocks that were implemented for <a href="http://frama-c.com/slicing.html" hreflang="en">slicing</a>.</p> -<h2>The ever important first step: identify missing library functions</h2> -<p>The first step as the faithful reader of this blog would now know before using the value analysis for anything is to -identify library functions the program depends on:</p> -<pre>frama-c impls.c main.c roco.c sim.c main_testcase_1.c -metrics -cpp-command "gcc -DTESTCASE=1 -C -E" -... -Undefined functions (10): - __builtin_inf (15 calls); __builtin_inff (15 calls); fprintf (2 calls); - __swbuf (10 calls); __builtin_fabsf (15 calls); exp (1 call); - __builtin_infl (15 calls); __builtin_fabsl (15 calls); - __builtin_fabs (15 calls); fabs (9 calls); -... -</pre> -<p>The host computer's standard headers have been used hence the -confusing <code>__builtin_</code> prefixes. Better not rely on them: the robot's -operating system probably bears little resemblance to the host's. -Placeholder headers provided with Frama-C can be used instead:</p> -<pre>frama-c impls.c main.c roco.c sim.c main_testcase_1.c -metrics -cpp-command "gcc -DTESTCASE=1 -C -E -nostdinc -I. -I/usr/local/share/frama-c/libc" -... -Undefined functions (3): - exp (1 call); fabs (9 calls); fprintf (2 calls); -... -</pre> -<p>Standard functions <code>exp()</code> and <code>fabs()</code> are missing from the Carbon release but -have been added to the development version. With the development version one -simply needs to list <code>/usr/local/share/frama-c/libc/math.c</code> as a file of -the analysis project. Function <code>exp()</code> is implemented as a value analysis -builtin taking advantage of the host's own <code>exp()</code> function.</p> -<p>If you wish to reproduce at home you have to provide -your own implementation for <code>exp()</code>. It may not need to be very accurate -but it needs to be analyzable with Carbon's value analysis. A good way would -be to clean up the implementation from Sun that -<a href="http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libm/src/e_exp.c?rev=1.5;content-type=text%2Fplain">everyone is using</a>. -As I already said in <a href="/floating-point/2011/02/25/Numerical-functions-are-not-merely-twisted">previous posts</a> accessing the bits of a floating-point -representation directly is <em>so</em> 1990s. If someone removed these ugly and -obsolete manipulations we would end up with a better implementation for -<code>exp()</code> (and it would be analyzable with the value analysis from Carbon).</p> -<p>For <code>fabs()</code> -you can use the function below. An implementation from a library would -probably unset the sign bit in the IEEE 754 representation but again -Carbon's value analysis doesn't handle this precisely yet. -The implementation below is handled -precisely in the sense that a singleton for the input <code>x</code> results in -a singleton for the returned value.</p> -<pre>double fabs(double x){ - if (x==0.0) return 0.0; - if (x>0.0) return x; - return -x; -} -</pre> -<p>Finally calls to <code>fprintf()</code> that do not have any -repercussions on the continuing execution can be replaced with -calls to the <code>Frama_C_show_each()</code> built-in. We can let the -pre-processor to do this for us -passing the option <code>-Dfprintf=Frama_C_show_each</code> to GCC when pre-processing.</p> -<h2>Looking for unspecified/undefined behaviors</h2> -<p>We are now ready to launch the value analysis. -Since we anticipate testcases 2 and 3 to be very similar we write a short -script:</p> -<pre>#!/bin/bash -export CPP="gcc -Dfprintf=Frama_C_show_each -DTESTCASE=$1 -C -E -nostdinc -I. -I/usr/local/share/frama-c/libc" -FILES="/usr/local/share/frama-c/libc/math.c impls.c main.c roco.c sim.c" -TESTCASE="main_testcase_$1.c" -exec frama-c ${FILES} ${TESTCASE} -val -slevel 50000 -unspecified-access -val-signed-overflow-alarms -calldeps -save state$1 -</pre> -<p>About ten minutes after running <code>script.sh 1 > log1</code> -we obtain a log (long:~70MiB) and a state (~1MiB). -The log is long because it contains progression messages that are only intended to help identify -analysis issues and can be ignored most of the time. The state contains all the information -that has been computed about the program including values of variables -in a very compact format.</p> -<p>The analysis is completely unrolled (because of option <code>-slevel 50000</code>) -and precise until the end. This means that the value analysis has in -effect simulated the execution of the program with the inputs -provided in <code>main_testcase_1.c</code>.</p> -<p>The log despite its size <strong>does not warn about any of the undefined or unspecified behaviors</strong> that the -value analysis is guaranteed to -identify (uninitialized access use of a dangling pointer -overflows in signed integer arithmetics invalid memory access invalid -comparison of pointers division by zero -undefined logical shift overflows in conversions from -floating-point to integer infinite or NaN resulting from a -floating-point operation undefined side-effects in expressions). -This is very important. It means that we can rest assured -that the strange dynamic behavior we are going to investigate -is not caused by the misuse of one of C's dangerous -constructs. Nothing would be more frustating than having to track the value -of a variable which according to the source code is not supposed to -change but is modified through a buffer overflow. The value analysis -guarantees we won't have to do that for this execution.</p> -<blockquote><p>What would of course be better would be to verify that there can be none of the above undefined behaviors for <strong>any</strong> command sequence. This would be a much stronger result but would also require a lot more work. When simulating a single execution inside the analyzer we only check that that particular execution is free of undefined behavior but it does not require any work from us (only <a href="/index.php?post/2011/03/01/Interpretation-speed">a few minutes of work from the computer</a>).</p> -</blockquote> -<h2>Exploiting the value analysis' results for program comprehension</h2> -<p>The values computed and stored in <code>state1</code> can be observed in -Frama-C's GUI using the command-line <code>frama-c-gui -load state1</code>. -The GUI can also be used to identify the definition -site(s) of a variable's value: select the variable at the program point you are interested in -and in the contextual menu invoke Dependencies → Show defs.</p> -<p>Here it is the value of variable <code>RoCo_engineVoltage</code> -as displayed by the call to <code>fprintf()</code> (that we transformed into a call -to <code>Frama_C_show_each()</code>) that is wrong so we request the definition site(s) -of that value:</p> -<p><a href="/assets/img/blog/imported-posts/ICPC11/s1.png" title="s1.png"><img src="/assets/img/blog/imported-posts/ICPC11/.s1_m.jpg" alt="s1.png" style="display:block; margin:0 auto;" title="s1.png avr. 2011" /></a></p> -<p>The GUI has pointed us to a call to function <code>RoCo_Process()</code> (using the yellow mark) -so we now request the definition -sites of <code>RoCo_engineVoltage</code> by the <code>return;</code> statement of that function. -We obtain the two sites identified below:</p> -<p><a href="/assets/img/blog/imported-posts/ICPC11/s2.png" title="s2.png"><img src="/assets/img/blog/imported-posts/ICPC11/.s2_m.jpg" alt="s2.png" style="display:block; margin:0 auto;" title="s2.png avr. 2011" /></a></p> -<p>The condition that decides which branch is executing is the one shown in the screenshot -below.</p> -<p><a href="/assets/img/blog/imported-posts/ICPC11/s3.png" title="s3.png"><img src="/assets/img/blog/imported-posts/ICPC11/.s3_m.jpg" alt="s3.png" style="display:block; margin:0 auto;" title="s3.png avr. 2011" /></a></p> -<p>The value analysis tell us the value of <code>RoCo_isActive</code> can be either <code>0</code> or <code>1</code> -at this point during execution but this variable is one of the variables whose value is printed in -the analysis log and its value was <code>1</code> at the instant we are interested in. We therefore focus -on the definition site where the value assigned to <code>RoCo_engineVoltage</code> is computed -in a call to <code>PT1_Filter()</code>.</p> -<p>The dependencies of the particular call to <code>PT1_Filter()</code> we are -interested in were computed by option -calldeps and can be found in the log. -The call we are interested in is at statement 433. The log contains:</p> -<pre>call PT1_Filter at statement 433: - voltageFilter FROM state; x; t1; dt; voltageFilter - \esult FROM state; x; t1; dt; voltageFilter -</pre> -<p>Apart from reading its arguments <code>state</code> <code>x</code> <code>t1</code> and <code>dt</code> the call accesses -a static variable <code>voltageFilter</code>. The address of <code>voltageFilter</code> is taken -so we have to be careful: this variable could be modified erroneously -through a pointer (although the address-taking appears to be only to -pass it to <code>PT1_Filter()</code> which is innocent enough).</p> -<p>In fact at this point we have no idea which of the variables involved -in the computation of the result of this call to <code>PT1_Filter()</code> is wrong. -Clicking on a variable in the GUI provides the set of values for this -variable at this program point but this is still too imprecise here -since it mixes all 10000 or so passages through the statement.</p> -<p>Let us take advantage of the "blackboard" structure of the analyzed -program and dump the entire program state at this statement -by inserting a call to <code>Frama_C_dump_each()</code>. -See <a href="/index.php?post/2011/04/21/Frama_C_dump_each">this previous post</a> for -a list of advantages of this built-in function over <code>printf()</code> or a -debugger.</p> -<pre>--- roco.c (revision 12956) -+++ roco.c (working copy) -@@ -293 6 +293 7 @@ - desiredEngineVoltage Engine_maxVoltage_PARAM); - limitationActive = (Engine_maxVoltage_PARAM == desiredEngineVoltage) || - (Engine_minVoltage_PARAM == desiredEngineVoltage); -+ Frama_C_dump_each(); - RoCo_engineVoltage = PT1_Filter (&voltageFilter desiredEngineVoltage - t13 dT); - wasInit = init; -</pre> -<p>We need to launch the analysis again and find something to do for 10 minutes. -This is a good time to start looking at bugs 2 and 3.</p> -<p>The log now contains state dumps for each passage through the statement -where <code>RoCo_engineVoltage</code> is computed.</p> -<p>According to the <code>ReadMe.txt</code> in the challenge package -an order is given at t=50s. The log shows that this order -fails to be executed speedily. -The state dump at which <code>lastTime</code> contains 50000 -and the next few ones show that of <code>RoCo_engineVoltage</code>'s dependencies -variable <code>desiredEngineVoltage</code> is the one with the suspicious value: it is only -<code>-0.8</code> whereas parameters in file <code>roco_config_testcase_1.h</code> and values of the variable elsewhere in our -log show that this voltage can go much higher. We are therefore left with the sub-problem of identifying why -this variable has this value at this program point.</p> -<p>We use the same tools we have already -used for <code>RoCo_engineVoltage</code> this time applied to variable <code>desiredEngineVoltage</code> -and this program point. The screenshot below shows the definitions sites for that value.</p> -<p><a href="/assets/img/blog/imported-posts/ICPC11/s4.png" title="s4.png"><img src="/assets/img/blog/imported-posts/ICPC11/.s4_m.jpg" alt="s4.png" style="display:block; margin:0 auto;" title="s4.png avr. 2011" /></a></p> -<p>The value of variable <code>desiredEngineVoltage</code> is defined by the call to function <code>Limiter_Out()</code> -whose argument is in turn defined by the call to <code>Interpolate_from_curve()</code> above.</p> -<p>Option -calldeps computed the implicit inputs of this call which can be found in the log:</p> -<pre>call Interpolate_from_curve at statement 423: - \esult FROM curve; x; - EngineSpeedToVoltage_CURVE{.numPoints; .x[0..4]; .y[1..3]; } -</pre> -<p>The state dump in which <code>lastTime==50000</code> shows that a low value for -<code>angleDiffRequest</code> is the cause for the low value of <code>desiredEngineVoltage</code>.</p> -<p>The "Show defs" action in the GUI finds three possible definition sites for -this value of <code>angleDiffRequest</code> shown in the screenshots below.</p> -<p><a href="/assets/img/blog/imported-posts/ICPC11/s5.png" title="s5.png"><img src="/assets/img/blog/imported-posts/ICPC11/.s5_m.jpg" alt="s5.png" style="display:block; margin:0 auto;" title="s5.png avr. 2011" /></a></p> -<p><a href="/assets/img/blog/imported-posts/ICPC11/s6.png" title="s6.png"><img src="/assets/img/blog/imported-posts/ICPC11/.s6_m.jpg" alt="s6.png" style="display:block; margin:0 auto;" title="s6.png avr. 2011" /></a></p> -<p><a href="/assets/img/blog/imported-posts/ICPC11/s7.png" title="s7.png"><img src="/assets/img/blog/imported-posts/ICPC11/.s7_m.jpg" alt="s7.png" style="display:block; margin:0 auto;" title="s7.png avr. 2011" /></a></p> -<p>We find in the log that variable <code>rampValue</code> remains at <code>0</code> in the cycles -that follow instant <code>50000</code>. The value we observe for <code>angleDiffRequest</code> -is compatible with the algorithm and values of variables at lines -264-277 of file roco.c. So it looks like the cause of the issue -is the value of variable <code>rampValue</code>. Action "Show defs" in the GUI -indicates that this value is computed by the call to <code>Ramp_out()</code> at line 240. -The value of <code>rampTarget</code> is computed as <code>0.0</code> or <code>1.0</code> from a number of -variables and of these variables <code>RoCo_legAngleValid</code> was always 1 -and <code>direction</code> was always <code>0</code> or <code>1</code>. The latter is suspicious since -in this execution orders are given to move in both directions:</p> -<p><a href="/assets/img/blog/imported-posts/ICPC11/s8.png" title="s8.png"><img src="/assets/img/blog/imported-posts/ICPC11/.s8_m.jpg" alt="s8.png" style="display:block; margin:0 auto;" title="s8.png avr. 2011" /></a></p> -<p>The command "Show defs" applied to variable <code>direction</code> shows that indeed -the variable may have been set to <code>0</code> or <code>1</code> in three different sites.</p> -<p><a href="/assets/img/blog/imported-posts/ICPC11/s9.png" title="s9.png"><img src="/assets/img/blog/imported-posts/ICPC11/.s9_m.jpg" alt="s9.png" style="display:block; margin:0 auto;" title="s9.png avr. 2011" /></a></p> -<p>The site that corresponds to the MoveByAngle command the middle one in the screenshot above -is suspicious: in the file main_testcase_1.c the angle passed to this command is negative. -This is not just a strange convention because the computation below for the third -definition site determined the direction for the other commands that are all in -the opposite direction and variable <code>direction</code> was assigned <code>1</code> again there.</p> -<p>This suggests the fix below.</p> -<pre>--- roco.c (revision 13019) -+++ roco.c (working copy) -@@ -211 7 +211 7 @@ - direction = 0; - } - else { -- direction = (RoCo_desiredDeltaAngle > 0.0) ? -1 : 1; -+ direction = (RoCo_desiredDeltaAngle > 0.0) ? 1 : -1; - } - RoCo_commandMoveByAngle = FALSE; - } -</pre> -<p>Looking at the source code for related issues one may notice that the value given to <code>direction</code> -is also affected by the piece of code below. It would be worth the time testing different values of -<code>t9</code> and <code>RoCo_hasMinMaxAngles_PARAM</code> although that complex computation is -only active when using commands other than MoveByAngle.</p> -<pre> if ((fabs(t9) > t11) && (direction == 0)) { - direction = ((((!RoCo_hasMinMaxAngles_PARAM) || - (fabs(t9) >= 180.0)) - ? t9 : -t9) > 0.0) ? 1 : -1; - } -</pre> -<h2>Thanks and Next</h2> -<p>My colleagues Benjamin Monate and Virgile Prevosto found the challenge and set up the files -in the development repository so that the only thing that was left to do was to identify the -bugs and started looking at them with me. -Anne Pacalet and David Mentré have provided feedback for transforming this -submission into a blog post. Anne Pacalet also implemented of all the code navigation -features used in this study. The organizers Jochen Quante and Andrew Begel have done -an impressive job of making this challenge interesting and indeed challenging.</p> -<p>I have also submitted my explanation of tasks 2 and 3 in the challenge. -However I thought someone might want -to look at these themselves now that I have shown how easy it is on task 1. -The only difficult part is finding an <code>exp()</code> function.</p> <p>To be continued...</p> {% endraw %} diff --git a/_posts/2011-06-11-Final-thoughts-on-the-ICPC-2011-industrial-challenge.html b/_posts/2011-06-11-Final-thoughts-on-the-ICPC-2011-industrial-challenge.html index 8a8d404623a32cf82883566dcf3e8b2c26129419..5de062a732878b9a4bfe11142ebdd36e173cca1b 100644 --- a/_posts/2011-06-11-Final-thoughts-on-the-ICPC-2011-industrial-challenge.html +++ b/_posts/2011-06-11-Final-thoughts-on-the-ICPC-2011-industrial-challenge.html @@ -58,56 +58,5 @@ Fixed in last revision.</p> <p>The reviewer had the valid remarks below (I hope ey won't mind that I quote em here. We're bridging the gap between two communities! If we have to breach etiquette and quote excerpts of reviews that are supposed to remain confidential so be it…)</p> <blockquote><p>the QA person needs advice on how to recognize when a new caller is reporting a similar bug; the explanations of the details were too vague to direct callers properly. QA also needs to know what to say to the customer when a bug is recognized: In addition to technical workarounds is it possible to return the chip? Is there an alternative available? Is there a testing method suggested for discovering similar flaws at the customer site in the future? Should the customer be compensated for exploded controllers?</p> </blockquote> -<p>I will be attending ICPC 2011. I hoped Anne Pacalet would be there too (as I already pointed out she implemented the code navigation features). She won't be able to come but she wants me to take notes during Margaret Burnett's invited talk.</p> - <p>I have received the review of my submission to the ICPC 2011 industrial challenge. If you have read the challenge description, you may remember that participating involved writing various fictional e-mails. In my submission, I skimped a bit on that part. Some of the e-mails I replaced by an e-mail to my fictional boss, explaining to him that my holidays had started and that he was in the best position to write them anyway. Which he would be. In fact, being my boss, he would know me well and prefer me never ever to write directly to important customers' CEOs.</p> -<p>That these e-mails were required tells something about the ICPC conference (that I have never attended and that I would not have thought of attending without this contest). \Comprehension" is the key word — with respect to what we are already concerned with in this community anyway. It's not just about the programs it's also about the humans that have to deal with the programs. In some ways we completely ignore these aspects: we would like the person verifying the software to trust that it works in the same way that you may trust a counter-intuitive mathematical result with a proof each step of which you can check is correct. I am naturally exaggerating our differences here: before the formal proof someone has to have the intuition. We are not working in opposite directions we are simply working each on difficult subjects that until now have been occupying all our respective attentions.</p> -<p>Even more telling is that in places were I did not think I was skimping the organizers expected more human/economical/social/psychological thinking than I provided in good faith. Where the contest required an e-mail to:</p> -<blockquote><p>RobotControllers.com Quality Assurance: Explain to this non-engineer how the code caused the cus- tomers’ problems and what effect your bug fixes had on the program’s output. Instruct this person how to recognize symptoms of the bug that may be communicated by customers.</p> -</blockquote> -<p>I simply wrote (people who have interacted with me on Frama-C's own issue tracker will recognize my patented style):</p> -<blockquote><p>Issue 1:</p> -<p> -Description: -When the moveby command is used the robot leg moves very slowly.</p> -<p> -Workaround: -Do not use the moveby command. -Status: -Fixed in last revision.</p> -<p> -Issue 2:</p> -<p> -Description: -The robot leg does not stop jiggling when it hits the target angle. -Workaround: -No workaround known. -Status: -Fixed in last revision.</p> -<p> -Issue 3:</p> -<p> -Description: -When issuing an order to move in a direction opposite to the one -the leg is currently moving destruction of the robot. -Workaround: -Wait for the completion of any command before issuing any new -command that would cause a change in direction. -Status: -Fixed in last revision.</p> -<p> -Issue 4:</p> -<p> -Description: -At the end of medium-range move orders the leg stops moving abruptly. -The robot smells slightly funny. -Workaround: -Issue only short-range orders where the leg does not build up speed -or long-range orders where the leg reaches its full speed. -Status: -Fixed in last revision.</p> -</blockquote> -<p>The reviewer had the valid remarks below (I hope ey won't mind that I quote em here. We're bridging the gap between two communities! If we have to breach etiquette and quote excerpts of reviews that are supposed to remain confidential so be it…)</p> -<blockquote><p>the QA person needs advice on how to recognize when a new caller is reporting a similar bug; the explanations of the details were too vague to direct callers properly. QA also needs to know what to say to the customer when a bug is recognized: In addition to technical workarounds is it possible to return the chip? Is there an alternative available? Is there a testing method suggested for discovering similar flaws at the customer site in the future? Should the customer be compensated for exploded controllers?</p> -</blockquote> <p>I will be attending ICPC 2011. I hoped Anne Pacalet would be there too (as I already pointed out she implemented the code navigation features). She won't be able to come but she wants me to take notes during Margaret Burnett's invited talk.</p> {% endraw %} diff --git a/_posts/2011-06-16-Happy-birthday-IBM..html b/_posts/2011-06-16-Happy-birthday-IBM..html index faf91627aa97608b3eac2d170a3df93889a138d6..0ad6465e1e946fc3f1b55b5e1af3d498da559a3c 100644 --- a/_posts/2011-06-16-Happy-birthday-IBM..html +++ b/_posts/2011-06-16-Happy-birthday-IBM..html @@ -14,12 +14,5 @@ summary: future of the company for his employees by telling them that Apple could be like Sony or it could be like IBM. I couldn't find a reference any more but this is definitely something he could have said. Apple has been trying to be like the Sony of the 1980s and did out-Sony Sony for the last ten years. And it does seem hard to be both: you can be at most one of Sony or IBM.</p> <p>Still I am not sure the dichotomy is very interesting. A better one —for us anyway— is whether we should choose to aim to be like Polaroid or like Kodak.</p> -<p>The choice has been made for a while of course or we wouldn't be where we are today. But it doesn't hurt from time to time to think about where we want to go. We still have choices to make occasionally. And this article about the SX-70 is as good an opportunity to prepare for them as any.</p> - <p>Today is IBM's 100th birthday, if the rumor is to be believed. Just the occasion for a link to <a href="http://technologizer.com/2011/06/08/polaroid/">this online article about the Polaroid SX-70</a> then. The article is the work of Harry McCracken. I am glad that 21st century internet allows authors such as him to be heard with their true voice. Harry has written and does write for traditional publications but either the format is constraining him or he is not allowed to pick his subjects as freely: it's just not the same. The linked article is representative of his Internet style. It is not typical in that he has outdone himself: this is probably the best article I will have read in 2011.</p> -<p>Why on IBM's 100th birthday? The reason as usual is terribly involved.</p> -<p>I vaguely remember a story about Steve Jobs during his first period at Apple defining the -future of the company for his employees by telling them that Apple could be like Sony or it could be like IBM. -I couldn't find a reference any more but this is definitely something he could have said. Apple has been trying to be like the Sony of the 1980s and did out-Sony Sony for the last ten years. And it does seem hard to be both: you can be at most one of Sony or IBM.</p> -<p>Still I am not sure the dichotomy is very interesting. A better one —for us anyway— is whether we should choose to aim to be like Polaroid or like Kodak.</p> <p>The choice has been made for a while of course or we wouldn't be where we are today. But it doesn't hurt from time to time to think about where we want to go. We still have choices to make occasionally. And this article about the SX-70 is as good an opportunity to prepare for them as any.</p> {% endraw %} diff --git a/_posts/2011-06-17-Clang-Static-Analyzer.html b/_posts/2011-06-17-Clang-Static-Analyzer.html index 610e7cf473b3ac1978ae82ae92add217f2a171a2..204fa3f8cb06189b1e90c3f90eed1b03781cee10 100644 --- a/_posts/2011-06-17-Clang-Static-Analyzer.html +++ b/_posts/2011-06-17-Clang-Static-Analyzer.html @@ -11,9 +11,5 @@ summary: <p>From the <a href="http://clang-analyzer.llvm.org/">Clang Static Analyzer homepage</a>:</p> <blockquote><p>Please help us in this endeavor by reporting false positives.</p> </blockquote> -<p>Please help us make Frama-C better by reporting false negatives.</p> - <p>From the <a href="http://clang-analyzer.llvm.org/">Clang Static Analyzer homepage</a>:</p> -<blockquote><p>Please help us in this endeavor by reporting false positives.</p> -</blockquote> <p>Please help us make Frama-C better by reporting false negatives.</p> {% endraw %} diff --git a/_posts/2011-06-18-Someone-elses-blog.html b/_posts/2011-06-18-Someone-elses-blog.html index 0bcade85f6cd0b4efe744cba3febec1ba0d46efe..7551cc4a7d701359d7746afda324e06c3db189ac 100644 --- a/_posts/2011-06-18-Someone-elses-blog.html +++ b/_posts/2011-06-18-Someone-elses-blog.html @@ -13,11 +13,5 @@ summary: <blockquote><p>Wow. That is incredibly professional and diplomatic.</p> </blockquote> <p>The archives have posts that are <a href="http://shaver.off.net/diary/2007/11/30/counting-still-easy-critical-thinking-still-surprisingly-hard/">more like what I might write in the corresponding situation</a> (assuming I was in a good mood). -Both the diplomatic and the less diplomatic posts avoid the mistake of characterizing tentacular loosely coordinated organizations (such as Microsoft) as single entities with a consistent purpose. The author Mike Shaver is a founding member of the Mozilla Organization which goes some way towards explaining this particular awareness.</p> - <p>I have discovered <a href="http://shaver.off.net/diary/2011/06/17/a-three-dimensional-platform/">a new blog</a>. Having read a few archived posts at random I think I am going to like it.</p> -<p>That blog mixes the technical with the personal much like this blog doesn't. My reaction to the linked post (also the current one at the time of writing) was:</p> -<blockquote><p>Wow. That is incredibly professional and diplomatic.</p> -</blockquote> -<p>The archives have posts that are <a href="http://shaver.off.net/diary/2007/11/30/counting-still-easy-critical-thinking-still-surprisingly-hard/">more like what I might write in the corresponding situation</a> (assuming I was in a good mood). Both the diplomatic and the less diplomatic posts avoid the mistake of characterizing tentacular loosely coordinated organizations (such as Microsoft) as single entities with a consistent purpose. The author Mike Shaver is a founding member of the Mozilla Organization which goes some way towards explaining this particular awareness.</p> {% endraw %} diff --git a/_posts/2011-07-19-New-version-of-some-text-editor.html b/_posts/2011-07-19-New-version-of-some-text-editor.html index fe6eb1cdfa161cc7d487e8e2ad11e897655a376d..db955706358181f2e88628a59ec05a3059583ae7 100644 --- a/_posts/2011-07-19-New-version-of-some-text-editor.html +++ b/_posts/2011-07-19-New-version-of-some-text-editor.html @@ -12,10 +12,5 @@ summary: <blockquote><p>I’ve been beta-testing 10 for months and at this point I couldn’t bear to go back to version 9.</p> </blockquote> <p>Wow!</p> -<p>I would hate an editor that come a new release puts you in a position to say things like that. I am pretty sure I could <a href="http://sunsite.univie.ac.at/textbooks/emacs/emacs_38.html" hreflang="en">go back to Emacs 19.3? from 1996</a> at any time if only people ceased to send me files in Unicode.</p> - <p>John Gruber <a href="http://daringfireball.net/linked/2011/07/19/bbedit-10" hreflang="en">writes</a> about new release 10 of text editor BBEdit:</p> -<blockquote><p>I’ve been beta-testing 10 for months and at this point I couldn’t bear to go back to version 9.</p> -</blockquote> -<p>Wow!</p> <p>I would hate an editor that come a new release puts you in a position to say things like that. I am pretty sure I could <a href="http://sunsite.univie.ac.at/textbooks/emacs/emacs_38.html" hreflang="en">go back to Emacs 19.3? from 1996</a> at any time if only people ceased to send me files in Unicode.</p> {% endraw %} diff --git a/_posts/2011-07-21-Back-to-the-drawing-board.html b/_posts/2011-07-21-Back-to-the-drawing-board.html index 61e2820585f065b9d1c1f1cb22330beb783d69c4..dab7fd3e6edc0b1a9a58024745d43b6cfe48edf9 100644 --- a/_posts/2011-07-21-Back-to-the-drawing-board.html +++ b/_posts/2011-07-21-Back-to-the-drawing-board.html @@ -87,85 +87,5 @@ m.c:23:[value] Failed to see context as an instance of the generic context: The particular state at the call site line 19 is found to be captured by the generic state with <code>S_p</code> being <code>A</code> and <code>S_q</code> being <code>B</code> so the pre-analysis can be reused (taking into account that the changes that happened to <code>S_p</code> in the pre-analysis happen to <code>A</code> here and so on).</p> <p>On the other hand the state at the second call site (line 23) is not found to be an instance of the generic state because there is an aliasing relation between <code>p</code> and <code>q</code> that may completely change the meaning of the function. The analysis concludes that the generic analysis cannot be reused here and enters a specialized analysis of <code>f</code> same as if option <code>-mem-exec</code> had not been used.</p> <p>I think this feature is a fine piece of engineering (yes I wrote that part myself. There are other parts I wrote myself I do not think are great at all). Nevertheless no-one used it and it had some long-standing bugs. The use case for this option was not clear. You can use instead <code>-no-results-function</code> <code>-slevel-function</code> or replace a complex function by a simpler stub written with value analysis primitives.</p> -<p>So this was a partial list of features that will go away in Nitrogen. There are many other bits that no-one is using and that only make new developments difficult. Many of these were never documented so if you use the value analysis in theory you shouldn't even notice that they are gone.</p> - <p><em>This post is a backward changelog that introduces actual new features. Beat that, Emacs 19 Antinews!</em></p> -<p>Shortly after the release of Carbon, I offered to my Frama-C co-developers the idea of a great clean-up of the value analysis for the next release. This would not immediately add new features (indeed, it would remove some of them), but it would make way for more exciting new ideas in the long term.</p> -<p>This has started. One thing is not working according to plan, hence this blog post. I was planning to have a two-stage removal where, in the next release, obsolete features would be undocumented but would still be there, perhaps with a boolean option to activate them. This turns out not to be convenient: some features are instead going to change in ways that make it difficult to choose between old and new behaviors, and it's just a pain in the backside to keep others lying around half-dead in the codebase. The transition is going to be faster than I initially thought. This blog post is partly to let everyone know that it is coming. If you use Frama-C productively, this is the time to contact the people listed on <a href="http://frama-c.com/about.html" hreflang="en">the contact page</a> and talk about a maintenance contract. We can only preserve features that we know people are using.</p> -<p>Here is a list of changes that have already happened in the development version for Nitrogen:</p> -<p>In Carbon and before <strong>relational information</strong> could sometimes be kept between the values of the program's variables. This did not work very well anyway and made the implementation of other more useful ideas impossible so this is gone. There may be a little loss of precision on some programs but that should be very infrequent for embedded code or for clean system code.</p> -<p>One example regression is for the following program:</p> -<pre>int t[10] *p x; -main(int c char **v){ - if (c) p=t; - Frama_C_show_each_before(p); - x = *p++; - Frama_C_show_each_after(p); -} -</pre> -<pre>$ /usr/local/Frama-C_Carbon/bin/frama-c -val t.c -... -[value] Called Frama_C_show_each_before({{ &NULL ; &t ;}}) -... -t.c:6:[kernel] warning: out of bounds read. assert \valid(tmp); -[value] Called Frama_C_show_each_after({{ &t + {4; } ;}}) -... -$ bin/toplevel.opt -val t.c -... -[value] Called Frama_C_show_each_before({{ &NULL ; &t }}) -... -t.c:6:[kernel] warning: out of bounds read. assert \valid(tmp); -[value] Called Frama_C_show_each_after({{ &NULL + {4} ; &t + {4} }}) -... -</pre> -<p>Before the assignment at the call to <code>Frama_C_show_each_before()</code> the value of <code>p</code> is <code>{{ &NULL ; &t }}</code>. The pointer <code>p</code> is then dereferenced. This is dangerous as underscored by the alarm. Once the pointer has been dereferenced Carbon knows that it wasn't <code>NULL</code> in the first place whereas the newer development version doesn't and thinks it may now also be <code>(int*)NULL+1</code>.</p> -<p>The issue here comes from the fact that the variable actually dereferenced in the Abstract Syntax Tree is not <code>p</code> but a variable <code>tmp</code> related to <code>p</code>:</p> -<pre>$ bin/toplevel.opt -print t.c -... - Frama_C_show_each_before(p); - { /* ... */ tmp = p; p ++; x = *tmp; } - Frama_C_show_each_after(p); -... -</pre> -<p>To be clear the representation of the program did not change here between Carbon and the development version. What changed is the ability that Carbon had to remember that <code>tmp</code> was first equal to <code>p</code> and then later to <code>p</code> minus four bytes so that the fact that <code>tmp</code> had been dereferenced and had to be valid meant that <code>p</code> could only be <code>t</code> plus four bytes.</p> -<p>The treatment of <strong>volatile</strong> variables will probably change in the next release this time because of a change in the representation of the program's AST.</p> -<p>Option <code>-mem-exec</code> is gone. This option made a single <strong>modular analysis of a function's code</strong> and re-used the results at each call site (instanciating pointers in the generic initial state appropriately with addresses from the state at the call site if needed). You can see it in action on the following program:</p> -<pre>int *p; -int *q; -void f(void) -{ - *p = 4; - *q = 5; -} -int A B; -main() -{ - A = 10; - B = 11; - p = &A; - q = &B; - f(); - p = &A; - q = &A; - f(); - return 0; -} -</pre> -<pre>$ /usr/local/Frama-C_Carbon/bin/frama-c -val -mem-exec f m.c -... -[value] computing for function f <-main. - Called from m.c:19. -... Instanciation succeeded: {{ S_p -> {{ A -> {0; } ;}}; - S_q -> {{ B -> {0; } ;}}; }} -[value] Done for function f -[value] computing for function f <-main. - Called from m.c:23. -m.c:23:[value] Failed to see context as an instance of the generic context: - inlining call to f. -... -</pre> -<p>Function <code>f</code> is pre-analyzed in a generic state in which <code>p</code> points to some location <code>S_p</code> and <code>q</code> points to <code>S_q</code>. -The particular state at the call site line 19 is found to be captured by the generic state with <code>S_p</code> being <code>A</code> and <code>S_q</code> being <code>B</code> so the pre-analysis can be reused (taking into account that the changes that happened to <code>S_p</code> in the pre-analysis happen to <code>A</code> here and so on).</p> -<p>On the other hand the state at the second call site (line 23) is not found to be an instance of the generic state because there is an aliasing relation between <code>p</code> and <code>q</code> that may completely change the meaning of the function. The analysis concludes that the generic analysis cannot be reused here and enters a specialized analysis of <code>f</code> same as if option <code>-mem-exec</code> had not been used.</p> -<p>I think this feature is a fine piece of engineering (yes I wrote that part myself. There are other parts I wrote myself I do not think are great at all). Nevertheless no-one used it and it had some long-standing bugs. The use case for this option was not clear. You can use instead <code>-no-results-function</code> <code>-slevel-function</code> or replace a complex function by a simpler stub written with value analysis primitives.</p> <p>So this was a partial list of features that will go away in Nitrogen. There are many other bits that no-one is using and that only make new developments difficult. Many of these were never documented so if you use the value analysis in theory you shouldn't even notice that they are gone.</p> {% endraw %} diff --git a/_posts/2011-07-22-Animated-donut-verification.html b/_posts/2011-07-22-Animated-donut-verification.html index 85f261da0fb5f08138e4f233cf3db090ccf38c7f..f066afc5406e4f0203750a8a41089074d5335d7c 100644 --- a/_posts/2011-07-22-Animated-donut-verification.html +++ b/_posts/2011-07-22-Animated-donut-verification.html @@ -90,88 +90,5 @@ donut.c:14:[value] warning: overflow in float: [--..--] -> [-3.40282346639e+3 [scope] [rm_asserts] removing 2 assertion(s) </pre> <p>It's still the same assertions. The development version of Frama-C shows the range of the index <code>k</code> (that is <code>[200..1760]</code>) when it prints the assertion <code>assert 0 ≤ k ∧ k < 1760;</code>. That suggests that pushing the value of <code>-slevel</code> to more than <code>1760</code> may eliminate this alarm.</p> -<p>I will let someone else continue from here if they want. This program could be very rewarding to verify (<del>a little birdie tells me that there is at least one true alarm to be found using the value analysis or any other techniques</del>I have completely lost faith in that little birdie. There may or may not be a bug we will know for sure when we are done but don't stay awake all night looking for one) so I recommended as a fun exercise for those who are bored from sandy holiday beaches.</p> - <p>Here's a cool <a href="http://a1k0n.net/2011/07/20/donut-math.html">obfuscated C program</a> by Andy Sloane that draws a revolving donut.</p> -<p>You know where this is heading... I am going to suggest that someone should verify it. -I will get us started.</p> -<p>1. Download <a href="http://a1k0n.net/2006/09/15/obfuscated-c-donut.html">the code</a></p> -<p>2. Determine what library functions it needs:</p> -<pre>$ frama-c -metrics donut.c -[kernel] preprocessing with "gcc -C -E -I. donut.c" -donut.c:1:[kernel] user error: syntax error -</pre> -<p>Oops. The donut is a little bit too obfuscated for our front-end it seems. The problem here is the idiom <code>k;</code> to declare an <code>int</code> variable <code>k</code>. Let's change this:</p> -<pre>int k;double sin() - cos();main(){float A= - 0 B=0 i j z[1760];char b[ - 1760];printf("\x1b[2J");for(;; - ){memset(b 32 1760);memset(z 0 7040) - ;for(j=0;6.28>j;j+=0.07)for(i=0;6.28 - >i;i+=0.02){float c=sin(i) d=cos(j) e= - sin(A) f=sin(j) g=cos(A) h=d+2 D=1/(c* - h*e+f*g+5) l=cos (i) m=cos(B) n=s\ -in(B) t=c*h*g-f* e;int x=40+30*D* -(l*h*m-t*n) y= 12+15*D*(l*h*n -+t*m) o=x+80*y N=8*((f*e-c*d*g - )*m-c*d*e-f*g-l *d*n);if(22>y&& - y>0&&x>0&&80>x&&D>z[o]){z[o]=D;;;b[o]= - ". -~:;=!*#$@"[N>0?N:0];}}/*#****!!-*/ - printf("\x1b[H");for(k=0;1761>k;k++) - putchar(k%80?b[k]:10);A+=0.04;B+= - 0.02;}}/*****####*******!!=;:~ - ~::==!!!**********!!!==::- - . ~~;;;========;;;:~-. - .. -------- */ -</pre> -<pre>$ frama-c -metrics donut.c -[kernel] preprocessing with "gcc -C -E -I. donut.c" -[metrics] Syntactic metrics - Defined function (1): - main (0 call); - Undefined functions (5): - putchar (1 call); sin (4 calls); cos (4 calls); printf (2 calls); - memset (2 calls); -</pre> -<p>Functions <code>putchar()</code> and <code>printf()</code> do not influence the rest of the execution so we can postpone finding a good modelization for them until the very end. We have a <code>memset()</code> implementation leftover from the Skein tutorial. Math functions <code>cos()</code> and <code>sin()</code> can in a first step be specified as returning <code>[-1.0 .. 1.0]</code>. The value analysis has for a long time had a <code>Frama_C_cos()</code> built-in that does a little better than that and the next release will have a <code>Frama_C_sin()</code> but these are not necessary yet.</p> -<p>Let's use a file sincos.c such as:</p> -<pre>#include "share/builtin.h" -double sin(double x) -{ - return Frama_C_double_interval(-1.0 1.0); -} -double cos(double x) -{ - return Frama_C_double_interval(-1.0 1.0); -} -</pre> -<p>3. Launch an imprecise analysis:</p> -<pre>$ bin/toplevel.opt -val share/builtin.c sincos.c donut.c share/libc.c | grep assert -</pre> -<p>We use the command above and get the results below. There are 9 alarms and 2 of them are redundant with the other 7 (these two would be removed in the GUI).</p> -<pre>share/libc.c:51:[kernel] warning: out of bounds write. assert \valid(tmp); -donut.c:14:[kernel] warning: accessing out of bounds index [-7610..9610]. assert 0 ≤ o ∧ o < 1760; -donut.c:14:[kernel] warning: accessing uninitialized left-value: assert \initialized(z[o]); -donut.c:14:[kernel] warning: accessing out of bounds index [-7610..9610]. assert 0 ≤ o ∧ o < 1760; -donut.c:15:[kernel] warning: out of bounds read. assert \valid(". -~:;=!*#$@"+tmp_7); -donut.c:15:[kernel] warning: accessing out of bounds index [-7610..9610]. assert 0 ≤ o ∧ o < 1760; -donut.c:17:[kernel] warning: accessing uninitialized left-value: assert \initialized(b[k]); -donut.c:17:[kernel] warning: accessing out of bounds index [0..1760]. assert 0 ≤ k ∧ k < 1760; -donut.c:14:[value] warning: overflow in float: [--..--] -> [-3.40282346639e+38 .. 3.40282346639e+38]. assert(Ook) -[scope] [rm_asserts] removing 2 assertion(s) -</pre> -<p>4. The imprecise analysis was fast. Let us launch a more precise analysis:</p> -<pre>$ bin/toplevel.opt -val share/builtin.c sincos.c donut.c share/libc.c -slevel 200 | grep assert -share/libc.c:51:[kernel] warning: out of bounds write. assert \valid(tmp); -donut.c:14:[kernel] warning: accessing out of bounds index [-7610..9610]. assert 0 ≤ o ∧ o < 1760; -donut.c:14:[kernel] warning: accessing uninitialized left-value: assert \initialized(z[o]); -donut.c:14:[kernel] warning: accessing out of bounds index [-7610..9610]. assert 0 ≤ o ∧ o < 1760; -donut.c:15:[kernel] warning: accessing out of bounds index [-7610..9610]. assert 0 ≤ o ∧ o < 1760; -donut.c:15:[kernel] warning: out of bounds read. assert \valid(". -~:;=!*#$@"+tmp_7); -donut.c:17:[kernel] warning: accessing uninitialized left-value: assert \initialized(b[k]); -donut.c:17:[kernel] warning: accessing out of bounds index [200..1760]. assert 0 ≤ k ∧ k < 1760; -donut.c:14:[value] warning: overflow in float: [--..--] -> [-3.40282346639e+38 .. 3.40282346639e+38]. assert(Ook) -[scope] [rm_asserts] removing 2 assertion(s) -</pre> -<p>It's still the same assertions. The development version of Frama-C shows the range of the index <code>k</code> (that is <code>[200..1760]</code>) when it prints the assertion <code>assert 0 ≤ k ∧ k < 1760;</code>. That suggests that pushing the value of <code>-slevel</code> to more than <code>1760</code> may eliminate this alarm.</p> <p>I will let someone else continue from here if they want. This program could be very rewarding to verify (<del>a little birdie tells me that there is at least one true alarm to be found using the value analysis or any other techniques</del>I have completely lost faith in that little birdie. There may or may not be a bug we will know for sure when we are done but don't stay awake all night looking for one) so I recommended as a fun exercise for those who are bored from sandy holiday beaches.</p> {% endraw %} diff --git a/_posts/2011-07-26-Fun-with-usual-arithmetic-conversions.html b/_posts/2011-07-26-Fun-with-usual-arithmetic-conversions.html index 793ea75b4e25aee64e23f320f75c7c87ddfbf809..a9145d391d5464a8b509946871d4bada3eb1ee8e 100644 --- a/_posts/2011-07-26-Fun-with-usual-arithmetic-conversions.html +++ b/_posts/2011-07-26-Fun-with-usual-arithmetic-conversions.html @@ -22,19 +22,5 @@ does not emit any alarm for the <code>c++;</code> instruction.</p> the expected modulo results, this instruction never displays undefined behavior. The really dangerous operation, signed addition, takes place between arguments of type <code>int</code> and returns an <code>int</code>. Thus, in this particular program and for the default x86_32 target architecture, the result of the addition is -always representable in the result type.</p> <p>A facetious colleague reports the following program as a bug:</p> -<pre>int main () { - signed char c=0; - while(1) c++; - return 0; -} -</pre> -<p>The commandline <code>frama-c -val -val-signed-overflow-alarms charpp.c</code>, he says, -does not emit any alarm for the <code>c++;</code> instruction.</p> -<p>Indeed, the <code>c++;</code> above is equivalent to <code>c = (signed char) ((int)c + 1);</code>.</p> -<p>If the implementation-defined(6.3.1.3 §3) conversions from <code>int</code> to <code>signed char</code> are assumed to give -the expected modulo results, this instruction never displays undefined behavior. The really dangerous operation, -signed addition, takes place between arguments of type <code>int</code> and returns an <code>int</code>. -Thus, in this particular program and for the default x86_32 target architecture, the result of the addition is -always representable in the result type.</p> +always representable in the result type.</p> {% endraw %} diff --git a/_posts/2011-07-29-Animated-donut-quickly-sorting-out-alarms.html b/_posts/2011-07-29-Animated-donut-quickly-sorting-out-alarms.html index a16aa3b876d44134c7931489cded6d1b01f8f3f5..4e36ce05b5dacf90e874b4a91f4a266a67e8a10e 100644 --- a/_posts/2011-07-29-Animated-donut-quickly-sorting-out-alarms.html +++ b/_posts/2011-07-29-Animated-donut-quickly-sorting-out-alarms.html @@ -115,113 +115,5 @@ in <a href="http://lists.gforge.inria.fr/pipermail/frama-c-discuss/2010-October/ fact the solution that was developed (but not yet documented) following this question could perhaps help a bit here.</p> <p>I owe an apology to Andy Sloane. I initially thought there was a bug in his code. -I have no regrets because of the interesting e-mail discussion that followed.</p> - <p>This post follows <a href="/donut/value/2011/07/22/Animated-donut-verification">that post</a>. It is a brief survey of the alarms obtained when analyzing donut.c -such as a programmer might do when <a href="http://en.wikipedia.org/wiki/Spivak_pronoun">ey</a> is only trying to find bugs -or in the context of verification -as a first step to get an estimate on the difficulty of the task.</p> -<p>The warning <code>donut.c:17: ... assert 0 ≤ k ∧ k > 1760;</code> looked like it might go away with enough unrolling but it doesn't (I tried up to <code>-slevel 50000</code>. It took very long and did not improve things over <code>-slevel 20000</code>).</p> -<pre>... ........ ..... - ................... .. - ...................... .. - .............................. - ..memset(b 32 1760);memset(z 0 7040) - ;................................... - ................. .................... - ...................................... - ................ ................. -................ ..... .......... -.............. .............. -............... ............... - ............... ............... - ..................z[o]................ - ...................................... - .................................... - .............b[k]................ - .............................. - .......................... - ...................... - .............. -donut.c:14:[kernel] warning: accessing uninitialized left-value: assert \initialized(z[o]); -donut.c:17:[kernel] warning: accessing uninitialized left-value: assert \initialized(b[k]); -</pre> -<p>However the alarms in the last post about arrays <code>z</code> and <code>b</code> possibly being used uninitialized do come from the loop inside <code>memset()</code> not being unrolled enough as seen above. These go away with a higher value of <code>-slevel</code>. Note that <code>z</code> is an array of 1760 floats being initialized byte by byte so the loop inside <code>memset()</code> needs to be unrolled at least 7040 times.</p> -<pre>donut.c:14:[value] warning: overflow in float... -</pre> -<p>The above alarm about an unknown sequence of bits being used as a floating-point comes from the access <code>z[o]</code> and is also caused by an imprecise analysis of the loop in which array <code>z</code> is modified. Analyzing that loop more precisely with a higher value of <code>-slevel</code> allows the analysis to infer that <code>z</code> contains well-formed finite floating-point numbers at all times once it has been initialized.</p> -<p>Speaking of floating-point overflows we should have written a pre-condition for functions <code>sin()</code> and <code>cos()</code>. They do not always return a value between -1.0 and 1.0. They may also fail if passed an infinity or NaN. The value analysis considers producing any infinity or NaN an alarm so this omission is not a very serious one.</p> -<p>Note that from the point of view of the values taken by variables <code>A</code> -and <code>B</code> the program is equivalent to the bits highlighted below. -The value analysis was never worried about these -because by default it assumes round-to-nearest mode. In round-to-nearest -these variables do not reach infinity. <code>A</code> and <code>B</code> stop -increasing when they reach the range of floating-point numbers that are -separated by twice 0.04 (resp. 0.02). When they reach that range -in about 2^23 iterations -the donut stops revolving (give or take a factor of 2 for the number of iterations).</p> -<pre>... ........ ..... - ................... .. - ...................... .. - ........................for(;; - ){.................................. - .................................... - ................. .................... - ...................................... - ................ ................. -................ ..... .......... -.............. .............. -............... ............... - ............... ............... - ...................................... - ...................................... - .................................... - ......................A+=0.04;B+= - 0.02;}........................ - .......................... - ...................... - .............. -</pre> -<p>With option <code>-all-rounding-modes</code> that does not exclude the possibility -that the FPU might be configured to round upwards the value analysis -correctly warns about overflows for A and B at line 17.</p> -<p>The alarm for variable <code>o</code> (used as an index) comes -from the fact that <code>o</code> is computed from <code>x</code> and <code>y</code> -and only then the program tests -whether <code>x</code> and <code>y</code> fall on the viewport. -The analyzer does not realize that only some of -the previously computed values for <code>o</code> are possible -at the point where this variable is used as index:</p> -<pre>x = (int)((float)40 + ((float)30 * D) * ((l * h) * m - t * n)); -y = (int)((float)12 + ((float)15 * D) * ((l * h) * n + t * m)); -o = x + 80 * y; -... -if (22 > y) { - if (y > 0) { - if (x > 0) { - if (80 > x) { -... z[o] ... -</pre> -<p>For what it's worth the analyzer finds that <code>-170 ≤ x ≤ 250</code> and -<code>-93 ≤ y ≤ 117</code>. It's probably terribly approximative but we didn't -guide it yet at this point it was just a few seconds of automatic -computation.</p> -<p>We could hope to remove the assertion <code>assert 0 ≤ o ∧ o > 1760;</code> for -<code>z[o]</code> by telling the analyzer to study separately the cases <code>0 ≤ y</code> -<code>0 < y < 22</code> and <code>22 ≤ y</code> and then to separate similarly for -variable <code>x</code> before the computation of the value of <code>o</code>. This would -definitely work if the snippet of code above was at the top of a -function but here it is instead inside an infinite loop. There is a risk -that it won't work because for each state that reaches the beginning -of the snippet up to 9 states may be created go round the loop's -body and be fed back to the same snippet. If some of these states do -not get factored this will go on until the unrolling limit is -reached. I did not try it yet and it might in fact still work despite this caveat.</p> -<p>If it doesn't work this is the kind of -situation where it is useful to reduce the problem to a representative -but short example and ask about it on the mailing list like -in <a href="http://lists.gforge.inria.fr/pipermail/frama-c-discuss/2010-October/002332.html">this case</a>. In -fact the solution that was developed (but not yet documented) following this -question could perhaps help a bit here.</p> -<p>I owe an apology to Andy Sloane. I initially thought there was a bug in his code. I have no regrets because of the interesting e-mail discussion that followed.</p> {% endraw %} diff --git a/_posts/2011-07-30-We-have-a-Csmith-proof-framework.html b/_posts/2011-07-30-We-have-a-Csmith-proof-framework.html index 06a8d6131b762f5c178efa9dbc264e812d110c72..cc13e8931d62b356cbe0418843b85420ad139ccd 100644 --- a/_posts/2011-07-30-We-have-a-Csmith-proof-framework.html +++ b/_posts/2011-07-30-We-have-a-Csmith-proof-framework.html @@ -13,11 +13,5 @@ summary: <p>Anne Pacalet Benjamin Monate Virgile Prevosto Boris Yakobowski and I have been fixing roughly 50 bugs in the framework's front-end pretty-printer and in the value analysis constant propagation and slicing plug-ins during the last 6 months. Fifty may seem like a large number but you have to consider the different functions the bugs were spread over. I am sure that Csmith found as many bugs in at least one open-source and widely respected compiler. As of today the web page claims "more than 350 previously-unknown compiler bugs" and the number is probably outdated since it increases weekly. The number does not include our own 50 as far as I know.</p> <p>More importantly all the Frama-C plug-ins for which I found a way to take advantage of Csmith seem to be completely immune now excepting a couple of minor limitations that can be circumvented for additional Csmith testing until they are definitely fixed. The difficult design constraint for a Csmith-based Frama-C testing script is that it must produce no false positives: the script must be able to run day and night on tens of processors and only require human review when it has definitely found a bug in Frama-C (it is also acceptable to find bugs in the reference C compiler or in Csmith itself but if the script taps my shoulder for me to look at something there had better be a bug somewhere).</p> <p>That does not mean that Frama-C's value analysis or slicing plug-ins have no bug left. There are many possible bugs that could not be found this way because of the limitations of the testing methodology (especially the "no false positive" constraint) and indeed in these plug-ins we were fixing bugs not found by Csmith during the same period. Still I think it is a noteworthy milestone.</p> -<p>Lastly Csmith-imperviousness is a moving target. There was a time when the front-end and value analysis plug-in had already reached Csmith-proofitude (it is better to do the layers from bottom to top so as to avoid cascading bug reports where for instance the slicing is wrong because the value analysis feeds it bad values because of a typing bug in the front-end). Two weeks later Xuejun Yang the main implementor of Csmith had improved it so that it generated new constructs and found new problems in these previously Csmith-robustified parts. I hear Xuejun is now writing his PhD. Hopefully this will allow us a few months to boast.</p> - <p><a href="http://embed.cs.utah.edu/csmith/">Csmith</a> that I mentioned <a href="/index.php?post/2011/05/31/The-stupidest-question-I-have-ever-heard-at-a-Computer-Science-presentation">earlier</a> in this blog is a random generator of C programs. That much sounds easy but it generates only well-defined programs which two or more compilers have no excuse for compiling into executables that produce different results. And it generates varied and interesting enough C programs that it is possible to find lots of compiler bugs this way. These two constraints are obviously difficult to reconcile and the people behind Csmith have done very impressive work.</p> -<p>Frama-C is a collection of analyses and transformations for C programs. In analyzing and transforming it gives meaning to these programs. There are various ways of checking that the meaning given is consistent with the meaning implemented in a reference C compiler so that Frama-C bugs can be found with this powerful tool too.</p> -<p>Anne Pacalet Benjamin Monate Virgile Prevosto Boris Yakobowski and I have been fixing roughly 50 bugs in the framework's front-end pretty-printer and in the value analysis constant propagation and slicing plug-ins during the last 6 months. Fifty may seem like a large number but you have to consider the different functions the bugs were spread over. I am sure that Csmith found as many bugs in at least one open-source and widely respected compiler. As of today the web page claims "more than 350 previously-unknown compiler bugs" and the number is probably outdated since it increases weekly. The number does not include our own 50 as far as I know.</p> -<p>More importantly all the Frama-C plug-ins for which I found a way to take advantage of Csmith seem to be completely immune now excepting a couple of minor limitations that can be circumvented for additional Csmith testing until they are definitely fixed. The difficult design constraint for a Csmith-based Frama-C testing script is that it must produce no false positives: the script must be able to run day and night on tens of processors and only require human review when it has definitely found a bug in Frama-C (it is also acceptable to find bugs in the reference C compiler or in Csmith itself but if the script taps my shoulder for me to look at something there had better be a bug somewhere).</p> -<p>That does not mean that Frama-C's value analysis or slicing plug-ins have no bug left. There are many possible bugs that could not be found this way because of the limitations of the testing methodology (especially the "no false positive" constraint) and indeed in these plug-ins we were fixing bugs not found by Csmith during the same period. Still I think it is a noteworthy milestone.</p> <p>Lastly Csmith-imperviousness is a moving target. There was a time when the front-end and value analysis plug-in had already reached Csmith-proofitude (it is better to do the layers from bottom to top so as to avoid cascading bug reports where for instance the slicing is wrong because the value analysis feeds it bad values because of a typing bug in the front-end). Two weeks later Xuejun Yang the main implementor of Csmith had improved it so that it generated new constructs and found new problems in these previously Csmith-robustified parts. I hear Xuejun is now writing his PhD. Hopefully this will allow us a few months to boast.</p> {% endraw %} diff --git a/_posts/2011-08-07-Donut-gibberish.html b/_posts/2011-08-07-Donut-gibberish.html index 82a204957b9b0791ffc0c6481b341921a7e02bea..34a36ad0ac65a2ba4114af30e04b5475b6caa4fa 100644 --- a/_posts/2011-08-07-Donut-gibberish.html +++ b/_posts/2011-08-07-Donut-gibberish.html @@ -99,97 +99,5 @@ double sin(double x) ... </pre> <p>The slicing plug-in always up for mischief noticed that <code>sin()</code> and <code>cos()</code> did not use their arguments and removed completely the computations of variables <code>A</code> and <code>B</code> and their declarations now useless. -The values of these variables do not matter but we'll need to know that <code>cos()</code> and <code>sin()</code> are applied to the same variables <code>i j A B</code> if we want to have a chance to establish the post-condition. The slicing was removing this crucial piece of knowledge from the sliced program but it was only taking advantage of the information that we had given it with our function stubs.</p> - <p>Hey, I left out one alarm <a href="/index.php?post/2011/08/01/Animated-donut">last time</a>:</p> -<pre>donut.c:15 ... out of bounds read. assert \valid(". -~:;=!*#$@"+tmp_7); -</pre> -<p>This corresponds to <code>". -~:;=!*#$@"[N>0?N:0]</code> in the obfuscated code. I wanted to have a blog post about this construct in particular because I was curious whether it would break the content management system's URL generation.</p> -<p>The reason why this alarm is a false alarm is a bit difficult to see in context so let us focus on the function below which contains only the relevant computations.</p> -<pre>double sin(double) cos(double); -/*@ ensures 0 <= \esult <= 11 ; */ -int compute(float A float B float i float j) -{ - float c=sin(i) l=cos(i); - float d=cos(j) f=sin(j); - float g=cos(A) e=sin(A); - float m=cos(B) n=sin(B); - int N=8*((f*e-c*d*g)*m-c*d*e-f*g-l*d*n); - return N>0?N:0; -} -</pre> -<p>How would we argue that it is allowable to do this in a real verification? If the target compiler implements IEEE 754 floating-point exactly then it doesn't matter what instructions are interspersed with the ones we are studying: they always give the same IEEE 754-mandated values. If the compiler only implements IEEE 754 approximately (say computing some intermediate values in higher precision and later double-rounding some of them at its whim) then we can analyze the function above with option <code>-all-rounding-modes</code> and argue that while the instructions around these ones may in the real program interfere with the computation all possible results of the real program are captured by the value analysis' predictions for this function.</p> -<p>I do not know whether this kind of argument would be accepted in an industrial context but on the other hand the difficulty here similarly to the case of variable <code>o</code> in the last post is artificially introduced by the program's obfuscation. So the point is probably moot: industrial code would not be allowed to mix up computations like this in the first place.</p> -<p>If the discussion above seems a bit abstract perhaps you have not read <a href="http://arxiv.org/abs/cs/0701192">David Monniaux's report on the pitfalls of floating-point computations for static analysis</a>. Consider it recommended.</p> -<p>Lastly modifying the program as below and invoking Frama-C's slicing plug-in with the command that follows was useful for extracting the function <code>compute()</code> above.</p> -<pre>int k;double sin() - cos();main(){float A= - 0 B=0 i j z[1760];char b[ - 1760];printf("\x1b[2J");for(;; - ){memset(b 32 1760);memset(z 0 7040) - ;for(j=0;6.28>j;j+=0.07)for(i=0;6.28 - >i;i+=0.02){float c=sin(i) d=cos(j) e= - sin(A) f=sin(j) g=cos(A) h=d+2 D=1/(c* - h*e+f*g+5) l=cos (i) m=cos(B) n=s\ -in(B) t=c*h*g-f* e;int x=40+30*D* -(l*h*m-t*n) y= 12+15*D*(l*h*n -+t*m) o=x+80*y N=8*((f*e-c*d*g - )*m-c*d*e-f*g-l *d*n); - /*@ slice pragma expr N; */ - if(22>y&& - y>0&&x>0&&80>x&&D>z[o]){z[o]=D;;;b[o]= - ". -~:;=!*#$@"[N>0?N:0];}}/*#****!!-*/ - printf("\x1b[H");for(k=0;1761>k;k++) - putchar(k%80?b[k]:10);A+=0.04;B+= - 0.02;}}/*****####*******!!=;:~ - ~::==!!!**********!!!==::- - . ~~;;;========;;;:~-. - .. -------- */ -</pre> -<pre>$ bin/toplevel.opt -val share/libc.c -slice-pragma main -slice-print donut.c -... -/* Generated by Frama-C */ -extern double sin(); -extern double cos(); -void main(void) -{ - float A; - float B; - float i; - float j; - A = (float)0; - B = (float)0; - while (1) { - j = (float)0; - while (6.28 > (double)j) { - i = (float)0; - while (6.28 > (double)i) { - { float c; float d; float e; float f; float g; float l; float m; - float n; int N; c = (float)sin(i); d = (float)cos(j); - e = (float)sin(A); f = (float)sin(j); g = (float)cos(A); - l = (float)cos(i); m = (float)cos(B); n = (float)sin(B); - N = (int)((float)8 * ((((f * e - (c * d) * g) * m - (c * d) * e) - - f * g) - (l * d) * n)); - /*@ slice pragma expr N; */ ; - } - i = (float)((double)i + 0.02); - } - j = (float)((double)j + 0.07); - } - A = (float)((double)A + 0.04); - B = (float)((double)B + 0.02); - } - return; -} -... -</pre> -<p>Aside: in my first attempt to produce the slice above I made the mistake of including the approximative <code>sin()</code> and <code>cos()</code> functions written earlier:</p> -<pre>#include "share/builtin.h" -double sin(double x) -{ - return Frama_C_double_interval(-1.0 1.0); -} -... -</pre> -<p>The slicing plug-in always up for mischief noticed that <code>sin()</code> and <code>cos()</code> did not use their arguments and removed completely the computations of variables <code>A</code> and <code>B</code> and their declarations now useless. The values of these variables do not matter but we'll need to know that <code>cos()</code> and <code>sin()</code> are applied to the same variables <code>i j A B</code> if we want to have a chance to establish the post-condition. The slicing was removing this crucial piece of knowledge from the sliced program but it was only taking advantage of the information that we had given it with our function stubs.</p> {% endraw %} diff --git a/_posts/2011-08-08-Holiday-stuff.html b/_posts/2011-08-08-Holiday-stuff.html index 2455ec68dc942849bd05ff28e07d29553f15dfee..760a7d09f62390d94b40e3d60c093313ccee6bf5 100644 --- a/_posts/2011-08-08-Holiday-stuff.html +++ b/_posts/2011-08-08-Holiday-stuff.html @@ -13,11 +13,5 @@ summary: <p>John Carmack famous programmer of 3D games <a href="http://www.youtube.com/watch?v=4zgYG-_ha28&feature=player_detailpage#t=54m00s">spoke at length about static analysis at QuakeCon 2011</a> a few days ago. He also says at one point that he wishes he could experiment with say OCaml.</p> <p>In the lab we are supposed to obtain an administrative authorization before publishing any article. If the article has non-CEA co-authors we must obtain an authorization in writing from each of them in order to apply for the authorization to publish (I'm simplifying a bit here. In reality we must submit an intranet form that will automatically be rejected because there the form has no field for co-author authorizations and then send the co-author authorizations in reply to the rejection mail). I have always assumed this was a CEA-wide thing and therefore I wonder whether my colleagues from the physics department had to fulfill this formality when they published this <a href="http://www.sciencedirect.com/science/article/pii/S0370269310003989">3469-author article</a>.</p> -<p>Note that I am not expressing any opinion on the scientific value of the article. It is a LHC article it seems normal for it to have plenty of authors. I am just wondering wondering whether the CEA publishing rule was applied what proportion of the nearly 200 institutes have a similar rule and how many e-mails were exchanged in total to appease the gods of red tape.</p> - <p>I do not expect that many people are diligently working at this time of year, and this is my excuse for posting this series of productivity-wasting links. Some of them are even on-topic.</p> -<p>For those who missed it, GNU/Linux Magazine/France has <a href="http://www.gnulinuxmag.com/index.php/2011/07/01/gnulinux-magazine-hs-n%C2%B055-juillet-aout-2011-chez-votre-marchand-de-journaux" hreflang="fr">a summer special</a> on the C programming language with a 7-page introduction to Frama-C. In French and as the URL says "chez votre marchand de journaux". In related news Dotclear the Content Management System for this blog allows to specify a link's target language in its markdown language. I have always wondered what that was good for. Well the link in this paragraph is dutifully marked as going to a French page. Tell us if you notice any difference.</p> -<p>John Carmack famous programmer of 3D games <a href="http://www.youtube.com/watch?v=4zgYG-_ha28&feature=player_detailpage#t=54m00s">spoke at length about static analysis at QuakeCon 2011</a> a few days ago. He also says at one point that he wishes he could experiment with say OCaml.</p> -<p>In the lab we are supposed to obtain an administrative authorization before publishing any article. If the article has non-CEA co-authors we must obtain an authorization in writing from each of them in order to apply for the authorization to publish (I'm simplifying a bit here. In reality we must submit an intranet form that will automatically be rejected because there the form has no field for co-author authorizations and then send the co-author authorizations in reply to the rejection mail). -I have always assumed this was a CEA-wide thing and therefore I wonder whether my colleagues from the physics department had to fulfill this formality when they published this <a href="http://www.sciencedirect.com/science/article/pii/S0370269310003989">3469-author article</a>.</p> <p>Note that I am not expressing any opinion on the scientific value of the article. It is a LHC article it seems normal for it to have plenty of authors. I am just wondering wondering whether the CEA publishing rule was applied what proportion of the nearly 200 institutes have a similar rule and how many e-mails were exchanged in total to appease the gods of red tape.</p> {% endraw %} diff --git a/_posts/2011-08-09-One-more-rant-for-the-holidays-style-self-consciousness.html b/_posts/2011-08-09-One-more-rant-for-the-holidays-style-self-consciousness.html index b66898bb86d662e7d28a52dc0d2cdbd23e5c1c60..636f6ddd05c6e1cbecc3579b1d3c5ea91babb580 100644 --- a/_posts/2011-08-09-One-more-rant-for-the-holidays-style-self-consciousness.html +++ b/_posts/2011-08-09-One-more-rant-for-the-holidays-style-self-consciousness.html @@ -10,8 +10,5 @@ summary: {% raw %} <p>One unexpected consequence of writing semi-regularly in a blog, in addition to the other bits of writing that I have to do, is that I am starting to hate my own style. It feels like English sentences always come out my fingers with the same rhythm to them. Precisely dull. I always use adverbs the same way. I would go on, but it's gotten to the point where I'm wondering whether I'm not going to switch to my native language mid-post. Better B quick!</p> <p>I read tons, from many different people. The Internet is great for that. Audiobooks have also long replaced music in my iPod. That is less varied for obvious technical reasons, but I listen to anything by Douglas Adams, and various other BBC radio broadcasts. There's \Bilbo the Hobbit" I like to go through when I know I'll have a long stretch of listening time such as <a href="http://www.saintelyon.com/course-raid-nocturne/" hreflang="fr">a night walk</a>. Rudyard Kipling's "Just So Stories" are great for alternating with chapters of "The Selfish Gene". One thing written and read by Scott Adams (the author of Dilbert not any other Scott Adams). Another by Orson Scott Card. Neal Stephenson. In a nutshell plentiful formats and authors. But I don't seem to be able to form sentences other than the repetitive tripe here which wouldn't be too bad and I'm getting allergic to it which is.</p> -<p>Do others feel the same way about any non-native language? How do you overcome it? Let's say you have an article to write some documentation to revise and you are completely and utterly tired of hearing yourself speak. What would you do?</p> - <p>One unexpected consequence of writing semi-regularly in a blog, in addition to the other bits of writing that I have to do, is that I am starting to hate my own style. It feels like English sentences always come out my fingers with the same rhythm to them. Precisely dull. I always use adverbs the same way. I would go on, but it's gotten to the point where I'm wondering whether I'm not going to switch to my native language mid-post. Better B quick!</p> -<p>I read tons, from many different people. The Internet is great for that. Audiobooks have also long replaced music in my iPod. That is less varied for obvious technical reasons, but I listen to anything by Douglas Adams, and various other BBC radio broadcasts. There's \Bilbo the Hobbit" I like to go through when I know I'll have a long stretch of listening time such as <a href="http://www.saintelyon.com/course-raid-nocturne/" hreflang="fr">a night walk</a>. Rudyard Kipling's "Just So Stories" are great for alternating with chapters of "The Selfish Gene". One thing written and read by Scott Adams (the author of Dilbert not any other Scott Adams). Another by Orson Scott Card. Neal Stephenson. In a nutshell plentiful formats and authors. But I don't seem to be able to form sentences other than the repetitive tripe here which wouldn't be too bad and I'm getting allergic to it which is.</p> <p>Do others feel the same way about any non-native language? How do you overcome it? Let's say you have an article to write some documentation to revise and you are completely and utterly tired of hearing yourself speak. What would you do?</p> {% endraw %} diff --git a/_posts/2011-08-10-Csmith-testing-reveals-that-Im-no-good-at-probabilities-and-lazy.html b/_posts/2011-08-10-Csmith-testing-reveals-that-Im-no-good-at-probabilities-and-lazy.html index 63895c79e9759a48957f21afa750a067e3254183..2afb64471843b3913b6b48974f93623507534b88 100644 --- a/_posts/2011-08-10-Csmith-testing-reveals-that-Im-no-good-at-probabilities-and-lazy.html +++ b/_posts/2011-08-10-Csmith-testing-reveals-that-Im-no-good-at-probabilities-and-lazy.html @@ -136,134 +136,5 @@ eventually replaced an approximate test by another that is just as approximate a different way; if you see other angles please write them in the comments.</p> <h2>Aside</h2> <p>Are you thinking "55 frames in the call stack? What a bunch of bloated analysis framework! This thing must be completely useless!"? Then you are <a href="/index.php?post/2011/07/16/Formal-verification-and-SLOC">making judgments based on criteria you are familiar with and ignoring those that are new to you</a>. A more correct reaction would be "I know how to implement a much lighter analyzer that will have all the same functionality and will be just as precise in 5000 lines of my favorite language over a week-end; I'll do that and show them."</p> -<p>Zaynah Dargaye provided useful comments on an early version of this post.</p> - <h2>Csmith testing</h2> -<p>A typical Frama-C Csmith testing script repeats four actions in an infinite loop:</p> -<ol> -<li>getting a random program from Csmith;</li> -<li>compiling and executing it;</li> -<li>analyzing it with Frama-C;</li> -<li>using the results from step 3, possibly together with those of step 2, to determine whether the program reveals something that would interest a Frama-C developer.</li> -</ol> -<p>Step four is the difficult part. I definitely want to hear about varied events that could happen during the analysis, and step four represents about half the testing script's line count. One difficulty is that if a Frama-C bug has already been identified, but isn't fixed yet, I do not want to be warned again about that bug until it is supposed to have been fixed. Sometimes it is possible to use Csmith command-line options to generate only programs that do not trigger the bug. Sometimes, this is impossible, and you have to recognize the bug in step 4.</p> -<p>A particular known bug in Frama-C was characterized by the backtrace below, that I am posting in its entirety to give you a chance to identify my mistake before I tell you about it.</p> -<pre> Raised at file \src/memory_state/new_offsetmap.ml" line 361 characters 26-37 - Called from file "src/memory_state/new_offsetmap.ml" line 377 characters 17-64 - Called from file "src/memory_state/new_offsetmap.ml" line 1394 characters 15-34 - Called from file "src/memory_state/new_offsetmap.ml" line 1436 characters 18-114 - Called from file "set.ml" line 293 characters 37-58 - Called from file "src/memory_state/new_offsetmap.ml" line 1433 characters 11-399 - Called from file "src/memory_state/offsetmap.ml" line 1308 characters 18-93 - Called from file "src/memory_state/lmap.ml" line 641 characters 24-260 - Called from file "src/memory_state/lmap.ml" line 626 characters 18-1023 - Called from file "src/memory_state/cvalue.ml" line 1171 characters 12-50 - Called from file "src/value/eval_exprs.ml" line 1399 characters 4-61 - Called from file "src/value/eval_exprs.ml" line 1447 characters 4-75 - Called from file "src/value/eval_exprs.ml" line 1058 characters 8-66 - Called from file "src/value/eval_exprs.ml" line 986 characters 10-62 - Called from file "src/value/eval_exprs.ml" line 1056 characters 8-52 - Called from file "src/value/eval_exprs.ml" line 1207 characters 4-55 - Called from file "src/value/eval_stmts.ml" line 446 characters 6-105 - Called from file "src/value/eval_stmts.ml" line 880 characters 54-69 - Called from file "list.ml" line 74 characters 24-34 - Called from file "src/memory_state/state_set.ml" line 26 characters 2-24 - Called from file "src/value/eval_stmts.ml" line 889 characters 14-232 - Called from file "cil/src/ext/dataflow.ml" line 320 characters 29-47 - Called from file "cil/src/ext/dataflow.ml" line 497 characters 8-21 - Called from file "cil/src/ext/dataflow.ml" line 501 characters 9-22 - Called from file "src/value/eval_funs.ml" line 100 characters 14-37 - Called from file "src/value/eval_funs.ml" line 502 characters 8-63 - Called from file "src/value/eval_stmts.ml" line 819 characters 12-71 - Called from file "src/value/eval_stmts.ml" line 831 characters 10-114 - Called from file "src/value/eval_stmts.ml" line 864 characters 38-62 - Called from file "list.ml" line 74 characters 24-34 - Called from file "src/value/eval_stmts.ml" line 920 characters 26-79 - Called from file "cil/src/ext/dataflow.ml" line 320 characters 29-47 - Called from file "cil/src/ext/dataflow.ml" line 497 characters 8-21 - Called from file "cil/src/ext/dataflow.ml" line 501 characters 9-22 - Called from file "src/value/eval_funs.ml" line 100 characters 14-37 - Called from file "src/value/eval_funs.ml" line 502 characters 8-63 - Called from file "src/value/eval_stmts.ml" line 819 characters 12-71 - Called from file "src/value/eval_stmts.ml" line 831 characters 10-114 - Called from file "src/value/eval_stmts.ml" line 864 characters 38-62 - Called from file "list.ml" line 74 characters 24-34 - Called from file "src/value/eval_stmts.ml" line 920 characters 26-79 - Called from file "cil/src/ext/dataflow.ml" line 320 characters 29-47 - Called from file "cil/src/ext/dataflow.ml" line 497 characters 8-21 - Called from file "cil/src/ext/dataflow.ml" line 501 characters 9-22 - Called from file "src/value/eval_funs.ml" line 100 characters 14-37 - Called from file "src/value/eval_funs.ml" line 482 characters 4-67 - Called from file "src/value/eval_funs.ml" line 564 characters 11-44 - Re-raised at file "src/value/eval_funs.ml" line 578 characters 47-50 - Called from file "src/project/state_builder.ml" line 1076 characters 9-13 - Re-raised at file "src/project/state_builder.ml" line 1080 characters 15-18 - Called from file "src/value/register.ml" line 49 characters 4-24 - Called from file "queue.ml" line 134 characters 6-20 - Called from file "src/kernel/boot.ml" line 36 characters 4-20 - Called from file "src/kernel/cmdline.ml" line 723 characters 2-9 - Called from file "src/kernel/cmdline.ml" line 200 characters 4-8 - Unexpected error (New_offsetmap.Make(V).End_reached). -</pre> -<p>The uncaught exception comes from new_offsetmap:361 in an auxiliary function -but in this particular case -the place whence this auxiliary function is called (line 377 in the same file) is -a good way to identify the bug. -If the auxiliary function raises the same exception when the function is called -from another place it's another bug. -If it's from the same call it's the same bug.</p> -<p>I adapted my shell script to include the following test in step 4:</p> -<pre>if grep "line 377" analysis_log -then true # I do not know how to negate a condition in shell and I do not want to learn -else ... # continue classifying the analysis -</pre> -<p>I wanted to grep for file name and line number but in the backtrace the file name is surrounded -by quotes and I didn't know how to -escape the quotes inside the grep command-line.</p> -<h2>Mergeable Interval Maps</h2> -<p>The file <code>new_offsetmap.ml</code> contains the implementation of the data structure -described in <a href="http://studia.complexica.net/Art/RI090101.pdf">this article</a>. Pages 6 to 33 -are in English. Incidentally Dotclear does not seem to offer any way to specify -that a linked document is half in one language and half in another.</p> -<p>Although the new data structure's implementation is far from complete it is useful for handling unions -to occasionally translate from the old datastructure to the new one. -Csmith generates programs where unions can be written through a member -and read from another (the members are only of integral types). The old data -structure can handle most sequences of write combinations having occurred before -an union is read but a few complex combinations are not handled. -Richard Bonichon and I already wrote the code to handle all possible combinations -in the new data structure and it would be a waste of time to backport this work -to the old data structure at this point.</p> -<p>You may have guessed that an exception is raised in this module because it's newer -and full of bugs but in fact what is currently implemented already works quite well (one of -the advantages of having lots of tests and a trusted reference implementation). -The reason the new implementation -detects bugs is that knowing in advance what it was going to be used for we included -lots of assertion checks for conditions we knew weren't supposed to happen. The bug comes -in much earlier during parsing and cannot conveniently be worked around when it is detected -in this module.</p> -<h2>My mistake</h2> -<p>What mistake did I make? The backtrace I have shown is 55 lines long. Each of them -contains the pattern "xxx lines" where the values for "xxx" are not independent but we'll -assume that they are for the sake of this argument. All files are more than 377 lines long -and some of them are more than 3779 lines long. It is not sufficiently improbable -that my script would hide from me another bug with a completely different backtrace -that just happens to contain "line 377" or even "line 3775".</p> -<p>I noticed this a few days ago. Resolute in my decision not to learn how to escape quotes -in shell I decided to make false negatives much less likely -by grepping for "line 377 characters 17-64" instead.</p> -<p>This is when I updated Frama-C from source control. The file <code>new_offsetmap.ml</code> -being work in progress the file had been modified and -the line that characterized the bug changed. So I gave up -and started to experiment with grepping special characters. -It turns out that it's possible to grep for doubles quotes by using the simple -syntax below.</p> -<pre>grep 'Raised at file "src/memory_state/new_offsetmap.ml"' analysis_log -</pre> -<p>What is the moral of this story? -What I refused to learn was very simple; I -eventually replaced an approximate test by another that is just as approximate but in -a different way; if you see other angles please write them in the comments.</p> -<h2>Aside</h2> -<p>Are you thinking "55 frames in the call stack? What a bunch of bloated analysis framework! This thing must be completely useless!"? Then you are <a href="/index.php?post/2011/07/16/Formal-verification-and-SLOC">making judgments based on criteria you are familiar with and ignoring those that are new to you</a>. A more correct reaction would be "I know how to implement a much lighter analyzer that will have all the same functionality and will be just as precise in 5000 lines of my favorite language over a week-end; I'll do that and show them."</p> <p>Zaynah Dargaye provided useful comments on an early version of this post.</p> {% endraw %} diff --git a/_posts/2011-08-12-Easy-value-analysis-example-putnum.html b/_posts/2011-08-12-Easy-value-analysis-example-putnum.html index 24e246dc25372eb695d283d8fdf04859be3af739..b2fa991c51ce7225a4782b596c67b4623634da6a 100644 --- a/_posts/2011-08-12-Easy-value-analysis-example-putnum.html +++ b/_posts/2011-08-12-Easy-value-analysis-example-putnum.html @@ -112,110 +112,5 @@ putnum.c:16:[kernel] warning: out of bounds write. assert \valid(ptr); ptr ∈ {{ &buf + [0..8] }} </pre> <p>On a 64-bit architecture all the elements of <code>buf[]</code> seem to be useful but there may be a problem with <code>ptr</code> at line 16. Determining whether this is a true or false alarm will be left as an exercise to the reader (download file <a href="/assets/img/blog/imported-posts/putnum/putnum.c">putnum.c</a>).</p> -<p>Zaynah Dargaye provided insights based on an early version of this post.</p> - <p>If some of the posts in this blog ever get re-organized into a course-style document, this one will be near the beginning, because it's simple and self-contained.</p> -<h2>The program</h2> -<p>This example was offered on our bug-tracking system:</p> -<pre>int putchar(int); -void print(const char *ptr) -{ - while (*ptr) - putchar(*ptr++); -} -void putnum(unsigned long n) -{ - char buf[10], *ptr = buf + sizeof(buf); - *--ptr = 0; - do { - *--ptr = \0123456789ABCDEF"[n&15]; - n >>= 4; - } while(n); - print(ptr); -} -</pre> -<p>A few minutes of looking at the code should allow you to infer for yourself that function <code>putnum()</code> is for printing unsigned hexadecimal numbers.</p> -<h2>The precision issue</h2> -<p>The reporter was disappointed that the value analysis emitted a number of alarms for this code which seems trivial. This brings to mind the quip by Richard Feynman that "mathematicians can prove only trivial theorems because every theorem that's proved is trivial". Excuse the approximate quote: this is another book that I sop up in audio form and these things are even worse than paper for searching. -But perhaps the case deserves to be called trivial indeed because in the original program as provided by the reporter in the BTS <code>putnum()</code> is called only with a single concrete value:</p> -<pre>int main(void) -{ - putnum(0x12345); - putchar('\ -'); - return 0; -} -</pre> -<p>This should help the value analysis: it likes to analyze functions with only the values for arguments and globals that appear to be really passed to them at execution. However remember that most classic bug-finding static analyzers would analyze function <code>putnum()</code> in abstracto and tell you what they think pertinent to tell you regardless of whether the function is called only with <code>0x12345</code> or indeed never called at all — and therefore like the plane that always stays on the ground is extremely safe.</p> -<p>Back to the value analysis. What are these alarms that it finds?</p> -<pre>$ frama-c -val putnum.c -... -putnum.c:16:[kernel] warning: out of bounds write. assert \valid(ptr); -putnum.c:7:[kernel] warning: accessing uninitialized left-value *ptr: assert(Ook) -putnum.c:8:[kernel] warning: accessing uninitialized left-value *tmp: assert(Ook) -putnum.c:7:[kernel] warning: out of bounds read. assert \valid(ptr); -putnum.c:8:[kernel] warning: out of bounds read. assert \valid(tmp); -... -</pre> -<p>Fair enough. The value analysis does emit a number of alarms. Some of them are nearly duplicates. For instance variable <code>tmp</code> is only in function <code>print()</code> the temporary introduced in the translation of <code>*ptr++</code>. It's by design that <a href="/value/2011/07/21/Back-to-the-drawing-board">the analysis no longer even tries to avoid multiple warnings in this case</a>. On the whole it does limit its study of function <code>putnum()</code> to the case where <code>n</code> is <code>0x12345</code>. The imprecision comes from somewhere else: the loop inside <code>putnum()</code>. By default the analyzer summarizes the loop in an unfavorable way. Variable <code>ptr</code> is only inferred to range over <code>{{ &buf + [-1..8] }}</code> at the point where it's dereferenced so it is not guaranteed to be valid:</p> -<p><img src="/assets/img/blog/imported-posts/putnum/loop_summary.png" alt="loop_summary.png" style="display:block; margin:0 auto;" title="loop_summary.png août 2011" /></p> -<p>Since the analyzer doesn't know which <code>buf[]</code> element exactly is written to all it can say is that each element between 0 and 8 may be <code>[48..70] or UNINITIALIZED</code>:</p> -<p><img src="/assets/img/blog/imported-posts/putnum/loop_buf.png" alt="loop_buf.png" style="display:block; margin:0 auto;" title="loop_buf.png août 2011" /></p> -<p>Note that <code>48</code> is <code>'0'</code> and <code>70</code> is <code>'F'</code> so it is not doing too bad really despite emitting all these alarms.</p> -<h2>The solution</h2> -<p>What's the step after checking what library functions are used in the program and thinking how to offer equivalent source code to the analyzer? Ah yes it is: "if the analysis is fast enough use option <code>-slevel</code> to make it more precise".</p> -<pre>$ frama-c -val putnum.c -slevel 50 -... -[value] Values for function putnum: - n ∈ {0; } - buf[0..3] ∈ UNINITIALIZED - [4] ∈ {49} - [5] ∈ {50} - [6] ∈ {51} - [7] ∈ {52} - [8] ∈ {53} - [9] ∈ {0} - ptr ∈ {{ &buf + {4} }} -</pre> -<p>The alarms all disappear. We can make sure this is not caused by a freakish accident but because the value analysis understand exactly what goes on during execution of this program: the hexadecimal representation of <code>0x12345</code> in the contents of array <code>buf[]</code> in a snapshot taken at the end of <code>putnum()</code>.</p> -<h2>Generalizing</h2> -<p>The exercise can be made more interesting by considering the safety of <code>putnum()</code> when called with an unknown argument:</p> -<pre>unsigned long unknown(); -int main(void) -{ - putnum(unknown()); - putchar('\ -'); - return 0; -} -</pre> -<p>I have to admit I made a mistake here when replying to the bug report: I did not try it. Biased by hours spent on difficult case studies I thought that the value analysis would need to have different execution paths (where the program is valid for slightly different reasons) manually separated in order to conclude that the program is safe. Something like the following hint placed in a strategic location according to the principles in <a href="/index.php?post/2011/03/26/Helping-the-value-analysis-2">this post</a>.</p> -<pre>/*@ assert n <= 15 || 16 <= n <= 65535 || 65536 <= n <= ... ; -</pre> -<p>Such an annotation typical of those needed for a larger-scale value-analysis-based verification is not required here (but it does not hurt). Even without it the value analysis separates the cases where the number is one-digit two-digits etc. long by itself in few millions of processor cycles — that is in a fraction of a second:</p> -<pre>$ frama-c -val putnum.c -slevel 500 -... -[value] Values for function putnum: - n ∈ {0; } - buf[0] ∈ UNINITIALIZED - [1..7] ∈ [48..70] or UNINITIALIZED - [8] ∈ [48..70] - [9] ∈ {0} - ptr ∈ {{ &buf + [1..8] }} -</pre> -<p>For an annotationless analysis a lot of information is contained in this snapshot of the program's state. The value analysis is strongly suggesting that it is safe to reduce the size of <code>buf[]</code> by one since <code>ptr</code> never goes lower than <code>buf+1</code> and <code>buf[0]</code> remains uninitialized for all possible <code>putnum()</code> arguments. -All numbers are printed with at least one digit (<code>buf[8]</code> is guaranteed to be initialized and in the range '0'..'F' and <code>ptr</code> points no higher than <code>buf[8]</code>). On the other hand elements 1 to 7 are not guaranteed to be written to.</p> -<p>But wait: the value analysis seems to be saying that it's safe to reduce the size of <code>buf[]</code> by one but perhaps this code is not intended <strong>only</strong> for 32-bit architectures? Perhaps the additional element serves to make the function safe on a 64-bit architecture. Let us try it out:</p> -<pre>$ frama-c -val putnum.c -slevel 500 -machdep x86_64 -... -putnum.c:16:[kernel] warning: out of bounds write. assert \valid(ptr); -... -[value] Values for function putnum: - n ∈ {0; } - buf[0..7] ∈ [48..70] or UNINITIALIZED - [8] ∈ [48..70] - [9] ∈ {0} - ptr ∈ {{ &buf + [0..8] }} -</pre> -<p>On a 64-bit architecture all the elements of <code>buf[]</code> seem to be useful but there may be a problem with <code>ptr</code> at line 16. Determining whether this is a true or false alarm will be left as an exercise to the reader (download file <a href="/assets/img/blog/imported-posts/putnum/putnum.c">putnum.c</a>).</p> <p>Zaynah Dargaye provided insights based on an early version of this post.</p> {% endraw %} diff --git a/_posts/2011-08-14-begin-while-repeat.html b/_posts/2011-08-14-begin-while-repeat.html index b332b53833db53d0aabcbda0fbdce59df4a94151..7c93ef5bd6ef18d00313aa204e80d9bb5e91a5ed 100644 --- a/_posts/2011-08-14-begin-while-repeat.html +++ b/_posts/2011-08-14-begin-while-repeat.html @@ -14,11 +14,5 @@ summary: It turns out that the answer is:</p> <pre>while (1a) ; let cond = (1b) in (2) ; cond do () done </pre> -<p>One tiny issue is that the OCaml mode for Emacs does not seem to do a very good job of indenting it. What a shame, such a useful idiom.</p> <p>A little while ago, I was commenting somewhere that Forth had the ultimate control structure, the <code>BEGIN (1) WHILE (2) REPEAT</code> construction.</p> -<p>(1) and (2) are holes to be filled with programs. <code>WHILE</code> takes an evaluated condition from the stack, so that (1) can usually be divided into (1a): do some stuff and (1b): determine whether the loop should exit. Regardless of the value of the condition, (2) is run, and then, if the condition was true, <code>REPEAT</code> sends control back to <code>BEGIN</code>, and if it was false, it continues with the rest of the program.</p> -<p>Sometimes you need the full power of the begin-while-repeat. Not coincidentally (because this structure is really useful), this happened to us recently, so we looked for the first time at how to write begin-while-repeat in OCaml. OCaml has only <code>while (e1) do (e2) done</code>, but you can nest expressions arbitrarily. -It turns out that the answer is:</p> -<pre>while (1a) ; let cond = (1b) in (2) ; cond do () done -</pre> <p>One tiny issue is that the OCaml mode for Emacs does not seem to do a very good job of indenting it. What a shame, such a useful idiom.</p> {% endraw %} diff --git a/_posts/2011-08-26-The-OCaml-compiler-does-have-some-nice-optimizations.html b/_posts/2011-08-26-The-OCaml-compiler-does-have-some-nice-optimizations.html index f1673d8755eb848cd918d24528cf35e18cb7d512..7b8cbb3a125b34e3a918374e4d9b7eb25d926968 100644 --- a/_posts/2011-08-26-The-OCaml-compiler-does-have-some-nice-optimizations.html +++ b/_posts/2011-08-26-The-OCaml-compiler-does-have-some-nice-optimizations.html @@ -57,55 +57,5 @@ I should have known better. Julien Signoles discovered that the compiler generat ret </pre> <p>The above is "AT&T" assembly syntax and corresponds to <code>return *arg;</code> in C. -It's even better than the generated code for the second low-level version because in the first version the compiler has more type information to rely on. Plus since I am reading the assembly for the whole module I can confirm that the function gets inlined where it is called directly (another optimization that the OCaml compiler does very well).</p> - <p>Many OCaml programmers use it because it offers a reasonable (to them) compromise between expressivity and control over resources use. Serious OCaml users are often heard complaining about relatively simple optimizations that the compiler does not have. But this reveals as much of the kind of programmers that end up using OCaml as it does of OCaml itself.</p> -<p>Case in point: the value analysis in Boron used to have a type similar to:</p> -<pre> type t = bool * bool * v -</pre> -<p>If this was C, the definition above would be a <code>struct</code>. Here, <code>bool</code> is the predefined type that you expect, <code>v</code> is the type of values a C expression can have in the value analysis, and the type <code>t</code> being defined is the type of values as found in memory. A value in memory can be a normal value (the <code>v</code> part) or it may have reason to be uninitialized (the first <code>bool</code>) or it may be a dangling pointer (the second <code>bool</code>). During analysis, a value in memory can be all of the above at once, as is variable <code>y</code> after the following snippet:</p> -<pre> void f(void) - { - int* y; - if (unknown condition 1) - y = NULL; - else if (unknown condition 2) - { - int l; - y = &l; - } - ... - } -</pre> -<p>After the first instructions of function <code>f</code>, variable <code>y</code> is either uninitialized or a dangling pointer or the normal value <code>NULL</code>. The value analysis \uninitialized" flag can also be seen in action in <a href="/index.php?post/2011/08/12/Putnum">this post</a>.</p> -<p>An OCaml value of the above type <code>t</code> occupies four words in memory: one header word for automatic memory management and one for each field. Each field occupies one word to make memory management genericity etc. easier.</p> -<p>In the period between Boron and Carbon I decided to make the representation of type <code>t</code> a bit more compact (this is one of several memory use improvements I boasted about in this blog). The two booleans can be represented as bits inside a same integer; this would save one word. I decided to go further and in effect to borrow two unused bits from the header word by using the definition below:</p> -<pre> type t = - C_uninit_escaping of v - | C_uninit_noescaping of v - | C_init_escaping of v - | C_init_noescaping of v -</pre> -<p>This type definition is no longer like a C <code>struct</code>. It is more like an union an union of <code>v</code> or <code>v</code> or <code>v</code> or <code>v</code> but a <a href="http://en.wikipedia.org/wiki/Tagged_union">discriminated union</a> where it's possible to recognize what kind of <code>v</code> one is talking about. C forces the programmer to manage <a href="http://en.wikipedia.org/wiki/Spivak_pronoun">eir</a> own tag. In OCaml some bits are reserved in the bloc header for the tag. A value of the new type <code>t</code> always occupies two words one word for the header (including some bits for the tag) and one word for the contents of type <code>v</code>.</p> -<p>During analysis when the C program gets a value from memory and uses it in a computation it is necessary to get the part of type <code>v</code> from a value of type <code>t</code>. With the old definition the function was:</p> -<pre> let get_v (_ _ v) = v -</pre> -<p>With the new definition the same function <code>get_v</code> would be:</p> -<pre> let get_v = - function - C_uninit_escaping v - | C_uninit_noescaping v - | C_init_escaping v - | C_init_noescaping v -> v -</pre> -<p>I was afraid that this would be compiled into an ugly 4-case test so I used a different implementation based on low-level OCaml primitives that are not supposed to be used:</p> -<pre> let get_v : t -> v = fun x -> Obj.obj (Obj.field (Obj.repr x) 0) -</pre> -<p>It is ugly too but my hope was that the compiled code would be better. It literally means "forget the type of the argument <code>x</code> (something you are never supposed to do in OCaml) and get the first field of that whatever that is". -I was so used to the compiler not optimizing to my liking that I did not even compare the code for the two versions. -I should have known better. Julien Signoles discovered that the compiler generates the following code for the first pure OCaml version:</p> -<pre> movq (%rax) %rax - ret -</pre> -<p>The above is "AT&T" assembly syntax and corresponds to <code>return *arg;</code> in C. It's even better than the generated code for the second low-level version because in the first version the compiler has more type information to rely on. Plus since I am reading the assembly for the whole module I can confirm that the function gets inlined where it is called directly (another optimization that the OCaml compiler does very well).</p> {% endraw %} diff --git a/_posts/2011-08-27-Only-intervals.html b/_posts/2011-08-27-Only-intervals.html index 8967edfab99942df342dcaabe44fb8c2ce6ce07a..45b9d662ff9df5f2af02f05830c67d8597d10caf 100644 --- a/_posts/2011-08-27-Only-intervals.html +++ b/_posts/2011-08-27-Only-intervals.html @@ -14,12 +14,5 @@ summary: <li>For those making the "intervals" remark programs are structurally simple sequences of computations involving simple variables so that a non-relational analysis is naturally an interval analysis. What other kind of interesting information could a non-relational analysis compute ? It's not as if programs exhibited uninitialized variables dangling pointers pointer arithmetics and dirty pointer manipulation tricks.</li> <li>And they are not interested in data flow properties either so that they completely miss Frama-C's various plug-ins for computing data flow properties with abstract interpretation and dedicated abstract domains.</li> </ul> -<p>It's all fine of course. May everyone find joy doing what they like most. I just wish Frama-C was dragged less often into these people's discussion. They don't need to hear about it because they don't have a C program to verify and it ruins my own fun when Google Alerts digs up this kind of comment. But I don't host a cat and it must be a law of nature that everyone should find something foul on their doorstep once in a while.</p> - <p>More often than is good for me, I find someone on the internet saying something to the effect that \Frama-C only does intervals". Sadly I think I see what they mean.</p> -<ul> -<li>they may be of the school of thought that static analysis is abstract interpretation so that although Frama-C is a static analysis framework with a large range of useful tricks it can do they identify it with the one plug-in that does mostly abstract interpretation and nothing more than abstract interpretation. That much is ordinary: for every person who knows about it at all there is a single plug-in that they think Frama-C is.</li> -<li>For those making the "intervals" remark programs are structurally simple sequences of computations involving simple variables so that a non-relational analysis is naturally an interval analysis. What other kind of interesting information could a non-relational analysis compute ? It's not as if programs exhibited uninitialized variables dangling pointers pointer arithmetics and dirty pointer manipulation tricks.</li> -<li>And they are not interested in data flow properties either so that they completely miss Frama-C's various plug-ins for computing data flow properties with abstract interpretation and dedicated abstract domains.</li> -</ul> <p>It's all fine of course. May everyone find joy doing what they like most. I just wish Frama-C was dragged less often into these people's discussion. They don't need to hear about it because they don't have a C program to verify and it ruins my own fun when Google Alerts digs up this kind of comment. But I don't host a cat and it must be a law of nature that everyone should find something foul on their doorstep once in a while.</p> {% endraw %} diff --git a/_posts/2011-08-29-CompCert-gets-a-safe-interpreter-mode.html b/_posts/2011-08-29-CompCert-gets-a-safe-interpreter-mode.html index cb75fa8fd869a421fb8ed3b0e28e8d9dd7b142a0..9683e3d5020c4fbd93414eb67bc3cda7db806c64 100644 --- a/_posts/2011-08-29-CompCert-gets-a-safe-interpreter-mode.html +++ b/_posts/2011-08-29-CompCert-gets-a-safe-interpreter-mode.html @@ -53,51 +53,5 @@ $ time ccomp -interp c.c <p>Value analysis: 0.848s</p> <p>CompCert interpreter: 0.616s</p> <h2>Conclusion</h2> -<p>I think this is not bad at all for either of the two interpreters. I have examples where the value analysis does better than CompCert but it wouldn't be fair to include them at this point because they poke at a known weakness in CompCert's interpreter. On the other hand I do not think that the value analysis will ever do much better than the results above. If I stumble on improvements that look like they'll improve both the analyzer and the interpreter in the value analysis I'll implement these immediately but I do not think I should compromise the analyzer's performance to improve the interpreter. It is slow enough as it is. Just ask Boris.</p> - <h2>Safe C interpreters galore</h2> -<p>The last release of <a href="http://compcert.inria.fr/">CompCert</a> includes a safe C interpreter based on the compiler's reference semantics. Like <a href="http://code.google.com/p/c-semantics/">KCC</a> and Frama-C's value analysis it detects a large class of undefined behaviors and some unspecified ones. Like them in order to remain useful it needs to make some difficult choices regarding what it accepts and what it rejects. C programs are seldom written entirely in the "strictly conforming" subset of the language even when their authors advertise them as "portable". I once found on the Internet a "portable memcpy()" that started by decrementing one of its pointer arguments (a definite undefined behavior if the pointer points to the beginning of a block). This is one case that CompCert's interpreter and Frama-C's value analysis both accept. To warn they both wait until you either dereference or compare the invalid pointer. I can't speak for Xavier but the reason why the value analysis waits is that too many programs do this and too many programmers do not even accept that it is wrong when you point it out to them (to be clear I am not talking about the industrial users interested in Frama-C for verification of critical C programs here; that would be cause for worry. I am talking about the random C programmer you may find anywhere else). It would be very easy to modify the value analysis to warn as soon as the invalid pointer is computed if someone desired strict enforcement of the standard.</p> -<p>While Xavier was implementing this C interpreter I was coincidentally working on an interpreter mode for the value analysis. This mode simply deactivates a number of features that are not useful for the step-by-step interpretation of deterministic C programs: recording memory states and detecting infinite loops. The option does not try to change the representation of memory states that are still sets of possible valuations for all the variables in memory — in interpreter mode the states just happen all to be singletons and singletons that the interpreter represents slightly inefficiently. In fact after it was done I realized that this option would double up as a useful tool for some of the <a href="/index.php?post/2011/03/03/cosine-for-real">brute-force numerical precision analyses that are possible with the value analysis</a> so that right now I am struggling to find a name for the option. Since a benchmark was coming up I also de-activated all consistency checks inside the value analysis. Lastly I linked Frama-C with a miracle library that I need to tell you more about in another blog post.</p> -<h2>Benchmark</h2> -<p>And there it was: the benchmark. This is an informal little thing strictly for fun. There is no point in doing more serious measurements yet since Xavier may still improve the representation of memory states in CompCert's interpreter. I used the three files below:</p> -<ul> -<li>SHA1 compression of a couple of small buffers with a final check of the result: <a href="/assets/img/blog/imported-posts/interp_benchmark/sha1.c">sha1.c</a></li> -<li>a program generated by the <a href="http://embed.cs.utah.edu/csmith/">Csmith</a> random C program generator. The program is in the intersection of what both interpreters support: <a href="/assets/img/blog/imported-posts/interp_benchmark/csmith.c">csmith.c</a></li> -<li>the program <code>main(){ signed char c; for(c=1; c; c++); return c;}</code></li> -</ul> -<p>For reference the commands used are (the Frama-C commands will not work with Carbon; you'll need to remove the unknown options; option <code>-obviously-terminates</code> can be approximated in Carbon with <code>-slevel 999999999 -no-results</code>):</p> -<pre>$ time ~/ppc/bin/toplevel.opt -val -obviously-terminates \ - -cpp-command "gcc -C -E -Dprintf=Frama_C_show_each" sha1.c -... -[value] Called Frama_C_show_each({{ &"Test `%s': %s" }} {{ &test_input_1 }} - {{ &"passed" }}) -... -[value] Called Frama_C_show_each({{ &"Test `%s': %s" }} {{ &test_input_2 }} - {{ &"passed" }}) -... -$ time ccomp -interp sha1.c -... -Test `abc': passed -Test `abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq': passed -... -</pre> -<pre>$ time ~/ppc/bin/toplevel.opt -val -obviously-terminates -big-ints-hex 0 \ - -cpp-command "gcc -C -E -Dprintf=Frama_C_show_each -Iruntime" csmith.c -... -[value] Called Frama_C_show_each({{ &"checksum = %X" }} {0x3F65930A}) -... -$ time ccomp -interp -Iruntime csmith.c -checksum = 3F65930A -</pre> -<pre>$ time ~/ppc/bin/toplevel.opt -val -obviously-terminates c.c -$ time ccomp -interp c.c -</pre> -<h2>Results</h2> -<p>The times shown are the medians of three runs.</p> -<p>For the small program with the <code>signed char</code> <code>ccomp -interp</code> takes 0.016s and the value analysis 0.096s. I am tempted to attribute the value analysis' bad score to startup time: Frama-C is probably heavier than a compiler by now and it loads all its available plug-ins at start-up. I could have improved this by disabling plug-ins that are not necessary for interpreting C programs this way.</p> -<p>For the SHA1 mini-benchmark the value analysis takes 0.388s and <code>ccomp -interp</code> takes 0.296s.</p> -<p>For the Csmith random program:</p> -<p>Value analysis: 0.848s</p> -<p>CompCert interpreter: 0.616s</p> -<h2>Conclusion</h2> <p>I think this is not bad at all for either of the two interpreters. I have examples where the value analysis does better than CompCert but it wouldn't be fair to include them at this point because they poke at a known weakness in CompCert's interpreter. On the other hand I do not think that the value analysis will ever do much better than the results above. If I stumble on improvements that look like they'll improve both the analyzer and the interpreter in the value analysis I'll implement these immediately but I do not think I should compromise the analyzer's performance to improve the interpreter. It is slow enough as it is. Just ask Boris.</p> {% endraw %} diff --git a/_posts/2011-09-09-Fun-with-constants.html b/_posts/2011-09-09-Fun-with-constants.html index da0a6fc99ec9a7d70808fa20141f30f0c661548f..582160337b38b9ac31693b09787e90444074572f 100644 --- a/_posts/2011-09-09-Fun-with-constants.html +++ b/_posts/2011-09-09-Fun-with-constants.html @@ -16,13 +16,5 @@ summary: printf (\%d" x+y+z); return (x+y+z) - 147; } -</pre>" <p>Another facetious colleague reports a strange behavior with the following C program:</p> -<pre>int main (void) { - int x = 100; - int y = 042; - int z = 005; - printf (\%d" x+y+z); - return (x+y+z) - 147; -} -</pre>" +</pre> {% endraw %} diff --git a/_posts/2011-09-12-Better-is-the-enemy-of-good...-sometimes.html b/_posts/2011-09-12-Better-is-the-enemy-of-good...-sometimes.html index a6b59a6d5f33518aa719d579eb3150ee59651a34..7580dfded64aa6b49d495d89c036ffed089c4ff0 100644 --- a/_posts/2011-09-12-Better-is-the-enemy-of-good...-sometimes.html +++ b/_posts/2011-09-12-Better-is-the-enemy-of-good...-sometimes.html @@ -129,127 +129,5 @@ And this is why until version Carbon only the naive modelization of <code>cos()</code> was provided.</p> <p>In the next release there will be in addition to the naive versions <code>Frama_C_cos_precise()</code> and -<code>Frama_C_sin_precise()</code> built-ins for when you want them. Typically this will be for the more precise analyses that do not involve widening.</p> - <p>This post is about widening. This technique was shown in the second part of -a <a href="/index.php?post/2011/01/27/On-memcpy-1">previous post about memcpy()</a> -where it was laboriously used to analyze imprecisely -function <code>memcpy()</code> as it is usually written. -The value analysis in Frama-C has the ability to summarize loops -in less time than they would take to execute. Indeed it can -analyze in finite time loops for which it is not clear whether -they terminate at all. This is the result of widening the -voluntary loss of precision in loops. -As a side-effect widening can produce some -counter-intuitive results. This post is about these -counter-intuitive results.</p> -<h2>The expected: better information in better information out</h2> -<p>Users generally expect that -the more you know about the memory state before -the interpretation of a piece of program the more you should -know about the memory state after this piece of program. -Users are right to expect this and indeed it is generally true:</p> -<pre>int u; -main(){ - u = Frama_C_interval(20 80); - if (u & 1) - u = 3 * u + 1; // odd - else - u = u / 2; // even -} -</pre> -<p>The command <code>frama-c -val c.c share/builtin.c</code> shows the final value of <code>u</code> to be in <code>[10..241]</code>. -If the first line of <code>main()</code> is changed to make the input value range -over <code>[40..60]</code> instead of <code>[20..80]</code> then the output -interval for <code>u</code> becomes <code>[20..181]</code>. This seems normal : -you know more about variable <code>u</code> going in (all the values in <code>[40..60]</code> -are included in <code>[20..80]</code>) so you know more about <code>u</code> -coming out (<code>[20..181]</code> is included in <code>[10..241]</code>). -Most of the analyzer's weaknesses such as in this case the inability -to recognize that the largest value that can get multiplied by 3 is -respectively 79 or 59 do not compromise this general principle. But widening -does.</p> -<h2>Better information in worse information out</h2> -<p>Widening happens when there is a loop in the program such as in -the example below:</p> -<pre>int u i; -main(){ - u = Frama_C_interval(40 60); - for (i=0; i<10; i++) - u = (25 + 3 * u) / 4; -} -</pre> -<pre>$ frama-c -val loop.c share/builtin.c -... -[value] Values for function main: - u ∈ [15..60] -</pre> -<p>Analyzing this program with the -default options produce the interval <code>[15..60]</code> for <code>u</code>. -Now if we change the initial set for <code>u</code> to -be <code>[25..60]</code> an interval that contains all the values -from <code>[40..60]</code> and more:</p> -<pre>$ frama-c -val loop.c share/builtin.c -... -[value] Values for function main: - u ∈ [25..60] -</pre> -<p>By using a larger less precise set as the input of this analysis -we obtain a more precise result. This is counter-intuitive -although it is rarely noticed in practice.</p> -<h2>Better modelization worse analysis</h2> -<p>There are several ways to make this unpleasant situation less likely to -be noticed. Only a few of these are implemented in Frama-C's -value analysis. Still it was difficult enough to find a short -example to illustrate my next point and the program is -only as short as I was able to make it. Consider the following -program:</p> -<pre>int i j; -double ftmp1; -double Frama_C_cos(double); -double Frama_C_cos_precise(double); -#define TH 0.196349540849361875 -#define NBC1 14 -#define S 0.35355339 -double cos(double x) -{ - return Frama_C_cos(x); -} -main(){ - for (i = 0; i < 8; i++) - for (j = 0; j < 8; j++) - { - ftmp1 = ((j == 0) ? S : 0.5) * - cos ((2.0 * i + 1.0) * j * TH); - ftmp1 *= (1 << NBC1); - } -} -</pre> -<p>If you analyze the above program with a smartish -modelization of function <code>cos()</code> one that recognizes -when its input is an interval <code>[l..u]</code> of floating-point -values on which <code>cos()</code> is monotonous and computes -the optimal output in this case you get -the following results:</p> -<pre>$ frama-c -val idct.c share/builtin.c -... - ftmp1 ∈ [-3.40282346639e+38 .. 8192.] -</pre> -<p>Replacing the <code>cos()</code> modelization by -a more naive one that returns <code>[-1. .. 1.]</code> -as soon as its input set isn't a singleton you get -the improved result:</p> -<pre>$ frama-c -val idct.c share/builtin.c -... - ftmp1 ∈ [-8192. .. 8192.] -</pre> -<p>This is slightly different from the <code>[25..60]</code> -example in that here we are not changing the input -set but the modelization of one of the functions involved -in the program. Still the causes are the same and the -effects just as puzzling when they are noticeable. -And this is why until version Carbon only -the naive modelization of <code>cos()</code> was -provided.</p> -<p>In the next release there will be in addition to the naive versions <code>Frama_C_cos_precise()</code> and <code>Frama_C_sin_precise()</code> built-ins for when you want them. Typically this will be for the more precise analyses that do not involve widening.</p> {% endraw %} diff --git a/_posts/2011-09-14-Frama-C-description.html b/_posts/2011-09-14-Frama-C-description.html index 961f54277028ed5f219a158a61576dd8514e24e5..b4c79cdf5f719b1a063f7cd43883573b49db0bf9 100644 --- a/_posts/2011-09-14-Frama-C-description.html +++ b/_posts/2011-09-14-Frama-C-description.html @@ -14,12 +14,5 @@ summary: <p>"Frama-C" is proper. I know that developers are first to take liberties (OCaml variable names must start with lowercase. Many contexts do not accept dashes inside names. Unix commands traditionally are all lowercase etc.). This much is entirely our fault.</p> <p>And now that I think of it it would be too easy to poke fun at someone who had to write a summary for a dozen comparably obscure tools that day so I will leave the jokes implied after all. At least it does not say Frama-C only has <a href="/position/rant/2011/08/27/Only-intervals">intervals</a> dammit! Ok I'm done now. Where was I? Ah yes. Apparently this page is some sort of wiki. Have you heard of them? They are pages on the internet that you can modify. Perhaps it wouldn't be appropriate for someone who isn't a Fedora user to go there and fix the description. But if you are reading this blog and are not a Frama-C developer and happen to use Fedora then you can probably think of a better description and it is morally acceptable for you to offer it on that wiki.</p> <p>PS: so much for fair use. Does implied criticism count? Well sue me.</p> -<p>PPS: the list of alarms detected by the value analysis is "uninitialized access use of a dangling pointer overflows in signed integer arithmetics invalid memory access invalid comparison of pointers division by zero undefined logical shift overflows in conversions from floating-point to integer infinite or NaN resulting from a floating-point operation undefined side-effects in expressions".</p> - <p>A <a href="http://fedoraproject.org/w/index.php?title=Documentation_Development_Tools_Beat">webpage hosted on fedoraproject.org</a> describes Frama-C as follows. I'm quoting the paragraph entirely although it is copyrighted by Red Hat Inc. and others. If I'm not too lazy I will criticize thoroughly which will make this fair use.</p> -<blockquote><p>frama-c is a C source code analysis tool which may be used standalone or integrated with Emacs. frama-c includes a source browser and can calculate simple metrics such as sloc call depth and cyclomatic complexity for a project. It can also generate simple call graphs. Various assertions about the code may be tested and the code may be validated against a number of theorems. frama-c accepts user written plugins for additional custom analyses. More information on frama-c may be found at http://frama-c.com/.</p> -</blockquote> -<p>"Frama-C" is proper. I know that developers are first to take liberties (OCaml variable names must start with lowercase. Many contexts do not accept dashes inside names. Unix commands traditionally are all lowercase etc.). This much is entirely our fault.</p> -<p>And now that I think of it it would be too easy to poke fun at someone who had to write a summary for a dozen comparably obscure tools that day so I will leave the jokes implied after all. At least it does not say Frama-C only has <a href="/position/rant/2011/08/27/Only-intervals">intervals</a> dammit! Ok I'm done now. Where was I? Ah yes. Apparently this page is some sort of wiki. Have you heard of them? They are pages on the internet that you can modify. Perhaps it wouldn't be appropriate for someone who isn't a Fedora user to go there and fix the description. But if you are reading this blog and are not a Frama-C developer and happen to use Fedora then you can probably think of a better description and it is morally acceptable for you to offer it on that wiki.</p> -<p>PS: so much for fair use. Does implied criticism count? Well sue me.</p> <p>PPS: the list of alarms detected by the value analysis is "uninitialized access use of a dangling pointer overflows in signed integer arithmetics invalid memory access invalid comparison of pointers division by zero undefined logical shift overflows in conversions from floating-point to integer infinite or NaN resulting from a floating-point operation undefined side-effects in expressions".</p> {% endraw %} diff --git a/_posts/2011-09-14-Linux-and-floating-point-nearly-there.html b/_posts/2011-09-14-Linux-and-floating-point-nearly-there.html index af9bc032b6f659643eacb401bec6ada168e06c5e..3ad2d700620f4db9b1e3cbb6a94ad882608f224e 100644 --- a/_posts/2011-09-14-Linux-and-floating-point-nearly-there.html +++ b/_posts/2011-09-14-Linux-and-floating-point-nearly-there.html @@ -25,23 +25,5 @@ $ bin/toplevel.top - : float = -0.141120008059867214 </pre> <p><code>2.76</code> is a large amplitude for the sine of any angle and <code>3.0</code> isn't even unreasonable as an argument to pass to trigonometric functions. Trigonometric functions on my other OS work from OCaml in all rounding modes. On this Linux computer the result is reasonable in the default nearest-even mode. This all rather points to an issue in libraries rather than OCaml itself.</p> -<p>If even desktop computers and servers provide this kind of third-rate trigonometric functions what should we assume about embedded code?</p> - <p>In the process of implementing the value analysis built-ins <code>Frama_C_precise_sin()</code> and <code>Frama_C_precise_cos()</code> from <a href="/index.php?post/2011/09/12/better">last post</a> I stumbled on some interesting floating-point results. The sensationalistic title blames Linux but I didn't fully investigate the problem yet and it could be somewhere else.</p> -<p>If you have the Frama-C sources lying around you might be able to reproduce it as below. Otherwise just read on; it is rather obvious what is wrong even for a floating-point issue.</p> -<pre>$ make bin/toplevel.top -... -$ bin/toplevel.top - Objective Caml version 3.12.1 -# open Ival ;; -# set_round_upward () ;; -- : unit = () -# sin (-3.0) ;; -- : float = -2.75991758268585219 -# set_round_nearest_even () ;; -- : unit = () -# sin (-3.0) ;; -- : float = -0.141120008059867214 -</pre> -<p><code>2.76</code> is a large amplitude for the sine of any angle and <code>3.0</code> isn't even unreasonable as an argument to pass to trigonometric functions. Trigonometric functions on my other OS work from OCaml in all rounding modes. On this Linux computer the result is reasonable in the default nearest-even mode. This all rather points to an issue in libraries rather than OCaml itself.</p> <p>If even desktop computers and servers provide this kind of third-rate trigonometric functions what should we assume about embedded code?</p> {% endraw %} diff --git a/_posts/2011-09-15-Big-round-number.html b/_posts/2011-09-15-Big-round-number.html index c07f266441490e61acb833e4750414afd7fc3fb0..df096020f4c7f7b30542859e66397b4a7545534b 100644 --- a/_posts/2011-09-15-Big-round-number.html +++ b/_posts/2011-09-15-Big-round-number.html @@ -8,5 +8,5 @@ title: "Big round number" summary: --- {% raw %} -<p>The last post was the 64th in this blog. I just thought you should know that.</p> <p>The last post was the 64th in this blog. I just thought you should know that.</p> +<p>The last post was the 64th in this blog. I just thought you should know that.</p> {% endraw %} diff --git a/_posts/2011-09-16-Safe-donut.html b/_posts/2011-09-16-Safe-donut.html index 4674c8ba11107691f3611e7c5e17afddd5253e09..2bf8a880efb53e36dc083be1f79d23de4dade96f 100644 --- a/_posts/2011-09-16-Safe-donut.html +++ b/_posts/2011-09-16-Safe-donut.html @@ -208,206 +208,5 @@ t_pr1.c.aa.c:15:[value] Function compute: postcondition got status valid. <p>I have already provided the "the function being analyzed is safe after all" conclusion in the previous post. This post is only for showing the "how" so that you can judge for yourself for instance how much cheating there was. There was quite a bit of C code written for the purpose of the verification: this code could itself have bugs. And there was a good amount of logs processing with shell scripts. There could be bugs there too. Stéphane Duprat would however point out that if we had done the verification with tests there would have been <a href="http://lists.gforge.inria.fr/pipermail/frama-c-discuss/2011-February/002461.html">testing code and logs-processing-scripts too</a>. The difference between the two approaches is that we used <code>Frama_C_float_interval()</code> in the places where we might have used a random number generator. It does not feel like a large conceptual leap and we obtained deeper properties in exchange (would you trust the function not to return <code>12</code> if like me you didn't understand what it computes at all and had only tested it a million times? A billion times? How many tests would be enough for you to <a href="http://blog.regehr.org/archives/364">sit under a piano</a>?)</p> <p>The possibility that variable <code>N</code> in function <code>compute()</code> held a number larger than 11 was related to the <a href="/index.php?post/2011/08/07/.%2C-%7E%3A%3B%21%2A%24%40%5BN0N%3A0%5D">last and most difficult of a series of alarms</a> that we found in a <a href="/donut/value/2011/07/22/Animated-donut-verification">mostly unmodified piece of obfuscated C code</a>. Some of the <a href="/index.php?post/2011/08/01/Animated-donut">other alarms</a> disappeared simply by playing with the <code>-slevel</code> setting which is the setting to think of immediately when the analysis is fast enough and some alarms remain. I explained where the other alarms came from (a call to <code>memset()</code> was not handled precisely enough etc.) but in actual use you don't need to: just increase the argument to <code>-slevel</code> and see if the alarms go away even before starting to think.</p> <p>The method I have shown here is a little bit laborious but one reason for us Frama-C developers to do these case studies is to find out about possible uses and make them more comfortable in future releases. This series of posts shows how to do this kind of verification now (well... it describes how to do them soon; the method shown will work with the Nitrogen release). This is absolutely not definitive. A plug-in could automate a lot of what we have done by hand here.</p> -<p>This post was improved by insights from Florent Kirchner.</p> - <p>This post documents the steps I followed in order to finish verifying function <code>compute()</code>, picking up from <a href="/donut/facetious-colleagues/floating-point/value/value-builtins/2011/09/17/Probably-safe-donut">there</a>.</p> -<h2>Previously on this blog</h2> -<p>In last episode we had found that some sub-cubes in the search space appeared to lead to dangerous value sets for variable <code>N</code>. These sets were:</p> -<pre> N ∈ {10; 11; 12} - N ∈ {6; 7; 8; 9; 10; 11; 12} - N ∈ {7; 8; 9; 10; 11; 12} - N ∈ {7; 8; 9; 10; 11; 12; 13} - N ∈ {8; 9; 10; 11; 12} - N ∈ {8; 9; 10; 11; 12; 13} - N ∈ {9; 10; 11; 12} - N ∈ {9; 10; 11; 12; 13} -</pre> -<p>There are only eight dangerous value sets for <code>N</code> but these correspond to many values of input variables <code>An Bn in jn</code> in the <a href="/assets/img/blog/imported-posts/an.c">analysis context</a> we wrote for the occasion. -Grepping for each of these eight lines in the original logs allows to get the corresponding values of <code>An Bn in jn</code>. These are the values for which we haven't concluded yet that <code>compute()</code> is safe:</p> -<pre>for i in 1 2 3 4 -do - for line in \ - "N ∈ {10; 11; 12}" \ - "N ∈ {6; 7; 8; 9; 10; 11; 12}" \ - "N ∈ {7; 8; 9; 10; 11; 12}" \ - "N ∈ {7; 8; 9; 10; 11; 12; 13}" \ - "N ∈ {8; 9; 10; 11; 12}" \ - "N ∈ {8; 9; 10; 11; 12; 13}" \ - "N ∈ {9; 10; 11; 12}" \ - "N ∈ {9; 10; 11; 12; 13}" - do - grep "$line" log$i -A4 -B0 | grep -v "N " - echo -- - done > pb$i -done -</pre> -<p>The results are well distributed among the four quarters of the search space that I initially chose arbitrarily. That's good news as it means things can be kept parallel by keeping these files separate. One file looks like:</p> -<pre> An ∈ {-26} - Bn ∈ {-15} - in ∈ {-26} - jn ∈ {18} --- - An ∈ {-26} - Bn ∈ {-15} - in ∈ {-26} - jn ∈ {19} --- - An ∈ {-26} - Bn ∈ {-15} - in ∈ {-3} - jn ∈ {6} --- -... -</pre> -<h2>How to re-analyze the problematic subcubes more precisely</h2> -<p>Each file pb1 ... pb4 can be processed a little bit further to look like C code:</p> -<pre>for i in 1 2 3 4 -do - sed -e s"/--/f();/" -e s"/∈ {/= /" -e s"/}/;/" < pb$i > pr$i.c -done -</pre> -<p>The above commands transform the interesting values files into:</p> -<pre> An = -26; - Bn = -15; - in = -26; - jn = 18; -f(); - An = -26; - Bn = -15; - in = -26; - jn = 19; -f(); - An = -26; - Bn = -15; - in = -3; - jn = 6; -f(); -... -</pre> -<p>Each of the four pieces of program weights in at a bit less than 7 MB of C code. I plan to make good use of this information tidbit the next time someone asks me <a href="/index.php?post/2011/07/16/Formal-verification-and-SLOC">what project sizes Frama-C's value analysis can handle</a>.</p> -<pre>$ ls -l pr?.c --rw-r--r-- 1 cuoq cuoq 6788869 2011-09-17 18:52 pr1.c --rw-r--r-- 1 cuoq cuoq 6551620 2011-09-17 18:52 pr2.c --rw-r--r-- 1 cuoq cuoq 6655238 2011-09-17 18:52 pr3.c --rw-r--r-- 1 cuoq cuoq 6486765 2011-09-17 18:52 pr4.c -</pre> -<p>The files pr1.c ... pr4.c are not complete C programs but they work well with the following prolog (<a href="/assets/img/blog/imported-posts/prolog.c">download</a>):</p> -<pre>... -int An Bn in jn; -void f(void) -{ - int Ans Bns ins jns; - float A B i j; - for (Ans=4*An; Ans<4*(An+1); Ans++) - { - A = Frama_C_float_interval(Ans / 32. (Ans + 1) / 32.); - for (Bns=4*Bn; Bns<4*(Bn+1); Bns++) - { - B = Frama_C_float_interval(Bns / 32. (Bns + 1) / 32.); - for (ins=4*in; ins<4*(in+1); ins++) - { - i = Frama_C_float_interval(ins / 32. (ins + 1) / 32.); - for (jns=4*jn; jns<4*(jn+1); jns++) - { - j = Frama_C_float_interval(jns / 32. (jns + 1) / 32.); - compute(A B i j); - } - } - } - } -} -main(){ -</pre> -<p>A closing bracket <code>}</code> is also needed to make the whole thing a syntactically correct C program.</p> -<p>Alas a regrettable performance bug in Frama-C's front end prevents from analyzing such huge generated C functions. We are a bit too close to the Nitrogen release to change data structures for representing the AST so this bug will probably remain for at least one release cycle. To circumvent the issue I simply split the files into 182 reasonably-sized chunks (reasonably-sized here meaning 10000 lines a more usual size for a function).</p> -<pre>split -l 10000 pr1.c pr1.c. -</pre> -<p>182 C files to analyze and 4 cores to analyze them with: this is an undreamed-of opportunity to make use of the <code>xargs -n 1 -P 4</code> command.</p> -<pre>ls pr?.c.* | xargs -n 1 -P 4 ./do.sh -</pre> -<p>Here is the script <code>do.sh</code> for handling one program. It first catenates the prolog -the chunk and a closing bracket and then it launches the value analysis on the -resulting C program:</p> -<pre>#!/bin/sh -( cat prolog.c ; cat $1 ; echo "}" ) > t_$1.c -frama-c -val share/builtin.c t_$1.c -obviously-terminates \ - -no-val-show-progress -all-rounding-modes > log_pass2_$1 2>&1 -</pre> -<h2>Results</h2> -<p>The above yada yada yada produces one log file for each of the 182 chunks:</p> -<pre>$ ls -l log_pass2_pr* --rw-r--r-- 1 cuoq cuoq 500913957 2011-09-17 20:50 log_pass2_pr1.c.aa --rw-r--r-- 1 cuoq cuoq 502329593 2011-09-17 20:49 log_pass2_pr1.c.ab --rw-r--r-- 1 cuoq cuoq 503146982 2011-09-17 20:51 log_pass2_pr1.c.ac -... --rw-r--r-- 1 cuoq cuoq 502560543 2011-09-18 01:22 log_pass2_pr1.c.ay --rw-r--r-- 1 cuoq cuoq 502283181 2011-09-18 01:23 log_pass2_pr1.c.az --rw-r--r-- 1 cuoq cuoq 503974409 2011-09-18 01:30 log_pass2_pr1.c.ba --rw-r--r-- 1 cuoq cuoq 501308298 2011-09-18 01:29 log_pass2_pr1.c.bb -... --rw-r--r-- 1 cuoq cuoq 502932885 2011-09-18 05:20 log_pass2_pr1.c.bs --rw-r--r-- 1 cuoq cuoq 422006804 2011-09-18 05:03 log_pass2_pr1.c.bt --rw-r--r-- 1 cuoq cuoq 502353901 2011-09-18 05:19 log_pass2_pr2.c.aa --rw-r--r-- 1 cuoq cuoq 502485241 2011-09-18 05:23 log_pass2_pr2.c.ab --rw-r--r-- 1 cuoq cuoq 503562848 2011-09-18 05:57 log_pass2_pr2.c.ac -... --rw-r--r-- 1 cuoq cuoq 184986900 2011-09-18 12:28 log_pass2_pr2.c.bs --rw-r--r-- 1 cuoq cuoq 498627515 2011-09-18 13:11 log_pass2_pr3.c.aa -... --rw-r--r-- 1 cuoq cuoq 263096852 2011-09-19 05:27 log_pass2_pr4.c.bs -</pre> -<p>Incidentally it appears from the above listing that the second -pass took about 36 hours (two nights and one day). -The inside of one log file looks like:</p> -<pre>[value] DUMPING STATE of file t_pr1.c.aa.c line 24 -... - N ∈ {10; 11} - An ∈ {-26} - Bn ∈ {-15} - in ∈ {-26} - jn ∈ {18} - Ans ∈ {-104} - Bns ∈ {-60} - ins ∈ {-104} - jns ∈ {72} - A ∈ [-3.25 .. -3.21875] - B ∈ [-1.875 .. -1.84375] - i ∈ [-3.25 .. -3.21875] - j ∈ [2.25 .. 2.28125] - =END OF DUMP== -t_pr1.c.aa.c:15:[value] Function compute: postcondition got status valid. -[value] DUMPING STATE of file t_pr1.c.aa.c line 24 -... - N ∈ {10; 11} - An ∈ {-26} - Bn ∈ {-15} - in ∈ {-26} - jn ∈ {18} - Ans ∈ {-104} - Bns ∈ {-60} - ins ∈ {-104} - jns ∈ {73} - A ∈ [-3.25 .. -3.21875] - B ∈ [-1.875 .. -1.84375] - i ∈ [-3.25 .. -3.21875] - j ∈ [2.28125 .. 2.3125] - =END OF DUMP== -... -</pre> -<p>Each value set for variable <code>N</code> is computed more precisely than in the first pass because the values for floating-point variables <code>A B i j</code> are known more precisely. Above <code>N</code> is determined to be either 10 or 11 (both safe values) for two of the subsubcubes under examination. Below is the complete list of sets of values computed for <code>N</code>:</p> -<pre>$ for i in log_pass2_pr* ; do grep "N " $i | sort -u ; done | sort -u - N ∈ {10} - N ∈ {10; 11} - N ∈ {11} - N ∈ {7; 8; 9} - N ∈ {8; 9} - N ∈ {8; 9; 10} - N ∈ {9} - N ∈ {9; 10} - N ∈ {9; 10; 11} -</pre> -<h2>Conclusion</h2> -<p>I have already provided the "the function being analyzed is safe after all" conclusion in the previous post. This post is only for showing the "how" so that you can judge for yourself for instance how much cheating there was. There was quite a bit of C code written for the purpose of the verification: this code could itself have bugs. And there was a good amount of logs processing with shell scripts. There could be bugs there too. Stéphane Duprat would however point out that if we had done the verification with tests there would have been <a href="http://lists.gforge.inria.fr/pipermail/frama-c-discuss/2011-February/002461.html">testing code and logs-processing-scripts too</a>. The difference between the two approaches is that we used <code>Frama_C_float_interval()</code> in the places where we might have used a random number generator. It does not feel like a large conceptual leap and we obtained deeper properties in exchange (would you trust the function not to return <code>12</code> if like me you didn't understand what it computes at all and had only tested it a million times? A billion times? How many tests would be enough for you to <a href="http://blog.regehr.org/archives/364">sit under a piano</a>?)</p> -<p>The possibility that variable <code>N</code> in function <code>compute()</code> held a number larger than 11 was related to the <a href="/index.php?post/2011/08/07/.%2C-%7E%3A%3B%21%2A%24%40%5BN0N%3A0%5D">last and most difficult of a series of alarms</a> that we found in a <a href="/donut/value/2011/07/22/Animated-donut-verification">mostly unmodified piece of obfuscated C code</a>. Some of the <a href="/index.php?post/2011/08/01/Animated-donut">other alarms</a> disappeared simply by playing with the <code>-slevel</code> setting which is the setting to think of immediately when the analysis is fast enough and some alarms remain. I explained where the other alarms came from (a call to <code>memset()</code> was not handled precisely enough etc.) but in actual use you don't need to: just increase the argument to <code>-slevel</code> and see if the alarms go away even before starting to think.</p> -<p>The method I have shown here is a little bit laborious but one reason for us Frama-C developers to do these case studies is to find out about possible uses and make them more comfortable in future releases. This series of posts shows how to do this kind of verification now (well... it describes how to do them soon; the method shown will work with the Nitrogen release). This is absolutely not definitive. A plug-in could automate a lot of what we have done by hand here.</p> <p>This post was improved by insights from Florent Kirchner.</p> {% endraw %} diff --git a/_posts/2011-09-16-Trail.html b/_posts/2011-09-16-Trail.html index 8f4674b44e730d9afa3caa0cfb2b713552582ab2..3fb8938057208e5125a7c05afcac48a8fd4628bc 100644 --- a/_posts/2011-09-16-Trail.html +++ b/_posts/2011-09-16-Trail.html @@ -9,5 +9,4 @@ summary: --- {% raw %} <p>As I write these words, Virgile Prevosto, one of the dozen Frama-C developers, has been running 320km (starting last Sunday at 10am CET). He has about 12km left before he finishes the <a href="http://lnx.vdatrailers.it/cronometraggio_2011_tdg/dettaglio_pettorale.php?Pettorale=459&GARA=1">"Tor des Géants" endurance trail</a>. That's TWO HUNDRED FULL-FLEDGED MILES in imperial units and I write this with the confidence of someone that Virgile shouldn't be able to censor at least for the next few hours. The topographic profile looks pretty cool too.</p> - <p>As I write these words, Virgile Prevosto, one of the dozen Frama-C developers, has been running 320km (starting last Sunday at 10am CET). He has about 12km left before he finishes the <a href="http://lnx.vdatrailers.it/cronometraggio_2011_tdg/dettaglio_pettorale.php?Pettorale=459&GARA=1">"Tor des Géants" endurance trail</a>. That's TWO HUNDRED FULL-FLEDGED MILES in imperial units and I write this with the confidence of someone that Virgile shouldn't be able to censor at least for the next few hours. The topographic profile looks pretty cool too.</p> {% endraw %} diff --git a/_posts/2011-09-17-Probably-safe-donut.html b/_posts/2011-09-17-Probably-safe-donut.html index 85d6160835bfa8da4af9539a4246cecb61b837e4..74992fff1bfd5a6a4ef372761181f08eb7b83645 100644 --- a/_posts/2011-09-17-Probably-safe-donut.html +++ b/_posts/2011-09-17-Probably-safe-donut.html @@ -290,288 +290,5 @@ an1.c:15:[value] Function compute: postcondition got status unknown. <pre>$ cat log? | grep "N " | grep " 12" | wc -l 360684 </pre> -<p>We are 95% there. The remaining 5% shouldn't take more than another 95% of the time.</p> - <h2>Introduction</h2> -<p>In the <a href="/donut/value/2011/07/22/Animated-donut-verification">first post</a> in the obfuscated animated donut series my colleague Anne pointed out that:</p> -<blockquote><p>The alarm about : assert \valid(". -~:;=!*#$@"+tmp_7); seems strange because the analysis tells us that tmp_7 ∈ <code>[0..40]</code> at this point... How can this be valid ?</p> -</blockquote> -<p>It is only safe to use an offset between 0 and 11 when accessing inside the quantization string <code>". -~:;=!*#$@"</code>. The value analysis determined that the offset was certainly between 0 and 40 so the analyzer can't be sure that the memory access is safe and emits an alarm. -Of course <code>[0..40]</code> is only a conservative approximation for the value of the offset at that point. This approximation is computed with model functions <code>sin()</code> and <code>cos()</code> only known to return values in <code>[-1.0 .. 1.0]</code>. These model functions completely lose the relation between the sine and the cosine of a same angle. The computation we are interested in is more clearly seen in the function below which was extracted <a href="/index.php?post/2011/08/07/.%2C-%7E%3A%3B%21%2A%24%40%5BN0N%3A0%5D">using</a> Frama-C's slicing plug-in.</p> -<pre>/*@ ensures 0 <= \esult <= 11 ; */ -int compute(float A float B float i float j) -{ - float c=sin(i) l=cos(i); - float d=cos(j) f=sin(j); - float g=cos(A) e=sin(A); - float m=cos(B) n=sin(B); - int N=8*((f*e-c*d*g)*m-c*d*e-f*g-l*d*n); - return N>0?N:0; -} -</pre> -<p>Both the sine and the cosine of each argument are computed and eventually used in the same formula. Surely the analyzer would do better if it could just remember that sin(x)²+cos(x)²=1. Alas it doesn't. It just knows that each is in <code>[-1.0 .. 1.0]</code>.</p> -<h2>Making progress</h2> -<p>But the Nitrogen release will have <a href="/index.php?post/2011/09/12/better">more precise</a> <code>sin()</code> and <code>cos()</code> modelizations! Focusing only on the sub-computation we are interested in we can split the variation domains for arguments <code>A B i j</code> of function <code>compute()</code> until it is clear whether or not <code>N</code> may be larger than 11.</p> -<p>I suggest to use the program below (<a href="/assets/img/blog/imported-posts/an.c">download</a>) where the code around <code>compute()</code> creates the right analysis context. Just like in unit testing there are stubs and witnesses in addition to the function under test.</p> -<pre>... -/*@ ensures 0 <= \esult <= 11 ; */ -int compute(float A float B float i float j) -{ - float c=sin(i) l=cos(i); - float d=cos(j) f=sin(j); - float g=cos(A) e=sin(A); - float m=cos(B) n=sin(B); - int N=8*((f*e-c*d*g)*m-c*d*e-f*g-l*d*n); -Frama_C_dump_each(); - return N>0?N:0; -} -main(){ - int An Bn in jn; - float A B i j; - for (An=-26; An<26; An++) - { - A = Frama_C_float_interval(An / 8. (An + 1) / 8.); - for (Bn=-26; Bn<26; Bn++) - { - B = Frama_C_float_interval(Bn / 8. (Bn + 1) / 8.); - for (in=-26; in<26; in++) - { - i = Frama_C_float_interval(in / 8. (in + 1) / 8.); - for (jn=-26; jn<26; jn++) - { - j = Frama_C_float_interval(jn / 8. (jn + 1) / 8.); - compute(A B i j); - } - } - } - } -} -</pre> -<p>Each <code>for</code> loop only covers the range <code>[-3.25 .. 3.25]</code>. In the real program <code>A</code> and <code>B</code> vary in much wider intervals. If target functions <code>sin()</code> and <code>cos()</code> use a decent argument reduction algorithm (and incidentally <strong>use the same one</strong>) the conclusions obtained for <code>[-3.25 .. 3.25]</code> should generalize to all finite floating-point numbers. This is really a property of the target platform that we cannot do anything about at this level other than clearly state that we are assuming it.</p> -<p>In fact the programs I analyzed were not exactly like above: this task is trivial to run in parallel so I split the search space in four and ran four analyzers at the same time:</p> -<pre>$ for i in 1 2 3 4 ; do ( time bin/toplevel.opt -val share/builtin.c \ -an$i.c -obviously-terminates -no-val-show-progress \ --all-rounding-modes ) > log$i 2>&1 & disown %1 ; done -</pre> -<p>After a bit less than two hours (YMMV) I got files log1 ... log4 that contained snapshots of the memory state just after variable <code>N</code> had been computed:</p> -<pre>[value] DUMPING STATE of file an1.c line 24 -... - c ∈ [-0.016591893509 .. 0.108195140958] - l ∈ [-1. .. -0.994129657745] - d ∈ [-1. .. -0.994129657745] - f ∈ [-0.016591893509 .. 0.108195140958] - g ∈ [-1. .. -0.994129657745] - e ∈ [-0.016591893509 .. 0.108195140958] - m ∈ [-1. .. -0.994129657745] - n ∈ [-0.016591893509 .. 0.108195140958] - N ∈ {-1; 0; 1} - An ∈ {-26} - Bn ∈ {-26} - in ∈ {-26} - jn ∈ {-26} - A ∈ [-3.25 .. -3.125] - B ∈ [-3.25 .. -3.125] - i ∈ [-3.25 .. -3.125] - j ∈ [-3.25 .. -3.125] - =END OF DUMP== -an1.c:15:[value] Function compute: postcondition got status valid. -[value] DUMPING STATE of file an1.c line 24 -... - c ∈ [-0.016591893509 .. 0.108195140958] - l ∈ [-1. .. -0.994129657745] - d ∈ [-0.999862372875 .. -0.989992439747] - f ∈ [-0.141120016575 .. -0.0165918916464] - g ∈ [-1. .. -0.994129657745] - e ∈ [-0.016591893509 .. 0.108195140958] - m ∈ [-1. .. -0.994129657745] - n ∈ [-0.016591893509 .. 0.108195140958] - N ∈ {-2; -1; 0; 1} - An ∈ {-26} - Bn ∈ {-26} - in ∈ {-26} - jn ∈ {-25} - A ∈ [-3.25 .. -3.125] - B ∈ [-3.25 .. -3.125] - i ∈ [-3.25 .. -3.125] - j ∈ [-3.125 .. -3.] - =END OF DUMP== -[value] DUMPING STATE of file an1.c line 24 -... -</pre> -<p>Some input sub-intervals for <code>A B i j</code> make the analyzer uncertain about the post-condition <code>N ≤ 11</code>. Here are the first such inputs obtained by searching for "unknown" in the log:</p> -<pre>... -[value] DUMPING STATE of file an1.c line 24 - ... - c ∈ [-0.850319802761 .. -0.778073191643] - l ∈ [-0.628173649311 .. -0.526266276836] - d ∈ [0.731688857079 .. 0.810963153839] - f ∈ [0.585097253323 .. 0.681638777256] - g ∈ [-1. .. -0.994129657745] - e ∈ [-0.016591893509 .. 0.108195140958] - m ∈ [-1. .. -0.994129657745] - n ∈ [-0.016591893509 .. 0.108195140958] - N ∈ {8; 9; 10; 11; 12} - An ∈ {-26} - Bn ∈ {-26} - in ∈ {-18} - jn ∈ {5} - A ∈ [-3.25 .. -3.125] - B ∈ [-3.25 .. -3.125] - i ∈ [-2.25 .. -2.125] - j ∈ [0.625 .. 0.75] - =END OF DUMP== -an1.c:15:[value] Function compute: postcondition got status unknown. -... -</pre> -<p>Here is the complete list of value sets obtained for variable <code>N</code> on the entire search space:</p> -<pre>$ cat log? | grep "N " | sort | uniq - N ∈ {0; 1} - N ∈ {0; 1; 2} - N ∈ {0; 1; 2; 3} - N ∈ {0; 1; 2; 3; 4} - N ∈ {0; 1; 2; 3; 4; 5} - N ∈ {0; 1; 2; 3; 4; 5; 6} - N ∈ {-1; 0} - N ∈ {-1; 0; 1} - N ∈ {10; 11} - N ∈ {10; 11; 12} - N ∈ {-1; 0; 1; 2} - N ∈ {-1; 0; 1; 2; 3} - N ∈ {-1; 0; 1; 2; 3; 4} - N ∈ {-10; -9} - N ∈ {-10; -9; -8} - N ∈ {-10; -9; -8; -7} - N ∈ {-10; -9; -8; -7; -6} - N ∈ {-10; -9; -8; -7; -6; -5} - N ∈ {-10; -9; -8; -7; -6; -5; -4} - N ∈ {-11; -10} - N ∈ {-11; -10; -9} - N ∈ {-11; -10; -9; -8} - N ∈ {-11; -10; -9; -8; -7} - N ∈ {-11; -10; -9; -8; -7; -6} - N ∈ {-11; -10; -9; -8; -7; -6; -5} - N ∈ {1; 2} - N ∈ {-12; -11; -10} - N ∈ {-12; -11; -10; -9} - N ∈ {-12; -11; -10; -9; -8} - N ∈ {-12; -11; -10; -9; -8; -7} - N ∈ {-12; -11; -10; -9; -8; -7; -6} - N ∈ {1; 2; 3} - N ∈ {1; 2; 3; 4} - N ∈ {1; 2; 3; 4; 5} - N ∈ {1; 2; 3; 4; 5; 6} - N ∈ {1; 2; 3; 4; 5; 6; 7} - N ∈ {-13; -12; -11; -10; -9} - N ∈ {-13; -12; -11; -10; -9; -8} - N ∈ {-13; -12; -11; -10; -9; -8; -7} - N ∈ {-2; -1} - N ∈ {-2; -1; 0} - N ∈ {-2; -1; 0; 1} - N ∈ {-2; -1; 0; 1; 2} - N ∈ {-2; -1; 0; 1; 2; 3} - N ∈ {2; 3} - N ∈ {2; 3; 4} - N ∈ {2; 3; 4; 5} - N ∈ {2; 3; 4; 5; 6} - N ∈ {2; 3; 4; 5; 6; 7} - N ∈ {2; 3; 4; 5; 6; 7; 8} - N ∈ {-3; -2} - N ∈ {-3; -2; -1} - N ∈ {-3; -2; -1; 0} - N ∈ {-3; -2; -1; 0; 1} - N ∈ {-3; -2; -1; 0; 1; 2} - N ∈ {3; 4} - N ∈ {3; 4; 5} - N ∈ {3; 4; 5; 6} - N ∈ {3; 4; 5; 6; 7} - N ∈ {3; 4; 5; 6; 7; 8} - N ∈ {3; 4; 5; 6; 7; 8; 9} - N ∈ {-4; -3} - N ∈ {-4; -3; -2} - N ∈ {-4; -3; -2; -1} - N ∈ {-4; -3; -2; -1; 0} - N ∈ {-4; -3; -2; -1; 0; 1} - N ∈ {4; 5} - N ∈ {4; 5; 6} - N ∈ {4; 5; 6; 7} - N ∈ {4; 5; 6; 7; 8} - N ∈ {4; 5; 6; 7; 8; 9} - N ∈ {4; 5; 6; 7; 8; 9; 10} - N ∈ {-5; -4} - N ∈ {-5; -4; -3} - N ∈ {-5; -4; -3; -2} - N ∈ {-5; -4; -3; -2; -1} - N ∈ {-5; -4; -3; -2; -1; 0} - N ∈ {5; 6} - N ∈ {5; 6; 7} - N ∈ {5; 6; 7; 8} - N ∈ {5; 6; 7; 8; 9} - N ∈ {5; 6; 7; 8; 9; 10} - N ∈ {5; 6; 7; 8; 9; 10; 11} - N ∈ {-6; -5} - N ∈ {-6; -5; -4} - N ∈ {-6; -5; -4; -3} - N ∈ {-6; -5; -4; -3; -2} - N ∈ {-6; -5; -4; -3; -2; -1} - N ∈ {-6; -5; -4; -3; -2; -1; 0} - N ∈ {6; 7} - N ∈ {6; 7; 8} - N ∈ {6; 7; 8; 9} - N ∈ {6; 7; 8; 9; 10} - N ∈ {6; 7; 8; 9; 10; 11} - N ∈ {6; 7; 8; 9; 10; 11; 12} - N ∈ {-7} - N ∈ {7} - N ∈ {-7; -6} - N ∈ {-7; -6; -5} - N ∈ {-7; -6; -5; -4} - N ∈ {-7; -6; -5; -4; -3} - N ∈ {-7; -6; -5; -4; -3; -2} - N ∈ {-7; -6; -5; -4; -3; -2; -1} - N ∈ {7; 8} - N ∈ {7; 8; 9} - N ∈ {7; 8; 9; 10} - N ∈ {7; 8; 9; 10; 11} - N ∈ {7; 8; 9; 10; 11; 12} - N ∈ {7; 8; 9; 10; 11; 12; 13} - N ∈ {-8; -7} - N ∈ {-8; -7; -6} - N ∈ {-8; -7; -6; -5} - N ∈ {-8; -7; -6; -5; -4} - N ∈ {-8; -7; -6; -5; -4; -3} - N ∈ {-8; -7; -6; -5; -4; -3; -2} - N ∈ {8; 9} - N ∈ {8; 9; 10} - N ∈ {8; 9; 10; 11} - N ∈ {8; 9; 10; 11; 12} - N ∈ {8; 9; 10; 11; 12; 13} - N ∈ {9; 10} - N ∈ {9; 10; 11} - N ∈ {9; 10; 11; 12} - N ∈ {9; 10; 11; 12; 13} - N ∈ {-9; -8} - N ∈ {-9; -8; -7} - N ∈ {-9; -8; -7; -6} - N ∈ {-9; -8; -7; -6; -5} - N ∈ {-9; -8; -7; -6; -5; -4} - N ∈ {-9; -8; -7; -6; -5; -4; -3} -</pre> -<p>The above is pretty cute and it is just short enough for manual inspection. The inspection reveals that all the lines with dangerous values for <code>N</code> contain the number <code>12</code> so that we can grep for that. We arrive at the following list of dangerous value sets for <code>N</code>:</p> -<pre> N ∈ {10; 11; 12} - N ∈ {6; 7; 8; 9; 10; 11; 12} - N ∈ {7; 8; 9; 10; 11; 12} - N ∈ {7; 8; 9; 10; 11; 12; 13} - N ∈ {8; 9; 10; 11; 12} - N ∈ {8; 9; 10; 11; 12; 13} - N ∈ {9; 10; 11; 12} - N ∈ {9; 10; 11; 12; 13} -</pre> -<blockquote><p>Note: it is normal that each dangerous line contains <code>12</code>: if the safety property that we are trying to establish is true then there must be a safe value (say <code>10</code>) in each set. And the sets contain several values as the result of approximations in interval arithmetics so that sets of values for <code>N</code> are intervals of integers. Any interval that contains both a safe value and an unsafe value must contain the largest safe value <code>11</code> and the smallest unsafe value <code>12</code>.</p> -</blockquote> -<h2>Conclusion</h2> -<p>We have improved our estimate of the maximum value of <code>N</code> from 40 to 13. That's pretty good although it is not quite enough to conclude that the donut program is safe.</p> -<p>In conclusion to this post now that we have ascertained that a dangerous set for <code>N</code> was a set that contains 12 we can compute the ratio of the search space for which we haven't yet established that the program was safe. We are exploring a dimension-4 cube by dividing it in sub-cubes. There are 52â´ = 7 311 616 sub-cubes. Of these this many are still not known to be safe:</p> -<pre>$ cat log? | grep "N " | grep " 12" | wc -l -360684 -</pre> <p>We are 95% there. The remaining 5% shouldn't take more than another 95% of the time.</p> {% endraw %} diff --git a/_posts/2011-09-19-Penultimate-donut-post-the-function-compute-is-safe.html b/_posts/2011-09-19-Penultimate-donut-post-the-function-compute-is-safe.html index ddfea7c68c8aa9c20a7d46b182b83694c1eb8544..d9421635ccc4b1905f5a299ef12677815bd53734 100644 --- a/_posts/2011-09-19-Penultimate-donut-post-the-function-compute-is-safe.html +++ b/_posts/2011-09-19-Penultimate-donut-post-the-function-compute-is-safe.html @@ -17,15 +17,5 @@ As pointed out by my colleague Benjamin Monate you can make <code>sort</code>'s <h2>Update on the donut verification</h2> <p>The computations for the remaining difficult 5% of the search space are now finished. I was hoping not to have to do a third pass so I split each side of the examined subcube in 4. In other words I divided each subcube in 4â´ or 256 subsubcubes. A little birdie told me that splitting each side in two wouldn't be sufficient. That birdie had been wrong before but this time it was absolutely sure— it got the tip straight from the subcube's mouth.</p> <p>I have kept the entire logs for this second pass since I didn't know yet whether I would need the additional information they contain. I would have needed them if a third pass had been necessary but it won't be. It is now official: function <code>compute()</code> is safe for all arguments between -3.25 and 3.25.</p> -<p>Now I must write the concluding post quickly because the full logs are taking 85GB on our computations server.</p> - <h2>Do two jobs, and do them well</h2> -<p>In the previous post, I used the command:</p> -<pre>$ cat log? | grep \N " | sort | uniq -</pre> -<p>This may be an inefficient way to get a list of unique lines containing "N ". The command <code>sort</code> does not know that it is sending its results to <code>uniq</code> so it has to keep all duplicates in memory or at least keep a count for each of them. -As pointed out by my colleague Benjamin Monate you can make <code>sort</code>'s job easier by telling it directly that you are only interested in unique lines. The option is <code>sort -u</code>. This can only make <code>sort</code>'s job simpler even if it has an optimization for dealing with duplicate lines efficiently.</p> -<h2>Update on the donut verification</h2> -<p>The computations for the remaining difficult 5% of the search space are now finished. I was hoping not to have to do a third pass so I split each side of the examined subcube in 4. In other words I divided each subcube in 4â´ or 256 subsubcubes. A little birdie told me that splitting each side in two wouldn't be sufficient. That birdie had been wrong before but this time it was absolutely sure— it got the tip straight from the subcube's mouth.</p> -<p>I have kept the entire logs for this second pass since I didn't know yet whether I would need the additional information they contain. I would have needed them if a third pass had been necessary but it won't be. It is now official: function <code>compute()</code> is safe for all arguments between -3.25 and 3.25.</p> <p>Now I must write the concluding post quickly because the full logs are taking 85GB on our computations server.</p> {% endraw %} diff --git a/_posts/2011-09-26-New-alarm-category.html b/_posts/2011-09-26-New-alarm-category.html index dc683c99ced343a4de119fb8010d681d208d87e1..e28077822027f76f721af8e77177efa0ae41722d 100644 --- a/_posts/2011-09-26-New-alarm-category.html +++ b/_posts/2011-09-26-New-alarm-category.html @@ -58,56 +58,5 @@ assert(separated or same) <p>I first heard about the 6.5.16.1:3 rule from Chucky Ellison and he had himself heard about it from Derek M. Jones. Later the Csmith random program generator generated a program that computed differently when compiled with Clang and when interpreted by the value analysis (and indeed that computed differently with different Clang optimization levels) -all because of this rule. This is technically a bug in (that development version of) Csmith which is supposed to generate defined C programs. But it successfully turned my <a href="/csmith/position/2011/07/30/We-have-a-Csmith-proof-framework">hate of false positives</a> against my laziness and forced me to implement detection for programs that break this rule.</p> - <p>There won't be many changes in the value analysis' documentation in Nitrogen. -For lack of time, the new options, some of which were alluded to in this blog, -will remain in their \to be documented" state. But documenting them more fully -can always be done here too once they are released.</p> -<p>The one big change in the <a href="http://frama-c.com/download/frama-c-value-analysis.pdf">value analysis manual</a> follows. It is a section -describing a new kind of alarm and inserts itself in section 3.2.2 "Log messages emitted by the value analysis — Proof obligations".</p> -<h2>Partially overlapping lvalue assignment</h2> -<p>Vaguely related to but different from undefined side-effects in expressions -the value analysis warns about the following program:</p> -<pre>struct S { int a; int b; int c; }; -struct T { int p; struct S s; }; -union U { struct S s; struct T t; } u; -void copy(struct S *p struct S *q) -{ - *p = *q; -} -int main(int c char **v){ - u.s.b = 1; - copy(&u.t.s &u.s); - return u.t.s.a + u.t.s.b + u.t.s.c; -} -</pre> -<p>The programmer thought ey was invoking implementation-defined behavior -in the above program using an union to type-pun between structs S and T. -Unfortunately this program returns 1 when compiled -with <code>clang -m32</code>; it returns 2 when compiled with <code>clang -m32 -O2</code> -and it returns 0 when compiled with <code>gcc -m32</code>.</p> -<p>For a -program as simple as the above all these compilers are -supposed to implement the same implementation-defined choices. Which -compiler if we may ask such a rhetorical -question is right? They all are because the program is undefined. -When function <code>copy()</code> is called from <code>main()</code> -the assignment <code>*p = *q;</code> breaks -C99's 6.5.16.1:3 rule. This rule states that -in an assignment from lvalue to lvalue -the left and right lvalues must overlap either exactly or not at all.</p> -<p>The program breaking this rule means compilers neither have to emit -warnings (none of the above did) nor produce code that does what the -programmer intended whatever that was. -Launched on the above program the value analysis says:</p> -<pre>... Partially overlapping lvalue assignment "*p=*q;". -Left address in bits: {{ u -> {32} }}. -Right address in bits: {{ u -> {0} }}. -assert(separated or same) -</pre> -<h2>Acknowledgments and moral of the story</h2> -<p>I first heard about the 6.5.16.1:3 rule from Chucky Ellison and he had himself heard about it from Derek M. Jones. -Later the Csmith random program generator generated a program that computed differently when compiled with -Clang and when interpreted by the value analysis (and indeed that computed differently with different Clang optimization levels) all because of this rule. This is technically a bug in (that development version of) Csmith which is supposed to generate defined C programs. But it successfully turned my <a href="/csmith/position/2011/07/30/We-have-a-Csmith-proof-framework">hate of false positives</a> against my laziness and forced me to implement detection for programs that break this rule.</p> {% endraw %} diff --git a/_posts/2011-09-27-About.html b/_posts/2011-09-27-About.html index c66edb7f1d1f397b55c0892d699e84e0531ae81a..0296855d78f170afef5a9535cf7086af38f19ee8 100644 --- a/_posts/2011-09-27-About.html +++ b/_posts/2011-09-27-About.html @@ -16,13 +16,5 @@ Perhaps reassuringly, it is not a new trend : Virgile's first serious post (afte </blockquote> <p>It must have happened to you to stumble on someone's blog (or any sort of episodic writings) to find the initial samples you read so great that you can't stop and after a few hours to overdose from too much of the same "big picture". The last time it happened to me was with <a href="http://prog21.dadgum.com/archives.html">this one</a> (perfectly healthy and recommended in small quantities though). I am also trying to avoid that. Since even people who are obviously much better than me at expressing their thoughts fall into that trap I mean.</p> <blockquote><p>By the same token there won't be any more analysis of numerical programs for a while. I don't care if the program is shaped like an egg and animates a flying swan in ASCII art I am not analyzing it.</p> -</blockquote>" <p>It struck me, writing both the last and the next posts, that I mostly assume that the reader — you — has already read and remembers the gist of previous posts and/or the documentation. I am pretty sure this would be considered a bad habit in some circles. In fact, there must be entire manuals and classes on the topic of avoiding exactly that. -Perhaps reassuringly, it is not a new trend : Virgile's first serious post (after the mandatory \hello world" post) was about arcane loop annotation minutia. My first post was the continuation of a an unfinished tutorial. If you did not unsubscribe after these two you knew what you were in for.</p> -<p>In truth whenever I throw in an opinion or a casual post I am always worried I will diminish the technical value of the entire feed. Perhaps there should be a "norant" tag that all technical posts would have. It is very simple to subscribe to tags (if you are reading this you can figure it out) but to the best of my knowledge it requires client-side work to exclude a tag from one's subscription so that one cannot simply avoid posts tagged "rant" but get the others.</p> -<p>The main reason I have for not providing the larger picture in every post — or indeed in any post — is that I find it boring to repeat myself and the larger picture does not change so quickly. Before this blog existed I would answer questions in the mailing list; it was always the same thing and I was getting really tired of it.</p> -<blockquote><p>We solved the "mailing list questions" problem accidentally when for technical reasons we decided not to distribute a Windows binary version. That took complete care of that.</p> -</blockquote> -<p>It must have happened to you to stumble on someone's blog (or any sort of episodic writings) to find the initial samples you read so great that you can't stop and after a few hours to overdose from too much of the same "big picture". The last time it happened to me was with <a href="http://prog21.dadgum.com/archives.html">this one</a> (perfectly healthy and recommended in small quantities though). I am also trying to avoid that. Since even people who are obviously much better than me at expressing their thoughts fall into that trap I mean.</p> -<blockquote><p>By the same token there won't be any more analysis of numerical programs for a while. I don't care if the program is shaped like an egg and animates a flying swan in ASCII art I am not analyzing it.</p> -</blockquote>" +</blockquote> {% endraw %} diff --git a/_posts/2011-09-27-Summary-of-a-2010-research-article.html b/_posts/2011-09-27-Summary-of-a-2010-research-article.html index 65fbfe45a01adfbc772f7d676cedab71af4c6989..5783046ee54ca491eaf576d6cd7b784f596c3d9b 100644 --- a/_posts/2011-09-27-Summary-of-a-2010-research-article.html +++ b/_posts/2011-09-27-Summary-of-a-2010-research-article.html @@ -51,49 +51,5 @@ The following operation is to build the union of the two memory states. The resu <p><img src="/assets/img/blog/imported-posts/rangemaps/trf.png" alt="trf.png" style="display:block; margin:0 auto;" title="trf.png sept. 2011" /></p> <p>With AVL trees it is normal for the tree to be re-balanced automatically when operated on. But both inclusion and union operations would be much easier if the trees coming from the <code>then</code> branch and the <code>else</code> branch were always balanced identically. If they were both balanced in the same way the initial state was it would be possible to recognize at a glance that the subtree for indices 2 3 4 is the same in the states coming from both branches and to re-use it as a subtree of the result.</p> -<p>Our contribution in the article "A Mergeable Interval Map" is a new kind of binary search tree that uses intervals as keys and that remains balanced through insertions and deletions but with the additional property that trees that have different operations applied to them remain balanced the same way. We call this property "mergeability" and it makes inclusion and union easier to compute. This means that a static analyzer using this representation is faster and consumes less memory than with a less adequate representation.</p> - <p>A number of colleagues and I have been tasked with writing a summary of an article they published in 2010. Each of us has to do this for an article of theirs, that is. I chose the article whose long version title is \A Mergeable Interval Map" (<a href="http://studia.complexica.net/index.php?option=com_content&view=article&id=185%3Aa-mergeable-interval-map%20pp-5-37&catid=56%3Anumber-1&Itemid=100&lang=en">link</a> PDF available in English starting with page number 10). The article describes a data structure to associate values to intervals. I like this data structure because it is uncomplicated and its necessity was made apparent by the implementation of previous ideas. The article on the other hand may not do as good a job as it should of explaining the constraints that led to invent a new data structure. This is an opportunity to try and improve that part.</p> -<p>Without further information concerning the intended audience I decided to assume that the reader is vaguely familiar with the low-level aspects of C (he does not need to be a C programmer). It should also help if he is vaguely familiar with say one modern programming language (Perl Python PHP C# or OCaml).</p> -<h2>A new data structure for static analysis</h2> -<p>When working on an analyzer for low-level embedded C whose selling point is that it automatically and correctly analyzes relatively large programs relatively precisely your analyzer will inevitably encounter a C program that does something like this:</p> -<pre>union U - { char c[4]; - int *p; }; -</pre> -<p>The analyzer does not necessarily have to handle type-punning through the above union very precisely (this for one requires hypotheses on the target platform's endianness and pointer size) but it should handle it correctly (or "soundly" as some prefer saying). If the union is used to manipulate the bytes of a pointer and the pointer is copied somewhere else as a consequence the analyzer should be aware that the member <code>c</code> of the struct from which the program reads overlap with member <code>p</code> through which an address was previously written.</p> -<pre>main(){ - u1.p = &i; - for (i=0; i<4; i++) - u2.c[i] = u1.c[i]; - *u2.p = 7; - return i; -} -</pre> -<p>The program above copies the address of variable <code>i</code> byte by byte from <code>u1</code> to <code>u2</code> and finally uses the copied address to surreptitiously write <code>7</code> into <code>i</code>. -An analyzer may lose track a little of what is happening here and still remain correct. It may say that <code>i</code> may contain any integer at the end of the program (and ask the programmer to make sure that he is accessing a valid address with <code>*u2.p</code>). This is what <code>frama-c -val</code> does. Alternately a correct analyzer may precisely follow what is happening in this program and conclude that the program always returns 7 (this is what <code>frama-c -val -slevel 10</code> does). But a correct analyzer should never say that the program returns 4 since this is not what happens in an actual run.</p> -<p>To return to the initial topic in order to be correct for the above program the value analysis must understand that members <code>c</code> and <code>p</code> of union <code>u1</code> overlap. The way it does this is by representing the memory range reserved for a variable (in this example <code>u1</code> <code>u2</code> or <code>i</code>) as a map from intervals to values. After the first instruction in <code>main()</code> the memory for <code>u1</code> can be represented as a map from interval <code>0..31</code> to <code>{{ &i }}</code> assuming that we use the bit as the basic memory unit and that a pointer occupies 32 bits in memory.</p> -<p>The map is a very useful data structure natively provided in many modern programming languages where it may also be called "dictionary" or "associative array". A map is a collection of bindings between keys and values. Bindings can be added removed and the map can be queried for the value associated to a given key. Typical implementations used in Perl or Python rely on <a href="http://en.wikipedia.org/wiki/Hash_table">hash tables</a> an efficient representation that allows all these operations.</p> -<p>It was not possible to use hash tables for the interval-indexed maps needed by the value analysis and one of the reasons was that the basic set of operations does not include "find the bindings with a key (interval) that intersects the key (interval) I have". Instead we used a <a href="http://en.wikipedia.org/wiki/Binary_search_tree">binary search tree</a> (with intervals as keys). Compared to hash tables binary search trees allow to look in the neighborhood of a key. For instance when the analyzer looks for the interval <code>0..7</code> in the tree that contains a binding for <code>0..31</code> (in the first iteration of the <code>for</code> loop in our example) it does not find it but it finds that the interval <code>0..7</code> is contained in <code>0..31</code> and that therefore the binding <code>0..31 : {{ &i }}</code> is pertinent. This is how the value analysis detects that the address of <code>i</code> that was previously written in memory through <code>u1.p</code> is being copied to <code>u2</code> in the <code>for</code> loop.</p> -<p>One general consideration with binary search trees is that some sort of heuristic is needed to keep them balanced. A balanced tree has the property that at each node the number of bindings on the left-hand side is about the same as the number of bindings on the right-hand side. Looking up keys (intervals) in a binary search tree is fast for all keys only if the tree is balanced. -The initial implementation of the value analysis used AVL trees as provided in OCaml's standard library. AVL trees are <a href="http://en.wikipedia.org/wiki/Self-balancing_binary_search_tree">self-balancing</a>: when the tree changes existing bindings may be moved about as needed to keep lookups efficient.</p> -<p>Implementation and experimentation revealed that there was another desirable property the ideal data structure should have for our use case.</p> -<pre>int t[16]; -... -if (... complex condition...) - t[0] = 3; -else - t[1] = 4; -</pre> -<p>In this new example with AVL trees and their automatic re-balancing operations the map representing <code>t</code> may end up balanced differently when propagated through the "then" and the "else" branches of the program. Say that the initial map is represented as below:</p> -<p><img src="/assets/img/blog/imported-posts/rangemaps/tri.png" alt="tri.png" style="display:block; margin:0 auto;" title="tri.png sept. 2011" /></p> -<p>In the memory state after the "then" branch the contents at index <code>0</code> are updated according to the assignment in that branch:</p> -<p><img src="/assets/img/blog/imported-posts/rangemaps/trat.png" alt="trat.png" style="display:block; margin:0 auto;" title="trat.png sept. 2011" /></p> -<p>In the memory state after the "else" branch the contents at index <code>1</code> are updated. Because of automatic re-balancing operations while this happens the resulting tree may look like:</p> -<p><img src="/assets/img/blog/imported-posts/rangemaps/trae.png" alt="trae.png" style="display:block; margin:0 auto;" title="trae.png sept. 2011" /></p> -<p>Next two very common operations in static analysis happen. The first is checking whether a memory state is included in another so that only one needs to be kept. Here neither state from the "then" and "else" branch contains the other. -The following operation is to build the union of the two memory states. The result may be represented by the tree below.</p> -<p><img src="/assets/img/blog/imported-posts/rangemaps/trf.png" alt="trf.png" style="display:block; margin:0 auto;" title="trf.png sept. 2011" /></p> -<p>With AVL trees it is normal for the tree to be re-balanced automatically when operated on. -But both inclusion and union operations would be much easier if the trees coming from the <code>then</code> branch and the <code>else</code> branch were always balanced identically. If they were both balanced in the same way the initial state was it would be possible to recognize at a glance that the subtree for indices 2 3 4 is the same in the states coming from both branches and to re-use it as a subtree of the result.</p> <p>Our contribution in the article "A Mergeable Interval Map" is a new kind of binary search tree that uses intervals as keys and that remains balanced through insertions and deletions but with the additional property that trees that have different operations applied to them remain balanced the same way. We call this property "mergeability" and it makes inclusion and union easier to compute. This means that a static analyzer using this representation is faster and consumes less memory than with a less adequate representation.</p> {% endraw %} diff --git a/_posts/2011-09-29-Bar-joke.html b/_posts/2011-09-29-Bar-joke.html index d1bb83175e1ef6b6c5a38e40c8d92c4dcc7f2314..cede25efa65e1c09a3f41a70ab463ea86c83884c 100644 --- a/_posts/2011-09-29-Bar-joke.html +++ b/_posts/2011-09-29-Bar-joke.html @@ -14,12 +14,5 @@ summary: <p><q>It has nothing to do with leaks; new GC algorithms reduced fragmentation.</q></p> <p>Well if I may dust off my middle school vocabulary for this occasion duh.</p> <p>Losing memory to fragmentation is a kind of memory leak.</p> -<p>I am not going to complain that punk programmers who reinvent decades old technology get more credit and success they deserve just because what they do looks new. Life is too short. But I do reserve the right to mock someone who implements a garbage collector. That leaks memory because of fragmentation. For whatever new programming language. In the 2010s.</p> - <p>So I walked into a bar, and I said:</p> -<p><q>Ah! Ah! There's a new Firefox, and one item in the release notes is \Drastically improved memory handling for certain use cases". Nice phrase. We'll remember it for when we too fix a memory leak.</q></p> -<p>Someone who knew about Firefox internals and didn't hear the "Ah! Ah!" part because of all the noise (busy day at the bar) interjected:</p> -<p><q>It has nothing to do with leaks; new GC algorithms reduced fragmentation.</q></p> -<p>Well if I may dust off my middle school vocabulary for this occasion duh.</p> -<p>Losing memory to fragmentation is a kind of memory leak.</p> <p>I am not going to complain that punk programmers who reinvent decades old technology get more credit and success they deserve just because what they do looks new. Life is too short. But I do reserve the right to mock someone who implements a garbage collector. That leaks memory because of fragmentation. For whatever new programming language. In the 2010s.</p> {% endraw %} diff --git a/_posts/2011-10-09-Zarith.html b/_posts/2011-10-09-Zarith.html index ba7b80206cc5551097536b032f9a4b74c4f21e16..58435eeeb63fbcf71a27b1be7d114400dd5229c7 100644 --- a/_posts/2011-10-09-Zarith.html +++ b/_posts/2011-10-09-Zarith.html @@ -16,14 +16,5 @@ summary: <p>The bottom line is that a multiprecision operation (say a multiplication) is most of the times executed as the processor's corresponding instruction with a couple of conditional branches before and after for handling the uncommon cases and a couple of memory accesses and jumps (including a computed one) for the OCaml ↔ C interface. This may seem like a lot but it's much less than the other multiprecision libraries. And of course the unboxed representation saves space too as small integers do not have to be allocated at all and just reside in the word that would otherwise have been a pointer to their representation.</p> <p>Benchmarks comparing Carbon and Nitrogen will come later; these will include the gains from switching from Big_int to Zarith. For minimal fuss Frama-C will continue to compile with Big_int (the multiprecision library provided as part of the OCaml distribution) and perhaps I will include "Nitrogen compiled with Big_int" in the benchmarks just to make the point.</p> <p>Meanwhile if you plan to use the value analysis for more than ten minutes trust me install Zarith now. You can use either the SVN version (<a href="http://forge.ocamlcore.org/scm/?group_id=243">instructions</a>) or the <a href="http://forge.ocamlcore.org/frs/?group_id=243">1.0 version</a>. If you already knew about Zarith and had installed it a long time ago I suggest you upgrade to benefit from bugfixes and so that Frama-C Nitrogen's <code>-save</code> and <code>-load</code> options work.</p> -<p>[EDIT: deleted compilation instruction for obsolete Frama-C version]</p> - <p>Perhaps you are looking for something to do pending the upcoming release of Frama-C (someone called it \Nitrozen" once by accident in a commit message. I would like the name to stick but I anticipate it won't)…</p> -<p>Or you are already a serious user of the value analysis plug-in or of one of the plug-ins that rely on it…</p> -<p>Or you might be in the near future…</p> -<p>Then this blog post is for you because this blog post is about Zarith that you should install.</p> -<p>Zarith is a multiprecision library for OCaml created by Antoine Miné. Zarith relies on <a href="http://gmplib.org/">GMP</a> for the actual computations on big integers. Small integers and there lies Zarith's advantage over previous multiprecision libraries for OCaml use the same unboxed representation as OCaml's 31/63-bit integers. For computing on small integers if you are not using some exotic architecture Zarith uses the processor's instruction set most efficiently relying on the processor's flags to detect whether the result can itself be represented as an unboxed integer.</p> -<p>The bottom line is that a multiprecision operation (say a multiplication) is most of the times executed as the processor's corresponding instruction with a couple of conditional branches before and after for handling the uncommon cases and a couple of memory accesses and jumps (including a computed one) for the OCaml ↔ C interface. This may seem like a lot but it's much less than the other multiprecision libraries. And of course the unboxed representation saves space too as small integers do not have to be allocated at all and just reside in the word that would otherwise have been a pointer to their representation.</p> -<p>Benchmarks comparing Carbon and Nitrogen will come later; these will include the gains from switching from Big_int to Zarith. For minimal fuss Frama-C will continue to compile with Big_int (the multiprecision library provided as part of the OCaml distribution) and perhaps I will include "Nitrogen compiled with Big_int" in the benchmarks just to make the point.</p> -<p>Meanwhile if you plan to use the value analysis for more than ten minutes trust me install Zarith now. You can use either the SVN version (<a href="http://forge.ocamlcore.org/scm/?group_id=243">instructions</a>) or the <a href="http://forge.ocamlcore.org/frs/?group_id=243">1.0 version</a>. If you already knew about Zarith and had installed it a long time ago I suggest you upgrade to benefit from bugfixes and so that Frama-C Nitrogen's <code>-save</code> and <code>-load</code> options work.</p> <p>[EDIT: deleted compilation instruction for obsolete Frama-C version]</p> {% endraw %} diff --git a/_posts/2011-10-11-Unpublishing.html b/_posts/2011-10-11-Unpublishing.html index 33d4149efa7d4fcc47e8d0119ba2c0bd70cba110..2bc6a25ed5c66b578faf9b7e375c9aae219936de 100644 --- a/_posts/2011-10-11-Unpublishing.html +++ b/_posts/2011-10-11-Unpublishing.html @@ -9,5 +9,4 @@ summary: --- {% raw %} <p>I have unpublished the last post. It was written in a hurry because it partially answered <a href="http://lists.gforge.inria.fr/pipermail/frama-c-discuss/2011-October/002819.html">a question in the mailing list</a>. It needs more work to explain the problem being solved. Sorry.</p> - <p>I have unpublished the last post. It was written in a hurry because it partially answered <a href="http://lists.gforge.inria.fr/pipermail/frama-c-discuss/2011-October/002819.html">a question in the mailing list</a>. It needs more work to explain the problem being solved. Sorry.</p> {% endraw %} diff --git a/_posts/2011-10-11-frama-c-discuss.html b/_posts/2011-10-11-frama-c-discuss.html index 01700c7cec42df2852109558717455fcad77473f..999daea32ccf08b9ef00e134f55ff57658dc8e29 100644 --- a/_posts/2011-10-11-frama-c-discuss.html +++ b/_posts/2011-10-11-frama-c-discuss.html @@ -10,8 +10,5 @@ summary: {% raw %} <p>Following a discussion about Open Source, science and the difficulty of making a living in this day and age, I went and looked at the <a href="http://lists.gforge.inria.fr/pipermail/frama-c-discuss/">frama-c-discuss mailing list archives</a> to confirm a suspicion.</p> -<p>Suspicion confirmed. The public mailing list is a waste of time. I vote we close it pure and simple.</p> - <p>Following a discussion about Open Source, science and the difficulty of making a living in this day and age, I went and looked at -the <a href="http://lists.gforge.inria.fr/pipermail/frama-c-discuss/">frama-c-discuss mailing list archives</a> to confirm a suspicion.</p> <p>Suspicion confirmed. The public mailing list is a waste of time. I vote we close it pure and simple.</p> {% endraw %} diff --git a/_posts/2011-10-14-Features-in-Frama-C-Nitrogen-part-1.html b/_posts/2011-10-14-Features-in-Frama-C-Nitrogen-part-1.html index 31df5137becd05a7d04a35a6b472a71578141097..05a1cfe4257ad3a952759ccc9828e132c33cc2d7 100644 --- a/_posts/2011-10-14-Features-in-Frama-C-Nitrogen-part-1.html +++ b/_posts/2011-10-14-Features-in-Frama-C-Nitrogen-part-1.html @@ -31,29 +31,5 @@ Total speed-up 1.5 3 4 </pre> <p>How did the value analysis improve so much overall? As exemplified by the timings with and without <a href="/ocaml/value/2011/10/09/Zarith">Zarith</a> this is the result of many small enhancements and refinements at all levels.</p> <h2>Conclusion</h2> -<p>As promised the two features described here are only worth noting for faithful users. It only matters that Frama-C compiles with OCaml 3.10.2 if you intend to compile it at all and you only care that it is much faster than before if you were already using it. Even so some of the existing users may not notice them. This is the kind of feature that I like because it does not complicate the user interface —the value analysis benchmarks above use the same options and produce the same results— and improves the software nonetheless. Existing users and people who try Frama-C for the first time with Nitrogen will both have a better time of it thanks to the effort spent on the two points described in this post and on tens of others big and small some of which I hope will receive their own minute of spotlight in this series. I have been forced to allude to one other small improvement a better treatment of <code>switch</code> in the value analysis that I like even better because it removes the need to learn one option.</p> - <p>Here is a series of posts that highlight interesting features in the recently released Frama-C Nitrogen 20111001. There is new functionality in Nitrogen, that we hope will entice both existing and prospective users. Other improvements yet will only have meaning for existing users. I will start off with two items from this second category.</p> -<h2>Nitrogen compiles with OCaml 3.10.2.</h2> -<p><strong>The only non-optional dependency for compiling Nitrogen is an OCaml compiler</strong>. But which one? Despite a now long history, the OCaml language is still evolving relatively rapidly. We have never been happier with our choice of an implementation language: it is evolving in a direction that suits us, and it is evolving conservatively (compare Perl 6, PHP 5, Python 3, …). On the other hand, Frama-C is large and contains tricky code; the plug-in architecture with dynamic loading in general on the one hand, and the hash-consing programming technique on the other hand, are only two examples. It is large enough and tricky enough to reveal many of the subtle difference between any two versions of the OCaml compiler.</p> -<p>Nitrogen compiles with the latest version of OCaml, of course. That's 3.12.1 at the time of this writing. We already know that it won't compile as-is with the future OCaml 3.13 (a patch will be released in due time). Similarly, support for older versions has to be gained, version by version. If you have only written medium-sized OCaml programs, you could easily underestimate the difficulty of this. I was lucky enough not to have to deal with it much during this cycle, but some of my colleagues had to. It always is a struggle. Sometimes the equivalent of <code>#define/#if</code> constructs from C pre-processing would help, but this is not idiomatic in OCaml. Again, the only non-optional dependency for compiling Nitrogen is an OCaml compiler, so we won't use fine solutions such as <a href="http://martin.jambon.free.fr/cppo.html">Cppo</a>.</p> -<p>For Windows and Mac OS X OCaml is not part of the operating system so we ship the version we like together with the binary package (if we make one). With Unix the issues are different: there are too many flavors for us to distribute binaries but there are efficient package systems and distributions to painlessly bring in required dependencies. Often Frama-C itself is packaged in binary or source form as part of these distributions thanks to the work of many volunteers. It may take some time for packages to be created for Nitrogen and some users do not want to wait. Linus Token for instance may rely on a computer he bought two years ago. Frama-C works fine on two-years old computers as seen in the next section. Linus installed his Unix distribution of choice when he bought his computer and now he expects Frama-C's sources to compile with the OCaml version from his distribution (OCaml programmers can be expected to have the latest OCaml compiler installed from its own sources but Linus is not an OCaml programmer). -The Unix distribution installed two years ago was on average 3 months old at that time and it may have been frozen for stability 3 months before being released. For Linus Frama-C has to compile with a 2.5-year-old compiler. And then there are industrial users who like to trail a little bit on the Linux front but at the same time want all the latest Frama-C features. For Nitrogen we chose to retain compatibility with OCaml 3.10.2 released in February 2008 and all OCaml versions released since.</p> -<h2>The value analysis is up to four times faster on realistic examples</h2> -<p>The second Nitrogen feature I want to highlight today the value analysis' speed. Here is a quick and dirty comparison for programs that could already be analyzed with Carbon. There are new alarms and precision improvements in Nitrogen but I made sure that in this comparison the two versions were doing the same amount of work.</p> -<p>For this comparison I did not cherry-pick benchmarks. I looked for programs of varying sizes in the archives of the blog and used the three that came first having decided in advance that I wouldn't dismiss any results I didn't like. Each analysis was run three times and the median time was kept. This is on a Core 2 mobile processor and the frequency is pinned at 1.5GHz through <a href="http://coolbook.se/CoolBook.html">CoolBook</a>. In plain English the timings are for an oldish but not antiquated notebook.</p> -<p>The options I used were:</p> -<pre>-slevel 1000 -val count.c --slevel 10000 -val -no-results -cpp-command "gcc -C -E -m32 -Dprintf=Frama_C_show_each" sha1.c --val -slevel 1000 -slevel-function main:0 *.c -cpp-command "gcc -m32 -C -E -I. " -</pre> -<p>The programs <code>count.c</code> and <code>sha1.c</code> came from <a href="/compcert/csmith/value/2011/08/29/CompCert-gets-a-safe-interpreter-mode">this post</a>. For <code>sha1.c</code> I had to disable the endianness detection code implemented with a <code>switch</code> to put the Carbon and Nitrogen versions on an equal footing. With the Carbon version there used to be a difficult choice to make in presence of <code>switch</code> <a href="/index.php?post/2011/02/28/switch-statements-in-the-value-analysis">remember</a>? I could also have used option <code>-simplify-cfg</code> for the Carbon execution but then the analyzers would not have been analyzing exactly the same program. The Skein-256 example is the verification that an arbitrary number of calls to <code>Skein_256_Update(... 80)</code> never cause a run-time error using <a href="/index.php?post/2011/06/02/Skein-7">Josh Ko's instrumentation</a>.</p> -<pre> count.c sha1.c Skein-256 -Carbon 0m0.491s 0m2.862s 1m10.201s -Nitrogen without Zarith 0m0.410s 0m1.724s 0m37.782s -Nitrogen with Zarith 0m0.313s 0m0.962s 0m16.700s -Total speed-up 1.5 3 4 -</pre> -<p>How did the value analysis improve so much overall? As exemplified by the timings with and without <a href="/ocaml/value/2011/10/09/Zarith">Zarith</a> this is the result of many small enhancements and refinements at all levels.</p> -<h2>Conclusion</h2> <p>As promised the two features described here are only worth noting for faithful users. It only matters that Frama-C compiles with OCaml 3.10.2 if you intend to compile it at all and you only care that it is much faster than before if you were already using it. Even so some of the existing users may not notice them. This is the kind of feature that I like because it does not complicate the user interface —the value analysis benchmarks above use the same options and produce the same results— and improves the software nonetheless. Existing users and people who try Frama-C for the first time with Nitrogen will both have a better time of it thanks to the effort spent on the two points described in this post and on tens of others big and small some of which I hope will receive their own minute of spotlight in this series. I have been forced to allude to one other small improvement a better treatment of <code>switch</code> in the value analysis that I like even better because it removes the need to learn one option.</p> {% endraw %} diff --git a/_posts/2011-10-16-Academie-francaise.html b/_posts/2011-10-16-Academie-francaise.html index 4e0bd43fa58b85e528269bbfc69d41bea8d1354f..91d8eea72fb07ee463c8bca8595dd997b350e18f 100644 --- a/_posts/2011-10-16-Academie-francaise.html +++ b/_posts/2011-10-16-Academie-francaise.html @@ -18,16 +18,5 @@ summary: <p>But it could have been worse: the Académie could have invented completely new words and suggested people should use those. We had to endure a wave of that in the late 1990s when Internet use spread.</p> <blockquote><p>Internet widespread use came relatively late in France because of the "Minitel" prior technology. This is no time to start a second rant but I must point out that neither the Minitel nor the late adoption of the Internet were the failures that some make out here and abroad. In particular the Minitel elegantly solved the problem of micro-payments something I haven't yet seen a good solution for on the Internet. Go back to that Guardian page and tell me that advertising is fine — and the Guardian is probably still operating its website at a loss. It would have to split an article as David Mitchell's on three pages to make enough impressions to recoup the costs of producing quality contents.</p> </blockquote> -<p>The Académie's website is not all like that fortunately. It does have useful suggestions and the words introducing the very "dire ne pas dire" section constitute a pleasant statement in stark contrast with the title. It's a good thing we have foreign newspapers to remind us to take a look once in a while.</p> - <p>This ranty post is because I never tire of trying the content management system on weird characters for its URLs.</p> -<p>No, this post is really because David Mitchell himself has <a href="http://www.guardian.co.uk/commentisfree/2011/oct/16/david-mitchell-flanders-lion-belgium">a new post</a> up I find interesting. It very much follows the same general direction his posts usually do (if you discover his weekly column with this link and like this episode good news! The archives have plenty more that you may like. But don't read all at once to avoid an <a href="/rant/2011/09/27/About">indigestion</a>).</p> -<p>This week David Mitchell concludes with a quip on the Académie Française. France doesn't have a royal family. Every country should have a reason for articles to be written in foreign newspapers about scandalous recent developments: that's just good economic sense. How will potential visitors think of your country if it does not have a reason to linger in the back of their heads? Advertising isn't cheap.</p> -<p>He is right about the last eccentricity. The Académie is probably doing it on purpose: everyone must be able to see that this is clearly wrong. Again the royal family recipe. It unites somehow.</p> -<p>The new section <a href="http://www.academie-francaise.fr/langue/dire_nepasdire/dire1.html" hreflang="fr">in question</a> contains quantities of lessons. For instance if you are looking for the welcoming and friendly tone of an administrative form from the 1980s do use the infinitive to express an imperative mood as in "dire ne pas dire".</p> -<p>Moving past the title the first bullet point is about the use of preposition "sur" (literally "on") to express large scale vicinity. The Académie suggests one should say one lives "à Paris" (that's the "dire" part) instead of "sur Paris" (the "ne pas dire"). Unfortunately the two do not nearly mean the same thing. When I visit my family for the Christmas holidays 500km from Paris and a friend of my father's asks me about my work or place of residence it is accurate to say that I live "sur Paris" (meaning in the general area of at a scale relative to the distance whence we are talking). I do not live "à Paris" a privilege I leave to people either richer or less demanding living-space-wise.</p> -<p>The Académie would expound that "sur" was not used this way in any written work until the 19th century. Well yes. The "sur" form isn't very useful in an era when people do not generally move at more than 50km/h. This new use is a remarkable adaptation of the language where a very short word magically took on a meaning that was suddenly very useful without any ambiguity. If I was a linguist I would like to study this.</p> -<p>But it could have been worse: the Académie could have invented completely new words and suggested people should use those. We had to endure a wave of that in the late 1990s when Internet use spread.</p> -<blockquote><p>Internet widespread use came relatively late in France because of the "Minitel" prior technology. This is no time to start a second rant but I must point out that neither the Minitel nor the late adoption of the Internet were the failures that some make out here and abroad. In particular the Minitel elegantly solved the problem of micro-payments something I haven't yet seen a good solution for on the Internet. Go back to that Guardian page and tell me that advertising is fine — and the Guardian is probably still operating its website at a loss. It would have to split an article as David Mitchell's on three pages to make enough impressions to recoup the costs of producing quality contents.</p> -</blockquote> <p>The Académie's website is not all like that fortunately. It does have useful suggestions and the words introducing the very "dire ne pas dire" section constitute a pleasant statement in stark contrast with the title. It's a good thing we have foreign newspapers to remind us to take a look once in a while.</p> {% endraw %} diff --git a/_posts/2011-10-21-How-to-waste-a-Friday-evening.html b/_posts/2011-10-21-How-to-waste-a-Friday-evening.html index 707d19bc933b10d73a6a63077abdd4e3abc1ac00..7d7d2d9e92678c87d16da7ca410aaa3f1e27fbc4 100644 --- a/_posts/2011-10-21-How-to-waste-a-Friday-evening.html +++ b/_posts/2011-10-21-How-to-waste-a-Friday-evening.html @@ -14,11 +14,5 @@ summary: <li>mess up the Clang double-check by forgetting the <code>-m32</code> option so that it looks that GCC and Clang both agree there is a bug in the value analysis (which produces a result different from the consensus);</li> <li>look for bug that isn't there;</li> <li>goto 3</li> -</ol> <p>Here is a quick recipe for completely wasting a Friday evening:</p> -<ol> -<li>use Csmith to generate a program that GCC happens to mis-compile in 32-bit into an executable that produces the same result as the correct 64-bit compilation of the same program;</li> -<li>mess up the Clang double-check by forgetting the <code>-m32</code> option so that it looks that GCC and Clang both agree there is a bug in the value analysis (which produces a result different from the consensus);</li> -<li>look for bug that isn't there;</li> -<li>goto 3</li> </ol> {% endraw %} diff --git a/_posts/2011-10-24-Escher-C-Verifier.html b/_posts/2011-10-24-Escher-C-Verifier.html index 40ebabb0a0caa91e75338a54beefd4a3292b9119..ee5c883223152b9b40127b831c2d52c36efb0f48 100644 --- a/_posts/2011-10-24-Escher-C-Verifier.html +++ b/_posts/2011-10-24-Escher-C-Verifier.html @@ -9,5 +9,4 @@ summary: --- {% raw %} <p>According to <a href="http://critical.eschertech.com/2011/10/24/escher-c-verifier-released/">David Crocker's blog</a> Escher C Verifier has been released. Congratulations!</p> - <p>According to <a href="http://critical.eschertech.com/2011/10/24/escher-c-verifier-released/">David Crocker's blog</a> Escher C Verifier has been released. Congratulations!</p> {% endraw %} diff --git a/_posts/2011-10-27-Covering-all-interlacings-in-a-single-short-context.html b/_posts/2011-10-27-Covering-all-interlacings-in-a-single-short-context.html index 21bd3ecb632b96e3cbd80707955f883f321e99d9..0c1ead294b3b1ca556b48f798dba250a746ce63f 100644 --- a/_posts/2011-10-27-Covering-all-interlacings-in-a-single-short-context.html +++ b/_posts/2011-10-27-Covering-all-interlacings-in-a-single-short-context.html @@ -97,95 +97,5 @@ void analysis_context(void) r ∈ {0} ... </pre> -<p>Oh variable <code>r</code> remains zero throughout the infinite loop. The silliness of my examples sometimes...</p> - <p>Answering the two questions from last post in reverse order:</p> -<p><q><strong>What shorter analysis context would test arbitrarily long sequences of interrupts, with repetitions?</strong></q></p> -<p>There was a hint in the previous post in the link to the <a href="/index.php?tag/skein">Skein-256</a> tutorial. A stronger hint would have been to link directly to <a href="https://svn.frama-c.com/blog/admin/post.php?id=87">this post</a> where an analysis context that encompasses many possible executions is offered. The analysis context there is for arbitrary numbers of calls to <code>Skein_256_Update()</code> and the key part of the analysis context is:</p> -<pre> ... - Skein_256_Init(&skein_context HASHLEN * 8); - while (Frama_C_interval(0 1)) - { - for (i=0; i<80; i++) - msg[i] = Frama_C_interval(0 255); - Skein_256_Update(&skein_context msg 80); - } - Skein_256_Final( &skein_context hash); - ... -</pre> -<p>By similarity with the above example an analysis context for arbitrarily long sequences of interrupts with repetitions can be written:</p> -<pre>... -void analysis_context(void) -{ - main(); - while (Frama_C_interval(0 1)) - { - if (Frama_C_interval(0 1)) interrupt_device1(); - if (Frama_C_interval(0 1)) interrupt_device2(); - if (Frama_C_interval(0 1)) interrupt_device3(); - } -} -</pre> -<blockquote><p>Most pitfalling value analysis usability pitfall number one: when using <code>Frama_C_interval()</code> one should not forget to include file <code>builtin.c</code> as part of the analysis project.</p> -</blockquote> -<p>The first question was actually more difficult:</p> -<p><q><strong>What shorter analysis context would test in a single analysis exactly the same behaviors as the lengthy six entry points ?</strong></q></p> -<p>Answer: the function below would.</p> -<pre>int called1 called2 called3; -... -void analysis_context(void) -{ - main(); - while (!(called1 && called2 && called3)) - { - if (Frama_C_interval(0 1) && !called1) { called1 = 1; interrupt_device1(); } - if (Frama_C_interval(0 1) && !called2) { called2 = 1; interrupt_device2(); } - if (Frama_C_interval(0 1) && !called3) { called3 = 1; interrupt_device3(); } - } -} -</pre> -<p>Variables <code>called1 called2 called3</code> are defined as zero-initialized global variables and are used to remember whether each interrupt has already been called.</p> -<p>The value analysis will provide results that hold for all possible executions of the above context. It does not matter that some of the possible executions of the above code escape in livelock and fail to terminate. All the executions in which the three interrupts are called in some order and the program then terminates are taken into account which is what matters for verifying safety.</p> -<p>To reiterate we are not yet worried about how the verification will be done at this stage. It may turn out later that changing the context code slightly makes it easier while still covering all the same executions. Or the value analysis may be able to brute-force its way through with an option such as <code>-slevel-function analysis_context:33</code>. We'll let the person in charge of verification make his choices and justify them if he needs to. Writing the analysis context is in a way a specification activity. While not completely ignoring the verification's feasibility it should be done without worrying too much about such details.</p> -<p>And what if the execution of interrupts are in fact interlaced (that is if they are in fact interruptible)? There is a plug-in for that (a phrase I would like to suggest as new Frama-C slogan). That plug-in is not distributed at this stage but if you are interested in the verification of comparatively precise properties on code with fine-grained concurrency write in and we'll tell you about it.</p> -<p>Post-scriptum: here is a complete example:</p> -<pre>int t[20] s[30]; -int *p i r; -main() -{ - p = t; - i = 0; -} -void interrupt_device1(void) -{ - r = p[i + Frama_C_interval(0 9)]; -} -void interrupt_device2(void) -{ - p = (Frama_C_interval(0 1)) ? t : (s + Frama_C_interval(0 10)); -} -void interrupt_device3(void) -{ - i = Frama_C_interval(0 10); -} -void analysis_context(void) -{ - main(); - while (Frama_C_interval(0 1)) - { - if (Frama_C_interval(0 1)) interrupt_device1(); - if (Frama_C_interval(0 1)) interrupt_device2(); - if (Frama_C_interval(0 1)) interrupt_device3(); - } -} -</pre> -<p>For some reason this example does not even need the <code>-slevel</code> option to be found safe:</p> -<pre>$ frama-c -val -main analysis_context .../share/builtin.c t.c -... -[value] Values for function analysis_context: - p ∈ {{ &t ; &s + [0..40] 0%4 }} - i ∈ [0..10] - r ∈ {0} -... -</pre> <p>Oh variable <code>r</code> remains zero throughout the infinite loop. The silliness of my examples sometimes...</p> {% endraw %} diff --git a/_posts/2011-10-27-Verifying-for-all-interlacings.html b/_posts/2011-10-27-Verifying-for-all-interlacings.html index 878d7ef7f3bd3f971e9688465b20d6db8bd44a2c..ef75641eebe91b4c744bd734828eb22b4531c4c6 100644 --- a/_posts/2011-10-27-Verifying-for-all-interlacings.html +++ b/_posts/2011-10-27-Verifying-for-all-interlacings.html @@ -62,59 +62,5 @@ The problem is that this method does not scale well to larger numbers of interru <ol> <li>What shorter analysis context would test exactly the same behaviors as the six entry points above in a single analysis?</li> <li>What shorter analysis context would test arbitrarily long sequences of interrupts with repetitions?</li> -</ol>" <p>A prospective user experimenting with Frama-C wonders whether it is possible to verify the behavior of an interrupt-driven system for all possible interlacing of interrupts.</p> -<p>We assume, for now, that interrupts are themselves uninterruptible. -The prospective user wants to verify that nothing wrong happens when each interrupt is called once, in any order. He wrote the analysis context below.</p> -<pre>void test_case1(void) -{ - main(); - interrupt_device1(); - interrupt_device2(); - interrupt_device3(); -} -void test_case2(void) -{ - main(); - interrupt_device1(); - interrupt_device3(); - interrupt_device2(); -} -void test_case3(void) -{ - main(); - interrupt_device2(); - interrupt_device1(); - interrupt_device3(); -} -void test_case4(void) -{ - main(); - interrupt_device2(); - interrupt_device3(); - interrupt_device1(); -} -void test_case5(void) -{ - main(); - interrupt_device3(); - interrupt_device1(); - interrupt_device2(); -} -void test_case6(void) -{ - main(); - interrupt_device3(); - interrupt_device2(); - interrupt_device1(); -} -</pre> -<p>Function <code>main()</code> does a bit of initialization. Each of the functions <code>test_case1()</code>, …, <code>test_case6()</code> is used as an entry point for the value analysis.</p> -<p>This method works: studying the six entry points one after the other, properties about many possible executions can be found. -The problem is that this method does not scale well to larger numbers of interrupts.</p> -<p>The next post will answer two questions, that I invite you to think about for yourself. Note that the writing of analysis contexts is mostly orthogonal to the careful selection of options and annotations that help the value analysis conclude to the safety of the code. This is why I am suggesting these exercises without offering the code of <code>interrupt_device1()</code>, …, <code>interrupt_device3()</code>. Only in the most difficult cases (as happened for the verification of the strongest properties for <a href="/index.php?tag/skein">Skein-256</a>) is it necessary to adapt the analysis context to make the verification possible. By the same token proofreading a verification in order to check that the right property was verified usually only means proofreading the analysis context not the options and annotations that enabled the value analysis to reach its conclusion. Most options are safe to use and the value analysis tells whether it uses a user annotation as an assumption or only as a hint.</p> -<p>Here are the questions the next post will focus on:</p> -<ol> -<li>What shorter analysis context would test exactly the same behaviors as the six entry points above in a single analysis?</li> -<li>What shorter analysis context would test arbitrarily long sequences of interrupts with repetitions?</li> -</ol>" +</ol> {% endraw %} diff --git a/_posts/2011-10-29-A-portable-OCaml-function-to-print-floats.html b/_posts/2011-10-29-A-portable-OCaml-function-to-print-floats.html index cbd1a6c84db6f61ec350cb63e20ac04d18190845..de2bbadcf85ac830bd61e72857061c9bde9c2334 100644 --- a/_posts/2011-10-29-A-portable-OCaml-function-to-print-floats.html +++ b/_posts/2011-10-29-A-portable-OCaml-function-to-print-floats.html @@ -87,84 +87,5 @@ let pretty_normal ~use_hex fmt f = firstdigit man exp -</pre>" <p>For printing the results of automated Frama-C tests, we need printing functions with the following properties:</p> -<ol> -<li>they should print all the information available (doing otherwise might mask an existing bug);</li> -<li>they should produce results readable enough for a person to validate the result of each test once;</li> -<li>and their output should not differ depending on the execution platform.</li> -</ol> -<p>For tests that manipulates floating-point data, we need a floating-point printing function with the above properties. -If you start with the OCaml function <code>Format.printf</code> and print enough digits to make condition 1 true, then a number of issues arise with condition 3. -For a while, we used hexadecimal in all tests outputs. For instance, the value for <code>d</code> in the program <code>d = 3.14;</code> was printed as <code>d ∈ 0x1.91eb851eb851fp1</code>. In this notation, the digits after <code>1.</code> are in base 16, and <code>p1</code> means \multiplied by <code>2^1</code>" by similarity with <code>e1</code> meaning "multiplied by <code>10^1</code>". Users were not fond of this notation. I don't know why. It is accepted for input by C99 compilers and can be printed with the <code>%a</code> format code in <code>printf()</code>. It is easy to see at a glance that the <code>d</code> is between <code>3</code> and <code>4</code> closer to <code>3</code> because <code>0x1.8p1</code> is <code>3</code> and <code>0x2.0p1</code> is <code>4</code>.</p> -<p>In order to improve condition 2 I wrote my own floating-point pretty-printing function. The goal here is not to have something very sophisticated but to make sure we do not miss a bug in a test output for the silly reason of having had ten fingers for a long time. For the same program <code>d = 3.14;</code> the new decimal pretty-printing function produces <code>d ∈ 3.1400000000000001</code> which is what could be expected considering that the number <code>3.14</code> cannot be represented exactly as a <code>double</code>. More important is that if the program is modified to read <code>d = 0x1.91eb851eb8520p1;</code> changing only the least significant bit in the floating-point representation of <code>d</code> the output becomes <code>d ∈ 3.1400000000000005</code> showing that there is a difference.</p> -<p>I have recently improved my improvement so I thought I might as well provide the function here (but you may have seen a previous version through other channels). The function I wrote only uses 64-bit ints and double-precision floats so that it would be straightforward to translate to most other programming languages.</p> -<p>It works by first isolating the sign exponent and mantissa of the floating-point number to print. The mantissa ranges over <code>0 .. 0xFFFFFFFFFFFFF</code> and we would like a sequence of decimal digits that ranges over <code>0 .. 9999999999999998</code> instead. For this purpose the mantissa is bitwise or-ed into the representation of the double-precision float <code>1.0</code> giving a result that ranges over <code>1.0 .. 2.0</code> (excluded). The basic idea is then to subtract <code>1.0</code> to multiply by <code>1e16</code> to convert to an integer and to print with width 16 and with leading zeroes (the <code>%016Ld</code> format).</p> -<p>The function is at the bottom of this post. The recent improvement is this test:</p> -<pre> let d re = - if d >= 1.5 - then d -. 1.5 5000000000000000L - else d -. 1.0 0L - in - ... -</pre> -<p>Without these lines the function was a bit unsatisfactory when the fractional part was above <code>0.5</code>. The printed decimal number was a strictly increasing function of the actual floating-point number which was enough to ensure condition 1 but some numbers that were exactly representable in both the floating-point double-precision format and as decimal numbers were printed with a decimal representation other than that representing exactly the number. It was bugging me although I doubt it ever bugged someone else. This is fixed by the above code which regains a vital bit of mantissa when the fractional part of the number to print is greater than 0.5. Even with this fix the function is not correctly rounded but it doesn't claim to be. It is only the closest we have bothered to come to satisfying conditions 1-3 simultaneously.</p> -<pre>let double_norm = Int64.shift_left 1L 52 -let double_mask = Int64.pred double_norm -let pretty_normal ~use_hex fmt f = - let i = Int64.bits_of_float f in - let s = 0L <> (Int64.logand Int64.min_int i) in - let i = Int64.logand Int64.max_int i in - let exp = Int64.to_int (Int64.shift_right_logical i 52) in - let man = Int64.logand i double_mask in - let s = if s then "-" else "" in - let firstdigit exp = - if exp <> 0 - then 1 (exp - 1023) - else 0 -1022 - in - if not use_hex - then begin - let firstdigit man exp = - if 0 <= exp && exp <= 12 - then begin - Int64.to_int - (Int64.shift_right_logical - (Int64.logor man double_norm) - (52 - exp)) - Int64.logand (Int64.shift_left man exp) double_mask - 0 - end - else firstdigit man exp - in - let d = - Int64.float_of_bits - (Int64.logor 0x3ff0000000000000L man) - in - let d re = - if d >= 1.5 - then d -. 1.5 5000000000000000L - else d -. 1.0 0L - in - let d = d *. 1e16 in - let decdigits = Int64.add re (Int64.of_float d) in - if exp = 0 - then - Format.fprintf fmt "%s%d.%016Ld" - s - firstdigit - decdigits - else - Format.fprintf fmt "%s%d.%016Ld*2^%d" - s - firstdigit - decdigits - exp - end - else - Format.fprintf fmt "%s0x%d.%013Lxp%d" - s - firstdigit - man - exp -</pre>" +</pre> {% endraw %} diff --git a/_posts/2011-11-05-What-functions-does-a-function-use-option--users.html b/_posts/2011-11-05-What-functions-does-a-function-use-option--users.html index 005e5c4ec44ff3d8a30d1bfb650e882207997021..b79eaf2524df3ec5b5e0be3f60d2bf132b1c8f68 100644 --- a/_posts/2011-11-05-What-functions-does-a-function-use-option--users.html +++ b/_posts/2011-11-05-What-functions-does-a-function-use-option--users.html @@ -62,60 +62,5 @@ More importantly, the list omits function <code>copy_int()</code>, which <strong </pre> <p>The users analysis exploits the results of the value analysis, so the results hold for the initial conditions the value analysis was configured for. Here, the value analysis was instructed to study the function <code>add()</code> by itself. In these conditions, <code>do_op()</code> only calls <code>really_add()</code>, but if the analysis focused on a larger program it would see that <code>do_op()</code> also sometimes call <code>really_mult()</code>. The users analysis can tell that <code>add()</code> uses <code>copy_int()</code>, <code>really_add()</code>, and <code>do_op()</code>, and does not use <code>really_mult()</code>.</p> <p>This kind of synthetic information is very useful when trying to get a grip on large programs, for instance, when trying to extract a useful function from a large codebase to make it a library. Unsurprisingly, plenty of tools already existed before Frama-C that tried to provide this sort of information. But having information on the dynamic behavior of the program can make a large difference in the value of the synthetic information computed.</p> -<p>My colleagues at Airbus Opérations SAS and Atos SA will present serious applications of the <code>-users</code> option at <a href="http://www.erts2012.org/">ERTS² 2012</a> (next February).</p> - <h2>Exploring unfamiliar code</h2> -<p>Sometimes, one finds oneself in the situation of exploring unfamiliar code. In these circumstances, it is sometimes useful to know which functions a function <code>f()</code> uses. This sounds like something that can be computed from the callgraph, and there exists plenty of tools out there that can extract a callgraph from a C program, but the callgraph approach has several drawbacks:</p> -<ol> -<li>A static callgraph does not include calls made through function pointers. Therefore, you do not see all the functions that <code>f()</code> uses: the list omits the functions that were directly or indirectly called through a function pointer.</li> -<li>The set of functions computed from the call graph is over-approximated, because if <code>f()</code> calls <code>g()</code> and <code>g()</code> may sometimes call <code>h()</code>, it doesn't necessarily mean that <code>f()</code> uses <code>h()</code>. Indeed, perhaps <code>g()</code> never calls <code>h()</code> when it is called from <code>f()</code>, but only when it is called from another function <code>k()</code>.</li> -</ol> -<h2>Example</h2> -<p>Here is an example that illustrates both issues.</p> -<pre>enum op { ADD, MULT }; -void copy_int(int *src, int *dst) -{ - *dst = *src; -} -int really_add(int u, int v) -{ - return u + v; -} -int really_mult(int u, int v) -{ - return u * v; -} -int do_op(enum op op, int u, int v) -{ - if (op == ADD) - return really_add(u, v); - else if (op == MULT) - return really_mult(u, v); - else - return -1; -} -int add(int x, int y) -{ - int a, b, res; - void (*fun_ptr)(int*, int*); - fun_ptr = copy_int; - (*fun_ptr)(&x, &a); - (*fun_ptr)(&y, &b); - res = do_op(ADD, a, b); - return res; -} -</pre> -<p>Using a syntactic callgraph to compute the functions used by <code>add()</code>, one finds <code>do_op()</code>, <code>really_add()</code>, and <code>really_mult()</code>. This list is over-approximated because <code>add()</code> does not really use <code>really_mult()</code>. -More importantly, the list omits function <code>copy_int()</code>, which <strong>is</strong> used by <code>add()</code>.</p> -<h2>Frama-C's users analysis</h2> -<p>Frama-C's users analysis computes this list instead:</p> -<pre>$ frama-c -users -lib-entry -main add example.c -... -[users] ====== DISPLAYING USERS ====== - do_op: really_add - add: copy_int really_add do_op - ====== END OF USERS ========== -</pre> -<p>The users analysis exploits the results of the value analysis, so the results hold for the initial conditions the value analysis was configured for. Here, the value analysis was instructed to study the function <code>add()</code> by itself. In these conditions, <code>do_op()</code> only calls <code>really_add()</code>, but if the analysis focused on a larger program it would see that <code>do_op()</code> also sometimes call <code>really_mult()</code>. The users analysis can tell that <code>add()</code> uses <code>copy_int()</code>, <code>really_add()</code>, and <code>do_op()</code>, and does not use <code>really_mult()</code>.</p> -<p>This kind of synthetic information is very useful when trying to get a grip on large programs, for instance, when trying to extract a useful function from a large codebase to make it a library. Unsurprisingly, plenty of tools already existed before Frama-C that tried to provide this sort of information. But having information on the dynamic behavior of the program can make a large difference in the value of the synthetic information computed.</p> <p>My colleagues at Airbus Opérations SAS and Atos SA will present serious applications of the <code>-users</code> option at <a href="http://www.erts2012.org/">ERTS² 2012</a> (next February).</p> {% endraw %} diff --git a/_posts/2011-11-08-Floating-point-quiz.html b/_posts/2011-11-08-Floating-point-quiz.html index 279c47324a5ca39d3bfb3ff19f78ea2eeaeba36a..f8dd11562c53bde15dd6d0297ffb7c6a57cd9e8e 100644 --- a/_posts/2011-11-08-Floating-point-quiz.html +++ b/_posts/2011-11-08-Floating-point-quiz.html @@ -54,51 +54,5 @@ summary: f2 ^ f1 original number </pre> -<p>I could make another series of questions, somewhat symmetrical to this one, where two different but standard-complicant compilers produce different results each time, but that wouldn't be as much fun. The examples here were relatively well defined. The rules that make them puzzling (or not) apply indiscriminately to most compilers. Unless they do not even try to follow C99's guideline that recommends IEEE 754 arithmetics.</p> <p>Here is a little quiz you can use to test your C floating-point expertise. I have tried to write the examples below so that the results do not depend too much on the platform and compiler. This is theoretically impossible since C99 does not mandate IEEE 754 floating-point semantics, but let us assume that the compiler at least tries. It could be a recent GCC on 8087-class hardware, for instance.</p> -<h2>Question 1</h2> -<p>What's the return code of this program?</p> -<pre>main(){ - return 0.1 == 0.1f; -} -</pre> -<p>Answer: the program returns <code>0</code>. Promotion and conversion rules mean that the comparison take place between <code>double</code> numbers. The decimal number <code>0.1</code> is represented differently as a single-precision <code>float</code> and as a double-precision <code>double</code> (and none of these two representations is exact), so when <code>0.1f</code> is promoted to <code>double</code>, the result is quite a bit different from the <code>double</code> representing <code>0.1</code>.</p> -<h2>Question 2</h2> -<pre>main(){ - float f = 0.1; - return f == 0.1f; -} -</pre> -<p>Answer: the program returns <code>1</code>. This time, the comparison takes place between <code>float</code> numbers. But first things first: variable <code>f</code> is initialized with the <code>double</code> representation of <code>0.1</code>, but this number has to be converted to <code>float</code> to fit <code>f</code>. As a result, <code>f</code> ends up containing only those digits of <code>0.1</code> that fit into a <code>float</code> mantissa. When the contents of <code>f</code> are read back, they compare exactly to the <code>0.1f</code> single-precision constant.</p> -<h2>Question 3</h2> -<pre>main(){ - float f = 0.1; - double d = 0.1f; - return f == d; -} -</pre> -<p>Answer: the program returns <code>1</code>. The comparison takes place between <code>double</code> numbers again. The left-hand side is the promotion to double of the single-precision representation of <code>0.1</code>. The right-hand side is the contents of double-precision variable <code>d</code>, that has been initialized with the conversion to <code>double</code> of the single-precision representation of <code>0.1</code>. The two sequences of operations produce the same result.</p> -<h2>Question 4</h2> -<pre>main(){ - double d1 = 1.01161128282547f; - double d2 = 1.01161128282547; - return d1 == d2; -} -</pre> -<p>Answer: the program returns <code>0</code>. The decimal number <code>1.01161128282547</code> is no more representable than <code>0.1</code>, and again, its <code>double</code> representation in <code>d2</code> has more digits than its <code>float</code> representation converted to double in <code>d1</code>.</p> -<blockquote><p>For a fractional number to be representable as a (base 2) floating-point number, its decimal expansion has to end in <code>5</code>, although the converse isn't true. Numbers <code>0.5</code> and <code>0.625</code> are representable as floating-point numbers, but <code>0.05</code>, <code>0.1</code> and <code>1.01161128282547</code> aren't. A number may also have the same representation as <code>float</code> and <code>double</code> although neither of these two representations is exact: for this to happen, it suffices that the 29 additional binary digits available in the <code>double</code> format be all zeroes.</p> -</blockquote> -<h2>Question 5</h2> -<pre>main(){ - float f1 = 1.01161128282547f; - float f2 = 1.01161128282547; - return f1 == f2; -} -</pre> -<p>Answer: if this looks like a trick question, it's because it is. The program returns <code>0</code>. Variable <code>f1</code> is initialized with the single-precision representation of <code>1.01161128282547</code>. On the other hand, <code>f2</code> receives the conversion to <code>float</code> of the double representation of this number. In this particular case, the two are not the same: the number 1.01161128282547 is actually very close to the middle point of two successive floating-point numbers. When it is first rounded to double (when initializing <code>f2</code>), it is rounded to the middle point itself (which happens to be representable as a <code>double</code>). When that <code>double</code> is rounded to a <code>float</code>, applicable rounding rules send it to the <code>float</code> on the opposite side of the middle point we started from. On the other hand, when initializing <code>f1</code>, the original number is rounded directly to the nearest <code>float</code>.</p> -<pre> ~1.01161122 ~1.01161128 ~1.01161134 - +------------------------------+------------------------------+ - f2 ^ f1 - original number -</pre> -<p>I could make another series of questions, somewhat symmetrical to this one, where two different but standard-complicant compilers produce different results each time, but that wouldn't be as much fun. The examples here were relatively well defined. The rules that make them puzzling (or not) apply indiscriminately to most compilers. Unless they do not even try to follow C99's guideline that recommends IEEE 754 arithmetics.</p> +<p>I could make another series of questions, somewhat symmetrical to this one, where two different but standard-complicant compilers produce different results each time, but that wouldn't be as much fun. The examples here were relatively well defined. The rules that make them puzzling (or not) apply indiscriminately to most compilers. Unless they do not even try to follow C99's guideline that recommends IEEE 754 arithmetics.</p> {% endraw %} diff --git a/_posts/2011-11-14-Analyzing-single-precision-floating-point-constants.html b/_posts/2011-11-14-Analyzing-single-precision-floating-point-constants.html index 68bf0cf79af32143b86a13479efecf3980d22266..38889f9c102bbcdda6a65e5ad76f54932f180186 100644 --- a/_posts/2011-11-14-Analyzing-single-precision-floating-point-constants.html +++ b/_posts/2011-11-14-Analyzing-single-precision-floating-point-constants.html @@ -81,79 +81,5 @@ warning: Floating-point constant 1.01161128282547f is not represented exactly. <h2>Conclusion</h2> <p>In the introduction I self-centeredly linked to two earlier posts from this blog. The post from one year ago showed one difficulty as an example of why single-precision floating-point was not supported precisely in Frama-C in general. The post from last week showed several contrived examples that can only be handled with a precise understanding of floating-point —including but not limited to the issue described one year ago— in the form of a quiz. What I find interesting is that there were unforeseen difficulties in the implementation of even the foreseen difficulty of getting the right value for a single-precision constant. And to reiterate the current development version of the value analysis correctly answers all five questions in the quiz.</p> -<p>This post was improved by suggestions from Fabrice Derepas and Florent Kirchner.</p> - <p>The <a href="/conversions-and-promotions/floating-point/2011/11/08/Floating-point-quiz">previous post</a> on this blog points out how subtle just floating-point constants can be. In a <a href="/cil/ocaml/floating-point/value/2010/11/20/IEEE-754-single-precision-numbers-in-Frama-C">previous previous post</a> exactly one year ago I was already alluding to these difficulties in the context of Frama-C's front-end.</p> -<h2>Programming a code analyzer that can answer question 5</h2> -<p>How should the program below be parsed to have a chance to be analyzed correctly?</p> -<pre>main(){ - float f1 = 1.01161128282547f; - float f2 = 1.01161128282547; - return f1 == f2; -} -</pre> -<p>In order to avoid the very double-rounding that could make variable <code>f1</code> appear equal to <code>f2</code> the method I delineated one year ago was to call <code>strtof()</code> to parse the single-precision constant. An analyzer that carelessly parses the initializer of <code>f1</code> with a call to double-precision function <code>strtod()</code> would wrongly conclude that both variables are double-rounded and therefore equal. In OCaml it is easy to slip because by default <code>strtod()</code> is the only interfaced conversion function.</p> -<p>I have now tried the "interface and call <code>strtof()</code>" method and in this post I report on the lesson I learned. It fits in one sentence.</p> -<blockquote><p>Calling <code>strtof()</code> from OCaml in order to avoid double rounding issues only works if the function <code>strtof()</code> is correct on the host system in the first place.</p> -</blockquote> -<p>The diagram and the program explaining the problem are almost identical from the previous post's question 5:</p> -<pre>#include <stdlib.h> -#include <stdio.h> -main(){ - float f1 = strtof("1.01161128282547" NULL); - float f2 = strtod("1.01161128282547" NULL); - printf("f1:%.9g\ -f2:%.9g" f1 f2); -} -</pre> -<pre> ~1.01161122 ~1.01161128 ~1.01161134 - +------------------------------+------------------------------+ - f2 ^ f1 - original number -</pre> -<p>This program when executed should display:</p> -<pre>$ ./a.out -f1:1.01161134 -f2:1.01161122 -</pre> -<p>It is expected for the program to print <code>1.01161122</code> for <code>f2</code> as the string in the program is converted to a <code>double</code> near <code>1.01161128</code> and then to a <code>float</code> (the <code>float</code> near <code>1.01161122</code> is chosen). For variable <code>f1</code> calling function <code>strtof()</code> to convert the string directly to a <code>float</code> should result in the float near <code>1.01161134</code> being computed. -Indeed this is what the program does on Mac OS X. However:</p> -<pre>$ ./a.out -f1:1.01161122 -f2:1.01161122 -$ uname -a -Linux 2.6.34.6-xxxx-grs-ipv6-64 #3 SMP Fri Sep 17 16:06:38 UTC 2010 x86_64 GNU/Linux -</pre> -<p>This is <a href="http://sourceware.org/bugzilla/show_bug.cgi?id=3479">a bug in Glibc</a>.</p> -<blockquote><p>Note that the standard only requires that conversion functions <code>strtod()</code> <code>strtof()</code> and conversions done by the C compiler when parsing must produce a result within one ULP of the exact value in an implementation-defined manner. However I do not think that "trying to return the nearest float but failing in some difficult cases and returning the second nearest" qualifies as "implementation-defined". There's an implementation all right but it's not much of a definition.</p> -</blockquote> -<p>An analyzer works on the source code. It is natural during the elaboration of the Abstract Syntax Tree to convert strings from the program's source code into floating-point numbers and the natural way to do this is to carefully call the host's function <code>strtof()</code> of single-precision constants and <code>strtod()</code> on double-precision constants. Unfortunately if the analyzer is running on GNU/Linux all this care is for nothing: the AST will contain wrong floating-point values (wrong in the sense of being different from the values the compiler will use for the same constants) and therefore the analyzer will for instance wrongly conclude that the program in question 5 in last post returns 1.</p> -<h2>Mitigation technique</h2> -<p>A simple technique to mitigate this issue is to analyze the program from question 5 less precisely taking into account rounding issues so as not to say anything false. This is what the value analysis in Nitrogen does:</p> -<pre>$ ~/frama-c-Nitrogen-20111001/bin/toplevel.opt -val q5.c -[...] - f1 ∈ [1.01161122322 .. 1.01161134243] - f2 ∈ [1.01161122322 .. 1.01161134243] - __retres ∈ {0; 1} -</pre> -<p>The sets computed for <code>f1</code> and <code>f2</code> are both over-approximated but correct. As a result of the approximation the analyzer is unsure whether the program returns <code>0</code> or <code>1</code>. This is a bit unsatisfactory because the analysis is imprecise on a simple and deterministic program. But at least it is sound.</p> -<h2>The solution: write your own <code>strtof()</code></h2> -<p>According to this <a href="http://www.exploringbinary.com/correct-decimal-to-floating-point-using-big-integers/">post on the Exploring Binary blog</a> it is easy to write your own correctly rounded decimal to binary function as long as you do not worry too much about performance. In the context of static analysis parsing time is small with respect to the time taken by subsequent treatments and it is reassuring to know that the values in the AST are the correct values regardless of bugs in the host's libraries. Following this principle I wrote Frama-C's own Caml conversion function based on the outline there. Preliminary tests indicate that this function is adequate for this usage. It will in all likelihood be used for both single and double precision constants in the next Frama-C release.</p> -<p>This means that the value analysis in the Oxygen release will be able to give precise and correct answers to all questions in the floating-point quiz from last post. No "maybe it is and maybe it ain't" answers as Nitrogen gives on this quiz and no incorrect answers like very old Frama-C versions gave. Here is the development version answering question 5:</p> -<pre>$ bin/toplevel.opt -val q5.c -[...] -warning: Floating-point constant 1.01161128282547f is not represented exactly. - Will use 0x1.02f8f60000000p0. See documentation for option -warn-decimal-float -[...] - f1 ∈ 1.01161134243 - f2 ∈ 1.01161122322 - __retres ∈ {0} -</pre> -<p>Small approximations soon snowball into large ones so I think it is important to be able to give the most precise value to the simplest expressions of the C language constants.</p> -<h2>Should we worry about being too precise ?</h2> -<p>The problem encountered with <code>strtof()</code> also highlights the relative fuzziness of the standard. If Frama-C is too precise it may omit the actual behavior of the program as compiled by the compiler. This would be unfortunate. Recent versions of GCC go to great lengths to offer correct rounding to nearest (using the <a href="http://www.mpfr.org/">MPFR library</a>). Another compiler may itself use <code>strtof()</code> for parsing. For covering both the possibilities that the program is compiled with GCC or this hypothetical other compiler Nitrogen's imprecise handling of single-precision constants was better.</p> -<p>I would say that a Frama-C plug-in may wish to offer both modes through a command-line option. The value analysis probably will eventually. Regardless it is also important that Frama-C always provides consistent results regardless of the host platform so it was necessary to implement a correctly rounded <code>string -> float</code> function even if we then add and subtract an ULP here and there in order to capture all possible compilations.</p> -<h2>Conclusion</h2> -<p>In the introduction I self-centeredly linked to two earlier posts from this blog. The post from one year ago showed one difficulty as an example of why single-precision floating-point was not supported precisely in Frama-C in general. The post from last week showed several contrived examples that can only be handled with a precise understanding of floating-point —including but not limited to the issue described one year ago— in the form of a quiz. -What I find interesting is that there were unforeseen difficulties in the implementation of even the foreseen difficulty of getting the right value for a single-precision constant. And to reiterate the current development version of the value analysis correctly answers all five questions in the quiz.</p> <p>This post was improved by suggestions from Fabrice Derepas and Florent Kirchner.</p> {% endraw %} diff --git a/_posts/2011-11-18-Just-a-few-more-digits-please.html b/_posts/2011-11-18-Just-a-few-more-digits-please.html index f888c1dda72d0414b8f81d2f3f31798049768661..3ed2955d628480ba0b8cb9bb829c4be044b23c17 100644 --- a/_posts/2011-11-18-Just-a-few-more-digits-please.html +++ b/_posts/2011-11-18-Just-a-few-more-digits-please.html @@ -61,59 +61,5 @@ It wouldn't be so important if every compiler had to correctly round constants t <li>That still leaves one almost unavoidable almost always unwanted warning per analysis run as soon as the program uses floating-point. Here comes my usability masterstroke: I have removed another unavoidable unwanted warning that appeared as soon as the program used floating-point. Starting with the Oxygen release floating-point will cease to be considered experimental in the value analysis and the analyzer will no longer tell you that it is each time it gets the chance keeping the signal/noise ratio about the same as before.</li> </ol> <h2>Conclusion</h2> -<p>In Frama-C Oxygen floating-point will no longer be considered experimental in the value analysis and the front-end will have a warning for inexact constants in the program. I'll bet you can't wait.</p> - <h2>Introduction: of Spivak pronouns</h2> -<p>In this post, I really let fly the <a href="http://en.wikipedia.org/wiki/Spivak_pronoun">Spivak pronouns</a>. They are not used for the first time in this blog or in documentation but they are abused here. I have no serious justification for this sudden peak. I have a couple of unserious ones: I started using Spivak pronouns a couple of years ago when I noticed that the EU expected research project proposals to explicitly state in which way the proposed project would close the gap between sexes in Europe. This is of course ridiculous. Safer and securer software verified faster and cheaper benefits everyone so we do not close any gap at all. The only way I thought to do our part here was to actively butcher the English language. Anything less would make us chauvinist pigs. So here I am.</p> -<h2>Have you been paying attention?</h2> -<p>If you were paying really close attention you may have noticed a new kind of log message in <a href="/ocaml/floating-point/2011/11/14/Analyzing-single-precision-floating-point-constants">last post</a>:</p> -<pre>warning: Floating-point constant 1.01161128282547f is not represented exactly. - Will use 0x1.02f8f60000000p0. See documentation for option -warn-decimal-float -</pre> -<p>This has been a subject of dispute between developers for a long while: should Frama-C have this warning -or is it undesirable? The reasons for having it are obvious which does not prevent them from being strong and good reasons: the program does not do what the programmer wrote. Perhaps ey thought the processor would use base-10 arithmetics to accommodate eir distasteful habit. Perhaps ey thought the computer should represent the number that ey was thinking of. Perhaps the programmer even expected the computer to <a href="http://stackoverflow.com/q/7785764/139746">understand ey meant "Ï€"</a> when ey wrote <code>3.14</code> (key quote: "I entered [sin(3.14)]. Shouldn't that give me an answer of 0? It gave me 0.001593").</p> -<p>Well of course Frama-C does not aim at being useful for users who are quite as naive as that. This constitutes in fact most of the counter argument: many numbers whether finitely representable in decimal or otherwise useful are not finitely representable as binary floating-point numbers and the programmer should know and expect this. Why tell em something ey should already know? It's a difficult line to draw.</p> -<p>In truth one reason and it's not a good one for this warning to appear now is "because we can". Function <code>strtod()</code> and its single-precision and extended-precision colleagues do not tell whether the conversion they applied was exact or rounded. But when you write your own correctly rounded version of these functions it's very easy to keep the information if you want it.</p> -<p>There is another factor at play here: how conveniently can the programmer express in eir program that ey knows what ey is doing?</p> -<h2>Example</h2> -<p>Let us look at the implications of the new message on an example. Consider the programmer who wants eir variable <code>d</code> to be initialized to the nearest double-precision representation of <code>0.1</code>. Ey writes:</p> -<pre>double d = 0.1 ; -main(){ - return 0; -} -</pre> -<p>This programmer knows what ey is doing. But Frama-C doesn't know that and just in case warns:</p> -<pre>Floating-point constant 0.1 is not represented exactly. Will use 0x1.999999999999ap-4. -</pre> -<p>The programmer could use <code>0x1.999999999999ap-4</code> as initializer of <code>d</code> but that would hardly improve the program's readability. Writing the decimal value inside a comment would still be bad style: the two constants are bound to desynchronize and then havoc will ensue. Comments are not intended for this. No the programmer may hope instead to demonstrate that ey knows what is going on by showing how many decimals he expects to be able to rely on:</p> -<pre>double d = 0.10000000000000000 ; -</pre> -<p>That doesn't work because <code>0.10000000000000000</code> is not represented exactly:</p> -<pre>Floating-point constant 0.10000000000000000 is not represented exactly. Will use… -</pre> -<p>Ah yes! thinks the programmer. I must show I understand that I can't count on decimals beyond these ones to be zeroes:</p> -<pre>double d = 0.100000000000000005 ; -</pre> -<p>But:</p> -<pre>Floating-point constant 0.100000000000000005 is not represented exactly… -</pre> -<p>Please reader allow me to make this story shorter that it could be. The programmer finally writes…</p> -<pre>double d = 0.1000000000000000055511151231257827021181583404541015625 ; -main(){ - return 0; -} -</pre> -<p>… and at last Frama-C accepts the program without a word.</p> -<h2>Mitigation techniques</h2> -<p>This is not a great user interface. The programmer must write more digits to demonstrate that ey knows exactly what the rounding error is than ey writes to unambiguously designate the double-precision floating-point ey wants. -It wouldn't be so important if every compiler had to correctly round constants to the nearest floating-point representation but as discussed in last post the standard does not mandate it. Crucially by displaying the <code>Will use 0x1.999999999999ap-4</code> part of the message Frama-C is also insuring itself against misunderstandings. The user cannot claim that because eir compiler does not round constants to the nearest Frama-C is unsound: it told em what values it would use.</p> -<blockquote><p>"Caveat emptor" or the first word thereof would make a great name for a static analysis tool but unfortunately it's already taken (by <a href="http://www.springerlink.com/content/h33p602vh34634v8/">one of the ancestors of Frama-C</a>).</p> -</blockquote> -<p>I have tried to adjust the usability compromise thus:</p> -<ol> -<li>Frama-C by default only warns about the first non-exact constant and on that occasion gives you the name of the relevant command-line option. If you want to ignore it it's only one message to skip.</li> -<li>The command-line option allows to activate warnings for all non-exact constants or for none of them if that's what you prefer.</li> -<li>That still leaves one almost unavoidable almost always unwanted warning per analysis run as soon as the program uses floating-point. Here comes my usability masterstroke: I have removed another unavoidable unwanted warning that appeared as soon as the program used floating-point. Starting with the Oxygen release floating-point will cease to be considered experimental in the value analysis and the analyzer will no longer tell you that it is each time it gets the chance keeping the signal/noise ratio about the same as before.</li> -</ol> -<h2>Conclusion</h2> <p>In Frama-C Oxygen floating-point will no longer be considered experimental in the value analysis and the front-end will have a warning for inexact constants in the program. I'll bet you can't wait.</p> {% endraw %} diff --git a/_posts/2011-11-23-Bug-in-Nitrogens-value-analysis.html b/_posts/2011-11-23-Bug-in-Nitrogens-value-analysis.html index aa73726b22144bc2144d2f6976a40ba4184d528a..e7fbf06bd5d9093e7f38f4268df722bda9b61830 100644 --- a/_posts/2011-11-23-Bug-in-Nitrogens-value-analysis.html +++ b/_posts/2011-11-23-Bug-in-Nitrogens-value-analysis.html @@ -60,58 +60,5 @@ t.c:8:[kernel] warning: out of bounds write. assert \valid(p); <p>Lastly if in the example <code>p</code> pointed only inside the literal string then the illegal write access would be even more obvious (since there would be no location for the write to happen) and the alarm would be emitted (that is the bug wouldn't occur).</p> <blockquote><p>Industrial users with SVN read access can simply use today's version where the bug is fixed.</p> </blockquote> -<p>Sometimes I wish the value analysis only propagated intervals. It would have simpler bugs then.</p> - <p>In the course of restructuring the value analysis, I noticed a difference in some regression tests. The \after" version had some new warnings that weren't in the "before" version. After further investigation it turned out that displaying the warnings was correct and that the "before" version was unsound.</p> -<p>This soundness bug is particularly hard to reproduce even if you know it's there. I am still pondering whether to back-port the fix to the released Nitrogen version because it basically means back-porting the internal architecture change not the kind of small obviously uniform improvements I like to release as post-release patches.</p> -<p>The bug appears in this example program:</p> -<pre>char *p = "foo"; -char c; -char s = 'F'; -void f(int u) -{ - if (u) p = &c; - *p = s; -} -</pre> -<p>Here is the entire output of an analysis with Nitrogen:</p> -<pre>$ ~/nitrogen-20111001/bin/toplevel.opt -val t.c -main f -[kernel] preprocessing with "gcc -C -E -I. t.c" -[value] Analyzing a complete application starting at f -[value] Computing initial state -[value] Initial state computed -[value] Values of globals at initialization - p ∈ {{ &"foo" }} - c ∈ {0} - s ∈ {70} -[value] Recording results for f -[value] done for function f -[value] ====== VALUES COMPUTED ====== -[value] Values for function f: - p ∈ {{ &c }} - c ∈ {70} -</pre> -<p>Here is the output of today's version. Can you spot the difference?</p> -<pre>[kernel] preprocessing with "gcc -C -E -I. t.c" -[value] Analyzing a complete application starting at f -[value] Computing initial state -[value] Initial state computed -[value] Values of globals at initialization - p ∈ {{ &"foo" }} - c ∈ {0} - s ∈ {70} -t.c:8:[kernel] warning: out of bounds write. assert \valid(p); -[value] Recording results for f -[value] done for function f -[value] ====== VALUES COMPUTED ====== -[value] Values for function f: - p ∈ {{ &c }} - c ∈ {70} -</pre> -<p>In Nitrogen the value analysis sees that it is illegal for <code>p</code> to point to literal string <code>"foo"</code> since <code>*p</code> is used for writing. It deduces that the value of <code>p</code> can only be <code>&c</code> and that the assignment of <code>'F'</code> (ASCII code 70) can only take place in <code>c</code> and that the final value of <code>c</code> is therefore necessarily 70 but it forgets to emit the alarm stating that <code>p</code> must not point to <code>"foo"</code>. The current development version follows the same reasoning but remembers to emit the alarm.</p> -<p>In order to observe this bug it is necessary to shape <code>*p = ...;</code> as an lvalue to lvalue assignment (<code>*p = 'F';</code> does not produce the bug). Lvalue to lvalue assignments are handled specially in order to <a href="/index.php?post/2011/01/27/On-memcpy-1">enable precise results on struct assignments</a> and <code>memcpy()</code> of addresses.</p> -<p>Besides the bug only occurs with pointers to literal strings or to arrays that are automatically allocated when the analysis entry point takes pointers in arguments — but the creation of these arrays is not documented in enough detail for users to realize there is a bug in this case.</p> -<p>Lastly if in the example <code>p</code> pointed only inside the literal string then the illegal write access would be even more obvious (since there would be no location for the write to happen) and the alarm would be emitted (that is the bug wouldn't occur).</p> -<blockquote><p>Industrial users with SVN read access can simply use today's version where the bug is fixed.</p> -</blockquote> <p>Sometimes I wish the value analysis only propagated intervals. It would have simpler bugs then.</p> {% endraw %} diff --git a/_posts/2011-11-23-Fixes-in-Nitrogens-value-analysis.html b/_posts/2011-11-23-Fixes-in-Nitrogens-value-analysis.html index f1d55de4e4b564998cbd4010b769cf409d38cf7b..6ef3d3b647447693e3301e21e56af8c8bf3cda7b 100644 --- a/_posts/2011-11-23-Fixes-in-Nitrogens-value-analysis.html +++ b/_posts/2011-11-23-Fixes-in-Nitrogens-value-analysis.html @@ -11,9 +11,5 @@ summary: <p>Speaking of bug fixes, <a href="/assets/img/blog/imported-posts/nitrogen_patchlevel_1">here is</a> what a proper post-release patch looks like. This patch fixes five issues identified since Nitrogen was released. I have not tested the patch itself (I have not even tried applying it to the original tarball) — this is where you come in dear reader. Let's call it "patchlevel 1" for now. It may be given more official status if no additional fixes are incorporated. Or perhaps not even then.</p> <p>It is recommended for users who build from source and for packagers who always manage their own sets of patches anyway. It contains only fixes for confirmed issues and each fix is simple enough to be an obviously uniform improvement.</p> -<p>Boris Yakobowski contributed several of the fixes in patchlevel 1. To be fair he may in the course of his excellent and broad-scoped developments have originally contributed some of the bugs being fixed too.</p> - <p>Speaking of bug fixes, <a href="/assets/img/blog/imported-posts/nitrogen_patchlevel_1">here is</a> what a proper post-release patch looks like. This patch fixes five issues identified since Nitrogen was released. I have not tested the patch itself (I have not even tried applying it to the original tarball) — this is where you come in dear reader. -Let's call it "patchlevel 1" for now. It may be given more official status if no additional fixes are incorporated. Or perhaps not even then.</p> -<p>It is recommended for users who build from source and for packagers who always manage their own sets of patches anyway. It contains only fixes for confirmed issues and each fix is simple enough to be an obviously uniform improvement.</p> <p>Boris Yakobowski contributed several of the fixes in patchlevel 1. To be fair he may in the course of his excellent and broad-scoped developments have originally contributed some of the bugs being fixed too.</p> {% endraw %} diff --git a/_posts/2011-11-25-Static-analysis-tools-comparisons.html b/_posts/2011-11-25-Static-analysis-tools-comparisons.html index f61bdcac5cd024bd2e67f1c91b2ac561ce8a657a..bb92363797c8a2a3d5e1498fc61442e543f2715a 100644 --- a/_posts/2011-11-25-Static-analysis-tools-comparisons.html +++ b/_posts/2011-11-25-Static-analysis-tools-comparisons.html @@ -130,128 +130,5 @@ ps_ovfl.c:5:[kernel] warning: overflow in float (0x1.fffffe091ff3dp127). </pre> <h2>Conclusion</h2> <p>In conclusion we should be careful about the way we express ourselves: static analysis has been oversold enough already. We would do well to learn the rules we pretend to enforce and we should avoid picking on other toolmakers something which is detrimental for all and that I do not completely avoid in this post. However I use each tool's own example which I think is a good sign that there is still some major overselling going on despite how detrimental this has already been in the past. I would tell you about examples on PVS-Studio's website but at least it has different goals and does not use the verb "prove" in the sense "my imperfect implementation based on an idealized formalization computes that…" all the time.</p> -<p>To end on a lighter note here is <a href="http://lcamtuf.coredump.cx/staticanalysis.jpg">a funny picture</a> to meditate.</p> - <p>It is very easy to make snap judgments about other static analyzers when you are yourself working on one. You do not even need to act in bad faith: you just try the other tools on the programs that you worked hard to give interesting results on — difficult examples, on which even your own tool does not give the best result. You intend to give the other tool a passing grade if it produces a result as approximated as yours, and to acknowledge that it's not as bad as you thought if it gives a better result.</p> -<p>The flaw in this line of reasoning is that even if you were honest enough to pick an example on which it was possible to improve on your own tool's result, you picked one on which your tool begins to produce a result. The example is automatically in the language subset that your analyzer handles, probably in the language subset it targets. The comparison is still heavily biased in favor of your tool, whether you realize it or not. This is how you may end up thinking that Frama-C's value analysis only manipulates intervals: by only trying it on programs for which it displays intervals (programs, say, translated to C from this <a href="http://pop-art.inrialpes.fr/interproc/interprocweb.cgi">toy language</a>).</p> -<h2>Astrée</h2> -<p>It is more instructive to take examples from other tools' websites the examples that they use to advertise and to see what your own tool can do with them. Let us do this in this post.</p> -<h3>Feeling lucky?</h3> -<p>Here is one:</p> -<p><img src="/assets/img/blog/imported-posts/astree.png" alt="astree.png" style="display:block; margin:0 auto;" title="astree.png nov. 2011" /></p> -<p>Let's try it in Frama-C's value analysis:</p> -<pre>$ bin/toplevel.opt -val astree.c -[kernel] preprocessing with "gcc -C -E -I. astree.c" -astree.c:4: Floating-point constant 1.0e38 is not represented exactly. - Will use 0x1.2ced32a16a1b1p126. See documentation for option -warn-decimal-float -... -astree.c:4: accessing uninitialized left-value: assert \initialized(&x); -astree.c:4: completely undefined value in {{ x -> {0} }} (size:<32>). -... -[value] Values at end of function main: - NON TERMINATING FUNCTION -</pre> -<p>The webpage adds: "Astrée proves that the above program is free of run-time errors when running on a machine with floats on 32 bits." That's reassuring. If we had not read that we might have feared that it contained undefined behavior due to the use of uninitialized variable <code>x</code> (and perhaps others but really there is such a big problem with <code>x</code> that the value analysis did not look any further). "Undefined behavior" means that anything can happen and you should consider yourself lucky if it's a run-time error. With an uninitialized float variable you just might be lucky (and get a run-time error instead of the proverbial demons flying out of your nose): the compiler may produce code that reads bits from the stack that happen to represent a signaling NaN and then applies a floating-point operation to it causing a run-time error.</p> -<h3>Miscommunication</h3> -<p>To be fair the release notes for the latest version of Astrée said that it could now emit alarms for uninitialized variables. I look forward to an example illustrating that. Perhaps that example will demonstrate an unsoundness in Frama-C's value analysis who knows?</p> -<p>Also the sentence "Astrée proves that the above program is free of run-time errors…" really means "Astrée does not find any of the run-time errors that it detects in the above program" and both its designers and its users at Airbus Operations S.A. are aware of this meaning. It's just that the somewhat pompous formulation is a little bit unfortunate on this example.</p> -<p>Coincidentally I sometimes notice the same phrase used about "Frama-C" this time by makers of comparable tools as below:</p> -<blockquote><p>Frama-C "proves" [something ridiculous] about [this program].</p> -</blockquote> -<p>It's usually just another instance of someone running other tools on the examples eir tool is good at of course and might more objectively be phrased as:</p> -<blockquote><p>An external plug-in of Frama-C separately distributed written by a PhD student so brilliant that he was able to produce useful software during his PhD in addition to making several solid contributions to the science of program analysis "proves" [something ridiculous] about [a program that's out of scope for this plug-in].</p> -</blockquote> -<p>It doesn't have the same ring to it. I see why toolmakers prefer to peddle their own imperfect creations using the first sentence.</p> -<h2>Polyspace</h2> -<h3>So many rhetorical questions</h3> -<p>Polyspace's website has this example:</p> -<p><img src="/assets/img/blog/imported-posts/polyspace.png" alt="polyspace.png" style="display:block; margin:0 auto;" title="polyspace.png nov. 2011" /></p> -<p>On the webpage the explanation of why this example is interesting is a little confusing:</p> -<blockquote><p>Now rounding is not the same when casting a constant to a float or a constant to a double:</p> -<p> -* floats are rounded to the nearest lower value;</p> -<p> -* doubles are rounded to the nearest higher value;</p> -</blockquote> -<p>Now are they really? Floating-point has an aura of arbitrariness about it but that would be a little bit over the top wouldn't it? Isn't it just that the number <code>3.40282347e+38</code> when rounded to float in round-to-nearest mode rounds downwards and when rounded to double in round-to-nearest mode rounds upwards?</p> -<h3>Letting the compiler be the judge</h3> -<p>According to the colored comments in the program Polyspace guarantees that there is an overflow. Well let's try it then:</p> -<pre>$ bin/toplevel.opt -val ps_ovfl.c -warn-decimal-float all -float-hex -... -ps_ovfl.c:4: Floating-point constant 3.40282347e+38f is not represented exactly. - Will use 0x1.fffffe0000000p127 -ps_ovfl.c:5: Floating-point constant 3.40282347e+38 is not represented exactly. - Will use 0x1.fffffe091ff3dp127 -... -[value] Values at end of function main: - x ∈ 0x1.fffffe0000000p127 - y ∈ 0x1.fffffe0000000p127 -</pre> -<p>Frama-C's value analysis does not agree about the example. Ah but this is about floating-point subtleties. It's not a cut-and-dry case of uninitialized variable. Perhaps Polyspace is right. However we may remember that in floating-point an overflow is not a run-time error: it produces an infinity a special kind of value that some numerical algorithms handle correctly but most don't. It makes sense for a static analyzer to treat infinities as errors (in fact the value analysis does too) but if a static analyzer says that an overflow certainly occurs(red alarm) and we are unsure of this diagnostic we <strong>can</strong> run the program and see what happens. It's not undefined in the C sense.</p> -<pre>#include <stdio.h> -void main(void) -{ - float x y; - x = 3.40282347e+38f; // is green - y = (float) 3.40282347e+38; // OVFL red - printf("%a %a %d" x y x == y); -} -</pre> -<pre>$ gcc ps_ovfl_modified.c -... -~/ppc $ ./a.out -0x1.fffffep+127 0x1.fffffep+127 1 -</pre> -<p>No no overflow it seems. Polyspace's red alarm led us to expect the output <code>0x1.fffffep+127 inf 0</code> but that's not what happens.</p> -<h3>An explanation why Polyspace makers think there should be an overflow</h3> -<p>The explanation on the webpage continues:</p> -<blockquote><p>In the case of the second assignment the value is cast to a double first - by your compiler using a temporary variable D1 - then into a float - another temporary variable - because of the cast. Float value is greater than MAXFLOAT so the check is red.</p> -</blockquote> -<p>Unfortunately this not how round-to-nearest works. When a double here <code>0x1.fffffe091ff3dp127</code> falls between two floats here <code>0x1.fffffep127</code> (MAXFLOAT) and <code>+infinity</code> the nearest one should be picked.</p> -<h3>A philosophical conundrum</h3> -<p>Which is nearest between a finite float and an infinite one? I would like to recommend this question for the next philosophy A-levels (or equivalent worldwide). In the world of IEEE 754 the answer is terribly pragmatic. Infinity starts at the first number in floating-point format that can't be represented for having too high an exponent. For single-precision this number is <code>0x1.0p128</code>. The midpoint between this unrepresentable number and the last finite float <code>0x1.fffffep127</code> is <code>0x1.ffffffp127</code> and therefore in round-to-nearest all numbers above <code>0x1.ffffffp127</code> round up to <code>+inf</code> whereas numbers below <code>0x1.ffffffp127</code> round down to <code>0x1.fffffep127</code>.</p> -<h3>Experimentation</h3> -<p>The number <code>0x1.ffffffp127</code> is representable as a <code>double</code> so that we can obtain a decimal approximation of it with a simple C program:</p> -<pre>#include <stdio.h> -main(){ - printf("%.16e" 0x1.ffffffp127); -} -$ gcc limit.c -$ ./a.out -3.4028235677973366e+38 -</pre> -<p>My claim is that regardless of what Polyspace's website says and although the number <code>3.402823567797336e+38</code> is much larger than the number in their example you can round it to a <code>double</code> and then to a <code>float</code> and you will still get the finite <code>0x1.fffffep127</code> (MAXFLOAT). Conversely the number <code>3.402823567797337e+38</code> is on the other side of the fence and rounds to <code>+inf</code>.</p> -<p>We can try it out:</p> -<pre>#include <stdio.h> -main(){ - printf("%a %a" (float) 3.402823567797336e+38 (float) 3.402823567797337e+38); -} -$ gcc experiment1.c -$ ./a.out -0x1.fffffep+127 inf -</pre> -<p>What about the number <code>3.4028235677973366e+38</code>? It is even more amusing. It is below the fence and converted directly to <code>float</code> it gives <code>0x1.fffffep127</code>. However converted to double it rounds to <code>0x1.ffffffp127</code>. Then when rounding to float the "even" rule for picking between two equidistant floats results in <code>0x1.0p128</code> being picked and the final float result is therefore <code>+inf</code>.</p> -<pre>#include <stdio.h> -main(){ - printf("%a %a" 3.4028235677973366e+38f (float) 3.402823567797366e+38); -} -$ gcc experiment2.c -$ ./a.out -0x1.fffffep+127 inf -</pre> -<p>This is a case of double rounding just like in question 5 <a href="/conversions-and-promotions/floating-point/2011/11/08/Floating-point-quiz">here</a>.</p> -<h3>But really Polyspace wouldn't be that wrong would it?</h3> -<p>I'm afraid it would. Unlike the webpage on Astrée's site I cannot find any plausible explanation for the misunderstanding. The example is wrong and the explanations that follow make it worse. It could be the case that Polyspace gives results that cover all possible floating-point rounding modes just like the value analysis option <code>-all-rounding-modes</code> does. There would be an overflow then (in round-upwards mode). Unfortunately Polyspace would have to emit an orange since in round-to-nearest and in round-downwards there is no overflow. It would have to produce results similar to those below predicting that either the overflow or the normal termination of the program can happen.</p> -<pre>$ bin/toplevel.opt -val ps_ovfl.c -all-rounding-modes -float-hex -... -ps_ovfl.c:5:[kernel] warning: overflow in float (0x1.fffffe091ff3dp127). - assert -0x1.fffffe0000000p127f ≤ (float)3.40282347e+38 ∧ - (float)3.40282347e+38 ≤ 0x1.fffffe0000000p127f; -... -[value] Values at end of function main: - x ∈ 0x1.fffffe0000000p127 - y ∈ 0x1.fffffe0000000p127 -</pre> -<h2>Conclusion</h2> -<p>In conclusion we should be careful about the way we express ourselves: static analysis has been oversold enough already. We would do well to learn the rules we pretend to enforce and we should avoid picking on other toolmakers something which is detrimental for all and that I do not completely avoid in this post. However I use each tool's own example which I think is a good sign that there is still some major overselling going on despite how detrimental this has already been in the past. I would tell you about examples on PVS-Studio's website but at least it has different goals and does not use the verb "prove" in the sense "my imperfect implementation based on an idealized formalization computes that…" all the time.</p> <p>To end on a lighter note here is <a href="http://lcamtuf.coredump.cx/staticanalysis.jpg">a funny picture</a> to meditate.</p> {% endraw %} diff --git a/_posts/2011-12-04-Explaining-why-Csmith-matters-even-more-than-previously-anticipated.html b/_posts/2011-12-04-Explaining-why-Csmith-matters-even-more-than-previously-anticipated.html index c4d7afdf73888f22da3cb57b48c95f6acfba26da..7822077393652e81e2548f210836c40a0de220bc 100644 --- a/_posts/2011-12-04-Explaining-why-Csmith-matters-even-more-than-previously-anticipated.html +++ b/_posts/2011-12-04-Explaining-why-Csmith-matters-even-more-than-previously-anticipated.html @@ -24,22 +24,5 @@ summary: <p>A Frama-C workshop or a Csmith workshop if either one existed would be a perfect fit. One half of the contents would make the report fully on-topic while the other half would give it a touch of exoticism. Unfortunately both are research tools without the users to justify their own event. John Regehr presented Csmith as the GCC Summit and I guess this might be a possibility but this potential report is at most on-topic by association there. On the static analysis side I do not see too many people being interested in the minutiae of C's pitfalls. One impression I got at ICPC and already commented on in this blog was that the "It's possible to do things on Java so let's study Java" school of thought has more proponents than the "There are large codebases in C let's see what we can do about C" school of thought. Even among the latter I am a bit worried such a report would be perceived as dealing with the details that other researchers have already interiorized as unimportant when they decided to ignore them in their own work.</p> <p>I am not complaining. In a world in which either Frama-C or Csmith or comparable tools were widely used someone would already have done this experiment before me. I might even have had to read a book discussing the proper way to do this sort of thing before I started. Truly each researcher probably finds emself in the same situation at one point or another. Experimented researchers are those who have learnt to anticipate that a possible line of work even if it gives useful results will give results that are hard to publish.</p> -<p>I am lucky in that "researcher" is only half my job description. Inventing methods to test Frama-C with Csmith as we were going along was much fun and fixing the bugs was the first and foremost objective.</p> - <h2>Csmith as a static analyzer fuzzer</h2> -<p>A new version of Csmith, the generator of random defined C programs, <a href="http://blog.regehr.org/archives/631" hreflang="en">was released a few days ago</a>. This is the version that many functions in Frama-C Nitrogen were <a href="/csmith/position/2011/07/30/We-have-a-Csmith-proof-framework">debugged against</a>. Conversely a few bugs in the development versions of Csmith characterized by programs being generated that were not defined (although they compiled and ran fine) were found by pre-Nitrogen development versions of Frama-C and are fixed in the 2.1.0 Csmith release.</p> -<p>The original intention behind Csmith was to find bugs in compilers. As I pointed out in earlier posts Csmith can also find bugs in static analysis tools.</p> -<blockquote><p>Here is <a href="http://bts.frama-c.com/view.php?id=1024">the latest bug found</a> by Csmith in Frama-C. To explain: ACSL properties such as alarms emitted by the value analysis are attached to the beginning of statements. When the danger is in the implicit cast in the assignment of a function's result to an lvalue the AST may have been normalized in such a way there is no good place to attach the corresponding alarm: before the assignment-cum-function-call it is too early to express properties about the function's result and after it it is too late. This Frama-C bug was found last because it cannot be found by <a href="/index.php?post/2011/03/01/Interpretation-speed">using the value analysis as a C interpreter</a> on defined programs my initial testing method. In order to find this bug alarms must be emitted during the analysis and there aren't any when interpreting a defined program. The bug was found with a different testing method where the value analysis is <strong>not</strong> used as an interpreter makes approximations and therefore emit alarms. A simple workaround for this bug is to normalize the program differently using the pre-existing option <code>-no-collapse-call-cast</code>.</p> -</blockquote> -<h2>One shouldn't base a research project on another research project</h2> -<p>I was Benjamin C. Pierce's intern for a couple of months as an undergraduate. The title of this section is one of the insights he gave me then that stuck. In context he probably meant the obvious fact that you do not want to spend your time running into bug after bug in the prototypal implementation left from the initial research project. Another more insidious way this warning holds is that even if the ideas from the first project have a solid implementation you may encounter a problem finding a public to tell about what you've done.</p> -<p>I find myself in a position where I would like to tell people that Csmith is even more useful than previously anticipated. It can not only find bugs in compilers but also with some effort in static analyzers. Isn't that important? (alright perhaps I am biased here)</p> -<p>Besides even when there is no bug to find Csmith can point out differences in assumptions between the static analyzer and the compiler used to compile safety-critical code. One thing I discovered using Csmith was for instance that you shouldn't expect different compilers to handle zero-width bitfields in packed structs the same way. None of the compilers I tried was wrong they were just using different conventions. Frama-C implements one of the conventions. I have simply added this combination of constructs to the list of features to check either that the analyzed program does not use or that the target compiler implements exactly the same way as Frama-C.</p> -<blockquote><p>Sadly Csmith authors think that generating programs that reveal these differences detracts from Csmith's original goals. When Csmith is used as originally intended compilers are compared to one another. If they do not give the same result one of them must be wrong. So they removed these combinations from the generated programs as I was reporting them (and they probably removed many more on their own that would have been interesting in the context of verifying that a static analyzer is well-matched with a specific compiler).</p> -</blockquote> -<h2>An experience report looking for a public</h2> -<p>That Csmith is even more useful than anticipated is only the (luckily positive) conclusion of the experiment. Building up to this conclusion there are the methods that were used in order to test various Frama-C functions the categorization of bugs that were found in both Frama-C and Csmith and perhaps a couple of interesting examples of these. This could fit well in the "experience report" format that some conferences have a tag for in their calls for papers. But I have had little success digging up a conference where submitting would not be a waste of time for me and for the future reviewers.</p> -<p>A Frama-C workshop or a Csmith workshop if either one existed would be a perfect fit. One half of the contents would make the report fully on-topic while the other half would give it a touch of exoticism. Unfortunately both are research tools without the users to justify their own event. John Regehr presented Csmith as the GCC Summit and I guess this might be a possibility but this potential report is at most on-topic by association there. On the static analysis side I do not see too many people being interested in the minutiae of C's pitfalls. One impression I got at ICPC and already commented on in this blog was that the "It's possible to do things on Java so let's study Java" school of thought has more proponents than the "There are large codebases in C let's see what we can do about C" school of thought. Even among the latter I am a bit worried such a report would be perceived as dealing with the details that other researchers have already interiorized as unimportant when they decided to ignore them in their own work.</p> -<p>I am not complaining. In a world in which either Frama-C or Csmith or comparable tools were widely used someone would already have done this experiment before me. I might even have had to read a book discussing the proper way to do this sort of thing before I started. -Truly each researcher probably finds emself in the same situation at one point or another. Experimented researchers are those who have learnt to anticipate that a possible line of work even if it gives useful results will give results that are hard to publish.</p> <p>I am lucky in that "researcher" is only half my job description. Inventing methods to test Frama-C with Csmith as we were going along was much fun and fixing the bugs was the first and foremost objective.</p> {% endraw %} diff --git a/_posts/2011-12-05-Formidable-colleagues-patchlevels-and-new-features-in-Nitrogen.html b/_posts/2011-12-05-Formidable-colleagues-patchlevels-and-new-features-in-Nitrogen.html index c4e192c617126bd41183284092b668c708df64ce..db64fb92865663e8ac892522bb3f1d4d8b7caf73 100644 --- a/_posts/2011-12-05-Formidable-colleagues-patchlevels-and-new-features-in-Nitrogen.html +++ b/_posts/2011-12-05-Formidable-colleagues-patchlevels-and-new-features-in-Nitrogen.html @@ -32,30 +32,5 @@ bl.c:8:[kernel] warning: out of bounds write. assert \valid(p); <p>One of the next steps will be to transform the "<code>p</code> points somewhere writable" condition before the assignment into "<code>u</code> is non-null" as a pre-condition of function <code>f()</code> using weakest pre-condition computation. Quite a lot of effort remains before this works. For one thing the value analysis does not yet distinguish between "valid for reading" and "valid for writing" in the ACSL predicates it annotates the program with (although it makes the distinction in the log messages).</p> <blockquote><p>Speaking of string constants I should also mention that the value analysis in Nitrogen emits a warning for <code>"foo" == "foo"</code>. I already boasted about that <a href="/index.php?post/2011/06/04/Valid-compare-pointers">here</a> but Nitrogen wasn't released at the time.</p> </blockquote> -<p>This post was brought to you thanks to the formidableness of Philippe Herrmann Virgile Prevosto and Boris Yakobowski.</p> - <p>My colleagues are formidable. Over the last few days, three of them fixed four bugs in my code. And one of the fixes was a simple, obviously correct fix for the bug previously discussed <a href="/index.php?post/2011/11/23/Bug-in-Nitrogen">here</a>.</p> -<p>In celebration of these terrific colleagues here is a new patchset for Nitrogen 20111001 <a href="/assets/img/blog/imported-posts/patchlevel2">patchlevel 2</a>. It replaces patchlevel 1. I have tested it as thoroughly as the previous one that is I didn't even check if it applied cleanly to the Nitrogen tarball.</p> -<p>Finally with the aforementioned bugfix out the door it is time to boast about another new feature available in Nitrogen: <strong>string constants</strong>. String constants are now properly treated as read-only: the program is not supposed to write there. If it does an alarm is emitted and for the sake of precision when analyzing the rest of the program it is assumed that the write did not take place in the string constant. If the pointer could also point somewhere writable then the write is assumed to take place there instead. If the pointer was only pointing to read-only or otherwise unwritable locations the propagation ends for that state.</p> -<p>If this seems a bit abstract here is the same example as before revisited:</p> -<pre>char *p = "foo"; -char c; -char s = 'F'; -void f(int u) -{ - if (u) p = &c; - *p = s; -} -</pre> -<p>Treating <code>f</code> as the entry point of the program the analyzer doesn't know what values may be passed for the argument <code>u</code>. Just before assigning to <code>*p</code> it assumes that <code>p</code> may point to <code>c</code> or inside <code>"foo"</code> but as the program tries to write to <code>*p</code> it warns that <code>p</code> had better point somewhere writable and since the user will of course make sure of that it then knows that <code>p</code> points to <code>c</code> and since <code>p</code> was pointing to <code>c</code> it also knows that <code>c</code> contains <code>'F'</code> at the end of the function:</p> -<pre>... -bl.c:8:[kernel] warning: out of bounds write. assert \valid(p); -... -[value] Values at end of function f: - p ∈ {{ &c }} - c ∈ {70} -</pre> -<p>One of the next steps will be to transform the "<code>p</code> points somewhere writable" condition before the assignment into "<code>u</code> is non-null" as a pre-condition of function <code>f()</code> using weakest pre-condition computation. Quite a lot of effort remains before this works. For one thing the value analysis does not yet distinguish between "valid for reading" and "valid for writing" in the ACSL predicates it annotates the program with (although it makes the distinction in the log messages).</p> -<blockquote><p>Speaking of string constants I should also mention that the value analysis in Nitrogen emits a warning for <code>"foo" == "foo"</code>. I already boasted about that <a href="/index.php?post/2011/06/04/Valid-compare-pointers">here</a> but Nitrogen wasn't released at the time.</p> -</blockquote> <p>This post was brought to you thanks to the formidableness of Philippe Herrmann Virgile Prevosto and Boris Yakobowski.</p> {% endraw %} diff --git a/_posts/2011-12-09-Overconfidence-expected.html b/_posts/2011-12-09-Overconfidence-expected.html index 821ce3b8d6efafe0713bc7dc3be4f31514d2ce52..1ca9a98054c4de88e1754ac385d2d8c84586e65f 100644 --- a/_posts/2011-12-09-Overconfidence-expected.html +++ b/_posts/2011-12-09-Overconfidence-expected.html @@ -11,9 +11,5 @@ summary: <p>I was previously complaining about the use of the word \prove" when describing either what Frama-C or another tool does to mean something other than what it means. But it seems we have come to the point over-confidence is actually expected lest readers get confused. In a submitted article one reviewer pointed out:</p> <blockquote><p>The authors themselves are not sure about the quality of the [proprietary] plug-in as "[the proprietary plug-in] SEEMS to produce correct results"</p> </blockquote> -<p>The verb "seems" in the original sentence only means that the proprietary plug-in produces sound results on all the 40000 lines the article documents it has been tried on but that we cannot exhibit a Coq witness of the soundness proof at this time. Anyway since this sentence was confusing it has been changed into a blanket statement of absolute confidence.</p> - <p>I was previously complaining about the use of the word \prove" when describing either what Frama-C or another tool does to mean something other than what it means. But it seems we have come to the point over-confidence is actually expected lest readers get confused. In a submitted article one reviewer pointed out:</p> -<blockquote><p>The authors themselves are not sure about the quality of the [proprietary] plug-in as "[the proprietary plug-in] SEEMS to produce correct results"</p> -</blockquote> <p>The verb "seems" in the original sentence only means that the proprietary plug-in produces sound results on all the 40000 lines the article documents it has been tried on but that we cannot exhibit a Coq witness of the soundness proof at this time. Anyway since this sentence was confusing it has been changed into a blanket statement of absolute confidence.</p> {% endraw %} diff --git a/_posts/2011-12-23-Z3-theorem-prover-in-Microsoft-Store-and-retrocomputing-Frama-C-package.html b/_posts/2011-12-23-Z3-theorem-prover-in-Microsoft-Store-and-retrocomputing-Frama-C-package.html index d26d29754d7d83d4b26336e63baac45d4908c6ea..7652c572e6c5005a8054eaddf190233b5a5b526a 100644 --- a/_posts/2011-12-23-Z3-theorem-prover-in-Microsoft-Store-and-retrocomputing-Frama-C-package.html +++ b/_posts/2011-12-23-Z3-theorem-prover-in-Microsoft-Store-and-retrocomputing-Frama-C-package.html @@ -14,12 +14,5 @@ summary: For some examples Yannick Moy wrote a rather nice <a href="http://frama-c.com/jessie/jessie-tutorial.pdf">tutorial</a> introducing Jessie. Jessie is not the only tool that applies Hoare rules mechanically to verify a program against a specification. There's another one right in Frama-C named Wp in addition to all such verifiers that aren't Frama-C plug-ins.</p> <p>Both Jessie and Wp can use Z3 in the last step of their work in which verifying a program against its specification is reduced to checking the validity of a number of logic formulas (you may have done that by hand during your computer science studies too and again it's much more fun when the computer does it).</p> <p>I would be remiss if I didn't mention that for the same price as the "non-commercial use only" Z3 license you can get a commercial-use-allowing license for competing (and competitive) SMT prover <a href="http://ergo.lri.fr/">Alt-Ergo</a>. I expect that by contrast the $15 000 Z3 license includes bare-bones support but if that sum of money is burning a hole in your pocket you might also discuss the possibility of an agreement with the makers of Alt-Ergo. They are researchers with lots of competing demands on their time but you may be able to work something out.</p> -<p>Lastly if you are interested in Alt-Ergo and/or the Wp Frama-C plug-in and have a PowerPC Mac you're in luck! The last version (0.94) of Alt-Ergo is included in this semi-official <a href="http://www.mediafire.com/?vfmb6hsw08eeno0">retrocomputing Frama-C Nitrogen binary package</a> for Mac OS X Leopard PowerPC. <a href="/assets/img/blog/imported-posts/README_ppc">Click here</a> for the "readme" of that package. The package is mostly a celebration of the <a href="/index.php?post/2011/10/17/Features-in-Nitrogen-1">performance improvements in the value analysis in Nitrogen</a> that make it very usable on a G4 powerbook.</p> - <p>This <a href="http://www.microsoftstore.com/store/msstore/en_US/pd/productID.242666500">page</a> where Microsoft Research's Z3 theorem prover is on sale for for just a bit less than $15 000 has come to my attention. This is interesting because Z3 is at the same time a <a href="http://research.microsoft.com/en-us/downloads/0a7db466-c2d7-4c51-8246-07e25900c7e7/">free download</a>. Note that the free download is covered by <a href="http://research.microsoft.com/en-us/downloads/0a7db466-c2d7-4c51-8246-07e25900c7e7/Z%203%20MSR-LA%20(2007-07-07).txt">this license</a> (executive summary: "non-commercial use only"). Presumably the $15 000 price tag buys you a more traditional license agreement.</p> -<p>I have two theories: the first is that the page is a mistake or a draft that was put online prematurely. The other is that Z3 is indeed now for sale for productive use which would be great news.</p> -<p>Z3 is an SMT solver that can be used among other applications as the last step of a program's verification through Hoare logic techniques. If you are from my generation and depending where you studied you may hazily remember from your studies applying Hoare logic rules by hand on simple programs... on paper. Well a decade's worth of research later it turns out it is much less tedious when the computer applies the rules automatically and then it even scales to moderately large functions whose verification may genuinely preoccupy someone. -For some examples Yannick Moy wrote a rather nice <a href="http://frama-c.com/jessie/jessie-tutorial.pdf">tutorial</a> introducing Jessie. Jessie is not the only tool that applies Hoare rules mechanically to verify a program against a specification. There's another one right in Frama-C named Wp in addition to all such verifiers that aren't Frama-C plug-ins.</p> -<p>Both Jessie and Wp can use Z3 in the last step of their work in which verifying a program against its specification is reduced to checking the validity of a number of logic formulas (you may have done that by hand during your computer science studies too and again it's much more fun when the computer does it).</p> -<p>I would be remiss if I didn't mention that for the same price as the "non-commercial use only" Z3 license you can get a commercial-use-allowing license for competing (and competitive) SMT prover <a href="http://ergo.lri.fr/">Alt-Ergo</a>. I expect that by contrast the $15 000 Z3 license includes bare-bones support but if that sum of money is burning a hole in your pocket you might also discuss the possibility of an agreement with the makers of Alt-Ergo. They are researchers with lots of competing demands on their time but you may be able to work something out.</p> <p>Lastly if you are interested in Alt-Ergo and/or the Wp Frama-C plug-in and have a PowerPC Mac you're in luck! The last version (0.94) of Alt-Ergo is included in this semi-official <a href="http://www.mediafire.com/?vfmb6hsw08eeno0">retrocomputing Frama-C Nitrogen binary package</a> for Mac OS X Leopard PowerPC. <a href="/assets/img/blog/imported-posts/README_ppc">Click here</a> for the "readme" of that package. The package is mostly a celebration of the <a href="/index.php?post/2011/10/17/Features-in-Nitrogen-1">performance improvements in the value analysis in Nitrogen</a> that make it very usable on a G4 powerbook.</p> {% endraw %} diff --git a/_posts/2011-12-30-Christmas-and-social-networks.html b/_posts/2011-12-30-Christmas-and-social-networks.html index 580da604fec2ba5a2c5e4074a762db5593d41477..df42853a1780edcc4db56ff03227b94c8c295fef 100644 --- a/_posts/2011-12-30-Christmas-and-social-networks.html +++ b/_posts/2011-12-30-Christmas-and-social-networks.html @@ -15,12 +15,5 @@ For instance I learned that French science TV show "C'est pas sorcier" is avail <p>I would recommend the friend who gave this DVD set to his child and is now ripping them to a more convenient format to remove that episode but in truth the episode is no different from the others. They all seem magical. If a professor of physics comes on record to explain something you implicitly trust him to know about the scientific method but as long as you do not reproduce all the experiments both positive and negative and the reasoning you're just watching a TV show.</p> <p>I googled various keywords hoping to find a reference for that partially remembered episode. No luck. Let me just warn you against googling "science dowsing". It made me sad. But <a href="http://www.fanfiction.net/s/5782108/1/Harry_Potter_and_the_Methods_of_Rationality">here's a link</a> about the scientific method that I found amusing. Key quote (people who want to believe in dowsing forget all the time that the dowsers have agreed to the conditions of the tests that later show nothing special is happening):</p> <blockquote><p>"Now just to be clear " Harry said "if the professor does levitate you Dad when you know you haven't been attached to any wires that's going to be sufficient evidence. You're not going to turn around and say that it's a magician's trick. That wouldn't be fair play. If you feel that way you should say so now and we can figure out a different experiment instead."</p> -</blockquote>" <p>I would use a social network where the discussions are about the near future's zeitgeist. As they are, people just use them to discuss what is happening now (\what are you doing?") which does not have the same usefulness.</p> -<p>Case in point: Christmas just came and went; presents given and received are discussed. Tons of great ideas if you are following people with interests similar to yours. But just a bit too late to use for yourself either for giving or as suggestion. Just wait till next year! -For instance I learned that French science TV show "C'est pas sorcier" is available in a new 38 DVD complete set. Well I could use one of these if you see what I mean. Did I mention that Christmas 2012 is barely 360 days away?</p> -<p>Reminiscing about this TV show I remembered their one slip-up an episode with an allusion to dowsing. My memory is hazy but I think it was just a parenthesis inside a larger and hopefully more researched topic.</p> -<p>I would recommend the friend who gave this DVD set to his child and is now ripping them to a more convenient format to remove that episode but in truth the episode is no different from the others. They all seem magical. If a professor of physics comes on record to explain something you implicitly trust him to know about the scientific method but as long as you do not reproduce all the experiments both positive and negative and the reasoning you're just watching a TV show.</p> -<p>I googled various keywords hoping to find a reference for that partially remembered episode. No luck. Let me just warn you against googling "science dowsing". It made me sad. But <a href="http://www.fanfiction.net/s/5782108/1/Harry_Potter_and_the_Methods_of_Rationality">here's a link</a> about the scientific method that I found amusing. Key quote (people who want to believe in dowsing forget all the time that the dowsers have agreed to the conditions of the tests that later show nothing special is happening):</p> -<blockquote><p>"Now just to be clear " Harry said "if the professor does levitate you Dad when you know you haven't been attached to any wires that's going to be sufficient evidence. You're not going to turn around and say that it's a magician's trick. That wouldn't be fair play. If you feel that way you should say so now and we can figure out a different experiment instead."</p> -</blockquote>" +</blockquote> {% endraw %} diff --git a/_posts/2011-12-30-More-Christmas-rant.html b/_posts/2011-12-30-More-Christmas-rant.html index 51f6d3f6a19f2307080fc1805e9a682a90a9702d..da3a4046388f50132387e329a1c919ff44bf4237 100644 --- a/_posts/2011-12-30-More-Christmas-rant.html +++ b/_posts/2011-12-30-More-Christmas-rant.html @@ -13,11 +13,5 @@ summary: <p>I have played Wolfenstein a little bit now and it's a lot of fun. The decors are beautifully rendered and dynamic (objects that would have been immovable in other games tumble when you use a grenade nearby). There are some original ideas the whole thing is very playable with a couple of nice references to previous opuses. And it does not open with a torture scene. I'm not suggesting you put it in the hands of children I'm just saying that you don't have to worry the intro sequence will put you off your meal the way Return to Castle Wolfenstein's did. This is what a sequel should be like.</p> <p>In addition to playing the game I have also read some reviews which made me realize I am completely out of touch. Reviews of this game were the very definition of "lukewarm". One reviewer found the graphics outdated and wondered whether that wasn't the same engine as Quake 4. Well he could have looked it up: it is. But then again another reviewer complained that the iPhone 4S's screen was "last year's resolution" so what does internet know?</p> <p>Reading this I couldn't believe time could pass so fast. "This can't be! It would mean I am in my mid-thirties!" I exlaimed. But I did look it up and yes id Tech 4 was first used in Doom 3 in 2004.</p> -<p>I also got Crysis 2 from the second-hand game bin so I actually know what a 3D game is supposed to look like in 2011. It looks great too but I would say that even for 3D games it is now time to put the emphasis on other elements than just the engine. I would create a start-up based on this insight but I am afraid I was <a href="http://en.wikipedia.org/wiki/Portal_2">not first to realize it</a>.</p> - <p>In 2011, I got an Xbox 360. It's not <a href="/link/rant/2011/12/30/Christmas-and-social-networks">what I would have liked</a> but you know what they say about not looking gift consoles in the mouth especially when you get them one solstice early. When in the game shop I saw in the second-hand games bin the game <a href="http://en.wikipedia.org/wiki/Wolfenstein_(2009_video_game)">Wolfenstein</a> having played both 1992's Wolfenstein 3D and 2001's Return to Castle Wolfenstein I did not hesitate.</p> -<p>I have never been a video game fanatic. I didn't finish Wolfenstein 3D for some reason —perhaps because Doom came out— and I didn't finish Return to Castle Wolfenstein that I was enjoying because it was becoming too hard at the point when supernatural creatures were everywhere.</p> -<p>I have played Wolfenstein a little bit now and it's a lot of fun. The decors are beautifully rendered and dynamic (objects that would have been immovable in other games tumble when you use a grenade nearby). There are some original ideas the whole thing is very playable with a couple of nice references to previous opuses. And it does not open with a torture scene. I'm not suggesting you put it in the hands of children I'm just saying that you don't have to worry the intro sequence will put you off your meal the way Return to Castle Wolfenstein's did. This is what a sequel should be like.</p> -<p>In addition to playing the game I have also read some reviews which made me realize I am completely out of touch. Reviews of this game were the very definition of "lukewarm". One reviewer found the graphics outdated and wondered whether that wasn't the same engine as Quake 4. Well he could have looked it up: it is. But then again another reviewer complained that the iPhone 4S's screen was "last year's resolution" so what does internet know?</p> -<p>Reading this I couldn't believe time could pass so fast. "This can't be! It would mean I am in my mid-thirties!" I exlaimed. But I did look it up and yes id Tech 4 was first used in Doom 3 in 2004.</p> <p>I also got Crysis 2 from the second-hand game bin so I actually know what a 3D game is supposed to look like in 2011. It looks great too but I would say that even for 3D games it is now time to put the emphasis on other elements than just the engine. I would create a start-up based on this insight but I am afraid I was <a href="http://en.wikipedia.org/wiki/Portal_2">not first to realize it</a>.</p> {% endraw %} diff --git a/_posts/2011-12-31-Do-not-use-AES-in-a-context-where-timing-attacks-are-possible.html b/_posts/2011-12-31-Do-not-use-AES-in-a-context-where-timing-attacks-are-possible.html index c2cc19a7227416358bded8e9acac66a6b2eca39e..8536aee53e12c8367cea5690a0abc83aa780ca40 100644 --- a/_posts/2011-12-31-Do-not-use-AES-in-a-context-where-timing-attacks-are-possible.html +++ b/_posts/2011-12-31-Do-not-use-AES-in-a-context-where-timing-attacks-are-possible.html @@ -67,65 +67,5 @@ Mem dependencies of rijndaelEncrypt: rk; Nr_0; pt; ct; in[0..15]; key[0..39]; <h2>Conclusion</h2> <p>One must be careful with a posteriori studies. There are plenty of bugs for which <strong>once they have been pointed out</strong> it is tempting to say "hey I could have found it with this or that static analysis tool! My tool finds these bugs. Everyone is so stupid not to be using it". The point is that much like a dowser being tested you only found the bug with your tool when someone else had told you where it was. Had you tried to find it before being told perhaps you would have given up right in the setup phase or you would have had so many false positives to review that you would never have gotten round to the bug or you would have gotten round to it but would have dismissed it quickly as another false positive.</p> <p>So I want to make it absolutely clear that I am not saying that the AES implementation conveniently posted in the mailing list should have been checked with Frama-C when it was written. This is a causal impossibility. However timing attacks are a recognized family of attacks now and cryptographic functions analyze rather well (based on experiments with AES and Skein) so Frama-C is definitely a tool that can be used nowadays to verify that new cryptographic functions are being implemented according to the state of the art.</p> -<p>This blog post owes to Adam Langley for describing the method in the context of Valgrind to Manuel Bernardo Barbosa and his students for courageously writing the first version of the array indices dependencies analysis (which I am sure took them more than 45 minutes) and applying it and to ç½—å©· for posting on frama-c-discuss a version of AES that was ready to analyze.</p> - <h2>Justification</h2> -<p>There recently was a thread in the Frama-C mailing list on verifying the Rijndael cipher, standardized and better-known as AES. -Nowadays, AES is mostly famous for being sensitive to timing attacks. An attacker measuring the time it takes to encrypt known plaintext with an unknown key <a href="http://cr.yp.to/antiforgery/cachetiming-20050414.pdf">can deduce the key</a> (key quote: "Using secret data as an array index is a recipe for disaster").</p> -<p>This brings me back to an experiment with University of Minho researchers where Frama-C's value analysis was used to verify that cryptographic C functions have constant execution time. The justification and the conclusion are the same as in <a href="http://www.imperialviolet.org/2010/04/01/ctgrind.html">this blog post</a> that had served as the starting point of that experiment.</p> -<p>There are two aspects to constant-time programming: checking that the execution path does not depend on secrets and (remember the key quote above) checking that array indices do not depend on secrets. I implemented the first check as an extension of Frama-C's dependencies analysis. Manuel Bernardo Barbosa et al similarly implemented the second one and they used both analyses to verify that cryptographic functions in <a href="http://nacl.cr.yp.to/">the NaCl library</a> were safe from timing attacks. I had a glance at their implementation but I had not made the effort to port it to new Frama-C releases (I assume they had not either).</p> -<h2>Example</h2> -<p>Consider the function <code>f()</code> below:</p> -<pre>int t[10] = {0 1 2 2 1 8 9 17 54 79}; -int u[10]; -int g; -int a; -void f(int n) -{ - int i; - int *p; - for (i = 0; i < t[n] * t[n+1] - 3; i++) - { - p = u + i + a; - if (g) - *p = i; - } -} -</pre> -<p>Execution path dependencies analysis relies on standard dependencies analysis (option <code>-deps</code>) which rely on the value analysis. Say you are interested in the execution times of function <code>f()</code> when array <code>t</code> has its initial values global variables <code>a</code> and <code>g</code> are each 0 or 1 and the argument <code>n</code> is between 0 and 5. You would then create the following analysis context as you would for any verification based on the value analysis:</p> -<pre>main(){ - a = Frama_C_interval(0 1); - g = Frama_C_interval(0 1); - f(Frama_C_interval(0 5)); -} -</pre> -<p>Analyzing this complete program for execution path dependencies:</p> -<pre>$ frama-c -experimental-path-deps -deps share/builtin.c ep.c -... -Computing path dependencies for function f -Path dependencies of f: t[0..6]; g; n -</pre> -<p>Within the initial conditions defined by the function <code>main()</code> (and in particular <code>n</code> between 0 and 5) the execution path depends on the initial values of <code>t[0..6] g</code> and <code>n</code> at the time <code>f()</code> is called. Note that variables <code>p</code> <code>a</code> and <code>u</code> are not included in this list although they are used because the execution path does not depend on them. So if <code>f()</code> was a cryptographic function and variable <code>a</code> contained a secret you would not have to worry that this secret can be deduced by observing through timing that the function has different execution paths depending on <code>a</code>.</p> -<p>But does this mean that you are safe from timing attacks though? As demonstrated in the article linked first in this post you should also worry that a malicious adversary will infer information from the array indices used in <code>f()</code>:</p> -<pre>$ frama-c -experimental-mem-deps -deps share/builtin.c ep.c -... -Computing mem dependencies for function f -Mem dependencies of f: t[0..6]; a; n -</pre> -<p>The above option that I quickly re-implemented when I saw that the verification of cryptographic functions was being discussed in the mailing list tells which of <code>f()</code>'s inputs influence the computation of array indices in the same way that option <code>-experimental-path-deps</code> tells which of <code>f()</code>'s inputs influence the execution path inside <code>f()</code>. In this example it tells that the contents of input variable <code>a</code> can leak through a cache-timing attack (because <code>a</code> is used in the computation of <code>p</code> and later <code>p</code> may be dereferenced for writing).</p> -<h2>What about AES then?</h2> -<pre>$ frama-c rijndael.c -cpp-command "gcc -C -E -I /usr/local/Frama-C/share/frama-c/libc" -no-annot -slevel 9999 mymain.c -experimental-mem-deps -deps -... -Mem dependencies of rijndaelEncrypt: rk; Nr_0; pt; ct; in[0..15]; key[0..39]; - Te0[0..255]; Te1[0..255]; Te2[0..255]; Te3[0..255] -</pre> -<p>The analysis finds that there is a risk that <code>in[0..15]</code> (the input buffer) and <code>key[0..39]</code> (the key) may be leaked through cache-timing attacks. The other variables are <code>Nr_0</code> the number of rounds <code>pt</code> and <code>ct</code> just pointers and the <code>Tei</code> arrays the S-boxes. Those aren't secrets so it doesn't matter that they are listed.</p> -<p>Like every other analysis in Frama-C this analysis always makes approximations on the safe side so we expected to find this result (since we knew the attack had been realized). The question is is the analysis precise enough to conclude that another cryptographic function is safe? The answer is yes: the hash function Skein-256 can be shown to have an execution time that depends only on the length of the input buffer but not of its contents.</p> -<h2>Implementation</h2> -<p>The option <code>-experimental-path-deps</code> has been available as a hidden proof-of-concept feature inside the official Frama-C distribution roughly since the Valgrind blog post was published in 2010.</p> -<p>I re-implemented the analysis of memory accesses dependencies analysis demonstrated here as <code>-experimental-mem-deps</code>. It has been available since Frama-C version Oxygen.</p> -<p>Note that the feature was very lightly tested. The new option <code>-experimental-mem-deps</code> was written in 45 minutes and the examples in this post are the only testing it received. If you feel that automatic analyses such as these are too automatic (they don't force you to write invariants for loops in the target code for instance) you can instead spend your time usefully by devising test suites to make sure they work as intended in all cases.</p> -<h2>Conclusion</h2> -<p>One must be careful with a posteriori studies. There are plenty of bugs for which <strong>once they have been pointed out</strong> it is tempting to say "hey I could have found it with this or that static analysis tool! My tool finds these bugs. Everyone is so stupid not to be using it". The point is that much like a dowser being tested you only found the bug with your tool when someone else had told you where it was. Had you tried to find it before being told perhaps you would have given up right in the setup phase or you would have had so many false positives to review that you would never have gotten round to the bug or you would have gotten round to it but would have dismissed it quickly as another false positive.</p> -<p>So I want to make it absolutely clear that I am not saying that the AES implementation conveniently posted in the mailing list should have been checked with Frama-C when it was written. This is a causal impossibility. However timing attacks are a recognized family of attacks now and cryptographic functions analyze rather well (based on experiments with AES and Skein) so Frama-C is definitely a tool that can be used nowadays to verify that new cryptographic functions are being implemented according to the state of the art.</p> <p>This blog post owes to Adam Langley for describing the method in the context of Valgrind to Manuel Bernardo Barbosa and his students for courageously writing the first version of the array indices dependencies analysis (which I am sure took them more than 45 minutes) and applying it and to ç½—å©· for posting on frama-c-discuss a version of AES that was ready to analyze.</p> {% endraw %} diff --git a/_posts/2012-01-05-Double-free-no-such-thing.html b/_posts/2012-01-05-Double-free-no-such-thing.html index b20f0e2290e458d152f103f45950aff77f5ef3af..7687c6f8898eab99d0351c378e322c46c5681553 100644 --- a/_posts/2012-01-05-Double-free-no-such-thing.html +++ b/_posts/2012-01-05-Double-free-no-such-thing.html @@ -82,79 +82,5 @@ test.c:18:[value] Non-termination in evaluation of function call expression argu } </pre> <p>On the other hand, I still have to detect that the program does not free a global variable, something the analysis currently allows to great comical effect. (Hey, I have only had a couple of hours!)</p> -<p>Please leave your thoughts in the comments.</p> <p>I have been able to divert a few hours yesterday and today for programming. -It was well worth it, as I have discovered a theorem. It is new to me, and I wonder whether it was ever published. The theorem is, a C program cannot double <code>free()</code> a block even if it tries! I thought this deserved an announcement. Some students I know would be glad to hear that.</p> -<p>Indeed, a C program can at most pass an indeterminate value to a function. This is highly objectionable in itself. Students, don't write programs that do this either!</p> -<p>Allow me to demonstrate on the following program:</p> -<pre>... -main(){ - int *p = malloc(12); - int *q = p; - free(p); - free(q); -} -</pre> -<p>You might think that the program above double-frees the block allocated and referenced by <code>p</code>. But it doesn't: after the first call to <code>free()</code>, the contents of <code>q</code> are indeterminate, so that it's impossible to free the block a second time. I will insert a few calls to primitive function <code>Frama_C_dump_each()</code> to show what happens:</p> -<pre>main(){ - int *p = malloc(12); - int *q = p; - Frama_C_dump_each(); - free(p); - Frama_C_dump_each(); - free(q); - Frama_C_dump_each(); -} -</pre> -<pre>$ frama-c -val this_is_not_a_double_free.c -</pre> -<p>The analysis follows the control flow of the program. First a block is allocated, and a snapshot of the memory state is printed a first time in the log:</p> -<pre>... -[value] computing for function malloc <- main. - Called from test.c:12. -[value] Recording results for malloc -[value] Done for function malloc -[value] DUMPING STATE of file test.c line 15 - p ∈ {{ &Frama_C_alloc }} - q ∈ {{ &Frama_C_alloc }} - =END OF DUMP== -... -</pre> -<p>Then <code>free()</code> is called and a second snapshot is logged:</p> -<pre>... -[value] computing for function free <- main. - Called from test.c:16. -[value] Recording results for free -[value] Done for function free -[value] DUMPING STATE of file test.c line 17 - p ∈ ESCAPINGADDR - q ∈ ESCAPINGADDR - =END OF DUMP== -... -</pre> -<p>And then, at the critical moment, the program passes an indeterminate value to a function:</p> -<pre>... -test.c:18:[kernel] warning: accessing left-value q that contains escaping addresses; - assert(Ook) -test.c:18:[kernel] warning: completely undefined value in {{ q -> {0} }} (size:<32>). -test.c:18:[value] Non-termination in evaluation of function call expression argument - (void *)q -... -[value] Values at end of function main: - NON TERMINATING FUNCTION -</pre> -<p>Note how the last call to <code>Frama_C_dump_each()</code> is not even printed. Execution stops at the time of calling the second <code>free()</code>. Generalizing this reasoning to all attempts to call <code>free()</code> twice, we demonstrate it is impossible to double-free a memory block.</p> -<p>QED</p> -<p>Question: does it show too much that this detection uses the same mechanism as the detection for addresses of local variables escaping their scope? I can change the message if it's too confusing. What would a better formulation be?</p> -<p>As I hope I have made clear, the message will be displayed as soon as the program does anything at all with a pointer that has been freed — and indeed, I have not implemented any special check for double frees. The program below is forbidden just the same, and does not get past the <code>q++;</code></p> -<pre>main(){ - int *p = malloc(12); - int *q = p; - Frama_C_dump_each(); - free(p); - q++; - ... -} -</pre> -<p>On the other hand, I still have to detect that the program does not free a global variable, something the analysis currently allows to great comical effect. (Hey, I have only had a couple of hours!)</p> -<p>Please leave your thoughts in the comments.</p> +<p>Please leave your thoughts in the comments.</p> {% endraw %} diff --git a/_posts/2012-01-05-More-big-round-numbers.html b/_posts/2012-01-05-More-big-round-numbers.html index 6d02aeab6584a400611c9153ce6a69f549849697..3f2cab648a34410c7af5bb3693aab2d884efefb4 100644 --- a/_posts/2012-01-05-More-big-round-numbers.html +++ b/_posts/2012-01-05-More-big-round-numbers.html @@ -16,14 +16,5 @@ Readers should now decide of future orientations. What does this blog need most? <li>And/or a <strong>nospivak</strong> tag, for subscribers who can't stand the Queen's English being disfigured so any longer?</li> <li>Or should any conjunction of atoms and their negations be offered (you can make disjunctions of these by subscribing as many feeds as necessary)?</li> </ul> -<p>While I'm here commenting on the passage of time, I should also point out that C1X was finalized into C11 during the holidays. When I say \the standard" as in <a href="/index.php?post/2012/01/05/free-revisited">last post</a> it will still mean "C99". I just know there's a joke in there."It's 2012 and I still don't check C11"? No. And don't <a href="https://twitter.com/#!/dwineman/status/153558190351581184">click here</a> if you are easily offended.</p> - <p>This blog simultaneously passed the 100-posts and the 50-comments milestones, and also its 15-months birthday. -Readers should now decide of future orientations. What does this blog need most?</p> -<ul> -<li>A <strong>norant</strong> tag, so that it's easy to subscribe to all posts but rants?</li> -<li>A <strong>spivak</strong> tag, in order for Spivak pronouns fans to get easy access to all posts that use them?</li> -<li>And/or a <strong>nospivak</strong> tag, for subscribers who can't stand the Queen's English being disfigured so any longer?</li> -<li>Or should any conjunction of atoms and their negations be offered (you can make disjunctions of these by subscribing as many feeds as necessary)?</li> -</ul> <p>While I'm here commenting on the passage of time, I should also point out that C1X was finalized into C11 during the holidays. When I say \the standard" as in <a href="/index.php?post/2012/01/05/free-revisited">last post</a> it will still mean "C99". I just know there's a joke in there."It's 2012 and I still don't check C11"? No. And don't <a href="https://twitter.com/#!/dwineman/status/153558190351581184">click here</a> if you are easily offended.</p> {% endraw %} diff --git a/_posts/2012-01-05-free-revisited-already.html b/_posts/2012-01-05-free-revisited-already.html index 18eb8a866d4b87586028127669eeae19da4e2e67..20a06b03879c117c44489b6e21c9f8cdd813c557 100644 --- a/_posts/2012-01-05-free-revisited-already.html +++ b/_posts/2012-01-05-free-revisited-already.html @@ -59,57 +59,5 @@ summary: </blockquote> <h3>Should we allow <code>q</code> to be incremented?</h3> <p>Well I don't want to for the same reason as in the uninitialized variable <code>y</code> example. This would postpone the moment the error is pointed out to the user and give em extra work to track the programming error (which is to do anything with <code>q</code> after the <code>free()</code>/end of block. The informative solution is to warn at <code>q++;</code> And I take informativeness very seriously. (You've been a great audience. I'll be here all week)</p> -<p>I think the standard should say that any pointer previously pointing inside the freed space becomes indeterminate. Anyway that's how it's treated in Frama-C's value analysis and if you don't like it you can use another analyzer unless you are Anne in which case you can't and you must use this one.</p> - <h2>If Frama-C doesn't work out, we can always make a comedy team</h2> -<p>Facetious colleagues ask me how I make Frama-C's value analysis' messages so informative. \Pascal " one of them says "in this case study the generated log contains 8GiB of information! It won't open in Emacs...". I helpfully point out that it is probably a 2^32 thing and that he should use a 64-bit Emacs.</p> -<h2>Informativeness with uninitialized variables</h2> -<p>Consider the program below:</p> -<pre>main(){ - int x = 1; - int y; - int z = 3; - int t = 4; - int u = 5; - x += y; - x += z; - x += t; - x += u; - printf("%d" x); -} -</pre> -<p>A less informative analyzer would predict that the <code>printf()</code> call prints any number or it might call the printed number "Uninitialized". Either way the user would be dumbfounded. Ey would have to track the origin of this imprecise diagnostic emself. Going backwards from causes to origins ey would finally end up to the declaration of local variable <code>y</code> which ey intended to initialize but forgot to.</p> -<p>The value analysis tells you right there at line 7 (<code>x += y;</code>) that the program is doing something wrong so that the way back up from cause to origin is much shorter. It's more informative to point out that the program is already doing something wrong at line 7 than to silently propagate a value indicating something wrong has happened somewhere.</p> -<h2>Informativeness with dangling pointers</h2> -<p>My most facetious colleague Anne wonders whether one shouldn't be allowed to increment <code>q</code> in the program from <a href="/index.php?post/2012/01/05/Double-free">last post</a>:</p> -<pre>main(){ - int *p = malloc(12); - int *q = p; - Frama_C_dump_each(); - free(p); - q++; - ... -} -</pre> -<p>This program is treated analogously to that program and by "analogously" I mean that the same functions are called behind the scenes and the same messages are printed:</p> -<pre>main(){ - int *p; - int *q; - { - int a[3]; - p = a; - q = p; - Frama_C_dump_each(); - } - q++; - ... -} -</pre> -<h3>Could we allow <code>q</code> to be incremented?</h3> -<p>In the example with <code>free()</code> perhaps. In the example with a local variable <code>a</code> the standard clearly calls the contents of <code>q</code> indeterminate and it's allowable for a static analyzer to emit an alarm when indeterminate memory contents are used for anything except copying.</p> -<p>The standard is surprisingly brief when it comes to defining <code>free()</code>.</p> -<blockquote><p>The <code>free</code> function causes the space pointed to by <code>ptr</code> to be deallocated that is made available for further allocation. [...] if the argument does not match a pointer earlier returned by the <code>calloc</code> <code>malloc</code> or <code>realloc</code> function or if the space has been deallocated by a call to <code>free</code> or <code>realloc</code> the behavior is undefined.</p> -</blockquote> -<h3>Should we allow <code>q</code> to be incremented?</h3> -<p>Well I don't want to for the same reason as in the uninitialized variable <code>y</code> example. This would postpone the moment the error is pointed out to the user and give em extra work to track the programming error (which is to do anything with <code>q</code> after the <code>free()</code>/end of block. The informative solution is to warn at <code>q++;</code> And I take informativeness very seriously. (You've been a great audience. I'll be here all week)</p> <p>I think the standard should say that any pointer previously pointing inside the freed space becomes indeterminate. Anyway that's how it's treated in Frama-C's value analysis and if you don't like it you can use another analyzer unless you are Anne in which case you can't and you must use this one.</p> {% endraw %} diff --git a/_posts/2012-01-07-Making-OCaml-native-code-0.5%-shorter-on-Mac-OS-X.html b/_posts/2012-01-07-Making-OCaml-native-code-0.5%-shorter-on-Mac-OS-X.html index d7687266b26040c0b9800860a16891b6d47db818..1a4e6ea76219b599e7259539a244b7d10312c39b 100644 --- a/_posts/2012-01-07-Making-OCaml-native-code-0.5%-shorter-on-Mac-OS-X.html +++ b/_posts/2012-01-07-Making-OCaml-native-code-0.5%-shorter-on-Mac-OS-X.html @@ -74,72 +74,5 @@ s/\([[:space:]]*j.*[[:space:]]*\)[.]\(L[0-9]*\)$/\1\2/g </pre> <p>The nearly 65000 bytes of difference between the two version represent the accumulation of all the inefficiently assembled jumps in a large piece of software such as Frama-C.</p> <h2>Conclusion</h2> -<p>If you play with the above compilation rule and sed script do not expect much in terms of speed improvements: changing an inefficient encoding into an efficient one of the same instruction helps the processor but only marginally. I guess it would be measurable but not with my usual protocol of launching three of each and keeping the median measurement. I would have to learn about confidence intervals which does not sound fun (not like gardening at all). Instead I will avoid making the claim that this hack improves execution speed and I will just postpone a bit more the moment I have to learn about statistics.</p> - <h2>Mac OS X and assembly labels</h2> -<p>A few months ago, I was moving things around in <a href="http://forge.ocamlcore.org/projects/zarith/">Zarith</a>. It's a good way to -relax not unlike gardening. And then I noticed something strange.</p> -<ul> -<li>On Mac OS X a label in assembly code is marked as local by prefixing it with "L" unlike another common convention of using ".".</li> -<li>On Mac OS X the assembler has some sort of strange limitation that makes it generate long variants of jump instructions if the destination label is not local even if the label is in the same compilation unit (and its relative position known).</li> -</ul> -<p>Here is a hand-written assembly snippet to show this:</p> -<pre> testl %eax %eax - jne L6 - testl %ebx %ebx - jne .L7 - movl $0 %ecx -L6: - movl $0 %eax -.L7: - movl $0 %ebx -</pre> -<p>The two above facts together mean that on Mac OS X the snippet is compiled into object code that can then be disassembled as:</p> -<pre>0x0000000000000057 <main+24>: test %eax %eax -0x0000000000000059 <main+26>: jne 0x68 <main+41> -0x000000000000005b <main+28>: test %ebx %ebx -0x000000000000005d <main+30>: jne 0x63 <main+36> -0x0000000000000063 <main+36>: mov $0x0 %ecx -0x0000000000000068 <main+41>: mov $0x0 %eax -0x000000000000006d <.L7+0>: mov $0x0 %ebx -</pre> -<p>You may notice that since <code>.L7</code> is not a local label <code>gdb</code> considers that it may be the name you want to see at address 0x6d. This is just a heuristic of little importance. The second conditional jump at <main+30> appears to be going to <main+36> but this is just because we are looking at an unlinked object file. The destination has been left blank in the object file and since it is expressed as a relative offset the default value 0 makes it look like the destination is the instruction that immediately follows. More to the point the first conditional jump at <main+26> occupies two bytes because the assembler sees that the destination is close and that the relative offset fits into one byte whereas the second conditional jump at <main+30> occupies 6 bytes leaving room for a 4-byte encoding of the target address.</p> -<h2>Enter OCaml. The plot thickens.</h2> -<p>Antoine Miné and Xavier Leroy then respectively contributed the following additional facts:</p> -<ul> -<li>OCaml generates labels intended to be local with a ".L" prefix on Mac OS X. This at first sight seems inefficient since it leads the assembler to use the long encoding of jumps all the time even when the destination is nearby.</li> -<li>But in fact Mac OS X's linker complains when you have subtracted local labels in the file being linked so that if you intend to subtract some of the labels you are generating you shouldn't make them local anyway.</li> -</ul> -<p>Subtracting addresses indicated by local labels is something that OCaml does in the process of generating meta-data accompanying the code in the assembly file. Thus on Mac OS X OCaml is prevented from using proper local labels with an "L" prefix.</p> -<p>Mac OS X's compilation chain is of course being obtuse. It could generate the short jump variants when the non-local destination label happens to be known and nearby. It could as well compute whatever subtractions between local labels occur in an assembly file while it is being assembled instead of leaving them for later and then complaining that it's impossible. The usual GNU compilation suite on a modern Linux distribution gets both of these features right and Mac OS X's gets both of them wrong leaving the OCaml native compiler no choice but to generate the inefficiently compiled non-local labels. Mac OS X deserves all the blame here.</p> -<h2>Solution: a hack</h2> -<p>Are we destined to keep ugly 6-byte jumps in our OCaml-generated native code on Mac OS X then? No because I made a hack. In Frama-C's Makefile I changed the rule to -compile .ml files into the .cmx .o ... natively compiled versions thus:</p> -<pre>--- share/Makefile.common (revision 16792) -+++ share/Makefile.common (working copy) -@@ -306 7 +306 10 @@ - %.cmx: %.ml - $(PRINT_OCAMLOPT) $@ -- $(OCAMLOPT) -c $(OFLAGS) $< -+ $(OCAMLOPT) -S -c $(OFLAGS) $< -+ sed -f /Users/pascal/ppc/sed_asm \ -+ < $(patsubst %.ml %.s $<) > $(patsubst %.ml %.1.S $<) -+ gcc -c $(patsubst %.ml %.1.S $<) -o $(patsubst %.ml %.o $<) - # .o are generated together with .cmx but %.o %.cmx: %.ml only confuses - # make when computing dependencies... -</pre> -<p>This uses <code>ocamlopt</code>'s -S option to generate the assembly file from the .ml source code file. Then a <a href="http://en.wikipedia.org/wiki/Sed">sed</a> script is applied to the assembly file to modify it a little. And finally the modified assembly file is compiled (gcc can be used for this).</p> -<p>The sed commands to transform the assembly file are these:</p> -<pre>s/^[.]\(L[0-9]*\):/.\1: \1:/g -s/\([[:space:]]*j.*[[:space:]]*\)[.]\(L[0-9]*\)$/\1\2/g -</pre> -<p>The first command transform all label declarations (e.g. <code>.L100:</code>) into a double declaration <code>.L100: L100:</code>. The two labels thus indicate the same location but the second one is local whereas the first one isn't.</p> -<p>The second command transforms labels when used inside jump instructions so that <code>jne .L100</code> is transformed into <code>jne L100</code>. Crucially it does not transform labels elsewhere for instance when referenced in the meta-data that the OCaml compiler generates where the compiler may have to subtract one label's address from another's.</p> -<h2>Results</h2> -<p>On Mac OS X the described trick makes Ocaml-generated native code smaller:</p> -<pre>-rwxr-xr-x 1 pascal staff 11479984 Jan 6 23:24 bin/toplevel.old --rwxr-xr-x 1 pascal staff 11414512 Jan 7 00:12 bin/toplevel.opt -</pre> -<p>The nearly 65000 bytes of difference between the two version represent the accumulation of all the inefficiently assembled jumps in a large piece of software such as Frama-C.</p> -<h2>Conclusion</h2> <p>If you play with the above compilation rule and sed script do not expect much in terms of speed improvements: changing an inefficient encoding into an efficient one of the same instruction helps the processor but only marginally. I guess it would be measurable but not with my usual protocol of launching three of each and keeping the median measurement. I would have to learn about confidence intervals which does not sound fun (not like gardening at all). Instead I will avoid making the claim that this hack improves execution speed and I will just postpone a bit more the moment I have to learn about statistics.</p> {% endraw %} diff --git a/_posts/2012-01-10-Static-analysis-benchmarks.html b/_posts/2012-01-10-Static-analysis-benchmarks.html index a8663e3fb326b016bc724ca3c0408008cdf27c7b..d03c6ecbf36f7c78112b9093e61b912b95f458d8 100644 --- a/_posts/2012-01-10-Static-analysis-benchmarks.html +++ b/_posts/2012-01-10-Static-analysis-benchmarks.html @@ -68,66 +68,5 @@ int main( int argc char * * argv ) Here for instance the value analysis warns that the program may use a dangling pointer in the second <code>printf()</code> — intended to symbolize the information leak. If the program instead called <code>malloc()</code> and tried to use the contents of the new block without having initialized it then the value analysis would warn about that. Generally speaking any way that I know of the contents of the initial block can be read from the heap is flagged at some point as an undefined behavior but this is not what case 1737 tests because case 1737 tests "analyzer warns about <code>realloc()</code>" and the correct answer is to warn about <code>realloc()</code>.</p> <h2>Conclusion</h2> <p>Coming back to the question of what field is immature from a customer point of view if your interest is in software security NIST's suite certainly can be used as a basis to understand what kind of static analyzer you may be after. You can try candidate static analyzers on cases that you have selected as most representative of your own problems. But it won't save you from reading each candidate's documentation understanding how each of them work and carefully examining their results. Any mechanical interpretation of the results will lead you to pick <code>grep realloc</code> without even understanding case 1737 and its limitations.</p> -<p>The issue for comparing embedded safety static analyzers is that the design space is too large and the design space for security static analysis certainly isn't any smaller. And if someone ever boasts that their security-oriented software analyzer covers 95% of the NIST SAMATE "benchmark" they are probably selling snake oil. Just saying.</p> - <h2>Reminiscing</h2> -<p>The first benchmark Frama-C's value analysis was ever evaluated on was the Verisec suite, described in <a href="http://www.cs.toronto.edu/~chechik/pubs/ase07.pdf">"A buffer overflow benchmark for software model checkers"</a>. My colleague Géraud Canet was doing the work thence the facetious-colleagues tag of this post. In retrospect Verisec was a solid piece of work. Being naive when it comes to statistics I didn't recognize it at the time but when I later examined other benchmarks I developed an appreciation for this one. It does a lot of things right.</p> -<ul> -<li>It contains good examples as well as bad. A static analyzer is for separating good programs from bad ones. It should be obvious that you cannot evaluate how well a static analyzer does using only bad programs.</li> -<li>The article's title says it's for "Software Model Checkers" but it does a good job of being accessible to a wide range of tools with varying abilities. Some good/bad program pairs are available in "no pointer only arrays" variants and in "small arrays only" variants providing more comparison points between different techniques. This may help discover that some technique detects a wrong behavior with small arrays but does not scale to larger ones whereas another one does not detect them at all.</li> -<li>The entries in the benchmark are moderate-sized snippets of code with unknown inputs. If by contrast in most or all of the examples the inputs were fixed and assuming that these examples did not escape in an infinite loop then a detection strategy based on the concrete execution of the program step by step and detection of wrong behaviors on the fly would sail through the benchmark. The benchmark would accurately capture the fact that for such cases an analyzer can easily be made correct and complete. What would be missing would be that users of static analysis tools turn to them to detect wrong behaviors that can occur with some inputs among many and not just to detect that there are some wrong behaviors when known (dangerous) inputs are used.</li> -</ul> -<p>Géraud was using the Verisec benchmark right too. He spent enough time on each case to uncover some interesting facts. One uncovered interesting fact was <a href="/assets/img/blog/imported-posts/scam09.pdf">a definite bug</a> in one of Verisec's "good" cases where the targeted bug was supposed to be fixed. The explanation was this: there were two bugs in the real-life snippet that had been used as "bad" case and only one had hitherto been noticed. The known bug had been fixed in the corresponding "good" case in the benchmark and in real life. The unknown bug had not as <a href="http://en.wikipedia.org/wiki/The_Song_of_la_Palice">the song of La Palisse</a> might have said.</p> -<p>When a static analysis benchmark is done right as the Verisec benchmark is it tries to measure the ability of tools to solve a hard problem: predicting whether something happens at run-time in a non-trivial program with unknown inputs. Furthermore the reason there is a need for static analyzers and for a benchmark is that humans are not good either at recognizing issues in code. So if the benchmark is representative of the problems a static analyzer should solve there exists no perfect oracle that can help decide what the correct answers are on each snippet and it can be expected to contain a few bugs classified as "good" code.</p> -<h2>Is safety static analysis incredibly immature?</h2> -<p>In a recent post I <a href="/benchmarks/floating-point/position/value/2011/11/25/Static-analysis-tools-comparisons">compared Frama-C's value analysis to PolySpace and Astrée</a>. It was a single-point comparison in each case each time using an example chosen by the people who sell the analyzer an example used on the analyzer's website to demonstrate the analyzer's precision. In that post's comments Sylvain regretted "that the field of static error-detection for embedded C (as opposed to security-oriented static analysis Cf. the [NIST SAMATE] test suite) is incredibly immature from a customer point of view".</p> -<p>His conclusion is at the opposite of the idea I was trying to express there. I was trying to say that embedded safety static analysis was mature and that all that remained to do to convince was to stop making unrealistic claims and derisive comparisons. Talk about scoring own goals. This blog post is my <strong>penitence</strong> for not having been clear the first time.</p> -<p>The field of software security is orders of magnitude more complex and disorganized than that of embedded safety. It deals with programs that are larger and use more difficult constructs (e.g. dynamic allocation). The properties that need to be verified are numerous and widely dispersed:</p> -<ul> -<li>There are the undefined behaviors that cause something to happen that was not intended by the programmer. These can breach any of a system's confidentiality integrity or availability. They are the same undefined behaviors that Polyspace Astrée or Frama-C's value analysis detect give or take that a previous version of Astrée did not detect uninitialized variables or that the Nitrogen version of Frama-C's value analysis (initially intended for embedded code) does not include the modelization of <code>free()</code> I have been <a href="/index.php?post/2012/01/05/Double-free">working on</a> recently — and therefore does not detect undefined behaviors related to <code>free()</code>.</li> -<li>There are security issues in code without undefined behaviors such as the <a href="http://arstechnica.com/business/news/2011/12/huge-portions-of-web-vulnerable-to-hashing-denial-of-service-attack.ars">hashing denial of service attack</a> everyone is talking about these days.</li> -<li>And as a last illustration of the variety of security properties timing information leaks <a href="/derived/analysis/skein/2011/12/31/Do-not-use-AES-in-a-context-where-timing-attacks-are-possible">the detection of which I recently discussed</a> belong to security considerations.</li> -</ul> -<blockquote><p>As a digression we are not worried about the hashing denial of service attack in Frama-C but the counter-measures in OCaml 3.13 (that allows to seed hash functions) are going to be a bit of a bother for Frama-C developers. He that among you never iterated on a hash-table when displaying the results of a regression test let him first cast a stone.</p> -</blockquote> -<p>The point is that software security people need a suite like NIST's to describe by example what their field is about (more than 45 000 C/C++ cases to date). The field of embedded safety does not have a similar suite because it does not need one. AbsInt the company that sells Astrée did not wait for me to (gently) make fun of their website before they implemented uninitialized variable detection: they did it of their own volition because they knew Astrée should do it and they had already released a new version with that feature at the time my colleague Florent Kirchner tried their example and noticed the uninitialized variable.</p> -<h2>A non-benchmark</h2> -<p>Also I think it's a slippery slope to call what NIST has a "test suite" because before long someone will call it a "benchmark" and NIST's suite is no benchmark. Many of the examples have definite inputs making them unrepresentative — specifically making them too easy to handle with techniques that do not scale to the billions of possible inputs that must be handled routinely in real life. There does not seem to be nearly enough "good" examples in the suite: the few I looked at were all "bad" examples and based on this sample an analyzer that always answered "there is an issue in the target code" would get a very good mark indeed if this was a benchmark.</p> -<p>Worse in some cases the "bad" line to find is extremely benign and there are more serious issues in the case. Consider <a href="http://samate.nist.gov/SRD/view_testcase.php?tID=1737">entry 1737</a> one of the few I looked at:</p> -<pre>... -void test( char * str ) -{ - char * buf; - char * newbuf; - char * oldbufaddress; - buf = malloc( MAXSIZE ); - if ( !buf ) - return; - strncpy( buf str MAXSIZE ); - buf[MAXSIZE - 1] = '\0'; - printf( "original buffer content is : %s" buf ); - oldbufaddress = buf; - buf = realloc( buf 1024 ); /*BAD */ - printf( "realloced buffer content is : %s" buf ); - printf( "original buffer address content is : %s" oldbufaddress ); - free( buf ); -} -int main( int argc char * * argv ) -{ - char * userstr; - if ( argc > 1 ) - { - userstr = argv[1]; - test( userstr ); - } -... -</pre> -<p>With the proper modelization for <code>printf()</code> <code>free()</code> and <code>realloc()</code> such as I am currently working on Frama-C's value analysis would warn about both <code>printf()</code> calls. The warning for the first call is because <code>realloc()</code> can fail and return <code>NULL</code> (passing <code>NULL</code> to <code>printf()</code> invokes undefined behavior). In this case there famously also exists a memory leak problem as the initial block is not freed but a memory leak is not an undefined behavior. The warning for the second call is because <code>oldbufaddress</code> becomes indeterminate if <code>realloc()</code> moves the block.</p> -<p>The above is <strong>not what the author of the test case wants to hear</strong>. What the author of the test case wants to hear clarified by the <a href="http://cwe.mitre.org/data/definitions/244.html">CWE-244</a> reference is that the <code>realloc()</code> call is dangerous because if <code>realloc()</code> moves the block it may leave the confidential information that was contained in the block lying on the heap. This is fine if the case is intended as a starting point for discussion (although it would be better without an undefined behavior unrelated to the specific issue being tested).</p> -<p>One problem is that there is no indication in the program that the block contains anything secret. A static analyzer that warns for this program should warn for any use of <code>realloc()</code> since this is how <code>realloc()</code> is intended to be used (it is intended to preserve the contents of the block being resized). An optimal analyzer for this issue is <code>grep realloc *.c</code>.</p> -<p>It does not hurt to zero the secret data before you <code>free()</code> a block and avoid <code>realloc()</code> in a "belt and suspenders" approach to security but if you use Frama-C's value analysis properly to verify that the program does not have undefined behaviors you do not have to do this and the code will still be safe from heap inspection vulnerabilities. Perhaps using the value analysis "properly" is inapplicable in your case; but you should at least be aware of the design choices here. Case 1737 by itself just seems to pick one specific circumvention method for a general issue and then confuses the resolution of the general issue with the application the specific method. <strong>The map is not the territory</strong>.</p> -<p>Were this case used as a benchmark it would very much remind me of primary school tests written by teachers without any deep understanding of the matter they were teaching and where you had to guess what was in these teachers' minds at each of their unclear questions. -Here for instance the value analysis warns that the program may use a dangling pointer in the second <code>printf()</code> — intended to symbolize the information leak. If the program instead called <code>malloc()</code> and tried to use the contents of the new block without having initialized it then the value analysis would warn about that. Generally speaking any way that I know of the contents of the initial block can be read from the heap is flagged at some point as an undefined behavior but this is not what case 1737 tests because case 1737 tests "analyzer warns about <code>realloc()</code>" and the correct answer is to warn about <code>realloc()</code>.</p> -<h2>Conclusion</h2> -<p>Coming back to the question of what field is immature from a customer point of view if your interest is in software security NIST's suite certainly can be used as a basis to understand what kind of static analyzer you may be after. You can try candidate static analyzers on cases that you have selected as most representative of your own problems. But it won't save you from reading each candidate's documentation understanding how each of them work and carefully examining their results. Any mechanical interpretation of the results will lead you to pick <code>grep realloc</code> without even understanding case 1737 and its limitations.</p> <p>The issue for comparing embedded safety static analyzers is that the design space is too large and the design space for security static analysis certainly isn't any smaller. And if someone ever boasts that their security-oriented software analyzer covers 95% of the NIST SAMATE "benchmark" they are probably selling snake oil. Just saying.</p> {% endraw %} diff --git a/_posts/2012-01-14-Public-announcements.html b/_posts/2012-01-14-Public-announcements.html index 9c4f9af268395dc5931308e156fa92b5f455dcd4..f2979ce2ec98e69a98ee07e437903d0567f980d8 100644 --- a/_posts/2012-01-14-Public-announcements.html +++ b/_posts/2012-01-14-Public-announcements.html @@ -16,14 +16,5 @@ summary: <p>One of the points that emerged was that we need to invent a word for alarms that are eventually categorized as innocuous but for which the information to classify them so was not in the source code provided to the analyzer. One actual example yesterday was the division of two values that came from sensors where Frama-C's value analysis warned that the result of the division might overflow the 16-bit int it was then stored into. Checking with the developers it turned out that specifications ensure that the values from the sensors will be such that the conversion is safe. Calling this a "false alarm" would be unfair to the analyzer since the information was not in the source code. I suggest to call this kind of alarm a "verification point". And so the bottom line of that particular experiment on a few thousand lines of C was a couple of true alarms a great many verification points and no false alarms. Apparently both the true alarms (that lead to code changes) and the verification points (that did not lead to code changes) were well received by the developers.</p> <p>The thing about Atos Origin and CS is that they are service providers. They will develop and/or verify software the way you contract them to and while they may use Frama-C a little bit for software quality even if it's not in the contract they can't use it very much then. By not making Frama-C verification part of the contract you are effectively tying their hands. If on the other hand you contract them to use it as part of the development and/or verification they already have experts who can do it efficiently (and one thing I am sure both these companies are good at is internally routing tasks to employees who have the corresponding competences).</p> <h2>Conclusion</h2> -<p>One wish I have for 2012 is to spend at least some of my time working on making Frama-C useful for non-Shuttle-like code. On the other hand if you are going to work on Shuttle-like code in 2012 you don't need to wait. Yesterday's meeting was another confirmation that for that purpose Frama-C is ready to be employed productively now.</p> - <h2>Yes, I have read that static analysis post</h2> -<p>If you are one of the three persons in the world who have not sent me a link to John Carmack's <a href="http://altdevblogaday.com/2011/12/24/static-code-analysis/">Christmas post on static analysis</a> go ahead and read it it might interest you. You can stop sending me that link now.</p> -<p>The post is very much a text version of the second half of his August <a href="http://www.youtube.com/watch?v=4zgYG-_ha28">QuakeCon keynote</a> which I prefer if only as someone who sometimes has to speak in public for the amazing delivery. Here's <a href="http://blog.regehr.org/archives/659">some commentary</a> on the PC-lint part of the post. I was myself going to comment on the "pursuing a Space Shuttle style code development process for game development" because the tools can be the same or at least take advantage of the same techniques and just be employed differently to answer different needs. I thought that if I only had time to put my arguments in order I might convincingly argue this and rebound on John Regehr's post by characterizing semantic static analyzers as limiting the programmer to the dialect of correct programs. But thinking about it I realize that I know nothing about game development and that it would be presumptuous to make strong claims there. In the case of Frama-C and Frama-C is not the only analyzer intended for "Space Shuttle style code" and quality objectives the total feedback we have is still limited enough to nearly double in one day and this feedback is still all about Space Shuttle style development and verification. And that day was yesterday.</p> -<h2>U3CAT meeting</h2> -<p>Yesterday was the day members of the national research project U3CAT gathered to tell each other about recent developments. Several presentations were on experiments done at <a href="http://atos.net/en-us/">Atos Origin SA</a> and <a href="http://uk.c-s.fr/">CS</a>. You can't expect them to reveal too much about the actual code but yes it was Space Shuttle-like and the results are very satisfying.</p> -<p>One of the points that emerged was that we need to invent a word for alarms that are eventually categorized as innocuous but for which the information to classify them so was not in the source code provided to the analyzer. One actual example yesterday was the division of two values that came from sensors where Frama-C's value analysis warned that the result of the division might overflow the 16-bit int it was then stored into. Checking with the developers it turned out that specifications ensure that the values from the sensors will be such that the conversion is safe. Calling this a "false alarm" would be unfair to the analyzer since the information was not in the source code. I suggest to call this kind of alarm a "verification point". And so the bottom line of that particular experiment on a few thousand lines of C was a couple of true alarms a great many verification points and no false alarms. Apparently both the true alarms (that lead to code changes) and the verification points (that did not lead to code changes) were well received by the developers.</p> -<p>The thing about Atos Origin and CS is that they are service providers. They will develop and/or verify software the way you contract them to and while they may use Frama-C a little bit for software quality even if it's not in the contract they can't use it very much then. By not making Frama-C verification part of the contract you are effectively tying their hands. If on the other hand you contract them to use it as part of the development and/or verification they already have experts who can do it efficiently (and one thing I am sure both these companies are good at is internally routing tasks to employees who have the corresponding competences).</p> -<h2>Conclusion</h2> <p>One wish I have for 2012 is to spend at least some of my time working on making Frama-C useful for non-Shuttle-like code. On the other hand if you are going to work on Shuttle-like code in 2012 you don't need to wait. Yesterday's meeting was another confirmation that for that purpose Frama-C is ready to be employed productively now.</p> {% endraw %} diff --git a/_posts/2012-01-16-Critics.html b/_posts/2012-01-16-Critics.html index 510d247bb4a97faba3271aea1029768333e10922..18ffef063b467298481c0b99f829305a64a94b54 100644 --- a/_posts/2012-01-16-Critics.html +++ b/_posts/2012-01-16-Critics.html @@ -14,12 +14,5 @@ summary: </blockquote> <p>I too remember the first time I heard those words in the theater during an afternoon showing of Ratatouille. I thought more than one person might take them to heart.</p> <p>The words personally remind me of a similar dichotomy between builders and breakers in the security-oriented aspects of computing. Builders make things and make things available. Breakers make things unavailable. It's a little bit more symmetrical than the creator/critic dichotomy because constructing a concrete security attack takes skill skill that the building camp may dismiss with as much ease as the breaking camp dismisses building skills. For breakers it's a <a href="http://www.schneier.com/blog/archives/2008/03/the_security_mi_1.html">mindset</a>. Most builders just don't see the point at all but they make things so who are you to argue?</p> -<p>I am a builder. I work on tools that are intended to solve safety issues. Even if/when these tools are applied to security problems they are more useful for defense than for attack. This is visible in the assumptions they require. Often I wonder what it's like on the other side but I am not sure you can experience both in the same lifetime.</p> - <p>This blog is not intended to be about computer gaming, even partially. In fact, the post I am about to link to comes from a feed I was subscribed to by accident when I changed news readers. I haven't bothered to fix this yet.</p> -<p>The <a href="http://arstechnica.com/gaming/news/2012/01/fare-well-kuuuuuuuccccchhheeeeeeeeeeerrrrrrrrrraaaaaaaaaaaaa.ars">post</a> starts with this quote:</p> -<blockquote><p>In many ways the work of a critic is easy. We risk very little yet enjoy a position over those who offer up their work and their selves to our judgment. We thrive on negative criticism which is fun to write and to read. But the bitter truth we critics must face is that in the grand scheme of things the average piece of junk is probably more meaningful than our criticism designating it so. But there are times when a critic truly risks something and that is in the discovery and defense of the new. The world is often unkind to new talents new creations. The new needs friends.</p> -</blockquote> -<p>I too remember the first time I heard those words in the theater during an afternoon showing of Ratatouille. I thought more than one person might take them to heart.</p> -<p>The words personally remind me of a similar dichotomy between builders and breakers in the security-oriented aspects of computing. Builders make things and make things available. Breakers make things unavailable. It's a little bit more symmetrical than the creator/critic dichotomy because constructing a concrete security attack takes skill skill that the building camp may dismiss with as much ease as the breaking camp dismisses building skills. For breakers it's a <a href="http://www.schneier.com/blog/archives/2008/03/the_security_mi_1.html">mindset</a>. Most builders just don't see the point at all but they make things so who are you to argue?</p> <p>I am a builder. I work on tools that are intended to solve safety issues. Even if/when these tools are applied to security problems they are more useful for defense than for attack. This is visible in the assumptions they require. Often I wonder what it's like on the other side but I am not sure you can experience both in the same lifetime.</p> {% endraw %} diff --git a/_posts/2012-01-16-Csmith-testing-again.html b/_posts/2012-01-16-Csmith-testing-again.html index d27e1cad3ecfcd53466b5925fa4ba72d62f749e3..c9513f52e5bc3c34880a94a8eb745e8c8b7c3606 100644 --- a/_posts/2012-01-16-Csmith-testing-again.html +++ b/_posts/2012-01-16-Csmith-testing-again.html @@ -10,8 +10,5 @@ summary: {% raw %} <p>My presentation Friday at the U3CAT meeting was on the topic of Frama-C Csmith testing. Several posts in this blog already describe facets of this work (it has its own <a href="/index.php?tag/csmith">tag</a>). Yet another angle can be found in <a href="/assets/img/blog/imported-posts/csmith.pdf">this short article draft</a>. Said draft by the way will soon need to be either finalized or resubmitted so remarks are welcome if you have them. <a href="/index.php?pages/Csmith-testing">This webpage</a> provides figures and implementation details that could have been included in the article to improve clarity but weren't because we were aiming for the 6-page short format. The webpage is not intended to make sense separately from the article.</p> -<p>January 25 2012: Updated with most recent draft of the article. <a href="/index.php?pages/Csmith-testing">The companion webpage</a> has been updated too</p> - <p>My presentation Friday at the U3CAT meeting was on the topic of Frama-C Csmith testing. Several posts in this blog already describe facets of this work (it has its own <a href="/index.php?tag/csmith">tag</a>). Yet another angle can be found in <a href="/assets/img/blog/imported-posts/csmith.pdf">this short article draft</a>. Said draft by the way will soon need to be either finalized or resubmitted so remarks are welcome if you have them. -<a href="/index.php?pages/Csmith-testing">This webpage</a> provides figures and implementation details that could have been included in the article to improve clarity but weren't because we were aiming for the 6-page short format. The webpage is not intended to make sense separately from the article.</p> <p>January 25 2012: Updated with most recent draft of the article. <a href="/index.php?pages/Csmith-testing">The companion webpage</a> has been updated too</p> {% endraw %} diff --git a/_posts/2012-01-16-Csmith-testing.html b/_posts/2012-01-16-Csmith-testing.html index 3c6723be62b90572c44dd47335ac180da9c4ecf5..4bf485b137e00052091768d52d559274aeac75ec 100644 --- a/_posts/2012-01-16-Csmith-testing.html +++ b/_posts/2012-01-16-Csmith-testing.html @@ -8,342 +8,7 @@ title: "Csmith testing" summary: --- {% raw %} -This page contains various remarks that did not make it into [our article about Csmith-testing Frama-C|/assets/img/blog/imported-posts/csmith.pdf]. -It is an annex of sorts, except that it is written in a less formal style that will be familiar to readers of [the Frama-C blog|/]. -It is not intended to make sense by itself: if you have not read the article, start there, and then come back here. Sorry for the disorganized presentation. -!!!! Why standard differential testing does not look directly applicable -Here is standard differential testing, as described by McKeeman in 1998. It works well when testing compilers, and when you can generate __defined__ programs which two different compilers are supposed to transform into binaries that compute the same results. -/// - Generator - ↓ - C program - ↙ ↘ - Compiler1 Compiler2 - ↓ ↓ - Binary1 Binary2 - ↓ ↓ - Result1 Result2 -/// -Result1 and Result2 are compared, and if they are different, then at least one of Compiler1 or Compiler2 must have a bug. This is how Csmith was originally intended to be used. The problem we faced was to take advantage of Csmith to test a static analysis framework (instead of a compiler). -%%% -It does not look like it would be fruitful just to replace Compiler1 and Compiler2 in this scheme with Analyzer1 and Analyzer2, because two different analyzers will make different approximations as part of their nominal behavior. Then they would both need to project their results (expressed in different abstract domains, and I am assuming both analyzers rely on abstract interpretation here) onto a common abstract domain for comparison. This would cause more approximations. All in all, you could hope to detect that something is wrong if the approximated, projected values predicted by Analyzer1 had an empty intersection with the approximated, projected values predicted by Analyzer2 on the same defined program. However, even if a bug manifests itself in one of the analyzer, it risks being hidden by all these approximations, and remaining unnoticed. -!!!! The “value analysis as C interpreter†oracle -So a second static analyzer is not the best oracle to test a static analyzer. Instead, we used oracles based on a reference compiler, even if in two instances this meant modifying the value analysis solely for the purpose of making it testable. One oracle we used (paragraph __Value analysis as C interpreter__ in the article) was to modify Frama-C's value analysis so that it would behave as a plain interpreter, analyzing the Csmith-generated program with maximum precision, to the point of predicting the actual value of the checksum computed by the program. -/// - Generator - ↓ - C program - ↙ ↘ - Compiler1 - ↓ Value analysis - Binary1 ↓ - ↓ - Result1 Result2 -/// -Here is one representative statement from a Csmith-generated program: -/// - (*l_1209) ^= func_2(func_7(g_13, g_13.f0, g_13.f0, - func_14(func_20(l_25, ((*l_29)--), func_32(func_34((((((*l_963) = - func_37((safe_unary_minus_func_int32_t_s(( - safe_rshift_func_uint16_t_u_s((safe_add_func_uint8_t_u_u(func_47( - l_25), (safe_mul_func_uint16_t_u_u(((safe_add_func_uint64_t_u_u((( - *l_102) = 0xC3DD168C87B4EC18LL), (safe_mul_func_int16_t_s_s(((( - g_117 = (safe_sub_func_int16_t_s_s(((safe_lshift_func_int16_t_s_u(( - g_116 = (g_115 = ((*l_112) ^= (((g_76.f1.f1 , g_110[2]) != &g_111) , - 0xF5F5L)))), l_25)) || g_76.f1.f1), g_76.f1.f2))) < l_118) >= (-8L)), - g_65)))) < l_25), g_13.f0)))), g_76.f1.f3)))), g_119, l_26[1], &g_65)) - == g_964) == 0x24AE7014CC3713C7LL) | l_25), g_966)), g_415), - l_988, g_967, l_118, l_25), l_25), l_118, (*g_676), l_988); -/// -This statement comes from [this example Csmith-generated program|/assets/img/blog/imported-posts/t.c]. Here are the results of the commands that could be executed when following this approach: -/// -$ ~/ppc/bin/toplevel.opt -cpp-command \gcc -C -E -Iruntime -Dprintf=Frama_C_show_each" \ - -val-signed-overflow-alarms -stop-at-first-alarm -no-val-show-progress -precise-unions \ - -machdep x86_64 -obviously-terminates -big-ints-hex 0 -val t.c -... -[value] Called Frama_C_show_each({{ &"checksum = %X" }} {0x2E412D3}) -... -$ gcc -Iruntime t.c && ./a.out -... -checksum = 2E412D3 -/// -The predicted values are the same meaning that there is no bug to observe here. One kind of “interesting†result in the Chinese curse sense of the word would be if the value analysis predicted a value different from execution say @@0x3F52E1A9@@. This could indicate a soundness bug. -Since we have decided for the purpose of testing that every construct that may appear in Csmith programs should be handled precisely (in a “singleton in singleton out†fashion) another interesting result that would require further investigation would be an imprecise result such as @@\[0 .. 0xFFFFFFFF]@@ for the computed checksum. Although there is nothing incorrect in this result we would be annoyed that it might hide an incorrect operation by absorbing it. [One real font-end bug|http://bts.frama-c.com/view.php?id=725] was found while investigating such a result. This bug only caused unjustified and disproportionate loss of precision in the value analysis (not a soundness issue) but it was a typing bug that could have had more severe consequences in another plug-in if it had continued unnoticed. -%%% -In fact the __Value analysis as C interpreter__ method found quantities of bugs because it was first to be applied to test Frama-C. Being used first it found most of Frama-C's front-end bugs. Front-end bugs probably could have been noticed using any other oracle. Still it was good to find them using this method that makes them easiest to understand. This is an example of the general idea that section __Bug triage__ in the article tries to convey regarding the bottom-up testing of functionalities. -Fixing [front-end bugs|http://bts.frama-c.com/search.php?project_id=1&search=csmith&category=Kernel&sticky_issues=off&sortby=id&dir=DESC&hide_status_id=-2] was satisfying because they potentially affect all plug-ins. Fixing them makes Frama-C a better framework for any use including for writing new more advanced plug-ins. -This method's main issue is that it uses the value analysis differently from the way it is commonly used. A bug that only occurred when the value analysis is making approximations would not be noticed with the above technique because the value analysis misused as a plain interpreter does not make approximations at all while tested with this oracle. -!!!! The more oracles the merrier -This sentence was part of one reviewer's summary: -> The idea is to define complementary oracles that cover most of the functionalities of the tool. -This is exactly it. This sentence or one like it should have been part -of the submitted article. As one slight nuance I would only say that we -tested as much as possible of the functionality of the tool — as much as we -knew how to test given the random program generator we had in fact. As an example -of untested functionality Csmith does not generate ACSL annotations as part -of its programs so Frama-C's handling of ACSL annotations has received -very little testing during this campaign. -!!!! Another value analysis-based oracle -Early in the lifecycle of the value analysis a bug was privately reported that was characterized by unsound results when @@+0.0@@ was the upper bound of the floating-point values a variable could have. This bug was fixed eons ago but had it still been there it could not have been found using the value analysis as an interpreter because in this mode the value analysis never manipulates value sets that are not singletons. In order to get a shot at bugs that occur only when the value analysis manipulates approximate values we used a different oracle described in the article under __Printing internal invariants in executable C form__. -When used as an analyzer that is with the default options on the same example as previously the value analysis produces results such as: -/// -$ ~/ppc/bin/toplevel.opt -cpp-command "gcc -C -E -Iruntime -Dprintf=Frama_C_show_each" \ - -val-signed-overflow-alarms -no-val-show-progress -machdep x86_64 -val t.c -... -[value] Called Frama_C_show_each({{ &"checksum = %X" }} [0..4294967295]) -... -[value] Values at end of function main: -... - g_125 ∈ {61; 72; 73} - g_228.f0 ∈ {-1; 7} -... -/// -The analyzer does not have any chance to predict the value of the checksum itself computed by the Csmith-generated program from the contents all global variables. On the other hand the values of some global variables are predicted more or less accurately depending on what the program does with them. Strategically inserting a call to the primitive @@Frama_C_dump_assert_each()@@ we can get the analyzer to print this information as a snippet of C code: -/// ---- t.c 2012-01-10 13:29:26.000000000 +0100 -+++ u.c 2012-01-10 13:54:31.000000000 +0100 -@@ -1600 6 +1600 7 @@ - } - } - platform_main_end(crc32_context ^ 0xFFFFFFFFUL print_hash_value); -+ Frama_C_dump_assert_each(); - return 0; - } -/// -Analyzing the Csmith-generated program thus modified prints: -/// -u.c:1603:[value] Frama_C_dump_assert_each called: - (*(unsigned int*)&i == 1 -... - && 61 <= *(unsigned char*)&g_125 && *(unsigned char*)&g_125 <= 73 - && -1 <= *(char*)&g_228 && *(char*)&g_228 <= 7 -... -/// -The entire memory state as predicted by the value analysis is printed as a C expression. Being pretty-printed directly from the untyped memory representation it is not very readable but it is intended for the compiler and the compiler does not mind. If the analyzer is right the expression evaluated at the end of the program should be true. A sed script inserts the expression into the program for instance: -/// - // Frama_C_dump_assert_each(); - int seems_ok = <generated expression> ; - printf("seems ok:%d" seems_ok); -/// -The instrumented program is then compiled and run: -/// -$ gcc -Iruntime v.c && ./a.out -... -checksum = 2E412D3 -seems ok:1 -/// -This time we are only concerned by the run-time value of variable @@seems_ok@@. If this variable is not printed as @@1@@ for a defined input program it indicates a bug in the analyzer or in the compiler. This technique can be summarized with the diagram below. -/// - Generator - ↓ - C program - ↙ ↘ - Value analysis - ↓ ↓ - Executable invariant - ↘ ↙ - Instrumented program - ↓ - Compiler - ↓ - Binary - ↓ - Diagnostic -/// -The primitive @@Frama_C_dump_assert_each()@@ too was implemented specifically for the purpose of Csmith testing. A refined version may find uses in the qualification of the value analysis when used for certification credit. -> Earlier I was saying that the ACSL-manipulating component of Frama-C received little testing in this campaign. Still a couple of bugs found were related to the ACSL annotations. These were for alarms emitted by the value analysis as ACSL annotations in the mode described here (working as a static analyzer) and subsequently re-interpreted by the value analysis. All Frama-C developers do not agree that the value analysis re-interpreting alarms that come from itself is a good idea (it is not supposed to learn anything new from them! In theory anyway). Nonetheless this helped identify some bugs so the idea has its merits if only as a kind of self-check. -!!!! Testing the constant propagation plug-in -Frama-C's [constant propagation plug-in|http://frama-c.com/constant_propagation.html] transforms programs. It replaces any expression that can only take one value during execution (as predicted by the value analysis) by this value. The result of this plug-in is supposed to be a program that produces the same results as the original. This can be tested following the diagram below: -/// - Generator - ↓ - C program - ↙ ↘ - Compiler Constant propagation plug-in - ↓ - ↓ Transformed program - ↓ - Binary1 Compiler - ↓ - ↓ Binary2 - ↓ - Result1 Result2 -/// -!!!! Testing the slicing plug-in -Frama-C's [slicing plug-in|http://frama-c.com/slicing.html] provides another program transformation. Frama-C's slicer is semantic. When used with the slicing criterion “preserve the call to @@printf()@@ and the checksum it receives as argument†it is supposed to produce a program that prints the same checksum as the original while removing any useless statement it finds. There are many of these in a randomly generated program despite the checksum being computed over all global variables at the end of the program. -/// - Generator - ↓ - C program - ↙ ↘ - Compiler Slicing plug-in - ↓ - ↓ Transformed program - ↓ - Binary1 Compiler - ↓ - ↓ Binary2 - ↓ - Result1 Result2 -/// -%%% -The slicer may remove from the Csmith-generated program assignment to local variables that do not subsequently impact the final values of global variables like this: -/// -void func_123(void) -{ -/* int l_437; - l_437 = g_232 + g_12; */ - g_15 = 3; -} -/// -The slicer may also remove assignments to global variables that are subsequently over-written without the intermediate value being used in the final checksum like this: -/// -void func_1(int p_1) -{ - int *l_12 = &g_15; -/* g_15 = x; */ - *l_12 = 3; -} -/// -It goes without saying that a sound slicer given the criterion “slice for the value of the checksum†should preserve all computations that influence the value of the checksum and consequently produce a program that computes the same checksum. That is the definition of “slicer†(or the definition of “sound†depending how you want to look at it). -%%% -In our running example the randomly generated @@func_2()@@ looks like this: -/// -/* - * reads : - * writes: - */ -static int32_t func_2(struct S3 p_3 int32_t p_4 int64_t p_5 int16_t p_6) -{ /* block id: 665 */ - int16_t l_1206 = 0x5E39L; - int32_t *l_1207 = (void*)0; - int32_t *l_1208[7] = {(void*)0 (void*)0 &g_116 (void*)0 (void*)0 &g_116 (void*)0}; - int i; - p_3.f2 &= l_1206; - return p_3.f3; -} -/// -The version sliced for the global criterion “compute the same checksum†sticks to the computation of the function's result and omits all the declarations and initializations of local variables. The parameters @@p_4 p_5 p_6@@ were not used for anything so these have been removed from the prototype of the function: -/// -static int32_t func_2_slice_1(struct S3 p_3) -{ - int32_t __retres; - __retres = (int)p_3.f3; - return (__retres); -} -/// -Perhaps the @@func_2()@@ example seems too simple. One could argue it was obvious that most of @@func_2()@@ was useless. Here is a more complicated example function @@func_1()@@ from the same Csmith-generated program. The original is like this: -/// -/* - * reads : g_13 g_28 g_56 g_60 g_64 g_75 g_76.f1.f4 g_76.f3 g_96 g_76.f2 g_76.f1.f1 g_110 g_113 g_76.f1.f2 g_65 g_76.f1.f3 g_119 g_125 g_116 g_191 g_261 g_117 g_288 g_115 g_76.f1 g_228.f0 g_103 g_287 g_76 g_414 g_415.f4 g_228 g_482 g_192 g_58 g_111 g_415.f0 g_596 g_415 g_642 g_597 g_656 g_675 g_680 g_676 g_575 g_631 g_776 g_805 g_964 g_966 g_777 g_967 g_1075 g_965 g_1095 g_1188 g_1189 g_1210 - * writes: g_28 g_56 g_58 g_60 g_64 g_75 g_96 g_76.f2 g_103 g_113 g_115 g_116 g_117 g_125 g_191 g_228 g_119 g_111 g_261 g_65 g_287.f0 g_287 g_414 g_76.f0 g_76.f3 g_642 g_656 g_675 g_680 g_482 g_931 g_631 g_1068 g_13 g_1210 - */ -static struct S0 func_1(void) -{ /* block id: 0 */ - uint32_t l_25 = 4294967290UL; - uint32_t *l_26[6]; - uint32_t *l_27[3][3] = {{&g_28 &g_28 &g_28} {&g_28 &g_28 &g_28} {&g_28 &g_28 &g_28}}; - uint32_t *l_29 = &g_28; - uint64_t *l_102 = &g_103; - int16_t *l_112 = &g_113[2][0]; - int16_t *l_114[5]; - uint8_t l_118 = 0x86L; - uint32_t **l_963 = &l_27[2][0]; - int32_t l_988 = 0xAEDD27D2L; - int32_t *l_1209 = &g_1210[3]; - struct S0 l_1213[7] = {{9L} {-1L} {9L} {-1L} {9L} {-1L} {9L}}; - const struct S0 *l_1215 = (void*)0; - const struct S0 **l_1214 = &l_1215; - int32_t *l_1216[2][9] = {{&g_116 (void*)0 &g_116 (void*)0 &g_116 (void*)0 &g_116 (void*)0 &g_116} {&g_116 (void*)0 &g_116 (void*)0 &g_116 (void*)0 &g_116 (void*)0 &g_116}}; - int32_t *l_1218 = (void*)0; - int i j; - for (i = 0; i < 6; i++) - l_26[i] = (void*)0; - for (i = 0; i < 5; i++) - l_114[i] = &g_115; - (*l_1209) ^= func_2(func_7(g_13 g_13.f0 g_13.f0 func_14(func_20(l_25 ((*l_29)--) func_32(func_34((((((*l_963) = func_37((safe_unary_minus_func_int32_t_s((safe_rshift_func_uint16_t_u_s((safe_add_func_uint8_t_u_u(func_47(l_25) (safe_mul_func_uint16_t_u_u(((safe_add_func_uint64_t_u_u(((*l_102) = 0xC3DD168C87B4EC18LL) (safe_mul_func_int16_t_s_s((((g_117 = (safe_sub_func_int16_t_s_s(((safe_lshift_func_int16_t_s_u((g_116 = (g_115 = ((*l_112) ^= (((g_76.f1.f1 g_110[2]) != &g_111) 0xF5F5L)))) l_25)) || g_76.f1.f1) g_76.f1.f2))) < l_118) >= (-8L)) g_65)))) < l_25) g_13.f0)))) g_76.f1.f3)))) g_119 l_26[1] &g_65)) == g_964) == 0x24AE7014CC3713C7LL) | l_25) g_966)) g_415) l_988 g_967 l_118 l_25) l_25) l_118 (*g_676) l_988); - l_1218 = l_1209; - return (**g_776); -} -/// -A large part of function @@func_1()@@ is the representative line quoted earlier. The version of @@func_1()@@ in the sliced program looks a little bit different because a normalization phase occurred before the slicer even started working. This normalization is usually not an issue for human-written programs: -/// -static void func_1_slice_1(void) -{ - uint32_t l_25; - uint32_t *l_29; - uint64_t *l_102; - int16_t *l_112; - uint8_t l_118; - int32_t l_988; - int32_t *l_1209; - int32_t tmp_17; - struct S3 tmp_16; - int32_t tmp_10; - uint16_t tmp_9; - uint8_t tmp_8; - uint16_t tmp_6; - uint64_t tmp_5; - int16_t tmp_3; - int16_t tmp_2; - int tmp_1; - uint64_t tmp_4; - uint8_t tmp_7; - uint32_t *tmp; - l_25 = (unsigned int)4294967290UL; - l_29 = & g_28; - l_102 = & g_103; - l_112 = & g_113[2][0]; - l_118 = (unsigned char)0x86L; - l_988 = (int)0xAEDD27D2L; - l_1209 = & g_1210[3]; - { /*undefined sequence*/ - { /*undefined sequence*/ - *l_112 = (short)((long)*l_112 ^ 0xF5F5L); - g_115 = *l_112; - g_116 = (int)g_115; - } - tmp_1 = 1; - tmp_2 = safe_sub_func_int16_t_s_s_slice_1((short)tmp_1 (short)g_76.f1.f2); - g_117 = (unsigned int)tmp_2; - tmp_3 = safe_mul_func_int16_t_s_s_slice_1((short)((long)(g_117 < (uint32_t)l_118) >= -8L) - (short)g_65); - tmp_4 = (unsigned long)0xC3DD168C87B4EC18LL; - *l_102 = tmp_4; - tmp_5 = safe_add_func_uint64_t_u_u_slice_1(tmp_4 (unsigned long)tmp_3); - tmp_6 = safe_mul_func_uint16_t_u_u_slice_1((unsigned short)(tmp_5 < (uint64_t)l_25) - (unsigned short)g_13.f0); - tmp_7 = func_47_slice_1((int)l_25); - tmp_8 = safe_add_func_uint8_t_u_u_slice_1(tmp_7 (unsigned char)tmp_6); - tmp_9 = safe_rshift_func_uint16_t_u_s_slice_1((unsigned short)tmp_8 - (int)g_76.f1.f3); - tmp_10 = safe_unary_minus_func_int32_t_s_slice_1((int)tmp_9); - tmp = func_37_slice_1((unsigned int)tmp_10 g_119 & g_65); - func_34_slice_1((unsigned short)((unsigned int)((long long)(tmp == g_964) == 0x24AE7014CC3713C7LL) | l_25)); - func_32_slice_1(); - *l_29 -= (uint32_t)1; - func_14_slice_1(l_988); - tmp_16 = func_7_slice_1(); - tmp_17 = func_2_slice_1(tmp_16); - *l_1209 ^= tmp_17; - } - return; -} -/// -The @@struct S0@@ returned by @@func_1()@@ in the original program was not used for anything. Consequently in the sliced program @@func_1()@@ has been changed in a function returning @@void@@. Some of the computations taking place in local variables are kept because in the complete program they end up influencing the final value of a global variable and therefore the computed checksum. I will let the reader judge for [emself|http://en.wikipedia.org/wiki/Spivak_pronoun] how obvious the frontier between useful and removable computations was. -The command to reproduce the slicing computation above should be something like this: -/// -frama-c -no-collapse-call-cast -cpp-command "gcc -C -E -D__FRAMAC -Iruntime" -machdep x86_64 -val-signed-overflow-alarms -no-val-show-progress -slice-calls Frama_C_show_each -slevel 50 -slevel-function crc32_gentab:0 t.c -then-on 'Slicing export' -print -ocode sliced.c -/// -!!!! Does random testing waste time? -A valid question with random testing is whether any of the bugs found would ever have occurred in a human-written program. Indeed some of the bugs found seem pretty unlikely. There are several answers to this question. -* One answer is that the craftsman takes satisfaction in fixing even unnoticeable defects. Frama-C is still small enough to aim to behave as specified. One may argue in some cases that the specification is the wrong one and some bugs have been postponed for a long time but the developers still aim at eventually fixing all bugs. -* The confidentiality culture in embedded systems and the open-source nature of Frama-C often mean that we receive bug reports that aren't all that they should be. We would rather handle perfect automatically generated bug reports from a script than some of the tripe that gets submitted on Frama-C's bug tracking system even if an automatically generated bug report has only one chance in three to have an incidence on human-written programs. -* In parallel to the Csmith experiment we were using Frama-C for case studies discovering and fixing bugs the traditional way. As a last argument in this discussion some of the bugs we found using the traditional techniques had a distinct “this could have been found with Csmith†feeling. Specifically bugs found the traditional way in Frama-C's typing of the C @@switch@@ construct would have been found in a jiffy by Csmith if only Csmith generated @@switch@@ constructs. -!!!! But wait! There's more -The complete set of scripts and patch used [is also provided|/assets/img/blog/imported-posts/csmith_testing.tgz] (if you can make sense of the stuff you are a better programmer than I am). If you want to report bugs found with these scripts or with a variation of them please do reduce them yourself before submitting. -%%% -The authors thank Eddie Kohler and the anonymous reviewers of the article for their remarks on intermediate versions of the article." <p>This page contains various remarks that did not make it into <a href="/assets/img/blog/imported-posts/csmith.pdf">our article about Csmith-testing Frama-C</a>. +<p>This page contains various remarks that did not make it into <a href="/assets/img/blog/imported-posts/csmith.pdf">our article about Csmith-testing Frama-C</a>. It is an annex of sorts except that it is written in a less formal style that will be familiar to readers of <a href="/">the Frama-C blog</a>. It is not intended to make sense by itself: if you have not read the article start there and then come back here. Sorry for the disorganized presentation.</p> <h2>Why standard differential testing does not look directly applicable</h2> diff --git a/_posts/2012-01-20-A-bit-of-explanation-regarding-the-quiz-in-the-last-post.html b/_posts/2012-01-20-A-bit-of-explanation-regarding-the-quiz-in-the-last-post.html index c84d8f17c2cbb3fab349a98730b082e60d41ea7c..35244bb12eefd6d27e68549d298619f993f7d0a5 100644 --- a/_posts/2012-01-20-A-bit-of-explanation-regarding-the-quiz-in-the-last-post.html +++ b/_posts/2012-01-20-A-bit-of-explanation-regarding-the-quiz-in-the-last-post.html @@ -35,33 +35,5 @@ hexadecimal-constant: </blockquote> <p>The difference really stems from the fact C90 did not have a <code>long long</code> type and the list of types to try for a decimal constant ended in <code>unsigned long</code> since that type contained values that did not fit in any other type. On a 32-bit architecture where <code>long</code> and <code>int</code> are both 32-bit <code>2147483648</code> fits neither <code>int</code> nor <code>long</code> and so ends up being typed as an <code>unsigned long</code>. Note that on an architecture where <code>long</code> is 64-bit then <code>2147483648</code> and <code>-2147483648</code> are typed as <code>long</code>.</p> <p>Finally when GCC is told with option <code>-std=c99</code> to apply C99 rules on an architecture where <code>long</code> is 32-bit then <code>2147483648</code> is typed as <code>long long</code> so that the expression <code>-2147483648</code> has type <code>long long</code> and value <code>-2147483648</code>.</p> -<p>This should explain the results obtained when compiling the three programs from last post with GCC on 32-bit and on 64-bit architectures.</p> - <p>There are only positive constants in C, as per section 6.4.4 in the C99 standard:</p> -<pre>integer-constant: - decimal-constant integer-suffixopt - octal-constant integer-suffixopt - hexadecimal-constant integer-suffixopt -decimal-constant: - nonzero-digit - decimal-constant digit -octal-constant: - 0 - octal-constant octal-digit -hexadecimal-constant: - hexadecimal-preï¬x hexadecimal-digit - hexadecimal-constant hexadecimal-digit -... -</pre> -<p>The minus sign is not part of the constant according to the grammar.</p> -<p>The expression <code>-0x80000000</code> is parsed and typed as the application of the unary negation operator <code>-</code> to the constant <code>0x80000000</code>. The table in section 6.4.4.1 of the standard shows that, when typing hexadecimal constants, unsigned types must be tried. The list of types to try to fit the hexadecimal constant in is, in order, <code>int</code>, <code>unsigned int</code>, <code>long</code>, <code>unsigned long</code>, <code>long long</code>, <code>unsigned long long</code>.</p> -<p>For many architectures, the first type in the list that fits <code>0x80000000</code> is <code>unsigned int</code>. Unary negation, when applied to an <code>unsigned int</code>, returns an <code>unsigned int</code>, so that <code>-0x80000000</code> has type <code>unsigned int</code> and value <code>0x80000000</code>.</p> -<p>Following the same reasoning as above, reading from the \Decimal Constant" column of the table in the C99 standard the types to try are <code>int</code> <code>long</code> and <code>long long</code>. This might lead you to expect <code>-2147483648</code> for the value of the expression <code>-2147483648</code> compiled with GCC. Instead when compiling this expression on a 32-bit architecture GCC emits a warning and the expression has the value <code>2147483648</code> instead. The warning is:</p> -<pre>t.c:6: warning: this decimal constant is unsigned only in ISO C90 -</pre> -<p>Indeed there is a subtlety here for 32-bit architectures. GCC by default follows the C90 standard. It's not so much that the spirit of the table in section 6.4.4.1 in C99 changed between C90 and C99. The spirit remained the same with unsigned types being tried for octal and hexadecimal constants and mostly only signed types being tried for decimal constants. Here is the relevant snippet from <a href="http://flash-gordon.me.uk/ansi.c.txt">the C90 standard</a>:</p> -<blockquote><p>The type of an integer constant is the first of the corresponding list in which its value can be represented. Unsuffixed decimal: int long int unsigned long int;</p> -</blockquote> -<p>The difference really stems from the fact C90 did not have a <code>long long</code> type and the list of types to try for a decimal constant ended in <code>unsigned long</code> since that type contained values that did not fit in any other type. On a 32-bit architecture where <code>long</code> and <code>int</code> are both 32-bit <code>2147483648</code> fits neither <code>int</code> nor <code>long</code> and so ends up being typed as an <code>unsigned long</code>. Note that on an architecture where <code>long</code> is 64-bit then <code>2147483648</code> and <code>-2147483648</code> are typed as <code>long</code>.</p> -<p>Finally when GCC is told with option <code>-std=c99</code> to apply C99 rules on an architecture where <code>long</code> is 32-bit then <code>2147483648</code> is typed as <code>long long</code> so that the expression <code>-2147483648</code> has type <code>long long</code> and value <code>-2147483648</code>.</p> <p>This should explain the results obtained when compiling the three programs from last post with GCC on 32-bit and on 64-bit architectures.</p> {% endraw %} diff --git a/_posts/2012-01-20-Checking-for-overflows-operation-by-operation.html b/_posts/2012-01-20-Checking-for-overflows-operation-by-operation.html index faaa524af18026be0978d3e6b0899f6f05d03cb4..c463ce9709ee844727de39b462f0c26e319a6a23 100644 --- a/_posts/2012-01-20-Checking-for-overflows-operation-by-operation.html +++ b/_posts/2012-01-20-Checking-for-overflows-operation-by-operation.html @@ -62,60 +62,5 @@ u.c:8:[value] Assertion got status valid. <h2>Conclusion</h2> <p>The conclusion is that looking at overflows atomically is not a silver bullet. Granted if all possible overflows in the program are verified to be impossible then machine integers in the program observationally behave like mathematical integers. But the more common case is that some overflows do in fact happen in the program and are justified as benign by the programmer. The issue pointed out by Bernard Botella is that it is possible to justify an overflow for which the rule seems too strict by exhibiting input values for which the expected result is computed and then to be surprised by the consequences.</p> -<p>Perhaps in another post we can look at ways around this issue.</p> - <p>My colleague Bernard Botella pointed out an interesting example in an offline discussion following <a href="/conversions-and-promotions/facetious-colleagues/2012/01/20/Constants-quiz">the last quiz</a>.</p> -<h2>The setup</h2> -<p>Consider the snippet:</p> -<pre>int s; -unsigned u1 u2; -... -s = u1 - u2; -</pre> -<p>The programmer's intention with the assignment is to compute in variable <code>s</code> of type <code>int</code> the mathematical difference between the value of <code>u1</code> and the value of <code>u2</code>. You would expect that using automatic plug-ins in Frama-C ey would be able to check that the initial values for <code>u1</code> and <code>u2</code> are in ranges for which this is always what happens.</p> -<p>In fact this looks like a perfect assignment for Rte and the value analysis. Rte can generate assertions for the various conversions and the value analysis can check whether the conditions are satisfied following the method outlined in a <a href="/index.php?post/2012/02/04/Using-Rte-and-Value-to-detect-overflows">recent post</a>.</p> -<p>This is after all exactly what static analyzers — and coding rules that forbid overflows — are for.</p> -<h2>An obvious false positive</h2> -<p>The overflow in the subtraction <code>u1 - u2</code> looks like it can be justified away. After all such a warning is emitted when <code>u1==3</code> and <code>u2==5</code> and <code>s</code> will still receive the expected value <code>-2</code> after the implementation-defined conversion from the value of expression <code>u1 - u2</code> that is <code>UINT_MAX - 1</code> to <code>int</code>.</p> -<p>The programmer may think “okay I can see why I get this warning it happens as soon as <code>u2</code> is larger than <code>u1</code> but this is defined and in my case innocuous. I only want to check that the mathematical difference fits in <code>s</code>. The check about the absence of overflow in the conversion to <code>int</code> is what I am really interested in.â€</p> -<p>Say that the programmer is using the Rte plug-in to express the conditions for both the subtraction and the implicit conversion to <code>int</code> to be safe pretty-printing an annotated program as a result:</p> -<pre>$ frama-c -rte-unsigned-ov -rte t.c -print -... -void main(void) -{ - /*@ assert rte: (unsigned int)(u1-u2) ≤ 2147483647; */ - /*@ assert rte: u1-u2 ≥ 0; */ - s = (int)(u1 - u2); - return; -} -</pre> -<p>Since the programmer has seen that the second assertion about an overflow in the subtraction <code>u1 - u2</code> is too restrictive preventing use with <code>u1==3</code> and <code>u2==5</code> ey removes it. -The programmer instead focuses on making sure that there is no overflow in the conversion to <code>int</code> of the difference and feels confident if ey sees that there isn't any warning about that. It seems normal right?</p> -<pre>void main(void) -{ - /*@ assert rte: (unsigned int)(u1-u2) ≤ 2147483647; */ - s = (int)(u1 - u2); - return; -} -</pre> -<h2>But…</h2> -<p>Consider the case where <code>u1</code> is very small <code>u2</code> is very large and the value analysis has been able to infer this information relatively precisely. We assume 0 ≤ u1 ≤ 10 and 3000000000 ≤ u2 ≤ 4000000000 for this example:</p> -<pre>/*@ requires 0 <= u1 <= 10 ; - requires 3000000000 <= u2 <= 4000000000 ; */ -void main(void) -{ - /*@ assert rte: (unsigned int)(u1-u2) ≤ 2147483647; */ - s = (int)(u1 - u2); - return; -} -</pre> -<p>In this case the value analysis does not warn about the conversion to <code>int</code> ...</p> -<pre>$ frama-c -val -lib-entry u.c -... -u.c:8:[value] Assertion got status valid. -</pre> -<p>... but the value in <code>s</code> is not the mathematical difference between <code>u1</code> and <code>u2</code>.</p> -<h2>Conclusion</h2> -<p>The conclusion is that looking at overflows atomically is not a silver bullet. Granted if all possible overflows in the program are verified to be impossible then machine integers in the program observationally behave like mathematical integers. But the more common case is that some overflows do in fact happen in the program and are justified as benign by the programmer. The issue pointed out by Bernard Botella is that -it is possible to justify an overflow for which the rule seems too strict by exhibiting input values for which the expected result is computed and then to be surprised by the consequences.</p> <p>Perhaps in another post we can look at ways around this issue.</p> {% endraw %} diff --git a/_posts/2012-01-20-Constants-quiz.html b/_posts/2012-01-20-Constants-quiz.html index d83915326594ee556727c89662d936dcddfea1fc..a575ddb7f1e7036ea8e2dac1f7feac2bc973e80a 100644 --- a/_posts/2012-01-20-Constants-quiz.html +++ b/_posts/2012-01-20-Constants-quiz.html @@ -38,36 +38,5 @@ int main() } $ gcc -std=c99 t.c && ./a.out </pre> -<p>You are probably reading this on a computer on which the answers are "2147483648" "2147483648" and "-2147483648".</p> - <p>What does the following program print?</p> -<pre>long long l; -#include <stdio.h> -int main() -{ - l = -0x80000000; - printf(\%lld" l); -} -$ gcc t.c && ./a.out -</pre> -<p>And this one? (beware trick question)</p> -<pre>long long l; -#include <stdio.h> -int main() -{ - l = -2147483648; - printf("%lld" l); -} -$ gcc t.c && ./a.out -</pre> -<p>What "it's too difficult!"? Okay here is a hint in the form of a third question:</p> -<pre>long long l; -#include <stdio.h> -int main() -{ - l = -2147483648; - printf("%lld" l); -} -$ gcc -std=c99 t.c && ./a.out -</pre> <p>You are probably reading this on a computer on which the answers are "2147483648" "2147483648" and "-2147483648".</p> {% endraw %} diff --git a/_posts/2012-01-20-Math-proofs-and-programming.html b/_posts/2012-01-20-Math-proofs-and-programming.html index cfc22495afbbdb4b7264a7ac3818cf8ffd628ada..35a04b78b45320bdecbd4df9f525d03df0959ff3 100644 --- a/_posts/2012-01-20-Math-proofs-and-programming.html +++ b/_posts/2012-01-20-Math-proofs-and-programming.html @@ -12,10 +12,5 @@ summary: <blockquote><p>In hindsight it is surprising that I disliked doing math proofs in high school despite already being a programmer.</p> </blockquote> <p>It says a lot about the French education system that I started teaching myself programming at 6 and officially switched from mathematics to computer science as a 20-year-old first-year ENS student. And I know why I disliked doing math proofs most of that time too: for exactly the same reason I would have disliked programming if it had been done with paper and ink.</p> -<p>As a 6-year-old child I would run the BASIC program I was typing (either from a listing or making it up as I was going along) every five or so typed statements. Try that with a math proof.</p> - <p>Speaking of John Carmack, in his twitter feed, he <a href="https://twitter.com/#!/ID_AA_Carmack/status/160402312978907136">notes</a>:</p> -<blockquote><p>In hindsight it is surprising that I disliked doing math proofs in high school despite already being a programmer.</p> -</blockquote> -<p>It says a lot about the French education system that I started teaching myself programming at 6 and officially switched from mathematics to computer science as a 20-year-old first-year ENS student. And I know why I disliked doing math proofs most of that time too: for exactly the same reason I would have disliked programming if it had been done with paper and ink.</p> <p>As a 6-year-old child I would run the BASIC program I was typing (either from a listing or making it up as I was going along) every five or so typed statements. Try that with a math proof.</p> {% endraw %} diff --git a/_posts/2012-01-21-A-reference-peeve.html b/_posts/2012-01-21-A-reference-peeve.html index 5e1ecf0470c6112ac09f3366adfab6f190295b7f..65d377ca2d9c7780af2a27c148f59c38c19ea958 100644 --- a/_posts/2012-01-21-A-reference-peeve.html +++ b/_posts/2012-01-21-A-reference-peeve.html @@ -12,10 +12,5 @@ summary: <p>Many people, some of whom should know better, mention Floyd, Hoare and Dijkstra in the same sentence as modern verification condition generators (Frama-C's Wp plug-in, Frama-C's Jessie plug-in, Microsoft Research's VCC, ...) as if there was nothing in between the <a href="http://en.wikipedia.org/wiki/Hoare_logic">writings of these great men</a> and those tools.</p> <p><a href="http://www.first.fraunhofer.de/fileadmin/FIRST/ACSL-by-Example.pdf">ACSL By Example</a> by example has a "The Hoare Calculus" section with rules that are close to some old publication from one of these three authors. It gives an intuition of how Jessie and now Wp work but you have to realize that these are not the rules that these tools actually use not by a far shot.</p> <p>It is one of the creators of modern verification generators' achievements that their verifiers work so well you don't notice they aren't using the simple intuitive rules. They aren't and if they were you <strong>would</strong> notice. If you are a pragmatist and want to feel the difference between this and that try making classical Hoare logic rules work to compute the actual weakest precondition for <a href="http://lists.gforge.inria.fr/pipermail/frama-c-discuss/2009-January/000912.html">this simple C function</a> and work your way up from there.</p> -<p>Implying that modern verification condition generators are direct applications of the work of Floyd Hoare and Dijkstra is akin to walking to say one of the contributors of the <a href="http://clang.llvm.org/">Clang compiler</a> and implying that ey is basically implementing <a href="http://eprints.cs.vt.edu/archive/00000875/01/CS82010-R.pdf">ideas from Backus et al</a>.</p> - <p>One thing has been peeving me for a while. It is small and does not impact me directly, so I didn't speak up, but perhaps I should.</p> -<p>Many people, some of whom should know better, mention Floyd, Hoare and Dijkstra in the same sentence as modern verification condition generators (Frama-C's Wp plug-in, Frama-C's Jessie plug-in, Microsoft Research's VCC, ...) as if there was nothing in between the <a href="http://en.wikipedia.org/wiki/Hoare_logic">writings of these great men</a> and those tools.</p> -<p><a href="http://www.first.fraunhofer.de/fileadmin/FIRST/ACSL-by-Example.pdf">ACSL By Example</a> by example has a "The Hoare Calculus" section with rules that are close to some old publication from one of these three authors. It gives an intuition of how Jessie and now Wp work but you have to realize that these are not the rules that these tools actually use not by a far shot.</p> -<p>It is one of the creators of modern verification generators' achievements that their verifiers work so well you don't notice they aren't using the simple intuitive rules. They aren't and if they were you <strong>would</strong> notice. If you are a pragmatist and want to feel the difference between this and that try making classical Hoare logic rules work to compute the actual weakest precondition for <a href="http://lists.gforge.inria.fr/pipermail/frama-c-discuss/2009-January/000912.html">this simple C function</a> and work your way up from there.</p> <p>Implying that modern verification condition generators are direct applications of the work of Floyd Hoare and Dijkstra is akin to walking to say one of the contributors of the <a href="http://clang.llvm.org/">Clang compiler</a> and implying that ey is basically implementing <a href="http://eprints.cs.vt.edu/archive/00000875/01/CS82010-R.pdf">ideas from Backus et al</a>.</p> {% endraw %} diff --git a/_posts/2012-01-23-Option-to-make-GCC-conform-to-C99-refloating-point.html b/_posts/2012-01-23-Option-to-make-GCC-conform-to-C99-refloating-point.html index 7d2abfa73a01f13a48013fed76f9087bdb0f58e4..c10812fa4c64098319810fd03173bfcde54655f8 100644 --- a/_posts/2012-01-23-Option-to-make-GCC-conform-to-C99-refloating-point.html +++ b/_posts/2012-01-23-Option-to-make-GCC-conform-to-C99-refloating-point.html @@ -10,8 +10,5 @@ summary: {% raw %} <p>The existence of this option to make GCC conform to C99 when compiling for the x87 floating-point instruction set is informative. The commentary that comes with the patch is quite interesting, if you are into this sort of thing.</p> <p>If you are not that much into the minutiae of the implementation of C99's floating-point on x87 hardware, on the other hand, don't follow <a href="http://gcc.gnu.org/ml/gcc-patches/2008-11/msg00105.html">this link</a>. The short story not contained there is that you can always use the SSE2 instruction set to get even more standard floating-point semantics and that you can always use Frama-C's value analysis option -all-rounding-modes to analyze x87 floating-point programs for all possible compilation choices even if the program is compiled without the option described there.</p> -<p>(Both these statements are true to the best of my understanding but I wouldn't sit under a piano hanging on them)</p> - <p>The existence of this option to make GCC conform to C99 when compiling for the x87 floating-point instruction set is informative. The commentary that comes with the patch is quite interesting, if you are into this sort of thing.</p> -<p>If you are not that much into the minutiae of the implementation of C99's floating-point on x87 hardware, on the other hand, don't follow <a href="http://gcc.gnu.org/ml/gcc-patches/2008-11/msg00105.html">this link</a>. The short story not contained there is that you can always use the SSE2 instruction set to get even more standard floating-point semantics and that you can always use Frama-C's value analysis option -all-rounding-modes to analyze x87 floating-point programs for all possible compilation choices even if the program is compiled without the option described there.</p> <p>(Both these statements are true to the best of my understanding but I wouldn't sit under a piano hanging on them)</p> {% endraw %} diff --git a/_posts/2012-02-04-Using-the-Rte-and-value-analysis-plug-ins-to-detect-overflows.html b/_posts/2012-02-04-Using-the-Rte-and-value-analysis-plug-ins-to-detect-overflows.html index b00b9f72e22d9bda0dfb566ad4ec1ffaf3faa83e..6c2ac19997b26e65617d6e7b3a98bd14c667161d 100644 --- a/_posts/2012-02-04-Using-the-Rte-and-value-analysis-plug-ins-to-detect-overflows.html +++ b/_posts/2012-02-04-Using-the-Rte-and-value-analysis-plug-ins-to-detect-overflows.html @@ -49,47 +49,5 @@ int main(void) <pre>m.c:3:[value] Assertion got status unknown. </pre> <h2>Credits</h2> -<p>John Regehr <a href="http://lists.gforge.inria.fr/pipermail/frama-c-discuss/2009-June/001235.html">convincingly argued</a> the case of option <code>-val-signed-overflow-alarms</code> at a time when it didn't exist yet. Faithful user Jean-Marc Harang provided the example used in this post and he also authored the referred presentation at the last U3CAT meeting. The Rte plug-in is developed by Philippe Herrmann.</p> - <p>This post is another of the methodological cheat cards that made up much of this blog at its beginnings, before I decided that controversial comparisons between static analyzers were more fun to write.</p> -<h2>The problem: detecting semantic coding rules transgressions</h2> -<p>By default, Frama-C's value analysis does not warn about integer overflows. You need to use option <code>-val-signed-overflow-alarms</code> for an alarm to be emitted whenever it looks like one of these might happen. Even then, the value analysis only warns about overflows occurring in signed arithmetic operations. It does not warn about overflows in unsigned operations, because these are defined. It does not warn either about overflows in conversions, such as <code>(unsigned int)(-1)</code>, that is defined because the destination type is unsigned, or <code>(int) UINT_MAX</code>, that is implementation-defined (and in practice, usually reveals the 2's complement representation used by the target architecture).</p> -<p>In consequence, the value analysis does not warn about the post-decrement operation in the following example, sent in by a faithful user.</p> -<pre>main(){ - unsigned int nb_trames = Frama_C_interval (0, 5120); - nb_trames -- ; - nb_trames /= 256 ; -} -</pre> -<p>The faithful user noticed that something was wrong in the function because the range computed by the value analysis for variable <code>nb_trames</code> included the case where <code>nb_trames</code> was initially <code>0</code> and eventually <code>UINT_MAX / 256</code>. This did not match the specification, but it was pure luck that the underflow was detected through this side-effect. -Sometimes, one would like a possible underflow such as <code>nb_trames -- ;</code> in the above example to be detected as wrong in itself, not because it is forbidden by the C standard (it isn't), but because it is forbidden by specifically applicable coding standards.</p> -<blockquote><p>Speaking of blogging beginnings and of controversy, the position on coding standards that I expressed in my <a href="http://rdn-consulting.com/blog/2009/05/15/guest-article-static-analysis-in-medical-device-software-part-1-the-traps-of-c/">very first blog post</a> was that "any fool can invent theirs and some have". Another thing that fools reputedly do is not change their minds. Perhaps coincidentally my opinion on the subject has mellowed a bit. Still there are many of these coding standards and I am unwilling to multiply in the value analysis options similar to <code>-val-signed-overflow-alarms</code> but for the various conditions that someone somewhere might think undesirable. In any case this unwillingness is only my opinion and this opinion is only in the context of the value analysis plug-in. Anyone is encouraged to write Frama-C plug-ins for verifying any coding standard they like and some have.</p> -</blockquote> -<p>One of the highlights of the last U3CAT meeting was in an industrial case study the combination of the value analysis and Rte plug-ins to detect overflows in unsigned arithmetic operations or in any kind of integer conversion.</p> -<h2>The Frama-C Rte plug-in</h2> -<p>The Rte plug-in can annotate a program with ACSL assertions that exclude unwanted conditions at execution. As the name of the plug-in indicates the initial motivation was to have assertions that excluded run-time errors but Rte is actually quite flexible in what it allows to forbid. In particular it allows to generate assertions that forbid the unsigned underflow from our example:</p> -<pre>$ frama-c -rte-unsigned-ov -rte m.c -print -... -extern int ( /* missing proto */ Frama_C_interval)(); -int main(void) -{ - int __retres; - unsigned int nb_trames; - nb_trames = (unsigned int)Frama_C_interval(0 5120); - /*@ assert rte: nb_trames-1U ≥ 0; */ - nb_trames --; - nb_trames /= (unsigned int)256; - __retres = 0; - return (__retres); -} -</pre> -<p>The normalization step applied to any program that goes through Frama-C shows but the original program is quite recognizable with the ACSL assertion <code>nb_trames-1U ≥ 0;</code> strategically inserted just before <code>nb_trames</code> is decremented.</p> -<h2>Evaluating with <code>-val</code> assertions emitted by Rte</h2> -<p>Assigning a truth value to the assertions inserted by Rte is as simple as running the value analysis on the annotated program it produced. It can be done in a single command like so:</p> -<pre>$ frama-c -rte-unsigned-ov -rte m.c share/builtin.c -then -val -</pre> -<p>And it works: the value analysis rightly detects that the conditions for the absence of unsigned overflow are not met.</p> -<pre>m.c:3:[value] Assertion got status unknown. -</pre> -<h2>Credits</h2> <p>John Regehr <a href="http://lists.gforge.inria.fr/pipermail/frama-c-discuss/2009-June/001235.html">convincingly argued</a> the case of option <code>-val-signed-overflow-alarms</code> at a time when it didn't exist yet. Faithful user Jean-Marc Harang provided the example used in this post and he also authored the referred presentation at the last U3CAT meeting. The Rte plug-in is developed by Philippe Herrmann.</p> {% endraw %} diff --git a/_posts/2012-02-09-Float-vs-real.html b/_posts/2012-02-09-Float-vs-real.html index b528ad8b587994004a5ea870e6da3e3f47761db7..2bee564e8cb9ac9b75cde8f8edbe694c052d5744 100644 --- a/_posts/2012-02-09-Float-vs-real.html +++ b/_posts/2012-02-09-Float-vs-real.html @@ -9,6 +9,5 @@ summary: --- {% raw %} <p>For some reason, uses of <code>real</code> to denote fixed-precision floating-point numbers (in languages such as FORTRAN) irritate me, but uses of <code>integer</code> or <code>int</code> to denote bounded integers do not. One notation isn't more accurate than the other, though.</p> -<p>Does anyone have an idea why that might be?</p> <p>For some reason, uses of <code>real</code> to denote fixed-precision floating-point numbers (in languages such as FORTRAN) irritate me, but uses of <code>integer</code> or <code>int</code> to denote bounded integers do not. One notation isn't more accurate than the other, though.</p> -<p>Does anyone have an idea why that might be?</p> +<p>Does anyone have an idea why that might be?</p> {% endraw %} diff --git a/_posts/2012-02-12-Checking-for-overflows-revisited-once.html b/_posts/2012-02-12-Checking-for-overflows-revisited-once.html index 686ad5e67b399eb31a8106e82aa5b7ddecb1499b..c7e80c71acdae1d85fa361e6c0d9c6c40891f160 100644 --- a/_posts/2012-02-12-Checking-for-overflows-revisited-once.html +++ b/_posts/2012-02-12-Checking-for-overflows-revisited-once.html @@ -30,28 +30,5 @@ f: </pre> <blockquote><p>As an anecdote when generating x86-64 code (and therefore having 64-bit subtraction available as a single instruction with only the drawback of a slightly larger encoding) <code>gcc -O0</code> keeps using 32-bit subtraction but <code>clang -O0</code> uses 64-bit subtraction. This does not reveal anything about the compilers: it does not make sense to compare for efficiency the code they generate with optimization disabled.</p> </blockquote> -<p>That's all for this post.</p> - <p>I do not have any solution I am 100% happy with to the overflow dilemma in the <a href="/index.php?post/2012/02/10/Overflow-checking">previous post</a>. Here is one of the solutions that does not make me 100% happy.</p> -<p>The first (partial) solution is: program so that overflows correspond exactly to unwanted circumstances (and then it becomes meaningful to verify the absence of overflows. There are great automatic tools for that. Have you heard of them?)</p> -<p>“Program so that…†sounds abstract but it may be as simple as using larger integer types that won't overflow for all intermediate computations:</p> -<pre> s = (int)((long long) u1 - (long long)u2); -</pre> -<p>Then the desired property (variable <code>s</code> contains the mathematical difference of <code>u1</code> and <code>u2</code>) entirely rests on the final conversion from <code>long long</code> to <code>int</code>.</p> -<p>This solution doesn't apply in the common situation where the code is already written and <strong>gratuitous changes to it are prohibited</strong>. Also you need to have an integer type large enough to contain all intermediate computations without overflows. In this example <code>unsigned int</code> is 32-bit and <code>long long</code> is 64-bit but the standard does not prevent <code>unsigned int</code> to be 64-bit and the same size as <code>long long</code> in which case the conversion from <code>unsigned int</code> to <code>long long</code> could overflow. Rte would only insert additional assertions for the two intermediate conversions that we have added in the assignment. This wouldn't help; it would only make things worse.</p> -<p>“Won't the generated code be less efficient?†you rightly ask. That all depends on the compiler. Optimizing compilers have no trouble at all optimizing the above assignment so that it uses only one 32-bit subtraction. On the Linux workstation on which I tried this both <code>clang -m32 -O0</code> and <code>gcc -m32 -O0</code> did. It is amusing because the code generated by both compilers with <code>-O0</code> is ugly (gratuitously moving registers to memory and then to registers again) but even with optimizations disabled they still both get the fact that it is only necessary to compute the least significant 32 bits of the result.</p> -<p>With optimizations both Clang and GCC generate clean code that naturally still uses a single 32-bit subtraction:</p> -<pre>$ gcc -S -O2 -m32 t.c -$ cat t.s -... -f: - pushl %ebp - movl %esp %ebp - movl 8(%ebp) %eax - subl 12(%ebp) %eax - popl %ebp - ret -</pre> -<blockquote><p>As an anecdote when generating x86-64 code (and therefore having 64-bit subtraction available as a single instruction with only the drawback of a slightly larger encoding) <code>gcc -O0</code> keeps using 32-bit subtraction but <code>clang -O0</code> uses 64-bit subtraction. This does not reveal anything about the compilers: it does not make sense to compare for efficiency the code they generate with optimization disabled.</p> -</blockquote> <p>That's all for this post.</p> {% endraw %} diff --git a/_posts/2012-02-18-Week-end-cryptographic-link.html b/_posts/2012-02-18-Week-end-cryptographic-link.html index 447b49930e48ea431c2266505ed98404783be7d3..89c063c17300ec244ac0c6168520a76cafe67a9b 100644 --- a/_posts/2012-02-18-Week-end-cryptographic-link.html +++ b/_posts/2012-02-18-Week-end-cryptographic-link.html @@ -9,5 +9,4 @@ summary: --- {% raw %} <p>A good read: <a href="http://dankaminsky.com/2012/02/17/primalfear/">Primal Fear: Demuddling The Broken Moduli Bug</a></p> - <p>A good read: <a href="http://dankaminsky.com/2012/02/17/primalfear/">Primal Fear: Demuddling The Broken Moduli Bug</a></p> {% endraw %} diff --git a/_posts/2012-03-02-ptrdiff_t-links-for-the-week-end.html b/_posts/2012-03-02-ptrdiff_t-links-for-the-week-end.html index f1afec38735d69cda8ba47dc1ff74258972fd108..693202ae433861cbdbdac690fc059ae27d7b877c 100644 --- a/_posts/2012-03-02-ptrdiff_t-links-for-the-week-end.html +++ b/_posts/2012-03-02-ptrdiff_t-links-for-the-week-end.html @@ -37,34 +37,5 @@ main(){ <p>Please take a moment to predict the number printed by the above program yourself before looking down.</p> <pre>$ gcc -m32 t.c && ./a.out -2144967296 -</pre>" <p>Here are two links related to <code>ptrdiff_t</code>:</p> -<ul> -<li><a href="http://blogs.msdn.com/b/david_leblanc/archive/2008/09/02/ptrdiff-t-is-evil.aspx">Ptrdiff_t is evil</a> a blog post for if you are not tired of conversion and promotion issues yet </li> -<li>and an interesting <a href="http://stackoverflow.com/a/9538071/139746">answer on StackOverflow</a>.</li> -</ul> -<p>I was doubtful about the second one (I had no difficulties to accept the first one after the previous conversions-and-promotions-related posts on this blog). But type <code>ptrdiff_t</code> is for storing pointer differences right? Why would a compilation platform (compiler and associated standard library including <code>malloc()</code>) make it just too small to hold all possible pointer differences? So I tested it and StackOverflow user R.. is right:</p> -<pre>#include <stddef.h> -#include <stdio.h> -main(){ - printf("%d" (int) sizeof(ptrdiff_t)); -} -</pre> -<p>Compiling as a 32-bit program:</p> -<pre>$ gcc -m32 t.c && ./a.out -4 -</pre> -<p>I am pretty sure I have allocated 2.2GB in a single <code>malloc()</code> call of a 32-bit process on this system. I was thankful for getting that much at the time too. But 4 bytes are not enough to hold all signed differences between two pointers to char within a single 2.2GB chunk of memory:</p> -<pre>#include <stdio.h> -#include <stdlib.h> -main(){ - char *p = malloc(2200000000U); - if (!p) return 1; - char *q = p + 2150000000U; - printf("%td" q - p); -} -</pre> -<p>Please take a moment to predict the number printed by the above program yourself before looking down.</p> -<pre>$ gcc -m32 t.c && ./a.out --2144967296 -</pre>" +</pre> {% endraw %} diff --git a/_posts/2012-03-12-Minimizing-the-number-of-alarms-emitted-by-the-value-analysis.html b/_posts/2012-03-12-Minimizing-the-number-of-alarms-emitted-by-the-value-analysis.html index 6a994a8a186f712dd8128c4c588beb8627fa8e2a..d66573117045071414cb5baa9f0fde19b5b8bd9e 100644 --- a/_posts/2012-03-12-Minimizing-the-number-of-alarms-emitted-by-the-value-analysis.html +++ b/_posts/2012-03-12-Minimizing-the-number-of-alarms-emitted-by-the-value-analysis.html @@ -145,143 +145,5 @@ int main (int c char **v) <p>Well it was worth trying. Unsurprisingly after the half hour is elapsed the same single alarm is found as in the <code>-slevel 100000</code> analysis.</p> <h2>Conclusion</h2> <p>The number of options available in the Frama-C platform can be a little bit overwhelming. It is for a good reason that the value analysis tutorial emphasizes option <code>-slevel</code> and this option only. On the example from this post it does not hurt very much only to know about this one: it allows you to obtain the optimal result and you do not seem to be penalized by more than a few seconds for not remembering all the other ones.</p> -<p>Unfortunately the example in this post is only one example and in special cases it may be necessary to have more than one string to one's bow.</p> - <p>This blog post describes for the first time some options that became available in Nitrogen, continuing <a href="/index.php?tag/nitrogen">this series</a>. This post also offers a benchmark but the results of this benchmark cannot be reproduced with Nitrogen. They should be reproducible with the next version of Frama-C.</p> -<h2>Alarms false alarms and redundant alarms</h2> -<p>Frama-C's value analysis computes two results for further processing: values and alarms. In this post we assume that the list of alarms is what the user is interested in. -That is eir objective is to obtain a list of conditions (alarms) that ey will only need to check never happens in order to be assured that the program is defined. Defined in the sense of the value analysis that is. Understandably the user would like to spend as little time and memory as possible to obtain this list. However because human or computation time is going to be spend further processing each alarm ey would like the list to be as short as possible. Ey is willing to spend some extra time and memory shortening the list within reason.</p> -<p>The user still wants the list to be exhaustive. One valid way to shorten the list is to remove false alarms from it if the extra time and memory can be used to determine that some of the alarms are false alarms. Another alarm that can validly be removed from the list is a redundant alarm that cannot happen as long as another previous alarm is verified not to happen first. One example of a redundant alarm that the value analysis cannot easily remove by itself is provided in the manual:</p> -<pre>int A B; -void main(int x int y) -{ - A = 100 / (x * y); - B = 333 % x; -} -</pre> -<p>This example assumes signed overflows give 2's complement results (and should not be considered as dangerous). With these settings the value analysis emits two alarms:</p> -<pre>$ frama-c -val div.c -div.c:4: ... assert (int)(x*y) ≢ 0; -div.c:5: ... assert x ≢ 0; -</pre> -<p>The alarm at line 5 is redundant with the alarm at line 4. The alarm at line 5 could theoretically be removed because if <code>x*y</code> is non-nil then <code>x</code> is guaranteed to be non-nil too (and the reasoning applies even if “<code>x*y</code> is non-nil†is taken to mean that the product is non-nil modulo 2^32).</p> -<blockquote><p>Unrelated exercise for the motivated reader: through command-line options and program annotations guide the analyzer so that it only emits the alarm at line 4 without making any assumption that it wasn't making in the original analysis.</p> -</blockquote> -<h2>Example: a string manipulation function</h2> -<p>This <a href="/assets/img/blog/imported-posts/libgd.tgz">example</a> was provided by some of my colleagues. More on that later. For now it suffices to say that the set-up is perfect: the command <code>frama-c -metrics gd_full_bad.c</code> shows that it only needs <code>Frama_C_interval()</code> provided in a file <code>builtin.c</code> with Frama-C. The analysis runs with <code>frama-c -val .../share/frama-c/builtin.c gd_full_bad.c</code>.</p> -<h2>The basic approach</h2> -<p>The green belt user having read the tutorial knows that after checking that eir analysis project does not call any missing functions and doing an imprecise analysis if said imprecise analysis is fast enough ey has the option to run the analysis again with option <code>-slevel</code> for a chance to obtain more precise results. More precise results means fewer alarms so a good first benchmark is to measure the effects of various values of <code>-slevel</code> on analysis time and how many alarms these analysis seconds gain us.</p> -<pre>for i in 0 10 100 1000 10000 100000 -do - /usr/bin/time ~/ppc/bin/toplevel.opt ... -slevel $i > log_slevel_$i 2> time_slevel_$i -done -</pre> -<p>The table below gives for each value used for the <code>-slevel</code> option the analysis time and the number of alarms emitted.</p> -<pre>slevel alarms time(s) - 0 13 0.61 - 10 13 0.62 - 100 13 1.0 - 1000 12 6.0 - 10000 9 105 -100000 1 441 -</pre> -<p>The single alarm that remains even with <code>-slevel 100000</code> is at a line preceded by the comment <code>/* BAD */</code> in the source code. With the information implicitly carried in the name of the file we can assume this one to be a true alarm intended to be found and that will not go away with any value of <code>-slevel</code>. Further assuming there are no other bugs to be found in this code (which is what the value analysis claims) one alarm is the optimal result and it is found in exchange for a wait of a little bit more than 7 minutes. The same alarm is present in the lists of 9 12 or 13 alarms found with the other values of <code>-slevel</code> together with respectively 8 11 and 12 false or redundant alarms.</p> -<h2>Improving results with advanced options</h2> -<h3>Improving results by doing less</h3> -<p>The advanced user knows that when you are not interested in the “values†component of the value analysis' results you can save a sometimes significant amount of time by instructing the analyzer not to save them for you. An hitherto less documented option is <code>-no-val-show-progress</code> that similarly saves the analyzer the bother of printing progression messages for when no-one is going to read them.</p> -<pre>slevel alarms time(s) - 0 13 0.45 - 10 13 0.47 - 100 13 0.9 - 1000 12 5.5 - 10000 9 97 -100000 1 439 -</pre> -<p>As you can see the difference is almost lost in the noise which means that I should probably compute confidence intervals and/or boot some of the other users out of the server I am using for this informal comparison. But I'm not going to. The shell commands -in this blog post are among other things so that I can run everything again at a quieter time.</p> -<h3>Improving results by doing more</h3> -<p>Little-known option <code>-remove-redundant-alarms</code> takes some time at the end of the analysis to detect whether some alarms are syntactically identical to prior alarms. If the variables involved in both alarms were left unmodified by the program in-between the latter alarm is identified as redundant and erased from the alarms database.</p> -<p>Detecting whether some alarms are redundant in this manner requires the “values†part of the value analysis' results to resolve pointers so if we use this option we cannot use option <code>-no-results</code>. For the good that one did us option <code>-remove-redundant-alarms</code> is worth a try.</p> -<blockquote><p>Note that <code>-remove-redundant-alarms</code> does not retroactively remove emitted alarms from the log. You can obtain the filtered list programmatically by looking for it in the GUI or with option <code>-print</code>.</p> -</blockquote> -<p>Running again the previous tests with option <code>-remove-redundant-alarms</code> the difference in computation time is lost in the noise when compared to the timings <strong>without</strong> option <code>-no-results</code>. For this negligible price one assertion is removed from the list of 13 obtained with values 0 10 and 100 of option <code>-slevel</code>.</p> -<p>One assertion removed as redundant may not seem like much but it means that for this particular example if you are starting from <code>-slevel 0</code> and are willing to spend just enough additional resources to go from 13 to 12 alarms you are better off investing in <code>-remove-redundant-alarms</code> that will take 0.10s to get you there than in <code>-slevel 1000</code> that will require 5s of additional computation time for the same result.</p> -<pre>$ ~/ppc/bin/toplevel.opt ... -remove-redundant-alarms -print > lrm -$ ~/ppc/bin/toplevel.opt ... -print > lpl -$ diff -u lpl lrm ---- lpl 2012-03-12 21:38:54.000000000 +0100 -+++ lrm 2012-03-12 21:38:49.000000000 +0100 -@@ -42 6 +42 9 @@ - gd_full_bad.c:143:[value] Assertion got status unknown. - gd_full_bad.c:46:[value] warning: 2's complement assumed for overflow - [value] done for function main -+[from] Computing for function search -+[from] Done for function search -+[scope] [rm_asserts] removing 1 assertion(s) - [value] ====== VALUES COMPUTED ====== - [value] Values at end of function Frama_C_interval: - Frama_C_entropy_source ∈ [--..--] -@@ -293 9 +296 6 @@ - } - } - len = 1; -- /*@ assert \valid{Here}(string+next); -- // synthesized -- */ - byte = (int)((unsigned char)*(string + next)); - if (byte < 0xC0) { len = 1; } - else { -</pre> -<p>As this log-level comparison shows with option <code>-remove-redundant-alarms</code> the same alarms are initially found (there are no differences there). With the option Frama-C works harder (lines starting with <code>+</code> indicate work that was done only when the option was present) and removes one alarm from the final printout (lines starting with <code>-</code>). The assertion <code>\valid{Here}(string+next)</code> was found to be redundant with a previous syntactically identical assertion.</p> -<h3>Trying to improve results by doing things differently</h3> -<p>Experiments with using the value analysis as a C interpreter that have been alluded to in this blog led to the introduction in Nitrogen of value analysis option <code>-obviously-terminates</code>. I have previously described this option as emulating infinite slevel and disabling fixpoint detection which is one way to see what it does. More accurately it disables the detection of previously-propagated states. Whereas one may associate fixpoint detection with the analysis of loops the detection of previously seen states normally occurs even outside of loops. It is this detection that is disabled by the option and therefore the option also influences the analysis of loop-free programs.</p> -<blockquote><p>The “obviously†in the name of the option is a reminder that it will only be useful for programs that terminate very obviously. Fixpoint detection and widening are the two techniques through which the value analysis terminates when analyzing programs that themselves do not terminate or do not clearly terminate. Option <code>-obviously-terminates</code> disables both. The consequence is that the analyzer can loop forever. When it is used to turn the value analysis into a C interpreter it makes it loop forever on C programs that loop forever — like an interpreter does. If the option is used outside “interpreter constraints†(for instance if there is initial imprecision on some inputs or if some functions are missing) then the value analysis may even loop while analyzing programs that in reality terminate for all their inputs. Lastly one should keep in mind that it is not enough that the termination of the analyzed program is obvious for the user. It needs to be obvious for the analyzer.</p> -</blockquote> -<h4>An example</h4> -<p>Consider the following loop-free program:</p> -<pre>int x y z t u ...; -int main (int c char **v) - x = c & 1; - if (x) - x = 1; - else - x = 2; - y = x + 1; - z = y; - t = z - 1; - u = t; - ... -</pre> -<p>When this program is analyzed with <code>-slevel 2</code> or more the analyzer spends its time at each statement wondering whether the state coming from the initial then branch has been propagated into something identical to the state coming from the initial else branch. This kind of test can be expensive especially when programs with many execution paths are analyzed with high values of <code>-slevel</code>. Also on this program or a program similar to this one making the test at each statement is a complete waste of time: two states will never be found to be identical if only because the state coming from the then and else branches always have different values for variable <code>x</code>.</p> -<p>Option <code>-obviously-terminates</code> disables these time-wasting tests and makes the analysis of a program like this one much faster.</p> -<h4>Another very slightly different example</h4> -<p>Consider the following following variation of the previous program:</p> -<pre>int x y z t u ...; -int main (int c char **v) - x = c & 1; - if (x) - x = 1; - else - x = 1; - y = x + 1; - z = y; - t = z - 1; - u = t; - ... -</pre> -<p>When analyzing this program without option <code>-obviously-terminates</code> the analyzer immediately recognizes that the states corresponding to the two branches of the <code>if</code> are the same state and merges them into one. Once a single state is left no further expensive inclusion tests are necessary and the analyzer zips through the rest of the program at maximal speed.</p> -<p>With option <code>-obviously-terminates</code> on the other hand the analyzer never tests whether the two branches can be merged. It basically does twice the work propagating each state in duplicate through the rest of the program.</p> -<h4>Concluding on option <code>-obviously-terminates</code></h4> -<p>When you are thinking of using option <code>-obviously-terminates</code>:</p> -<ol> -<li>You should wonder whether the analysis will then terminate.</li> -<li>You should wonder whether the analyzed program is more like the first example or more like the second one. If it is more like the first one you may hope that the analysis with what will effectively amount to infinite slevel will be faster.</li> -</ol> -<p>When an analysis with option <code>-obviously-terminates</code> finishes the results obtained are functionally equivalent to results that would have been obtained with an infinite slevel.</p> -<h4>What about the current benchmark?</h4> -<p>The value <code>-slevel 100000</code> the highest one we used also amounts to offering infinite slevel to the analyzer: the analyzer does not consume the 100000 allowed states using up only about half. One last data point we can therefore obtain is the analysis time with option <code>-obviously-terminates</code> in replacement of <code>-slevel 100000</code>.</p> -<p>It turns out that the benchmark is more like the second example above: the analysis takes longer with option <code>-obviously-terminates</code> about half an hour instead of 7 minutes. The option makes having states propagated through the same program point comparatively cheap because inclusion does not have to be tested. On the other hand because inclusion is not tested some program points see 500000 states propagated through them or about ten times more than the maximum when option <code>-obviously-terminates</code> is not used. Although each of them is less expensive to handle having to deal with ten times as many states hurts the bottom line for this benchmark.</p> -<p>Well it was worth trying. Unsurprisingly after the half hour is elapsed the same single alarm is found as in the <code>-slevel 100000</code> analysis.</p> -<h2>Conclusion</h2> -<p>The number of options available in the Frama-C platform can be a little bit overwhelming. It is for a good reason that the value analysis tutorial emphasizes option <code>-slevel</code> and this option only. On the example from this post it does not hurt very much only to know about this one: it allows you to obtain the optimal result and you do not seem to be penalized by more than a few seconds for not remembering all the other ones.</p> <p>Unfortunately the example in this post is only one example and in special cases it may be necessary to have more than one string to one's bow.</p> {% endraw %} diff --git a/_posts/2012-03-14-But-wait-There-may-be-more.html b/_posts/2012-03-14-But-wait-There-may-be-more.html index 9bc3beac6e174dbe91d1c51cabfdcc814041e092..ef569ee389d9ad8a37bd49636f88431775a5646d 100644 --- a/_posts/2012-03-14-But-wait-There-may-be-more.html +++ b/_posts/2012-03-14-But-wait-There-may-be-more.html @@ -13,11 +13,5 @@ summary: <p>Boris who knows everything about false alarms and generally Frama-C's value analysis' limitations claims that the example from the last post is too simple and suspects me to have doctored it to make it analyze optimally in “only†7 minutes. How unfair!</p> <p>The example in last post comes straight from Omar Chebaro's PhD thesis. Omar worked during his PhD on SANTE (more information <a href="http://lifc.univ-fcomte.fr/~publis/papers/Author/CHEBARO-O.html">here</a>) a Frama-C plug-in that combines results from the value analysis plug-in and concolic test-case generation with PathCrawler for one identifying false alarms when possible and two providing input vectors for true alarms (again when possible). There is no reason to doubt Omar's scientific integrity but even if he had a slight bias the bias would not necessarily be to make things easy for the value analysis. He might just as well be tempted to make the value analysis emit more alarms in order to show the necessity of sorting them out with dynamic analysis.</p> <p>I do have a bias and my motive in last post is clearly to show that the value analysis on that example with the right options can limit its list of alarms to a single one which happens to be a true alarm. But I did not choose the example nor did I modify it to make it easier to analyze.</p> -<p>Note that SANTE is still useful in conditions where the value analysis emits a single alarm: at the end of last post we only know that the alarm is true because of a comment in the source code telling us so. Using PathCrawler to classify that alarm gives SANTE a chance to confirm that it is true and to provide an input vector that the developer would certainly appreciate if only for debugging purposes.</p> - <p>My colleague Boris Yakobowski is on holidays, and while leisurely browsing the internet, he seems to have stumbled upon my previous post. He e-mailed me about it.</p> -<p>For some reason, it does not feel right to provide much biography when mentioning <a href="/index.php?tag/facetious-colleagues">facetious colleagues</a> perhaps because it would look too self-congratulatory from the outside. Just this once a little bit of context appears to be necessary: Boris is the person who has using Frama-C's value analysis managed to analyze the largest codebase to date. Without qualification this does not mean much: anyone can type "frama-c -val *.c" in a directory and call it an analysis. But there is a point at which one can convincingly argue that the analysis is meaningful and that the results obtained are the best the tool can give. The latter for instance means all remaining alarms have been examined and for each the verifier has some confidence that it is false and an explanation why the analyzer emits the alarm instead of doing the precise thing and not emitting it. In short Boris has reached this point for a pretty big piece of embedded software.</p> -<p>Boris who knows everything about false alarms and generally Frama-C's value analysis' limitations claims that the example from the last post is too simple and suspects me to have doctored it to make it analyze optimally in “only†7 minutes. How unfair!</p> -<p>The example in last post comes straight from Omar Chebaro's PhD thesis. Omar worked during his PhD on SANTE (more information <a href="http://lifc.univ-fcomte.fr/~publis/papers/Author/CHEBARO-O.html">here</a>) a Frama-C plug-in that combines results from the value analysis plug-in and concolic test-case generation with PathCrawler for one identifying false alarms when possible and two providing input vectors for true alarms (again when possible). There is no reason to doubt Omar's scientific integrity but even if he had a slight bias the bias would not necessarily be to make things easy for the value analysis. He might just as well be tempted to make the value analysis emit more alarms in order to show the necessity of sorting them out with dynamic analysis.</p> -<p>I do have a bias and my motive in last post is clearly to show that the value analysis on that example with the right options can limit its list of alarms to a single one which happens to be a true alarm. But I did not choose the example nor did I modify it to make it easier to analyze.</p> <p>Note that SANTE is still useful in conditions where the value analysis emits a single alarm: at the end of last post we only know that the alarm is true because of a comment in the source code telling us so. Using PathCrawler to classify that alarm gives SANTE a chance to confirm that it is true and to provide an input vector that the developer would certainly appreciate if only for debugging purposes.</p> {% endraw %} diff --git a/_posts/2012-03-16-Security-and-safety.html b/_posts/2012-03-16-Security-and-safety.html index f7c02de5314374c74db266d9cbc1da4d0f0d3524..43232326e6816a3e0fbacb140654363cff400313 100644 --- a/_posts/2012-03-16-Security-and-safety.html +++ b/_posts/2012-03-16-Security-and-safety.html @@ -15,13 +15,5 @@ Fortunately, a large “security†“administration†provides:</p> <p>And that's the difference really.</p> <p>The intuition is that good protection can be obtained by accumulating imperfect layers. The intuition works well when the probabilities of failure of each layer are somewhat independent. When they are completely independent probability theory tells us that they can be multiplied. And the definition of security as opposed to safety is that when dealing with a security issue you cannot assume that the probabilities of failure of your layers are independent because all the layers tend to fail in the same conditions namely when a smart attacker is trying to get through them.</p> <p>Consider layer number two in the previously linked diagram “Customs and border protectionâ€. This means requiring the potentially dangerous visitor to fill in a form asking whether <a href="http://en.wikipedia.org/wiki/Spivak_pronoun">ey</a> plans to overthrow the government during eir stay. Terrorists who fail at this layer are the same terrorists who cannot figure out how to gather arbitrary quantities of liquid explosive past security 100ml at a time or inside their bodies or not to use liquid explosives at all. Conversely and critically the very same terrorist who can figure out the latter issue can figure out the correct answer to the government-overthrowing multiple-choice question on eir applicable immigration form.</p> -<p>And if you are still unconvinced please consider computer security. Tons of partial protection layers have been implemented in recent years: non-executable this and randomized that. If each layer had improved computer security commensurately to its ability to thwart the average hacker we would safe browsing the “interwebs†(this is a technical term that security experts use). Unfortunately all the protection layers are only good at disarming the same hackers: the inferior ones. Each layer adds some security but not the quantity of security that intuition predicts.</p> - <p>I usually feel uncomfortable diving into the subject of safety vs security, because while I think I have a good intuition of the difference between them, I find this difference hard to formalize in writing. -Fortunately, a large “security†“administration†provides:</p> -<p>“We use layers of security to ensure the security of [...]†(<a href="http://www.tsa.gov/what_we_do/layers/index.shtm">source</a> proudly linked from <a href="http://blog.tsa.gov/2012/03/viral-video-about-body-scanners.html">here</a>)</p> -<p>The difference between safety and security is that if the aforementioned administration was trying to ensure the safety of the traveling public then accumulating a large enough number of rubbish detection layers would work. In safety you are working against a harsh but neutral universe. It is okay simply to do your best to ensure that a safety-critical component works as designed and then to put in some redundancy and perhaps some fail-safe mechanism because you are actually multiplying probabilities of failure. Assuming your design works and naming pâ‚ and pâ‚‚ the (low) probabilities that the component fails and that the fail-safe fails the probability that two out of three redundant components and the fail-safe fail simultaneously is of the order of some factor of p₲*pâ‚‚. Accumulate enough layers and you can make the overall probability of failure low enough.</p> -<p>And that's the difference really.</p> -<p>The intuition is that good protection can be obtained by accumulating imperfect layers. The intuition works well when the probabilities of failure of each layer are somewhat independent. When they are completely independent probability theory tells us that they can be multiplied. And the definition of security as opposed to safety is that when dealing with a security issue you cannot assume that the probabilities of failure of your layers are independent because all the layers tend to fail in the same conditions namely when a smart attacker is trying to get through them.</p> -<p>Consider layer number two in the previously linked diagram “Customs and border protectionâ€. This means requiring the potentially dangerous visitor to fill in a form asking whether <a href="http://en.wikipedia.org/wiki/Spivak_pronoun">ey</a> plans to overthrow the government during eir stay. Terrorists who fail at this layer are the same terrorists who cannot figure out how to gather arbitrary quantities of liquid explosive past security 100ml at a time or inside their bodies or not to use liquid explosives at all. Conversely and critically the very same terrorist who can figure out the latter issue can figure out the correct answer to the government-overthrowing multiple-choice question on eir applicable immigration form.</p> <p>And if you are still unconvinced please consider computer security. Tons of partial protection layers have been implemented in recent years: non-executable this and randomized that. If each layer had improved computer security commensurately to its ability to thwart the average hacker we would safe browsing the “interwebs†(this is a technical term that security experts use). Unfortunately all the protection layers are only good at disarming the same hackers: the inferior ones. Each layer adds some security but not the quantity of security that intuition predicts.</p> {% endraw %} diff --git a/_posts/2012-03-19-So-many-programs-to-verify-so-little-time.html b/_posts/2012-03-19-So-many-programs-to-verify-so-little-time.html index d6e3e9a7a50de1c9a3ea34d020c5fa45fd84cec8..532273d8b0e16d807142f6b03d395fde3fad2477 100644 --- a/_posts/2012-03-19-So-many-programs-to-verify-so-little-time.html +++ b/_posts/2012-03-19-So-many-programs-to-verify-so-little-time.html @@ -70,68 +70,5 @@ int main(){ <h2>Second example: the 2006 IOCCC entry \stewart"</h2> <p>The actual winning entries to the pending contest are taking forever to appear but we'll always have the past entries. The program is <a href="http://www.ioccc.org/2006/stewart/stewart.c">here</a>. You can get some additional files and information from the <a href="http://www.ioccc.org/years.html">winners' page</a>. IOCCC programs often use recursion libraries or syscalls but this one looks relatively analyzable. Just stub <code>fopen()</code> and each call to <code>fscanf()</code> appropriately.</p> -<p>This program uses floating-point.</p> - <p>This post offers two C programs that look analyzable. Each is self-contained, not so small that verification is trivial, but not so big that it's a man-year effort. If it was me doing the work, I would see what Frama-C's value analysis can do, but if you decide to do it, it is your privilege to use any tool you like.</p> -<h2>First example: extraitMax()</h2> -<p>The first example comes, like another recent one, from Omar Chebaro's thesis. Like the previous example, I have no idea what it does:</p> -<pre>int extraitMax(int Nd, int *Td){ - int G = 0; - int Nr = 0; - int Tr[100]; - int i = 1, fin = 0; - int tmp; - G = Td[1]; - Nr = Nd - 1; - for(i=0; i<Nd; i++){ - Tr[i] = Td[i]; - } - Tr[1] = Td[Nd]; - fin = 0; - while(i*2<=Nr && !fin){ - if( ((2*i)+1) <= Nr){ - if(Tr[i] < Tr[2*i] || Tr[i] < Tr[(2*i)+1]){ - if(Tr[2*i] >= Tr[(2*i)+1] ){ - tmp = Tr[i]; - Tr[i] = Tr[2*i]; - Tr[2*i] = tmp; - i = 2*i; - } - else{ - tmp = Tr[i]; - Tr[i] = Tr[(2*i)+1]; - Tr[(2*i)+1] = tmp; - i = (2*i)+1; - } - } - else - fin = 1; - } - else{ - if(Tr[i] < Tr[2*i]){ - tmp = Tr[i]; - Tr[i] = Tr[2*i]; - Tr[2*i] = tmp; - i = 2*i; - } - else - fin = 1; - } - } -} -int main(){ - int n = Frama_C_interval(2, 100); - int T[100]; - int i; - for(i = 0; i < n; i++){ - T[i] = Frama_C_interval(0, 127); - } - extraitMax(n, T); -} -</pre> -<p>Without having tried, there must be some alarms about the initializedness of arrays <code>T</code> and <code>Tr</code> that should easily go away by separately analyzing the different values of <code>n</code>.</p> -<p>It would be nice to show that this one terminates. This gives me an idea for one way the previously described option <code>-obviously-terminates</code> can be useful: it seems to me that if the analysis terminates when this option is set, it shows that all executions that are defined in the sense of the value analysis terminate. I am not saying that this method works for this program, though: it just looks like it might.</p> -<h2>Second example: the 2006 IOCCC entry \stewart"</h2> -<p>The actual winning entries to the pending contest are taking forever to appear but we'll always have the past entries. -The program is <a href="http://www.ioccc.org/2006/stewart/stewart.c">here</a>. You can get some additional files and information from the <a href="http://www.ioccc.org/years.html">winners' page</a>. IOCCC programs often use recursion libraries or syscalls but this one looks relatively analyzable. Just stub <code>fopen()</code> and each call to <code>fscanf()</code> appropriately.</p> <p>This program uses floating-point.</p> {% endraw %} diff --git a/_posts/2012-03-27-Overflow-alarms-vs-informative-messages-about-2s-complement.html b/_posts/2012-03-27-Overflow-alarms-vs-informative-messages-about-2s-complement.html index 1b49431108a9878c254d8135ed8cd30f313d7dc2..555f767286ab108771e610165770009273e2aaef 100644 --- a/_posts/2012-03-27-Overflow-alarms-vs-informative-messages-about-2s-complement.html +++ b/_posts/2012-03-27-Overflow-alarms-vs-informative-messages-about-2s-complement.html @@ -49,47 +49,5 @@ o.c:6:[value] assigning non deterministic value for the first time </ol> <blockquote><p>It may seem strange that in the second case the value analysis does not affirm more strongly that there is a definite problem with some of the values in the user-specified <code>Frama_C_interval(0 2000000000)</code> range for variable <code>x</code> but that's not what it is optimized for. It is optimized for verifying that there aren't any issues not so much for reliably telling the user what original inputs cause the issues. User expertise or alternative techniques must take up from there. Think of the range <code>[0..2000000000]</code> for <code>x</code> as the result of previous computations without it being known whether the interval is so wide because the values can really happen with user-specified inputs or because of earlier over-approximations.</p> </blockquote> -<p>Stéphane Duprat Florent Kirchner and Philippe Herrmann proofread this post.</p> - <p>A privately sent question may deserve a quick blog post.</p> -<h2>Context</h2> -<p>The example is as below:</p> -<pre>int x, y, s; -main(){ - x = Frama_C_interval(0, 2000000000); - y = 1000000000; - s = x + y; - Frama_C_dump_each(); -} -</pre> -<p>Sorry for all the zeroes. There are nine of them in each large constant, so that the program is flirting with the limits of 32-bit 2's complement integers. Frama-C's value analysis with default options finds the following to say:</p> -<pre>$ frama-c -val share/builtin.c o.c -... -o.c:6:[value] warning: 2's complement assumed for overflow -o.c:6:[value] assigning non deterministic value for the first time -[value] DUMPING STATE of file o.c line 7 - x ∈ [0..2000000000] - y ∈ {1000000000} - s ∈ [--..--] -</pre> -<p>There is an option, <code>-val-signed-overflow-alarms</code>, to change the behavior of the value analysis with respect to integer overflows:</p> -<pre>$ frama-c -val -val-signed-overflow-alarms share/builtin.c o.c -... -o.c:6:[kernel] warning: Signed overflow. assert x+y ≤ 2147483647LL; -o.c:6:[value] assigning non deterministic value for the first time -[value] DUMPING STATE of file o.c line 7 - x ∈ [0..2000000000] - y ∈ {1000000000} - s ∈ [1000000000..2147483647] -</pre> -<p>The warning with the first command was introduced in Nitrogen, and this post therefore is in a way part of the series describing new features in Nitrogen.</p> -<p>The new warning, “2's complement assumed for overflowâ€, is emitted in exactly the same circumstances the alarm “assert x+y ≤ 2147483647LL†would have been emitted if option <code>-val-signed-overflow-alarms</code> had been used.</p> -<h2>Question and answer</h2> -<p>The question is whether the warnings obtained in each case, “2's complement assumed for overflow†and “Signed overflow. assert x+y ≤ 2147483647LL†respectively, mean the same thing. The answer is that no, they don't. The consequences of the differences between them can be seen in the values computed for variable <code>s</code> after the overflow.</p> -<ol> -<li>The warning “2's complement assumed for overflow†is a gentle reminder that the value analysis is unable to establish an overflow does not happen at line 6. The value analysis is, the message kindly informs, going to assume that the overflow, if it happens at all, happens on purpose. The programmer may for instance have read <a href="http://thiemonagel.de/2010/01/signed-integer-overflow/">that blog post</a> in addition to this one and use the appropriate options to force GCC to give 2's complement results on signed overflows. The message considered here is informative only. The user should is expected to react with “ah yes that's right my program overflows on purpose here†and go on with some of eir analysis. Only two billion and one values can actually be obtained as a result of this 2's complement addition <code>[-2147483648..-1294967296] ∪ [1000000000..2147483647]</code> but since the value analysis can only represent large sets of integers as a single interval the end result is that all <code>int</code> values appear to be possible values for variable <code>s</code>.</li> -<li>The warning “Signed overflow. assert x+y ≤ 2147483647LL†contains the word “assertâ€. It is an <strong>alarm</strong>. <strong>The user should do something about it</strong> and in this case the user should realize ey is trying to prove that there are no undefined signed overflows in a program that really contains undefined signed overflows. Something is seriously wrong in the target program! The value analysis wants to be as precise as possible for the rest of the program so without deciding of the status of the alarm it assumes for the rest of the propagation that it was false. If the overflow alarm is false then <code>s</code> is guaranteed to be in the range <code>[1000000000..2147483647]</code>. This is a subset of the values that are possible with 2's complement addition. Now the value analysis also reserves the right to reduce after the alarm the values for variable <code>x</code> to the range <code>[0..1147483647]</code> since these are the only values that do <strong>not</strong> cause an undefined overflow. It does not take advantage of this information at this level for now but a future version will. The reasoning here is the same as the reasoning in Q1 and Q2 in the Frequently Asked Questions section of <a href="http://frama-c.com/download/frama-c-value-analysis.pdf">the manual</a>.</li> -</ol> -<blockquote><p>It may seem strange that in the second case the value analysis does not affirm more strongly that there is a definite problem with some of the values in the user-specified <code>Frama_C_interval(0 2000000000)</code> range for variable <code>x</code> but that's not what it is optimized for. It is optimized for verifying that there aren't any issues not so much for reliably telling the user what original inputs cause the issues. User expertise or alternative techniques must take up from there. Think of the range <code>[0..2000000000]</code> for <code>x</code> as the result of previous computations without it being known whether the interval is so wide because the values can really happen with user-specified inputs or because of earlier over-approximations.</p> -</blockquote> <p>Stéphane Duprat Florent Kirchner and Philippe Herrmann proofread this post.</p> {% endraw %} diff --git a/_posts/2012-03-28-More-about-integer-overflows.html b/_posts/2012-03-28-More-about-integer-overflows.html index 1825a0cafe5c984f128aad22235706ece79ba5db..5539e6cde141013f19ef1a6b6d7d85ad9fe80fec 100644 --- a/_posts/2012-03-28-More-about-integer-overflows.html +++ b/_posts/2012-03-28-More-about-integer-overflows.html @@ -9,7 +9,5 @@ summary: --- {% raw %} <p>It may be because I read an earlier draft that has had the time to sink in, but I find <a href="http://www.cs.utah.edu/~regehr/papers/overflow12.pdf">this article</a> on the subject of integer overflows extremely clear and informative. It relates to the previous post. Key quote:</p> -<p><q>integer overflow issues in C and C++ [...] are common even in mature widely used programs and [...] are widely misunderstood by developers.</q></p> - <p>It may be because I read an earlier draft that has had the time to sink in, but I find <a href="http://www.cs.utah.edu/~regehr/papers/overflow12.pdf">this article</a> on the subject of integer overflows extremely clear and informative. It relates to the previous post. Key quote:</p> <p><q>integer overflow issues in C and C++ [...] are common even in mature widely used programs and [...] are widely misunderstood by developers.</q></p> {% endraw %} diff --git a/_posts/2012-03-29-Why-do-signed-overflows-so-often-do-what-programmers-expect.html b/_posts/2012-03-29-Why-do-signed-overflows-so-often-do-what-programmers-expect.html index b5ea8220aa86582ec556e57e9176c2bce36a566d..3b4719b84da1ce8f86caa3cdc39a6c447375c33b 100644 --- a/_posts/2012-03-29-Why-do-signed-overflows-so-often-do-what-programmers-expect.html +++ b/_posts/2012-03-29-Why-do-signed-overflows-so-often-do-what-programmers-expect.html @@ -16,14 +16,5 @@ summary: <h2>And now for some more Regehr links</h2> <p><a href="http://blog.regehr.org/archives/320">This blog post</a> shows how good compilers already are.</p> <p>I put forward a weak version of the argument presented here on the Frama-C mailing list a long time ago and John answered with an <a href="http://lists.gforge.inria.fr/pipermail/frama-c-discuss/2009-June/001235.html">example</a> C program where the compiler can take advantage of the undefinedness of signed overflows to generate code that does not give 2's complement results.</p> -<p>John also discussed undefined behaviors on his blog which prompted Chris Lattner to write a <a href="http://blog.llvm.org/2011/05/what-every-c-programmer-should-know_14.html">3-post series</a> with more of the compiler implementer's point of view and revealing examples.</p> - <h2>Semi-serious musings</h2> -<p>During the Frama-C random testing experiment described at length on this blog and <a href="/index.php?pages/Csmith-testing">this page</a> we found a few bugs in Csmith too. John Regehr one of the Csmith developers and not entirely coincidentally a co-author of the article linked in the previous post is also a co-author in the NFM12 article where the random testing of Frama-C is described. Some time ago while in the context of the latter article discussing the fact that Csmith had been used intensively finding 400+ bugs in compilers without the bugs that Frama-C uncovered being an annoyance or even noticed he said:</p> -<blockquote><p>It would also maybe be useful to remark that the Csmith bugs had not been detected because compilers are pretty weak at exploiting undefined behaviors (though they do this sometimes).</p> -</blockquote> -<p>I do not agree about the choice of the adjective “weakâ€. I find compilers are pretty good at what they are supposed to do which is apparently to <strong>ignore</strong> undefined behaviors in the program and generate the shortest and/or fastest sequences of instructions that compute the correct result <strong>for all defined executions</strong>. Sometimes an opportunity arises to exploit the fact that some inputs cause undefined behavior to shorten/fasten the sequence of instructions. But in the general case with industry-standard instruction sets there just isn't any such opportunity. The shortest fastest sequence that works for all defined inputs is the sequence that happens to give 2's complement semantics to signed overflows. I think that this is a fundamental fact of current instruction sets and considering the rate at which these change I do not expect programmers misunderstandings about signed overflows to change in the near or far future. Even with much progress in compilation techniques signed overflow will continue to give 2's complement results most of the times and programmers will continue to be surprised when it doesn't.</p> -<h2>And now for some more Regehr links</h2> -<p><a href="http://blog.regehr.org/archives/320">This blog post</a> shows how good compilers already are.</p> -<p>I put forward a weak version of the argument presented here on the Frama-C mailing list a long time ago and John answered with an <a href="http://lists.gforge.inria.fr/pipermail/frama-c-discuss/2009-June/001235.html">example</a> C program where the compiler can take advantage of the undefinedness of signed overflows to generate code that does not give 2's complement results.</p> <p>John also discussed undefined behaviors on his blog which prompted Chris Lattner to write a <a href="http://blog.llvm.org/2011/05/what-every-c-programmer-should-know_14.html">3-post series</a> with more of the compiler implementer's point of view and revealing examples.</p> {% endraw %} diff --git a/_posts/2012-04-12-A-convert-to-floating-point-function-at-the-frontier-of-formal-verification.html b/_posts/2012-04-12-A-convert-to-floating-point-function-at-the-frontier-of-formal-verification.html index 6662473bf86ccfa52420c4ddfea6ef60d24d48e0..d9a51f15f62503c656a4553cc8f0bc0cf321c3c5 100644 --- a/_posts/2012-04-12-A-convert-to-floating-point-function-at-the-frontier-of-formal-verification.html +++ b/_posts/2012-04-12-A-convert-to-floating-point-function-at-the-frontier-of-formal-verification.html @@ -20,18 +20,5 @@ summary: <li>the correctly rounded but non-portable and terribly complicated version (<a href="http://www.netlib.org/fp/dtoa.c">David M. Gay's implementation</a>);</li> <li>and the naïve version (the <a href="http://www.exploringbinary.com/correct-decimal-to-floating-point-using-big-integers/">pseudo-code from Rick Regan</a> that I ended up basing my own function on).</li> </ol> -<p>The new function I am suggesting to formally verify nicely fills the gap between 3. and 4. above. It is quite clean and portable but from a quick code review I expect it to be faster than say my own implementation. It is written to be correctly rounded according to the FPU's rounding mode. It seems to use base-10â¹ multi-precision integers. I am still trying to make sense of parts of it.</p> - <p>The function in <a href="http://www.openwall.com/lists/musl/2012/04/10/6">this post to the musl mailing list</a> is a good candidate for formal verification. It should just barely be possible to verify the absence of undefined behaviors with Frama-C's value analysis and it should just barely be possible to verify it functionally with one of the Jessie or Wp plug-ins.</p> -<h2>Context</h2> -<p><a href="http://www.etalabs.net/musl/">Musl</a> is a libc project. Key quote: “musl is lightweight fast simple free and strives to be correct in the sense of standards-conformance and safetyâ€.</p> -<p>The function highlighted in this post converts the decimal representation of a number to a <code>long double</code> in a correctly rounded manner. The <code>long double</code> type is not very portable and therefore I do not expect any Frama-C plug-in to support it but after replacing all instances of <code>long double</code> with <code>double</code> and choosing the corresponding <code>LDBL_MANT_DIG</code> and <code>LDBL_MAX_EXP</code> the function becomes a plain decimal-to-double conversion function that it should be possible to verify formally with Frama-C.</p> -<h2>Motivation</h2> -<p>The formal verification I am encouraging the valiant reader to attempt would be useful too! This is a brand-new implementation. I was looking for one such decimal-to-binary function at about the time I was writing <a href="/ocaml/floating-point/2011/11/14/Analyzing-single-precision-floating-point-constants">this post</a>. At the time there were about four categories of Open Source implementations:</p> -<ol> -<li>the <a href="http://rxr.whitequark.org/mri/source/missing/strtod.c?v=1.8.7-p370">very wrong version</a> available in Ruby and Tcl to compile on platforms that lack <code>strtod()</code>. This one can return a result off by 15 ULPs or so;</li> -<li>the slightly wrong and somewhat complicated version (Glibc);</li> -<li>the correctly rounded but non-portable and terribly complicated version (<a href="http://www.netlib.org/fp/dtoa.c">David M. Gay's implementation</a>);</li> -<li>and the naïve version (the <a href="http://www.exploringbinary.com/correct-decimal-to-floating-point-using-big-integers/">pseudo-code from Rick Regan</a> that I ended up basing my own function on).</li> -</ol> <p>The new function I am suggesting to formally verify nicely fills the gap between 3. and 4. above. It is quite clean and portable but from a quick code review I expect it to be faster than say my own implementation. It is written to be correctly rounded according to the FPU's rounding mode. It seems to use base-10â¹ multi-precision integers. I am still trying to make sense of parts of it.</p> {% endraw %} diff --git a/_posts/2012-04-12-Helping-the-value-analysis---part-3.html b/_posts/2012-04-12-Helping-the-value-analysis---part-3.html index c12af74fc51e5ee571bc1f42efc73d2b8b939ff7..19cdd8b11c5107d7297fdc8b7e65f09f1db9900c 100644 --- a/_posts/2012-04-12-Helping-the-value-analysis---part-3.html +++ b/_posts/2012-04-12-Helping-the-value-analysis---part-3.html @@ -41,39 +41,5 @@ summary: </pre> <p>The plug-in now splits the state propagated through the <code>assert</code> annotation continues with two independent analyses and later merges the results. To allow this the parameter <code>-slevel N</code> with <code>N</code> at least two must be passed to Frama-C. With these changes the range of possible values for the first analysis is <code>[-10 -1]</code> and the second is <code>[0 10]</code>. The first range is not interesting since there is no zero in there and the abstract interpretation will therefore not enter the <strong>then</strong> block of the if condition. However it will do this for the second range but now it can compute a range that includes all of the original elements without zero (<code>[1 10]</code>). Therefore it can now detect that <code>x</code> can not be zero inside the division expression. Everything is fine...</p> <h2>Final thoughts</h2> -<p>If you want to track the states of the Value Analysis plug-in I recommend the special Frama-C functions <code>Frama_C_dump_each()</code> and <code>Frama_C_show_each()</code>. Just insert them in the C file at the position you are interested in.</p> - <p>Sven Mattsen is working at CEA until the summer. He is the author of this post. The post continues the series explaining how to guide the value analysis towards more precise conclusions. It starts where <a href="/index.php?post/2011/03/23/Helping-the-value-analysis-1">that one</a> and <a href="/index.php?post/2011/03/26/Helping-the-value-analysis-2">that other</a> left off.</p> -<h2>Problem</h2> -<p>This article is concerned with the Value Analysis plug-in of Frama-C which implements an automatic approach towards verifying C programs. The Value Analysis provides an overapproximated set of possible values for each occurence of each variable of a C program. I will describe how to guide the value analysis in the example below:</p> -<pre>int main(int argc char* argv[]) { - int x = argc % 11; - return 100 / x; -} -</pre> -<p>We can call the value analysis on this program by issuing <code>frama-c -val smallcprogram.c</code> on the shell. Among other things the plug-in tells us that <code>x</code> is always in the range from <code>-10</code> to <code>10</code> at the point of the division. Frama-C also warns of a possible division by zero in the argument to <code>return</code>. Great we had overlooked that. Let us insert a check for this and return <code>0</code> in this case.</p> -<pre>int main(int argc char* argv[]) { - int x = argc % 11; - if(x != 0) - return 100 / x; - else - return 0; -} -</pre> -<p>When we call Frama-C again it gives the same result including the warning for a possible division by zero. This is despite the division being guarded by the <code>if(x != 0)</code>. This time the alarm is a false alarm.</p> -<h2>Explanation</h2> -<p>What happened? The Value Analysis plug-in performs an abstract interpretation of the program with the abstract domain being ranges of integers (the actual abstract domain is more complex but for this example it is enough to consider this much simpler domain). Apart from the type the value analysis does not know anything about the variable <code>argc</code> and therefore sets the range of possible values for it to <code>[MININT MAXINT]</code>. When <code>x</code> is initialized the set of possible values of the expression <code>argc % 11</code> is computed which is <code>[-10 10]</code>. Now it gets interesting. Inside the <strong>then</strong> block of the if condition we know that <code>x</code> can have every possible value within <code>[-10 10]</code> except <code>0</code>. However in our simplified version of the value analysis it cannot represent <code>[-10 10] \ 0</code> and therefore overapproximates to <code>[-10 10]</code>. This is precisely the reason why we still get this warning.</p> -<h2>Solution</h2> -<p>One way to get around this issue is to split the range of possible values of <code>x</code> right before the if condition into two sub-ranges. Luckily the Value Analysis plug-in allows us to do just that by inserting an assertion:</p> -<pre>int main(int argc char* argv[]) { - int x = argc % 11; - /*@ assert x < 0 || x >= 0;*/ - if(x != 0) - return 100 / x; - else - return 0; -} -</pre> -<p>The plug-in now splits the state propagated through the <code>assert</code> annotation continues with two independent analyses and later merges the results. To allow this the parameter <code>-slevel N</code> with <code>N</code> at least two must be passed to Frama-C. With these changes the range of possible values for the first analysis is <code>[-10 -1]</code> and the second is <code>[0 10]</code>. The first range is not interesting since there is no zero in there and the abstract interpretation will therefore not enter the <strong>then</strong> block of the if condition. However it will do this for the second range but now it can compute a range that includes all of the original elements without zero (<code>[1 10]</code>). Therefore it can now detect that <code>x</code> can not be zero inside the division expression. Everything is fine...</p> -<h2>Final thoughts</h2> <p>If you want to track the states of the Value Analysis plug-in I recommend the special Frama-C functions <code>Frama_C_dump_each()</code> and <code>Frama_C_show_each()</code>. Just insert them in the C file at the position you are interested in.</p> {% endraw %} diff --git a/_posts/2012-04-12-I-discovered-another-blog.html b/_posts/2012-04-12-I-discovered-another-blog.html index d0c2b5838e4ca7e4f5387d0f19aade2f76b1abc5..a92b6a7076441121d492bcbe60a86ab7c8416ea9 100644 --- a/_posts/2012-04-12-I-discovered-another-blog.html +++ b/_posts/2012-04-12-I-discovered-another-blog.html @@ -9,5 +9,4 @@ summary: --- {% raw %} <p>If you like this blog, then on the basis of recent posts, you will with good probability like <a href="http://kqueue.org/">that blog</a>. The recent posts I have read all deal with various subtle undefined behaviors in C.</p> - <p>If you like this blog, then on the basis of recent posts, you will with good probability like <a href="http://kqueue.org/">that blog</a>. The recent posts I have read all deal with various subtle undefined behaviors in C.</p> {% endraw %} diff --git a/_posts/2012-04-19-On-arrays-vs.-pointers.html b/_posts/2012-04-19-On-arrays-vs.-pointers.html index d04cc19ab6d5d23c124a250b82792d20547557d1..1d1e48c2740908ea0948c5bf91cbea9b0b2c6270 100644 --- a/_posts/2012-04-19-On-arrays-vs.-pointers.html +++ b/_posts/2012-04-19-On-arrays-vs.-pointers.html @@ -40,38 +40,5 @@ virgile@is220177:~/tmp$ ./test virgile@is220177:~/tmp$ echo $? 145 </pre> -<p>In summary the future behavior of Frama-C that will starting from Oxygen flatly reject such code (instead of just emitting a warning) is not exceedingly pedantic. Such a discrepancy between declarations is really an important issue.</p> - <p>This post is a follow-up of <a href="http://bts.frama-c.com/view.php?id=990">bug 990</a>. When this issue was resolved the following question arose: "Why is it so dangerous to have a global <code>c</code> declared as a pointer in one compilation unit and defined as an array in another one given the fact that almost anywhere an array decays as a pointer to their first element when needed?" Well the key to the answer lies in the *almost*. In fact if <code>a</code> is an array the associated pointer expression is <code>&a[0]</code> which means that it is not an lvalue on the contrary to a pointer variable <code>p</code>. In other words the compilation unit that sees <code>c</code> as a pointer can assign new values into it while it is not really expected by the compilation unit where <code>c</code> is defined. Worse this point cannot be checked by a compiler since there's no type at linking phase where the issue could be spotted. Take for instance the following two files: -<code>main.c</code></p> -<pre>extern char* c; -extern char f(void); -int main () { - char *oldc; - char c1[] = "bar"; - c = c1; - char test = f(); - c = oldc; - switch (test) { - case 'o': return 0; - case 'r': return 1; - default: return test; - } - } -</pre> -<p>and <code>aux.c</code></p> -<pre>char c [] = "foo"; -char f() { return c[2]; } -</pre> -<p>gcc (Ubuntu/Linaro 4.6.3-1ubuntu5 to be precise) compiles them without any message:</p> -<pre>gcc -o test aux.c main.c -</pre> -<p>Yet what should be the exit status of <code>test</code>? One could imagine that it might be <code>0</code> if the compiler optimizes in <code>f</code> the fact that <code>c</code> is at a constant address or <code>1</code> if it uses the actual address of <code>c</code> (treating it effectively as pointer) when <code>f</code> is called. In fact on my machine the exit status is a completely arbitrary number that depends on whatever lies in the memory when <code>test</code> is launched:</p> -<pre>virgile@is220177:~/tmp$ ./test -virgile@is220177:~/tmp$ echo $? -98 -virgile@is220177:~/tmp$ ./test -virgile@is220177:~/tmp$ echo $? -145 -</pre> <p>In summary the future behavior of Frama-C that will starting from Oxygen flatly reject such code (instead of just emitting a warning) is not exceedingly pedantic. Such a discrepancy between declarations is really an important issue.</p> {% endraw %} diff --git a/_posts/2012-04-28-The-value-analysis-propagation-order-is-inscrutable.html b/_posts/2012-04-28-The-value-analysis-propagation-order-is-inscrutable.html index dfb6f10ef7a2abde447eaa63e1e50d57f7d0cbdb..beed4d9a4f5493f15d460900c75bc8c585c8613b 100644 --- a/_posts/2012-04-28-The-value-analysis-propagation-order-is-inscrutable.html +++ b/_posts/2012-04-28-The-value-analysis-propagation-order-is-inscrutable.html @@ -35,33 +35,5 @@ user 0m1.911s ... user 0m1.159s </pre> -<p>The latter time is slightly longer but still close to the time it took with Nitrogen without the additional statement that perturbs propagation (0.72s). Actually the difference may well be only the price of handling the additional statement.</p> - <p>Frama-C has a mailing-list. It's a place people visit for free to complain that they are not getting the quality, technical, detailed answers that they deserve, and to tell us what our priorities should be. I expressed my opinion about the mailing list a long time ago in this very blog. It hasn't gotten any better, and I recently unsubscribed. It is liberating. If you are an unsatisfied user, you should, too.</p> -<p>Every once in a while, there seems to be <a href="http://lists.gforge.inria.fr/pipermail/frama-c-discuss/2012-April/003214.html">an interesting message</a> though. My colleagues tell me about these while we wait for the elevator so not only am I not missing anything but in addition they no longer have time to launch discussions about the housing market situation in intra-muros Paris. This is what is called a win-win situation.</p> -<p>The recent interesting question in the mailing list is roughly “why does the value analysis behavior change when I add a statement inside nested loops and how can I get the behavior that gives the best results for what I would like to do?â€. So that's two questions.</p> -<p>The answer to the first question is the title of this post. The value analysis works forwards on the control flow graph of the program and when there are arbitrary decisions to take such as in case of a choice which statements to propagate to next it propagates according to its whim. When looking at the control flow graph (and it is necessary to handle arbitrary control flow graphs because embedded code can use <code>goto</code>) the initial structure of the program is much less apparent. The notions of “outer loop†and “inner loop†pretty much disappear.</p> -<p>The propagation order is not specified and may even change between Frama-C versions. The addition of a single statement may also completely change the flow of the analysis inside the program with no apparent reason. Here adding one statement probably causes the analysis to re-analyze the outer loop before having converged on the inner loop causing a slightly inefficient use of the allowed <code>-slevel</code> value—but a large enough <code>-slevel</code> still allows to obtain the precise analysis one wishes.</p> -<p>The answer to the second question is that industrial users with SVN access can already test a new feature that gives users more control over the propagation at the scale of the individual statements. This is in the continuity of the move from a single global <code>-slevel</code> option to <code>-slevel-function</code> options that can be set ahem function by function. Oh and if you are an industrial user and you were still wondering what the new feature was for well David's program is another example where it is useful.</p> -<p>David's goal is apparently to get a precise value for variable <code>k</code> outside the loop. When a single unrelated statement is added in the wrong place it ceases to work:</p> -<pre>$ time frama-c ... -slevel 100 -... - k ∈ [34..143] -... -user 0m0.673s -</pre> -<p>The <code>-slevel</code> option is made less efficient by the additional statement out of bad luck but it still works. You just have to use more of it (and analysis becomes a little bit slower):</p> -<pre>$ time frama-c ... -slevel 620 -... - k ∈ {50} -... -user 0m1.911s -</pre> -<p>Or with the development version and a simple additional annotation inside the source code that could likely be placed automatically:</p> -<pre>$ time bin/toplevel.opt ... -slevel 100 -... - k ∈ {50} -... -user 0m1.159s -</pre> <p>The latter time is slightly longer but still close to the time it took with Nitrogen without the additional statement that perturbs propagation (0.72s). Actually the difference may well be only the price of handling the additional statement.</p> {% endraw %} diff --git a/_posts/2012-04-29-Benchmarking-static-analyzers.html b/_posts/2012-04-29-Benchmarking-static-analyzers.html index a66ac2299fdb7424d6f3a7e58bc97c26879415c9..219958cf4c4c481e2bce1d65726c32d36579e314 100644 --- a/_posts/2012-04-29-Benchmarking-static-analyzers.html +++ b/_posts/2012-04-29-Benchmarking-static-analyzers.html @@ -33,31 +33,5 @@ this can be contrasted to the condition <code>&a == &b + 1</code>. You m <p>This is a non-issue really. All real C programs invoke implementation-defined behavior. As an example the line <code>int x = 38000;</code> invokes implementation-defined behavior. Therefore all static analyzers that aim to be useful for real programs assume some implementation choices and they all tend to assume the compilation choices of the dominant platform so implementation-defined behavior causes very little trouble in practice.</p> <h2>Acknowledgments</h2> -<p>Radu Grigore provided many ideas that did not fit in the article and is directly responsible for the existence of this blog post.</p> - <h2>A meta-article on benchmarking</h2> -<p>Some colleagues and I are about to submit <a href="https://www.dropbox.com/s/el2lidf5v71ogm6/p.pdf">this article</a> on the subject of benchmarking static analyzers. Rather than another benchmark it is a list of general recommendations and pitfalls when benchmarking static analyzers. The article is illustrated on C program constructs because that's what we are familiar with but these examples are only intended to show how complicated static analysis can be in general. Had we focused on another language the underlying ideas would have remained the same: different users and toolmakers have different views of what static analysis is about. Even if they agreed on what static analysis is about there would still be no perfect oracle to tell what the right answer to a particular testcase is.</p> -<p>Discussing this article as it was being written several valid points have been raised but unfortunately the limit for the category in which we wish to submit is 4 pages so I have to address these here. Consider this post a sort of addendum to the article.</p> -<h2>Why should the C standard be the ultimate authority?</h2> -<p>The short facetious answer to this question is that the C standard is the democracy of C semantics: it is the worst form of reference document we have to the exception of all others.</p> -<h5>Which version of the C standard?</h5> -<p>This is not a big problem in practice. Everyone seems to focus on what compilers use for obvious reasons and what compilers use is C90. In Frama-C we refer to C99 when it is convenient. For instance in C99 division is defined in more detail than in C90. C90 does not specify whether division rounds towards minus infinity (Euclidean division with a positive remainder) or rounds towards zero (all processors implement division like this because it means that the sign of the results can be computed independently from their magnitudes saving transistors). C99 specifies that division rounds towards zero. More information is good so Frama-C follows C99 here. But when C90 and C99 are mutually exclusive and compilers all implement C90 we follow the compilers. In <a href="/conversions-and-promotions/facetious-colleagues/2012/01/20/Constants-quiz">this post</a> about subtle typing issues we are with <code>gcc</code> predicting <code>2147483648</code> for the second example not with <code>gcc -std=c99</code> which compiles the program as displaying <code>-2147483648</code>. (See <a href="/index.php?post/2012/01/20/Constants-quiz-answers">the following post</a> for the explanations behind these differences).</p> -<h5>What if most implementations agree with each other but disagree with the standard?</h5> -<p>There are a couple of more interesting examples that we intended for the article to illustrate this very dilemma. -One is about pointer comparisons. Technically the comparison <code>&a < &b</code> is undefined behavior. The same reasoning that in the article justifies that analyzers do not have to worry what happens in the program after an illegal pointer access could be applied to this expression.</p> -<p>The point here is not just that most analyzers do not care about this issue and simply treat the comparison as returning <code>0</code> or <code>1</code>. -The point is that there are good reasons for an analyzer to let this kind of comparison slip: it happens naturally when a user implementation of <code>memmove()</code> is passed <code>&a</code> as source and <code>&b</code> as destination. An analyzer that lets this construct slip may be an analyzer that received more testing and for which usability studies revealed that users were too confused when <code>&a < &b</code> was treated as if it halted execution. Since there are arguments both ways it is difficult for organizers to arbitrarily decide what an analyzer should do when confronted with this expression. And since it does not seem too fundamental the simple escape that we recommend is to omit the construction from the benchmark. It shouldn't occur in any -testcase not as the goal of the testcase (the undefined behavior to be detected) nor as an incidental construct that would bias testcases intended for another criterion.</p> -<p>For the sake of exhaustiveness -this can be contrasted to the condition <code>&a == &b + 1</code>. You may expect that this would be undefined too but for some reason it is only unspecified. The implementation may return <code>0</code> or <code>1</code> and it will not return the same value everytime. Derek Jones would point out here that an implementation could rely on just-in-time compilation and that the value of <code>&a == &b + 1</code> could as a result change from one evaluation to the other for the same expression referring to the same variables <code>a</code> and <code>b</code>. Anyway it is not undefined so if the standard was the absolute reference static analyzers would not be allowed to consider that execution gets stuck on evaluating <code>&a == &b + 1</code>.</p> -<p>In Frama-C's value analysis we do not see much reason to treat equality and inequality differently but we recognize that both stopping execution and continuing with results <code>{0; 1}</code> can have their uses so we offer an option to choose between these two behaviors. This <a href="/index.php?tag/unspecified%20behavior">series of posts</a> already covers this kind of nuance.</p> -<p>Frama-C's value analysis detects warns and considers execution stuck on uninitialized variables. But by design it avoids warning (and considering execution stuck) on the statement <code>y = x;</code> or <code>*dst = *src;</code>. This is a compromise made necessary by the necessity to analyze user implementations of <code>memcpy()</code> which may use exactly that second statement for uninitialized data when copying a struct or union.</p> -<p>One <a href="http://bts.frama-c.com/view.php?id=69">long-standing bug</a> in Frama-C's front-end is that it erases a possible bug during parsing and normalization. According to the letter of the standard <code>addressee().a</code> is dangerous. However this misfeature of the C99 standard has quite a history (in the circle of people who care about this sort of thing) as illustrated by the numerous comments on the <a href="https://www.securecoding.cert.org/confluence/display/seccode/EXP35-C.+Do+not+access+or+modify+an+array+in+the+result+of+a+function+call+after+a+subsequent+sequence+point">linked CERT page</a>. A static analyzer could omit this bug (and consider execution continues) by a conscious design decision (for instance if it specializes in a compiler that documents that this construct is safe). Another static analyzer could treat it as undefined and consider that execution gets stuck. Again the construct is not very interesting in itself so it shouldn't be restrictive to omit it from the explicit goals of the benchmark and to omit it from the incidental features that might perturb other tests.</p> -<p>Finally there are areas where the standard under-specifies things. One egregious example is floating-point. David Monniaux's <a href="http://arxiv.org/abs/cs/0701192">report</a> is still the reference I recommend for these floating-point issues.</p> -<p>All but the last of these examples are cases of “Don't do that thenâ€: the issue can simply be avoided by not using any of the ambiguous constructs for which it is unclear whether an analyzer should be allowed to consider them blocking. Also all the issues in these first examples disappear when toolmakers are allowed to participate: when their analyzer scores badly on a test because it is better than others are detecting incidental issues they will be prompt to point out the problem.</p> -<p>For the last example floating-point I do not have a solution to offer. Some real-life software <a href="http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/">issues</a> come specifically from the liberties that the standard allows and from the fact that compilers take advantage of them so it is a worthy goal for a static analyzer to try to model these liberties and a worthy goal for a benchmark to measure how well the static analyzer is doing. But floating-point in C is a mess and since one of the issues is that compilation is under-specified it does not suffice to use one (or even several) compilations as reference.</p> -<h5>What about implementation-defined behavior?</h5> -<p>This is a non-issue really. -All real C programs invoke implementation-defined behavior. As an example the line <code>int x = 38000;</code> invokes implementation-defined behavior. Therefore all static analyzers that aim to be useful for real programs assume some implementation choices and they all tend to assume the compilation choices of the dominant platform so implementation-defined behavior causes very little trouble in practice.</p> -<h2>Acknowledgments</h2> <p>Radu Grigore provided many ideas that did not fit in the article and is directly responsible for the existence of this blog post.</p> {% endraw %} diff --git a/_posts/2012-05-08-Facebook.html b/_posts/2012-05-08-Facebook.html index 818cdf66dbaec660148f0b320b45aac231667d5e..9739211c8c6d759c7ae0cfc348648644d91ff09a 100644 --- a/_posts/2012-05-08-Facebook.html +++ b/_posts/2012-05-08-Facebook.html @@ -11,8 +11,5 @@ summary: <p>When I created a Facebook account, I did something that I fully expect will be made a felony before 2030: I filled the inquisitive, mandatory field on the electronic form with false information. You see, Facebook was asking me about my birth date, which it didn't need to know.</p> <p>There is just one thing I didn't anticipate...</p> <p>Facebook was asking so that it could then pass the information around, sometimes legitimately to people who might already have known it anyway, and for money to anyone with money.</p> -<p>If you wished me a happy birthday, I am so very sorry, but I was not born on May 8. Please find relief in the thought that this is as embarrassing for me as it is for you.</p> <p>When I created a Facebook account, I did something that I fully expect will be made a felony before 2030: I filled the inquisitive, mandatory field on the electronic form with false information. You see, Facebook was asking me about my birth date, which it didn't need to know.</p> -<p>There is just one thing I didn't anticipate...</p> -<p>Facebook was asking so that it could then pass the information around, sometimes legitimately to people who might already have known it anyway, and for money to anyone with money.</p> -<p>If you wished me a happy birthday, I am so very sorry, but I was not born on May 8. Please find relief in the thought that this is as embarrassing for me as it is for you.</p> +<p>If you wished me a happy birthday, I am so very sorry, but I was not born on May 8. Please find relief in the thought that this is as embarrassing for me as it is for you.</p> {% endraw %} diff --git a/_posts/2012-05-11-Life-stole-my-joke-and-all-I-got-is-this-lousy-blog-post.html b/_posts/2012-05-11-Life-stole-my-joke-and-all-I-got-is-this-lousy-blog-post.html index 06af6a9a4f713747114ddd85fe0fdf2bf886c84e..72dc7c1f2824774c7d2a723a76a9e625932cd602 100644 --- a/_posts/2012-05-11-Life-stole-my-joke-and-all-I-got-is-this-lousy-blog-post.html +++ b/_posts/2012-05-11-Life-stole-my-joke-and-all-I-got-is-this-lousy-blog-post.html @@ -17,15 +17,5 @@ summary: <li>am I the only one to find “I [didn't think] the fellow was homosexual†a lousy excuse? It does not matter whether one “thinksâ€. From the point of view of the victim it shouldn't be necessary to broadcast one's sexual orientation to be morally protected from harassment. A student who takes offence at any visible lifestyle choice of eir colleagues that aren't any of eir business is guilty of intolerance. If it later turns out that a relatively large proportion of eir victims are from a same minority that's just bad luck for em because it makes the crime more obvious. But even if the victims did not happen to be from a recognizable minority the crime would still be the same crime.</li> <li>Finally the only way I can imagine a kid doing the kind of “hijinks†described in the article and not being sent home for the remainder of the schoolyear is if ey is a very rich kid in a school/university that needs to worry where its next budget is going to come from. Since French Universities have begun to “gain autonomy†under our own previous president are we now going to have the same system where rich kids get a free pass with discipline even at the cost of the peace of mind of their fellow students? A few decades from now will we have to elect them for the highest offices too?</li> </ul> -<p>If told that this post is too off-topic for this blog I plan to use the “but the link to the original article came from my colleague Eric Eide†defense. That and something on the general topic of conference attendance and testicle massages.</p> - <p>On a recent occasion to visit the USA on a professional basis, I nearly declined. I had a lengthy explanation ready for my refusal, and it might even have become a rant-tagged blog post. I finally went, so that hypothetical blog post never became. Today, I feel I have been cheated: a really good bit of my explanation would, if I were to re-use it now in another rant, appear unimaginative; stale, even.</p> -<p>See, my explanation of why I didn't want to be a visitor in the USA included a passage on how schools everywhere in the world, at all levels, have bullies, but only in the US these get elected president. (You had to see it in context. There were tie-ins with culture and international politics. It was a beautiful rant)</p> -<p>The reason this bit is suddenly worthless is of course the latest mini-scandal in US election debates. <a href="http://www.sltrib.com/sltrib/world/54089149-68/romney-gay-lauber-post.html.csp">Here</a> is the article through which I first heard of it. My rant was about another person who may or may not have been US president at some point in eir political career.</p> -<p>It is not my place to comment on foreign <em>presidentiables</em>. The following comments are intended only in the abstract.</p> -<ul> -<li>About the facts themselves the fact that a brat bullied five homosexual fellow students does not in itself imply that the brat has a bias. If ey similarly bullied 95 heterosexual students say forcibly cutting the hair of 19 of them and if 5% actually is the percentage of the population who recognizes itself as homosexual ey cannot be blamed for being biased—although ey can still be blamed for being a bully.</li> -<li>am I the only one to find “I [didn't think] the fellow was homosexual†a lousy excuse? It does not matter whether one “thinksâ€. From the point of view of the victim it shouldn't be necessary to broadcast one's sexual orientation to be morally protected from harassment. A student who takes offence at any visible lifestyle choice of eir colleagues that aren't any of eir business is guilty of intolerance. If it later turns out that a relatively large proportion of eir victims are from a same minority that's just bad luck for em because it makes the crime more obvious. But even if the victims did not happen to be from a recognizable minority the crime would still be the same crime.</li> -<li>Finally the only way I can imagine a kid doing the kind of “hijinks†described in the article and not being sent home for the remainder of the schoolyear is if ey is a very rich kid in a school/university that needs to worry where its next budget is going to come from. Since French Universities have begun to “gain autonomy†under our own previous president are we now going to have the same system where rich kids get a free pass with discipline even at the cost of the peace of mind of their fellow students? A few decades from now will we have to elect them for the highest offices too?</li> -</ul> <p>If told that this post is too off-topic for this blog I plan to use the “but the link to the original article came from my colleague Eric Eide†defense. That and something on the general topic of conference attendance and testicle massages.</p> {% endraw %} diff --git a/_posts/2012-05-14-On-ending-discussions-and-painting-bikesheds.html b/_posts/2012-05-14-On-ending-discussions-and-painting-bikesheds.html index d5ad923aa755829b47f0c810446bf58ac05ba41b..cb5c3a0631b0aaefb1161ac9e252a7af71c9216d 100644 --- a/_posts/2012-05-14-On-ending-discussions-and-painting-bikesheds.html +++ b/_posts/2012-05-14-On-ending-discussions-and-painting-bikesheds.html @@ -15,13 +15,5 @@ If everyone who has expressed their opinion had created as much great software a I might even not have to use Mac OS X.</p> <p>Now of course the Github discussion is a little bit difficult to follow because the comment Linus was replying to has been deleted. A little bit of investigation is needed to find out that he was probably replying to the sentence “I did not realizes that Linus' shit does not stink. Thanks for clearing that up...†(<a href="https://github.com/pirtlj">source</a>).</p> <p>“You're a moron†seems to me a perfectly fine retort to someone who thus butts into a public discussion in which you have already made your technical arguments clear. Plenty of alternatives are also acceptable of course including ending the thread. I do not see what the racket over Linus' answer is. But my point is that even if I thought his answer was unacceptable I would first question whether my opinion should matter as someone whose contribution is relatively small. Where is the evidence that doing things my way is better? Is there for instance anyone in the world with a comparable contribution (especially in terms of visibility) who isn't brutally frank in <a href="http://en.wikipedia.org/wiki/Spivak_pronoun">eir</a> interactions with the thousands of persons ey has to deal with—some of whom statistically have to be pretty dim-witted? Perhaps this is the kind of personality one needs to have to build something useful in the first place. Perhaps one becomes more and more direct with each of the million e-mails I roughly estimate one needs to handle in the lifetime of such a project. Where in other words is the person that Linus Torvalds could use as role model?</p> -<p>To reiterate I wish everyone who has been expressing their opinion on how to handle Open Source contributions had written the kind of highly visible useful software that justifies having an opinion on contribution management. If they had written so much more so much more useful software that someone like Linus could be on his way without being missed that would be great.</p> - <p>A high-profile maintainer to a large Open-Source project recently found himself involved in a <a href="https://github.com/torvalds/linux/pull/17#issuecomment-5654674">discussion</a> in which at some point after having explained his arguments—I think—very clearly he had to call someone else a moron. -Now everyone with write access to the internet is weighting in on how this is no way to behave and how the bike-shed really should be painted a more friendly color.</p> -<p>Most of the people I have seen opine do so with the confidence of someone who has created something as widely useful as Linux and knows how things are done. Dominik Dabrowski comments “You might have fun raging on the internet but I think your goals would be better served if ...â€. Kenneth Reitz writes a blog post with the title “Be Cordial or Be on Your Wayâ€. -If everyone who has expressed their opinion had created as much great software as Linus this would be a better world. -I might even not have to use Mac OS X.</p> -<p>Now of course the Github discussion is a little bit difficult to follow because the comment Linus was replying to has been deleted. A little bit of investigation is needed to find out that he was probably replying to the sentence “I did not realizes that Linus' shit does not stink. Thanks for clearing that up...†(<a href="https://github.com/pirtlj">source</a>).</p> -<p>“You're a moron†seems to me a perfectly fine retort to someone who thus butts into a public discussion in which you have already made your technical arguments clear. Plenty of alternatives are also acceptable of course including ending the thread. I do not see what the racket over Linus' answer is. But my point is that even if I thought his answer was unacceptable I would first question whether my opinion should matter as someone whose contribution is relatively small. Where is the evidence that doing things my way is better? Is there for instance anyone in the world with a comparable contribution (especially in terms of visibility) who isn't brutally frank in <a href="http://en.wikipedia.org/wiki/Spivak_pronoun">eir</a> interactions with the thousands of persons ey has to deal with—some of whom statistically have to be pretty dim-witted? Perhaps this is the kind of personality one needs to have to build something useful in the first place. Perhaps one becomes more and more direct with each of the million e-mails I roughly estimate one needs to handle in the lifetime of such a project. Where in other words is the person that Linus Torvalds could use as role model?</p> <p>To reiterate I wish everyone who has been expressing their opinion on how to handle Open Source contributions had written the kind of highly visible useful software that justifies having an opinion on contribution management. If they had written so much more so much more useful software that someone like Linus could be on his way without being missed that would be great.</p> {% endraw %} diff --git a/_posts/2012-05-21-Iterating-over-the-AST.html b/_posts/2012-05-21-Iterating-over-the-AST.html index 5c2c7a3f97ddc0d36f09358f6949613e2be35299..77250bd43c72276cbf2bf85d4bdd6e6ada67641b 100644 --- a/_posts/2012-05-21-Iterating-over-the-AST.html +++ b/_posts/2012-05-21-Iterating-over-the-AST.html @@ -8,75 +8,7 @@ title: "Iterating over the AST" summary: --- {% raw %} -!!! Context -A facetious colleague who claims that he should be better writing his thesis but keeps committing Coq and OCaml files on Frama-C's repository, asked me the following question: {{Is there a function in Frama-C's kernel that can fold$$For those who are not familiar with functional programming: [http://en.wikipedia.org/wiki/Fold_%28higher-order_function%29]$$ a function over all types that appear in a C program?}} -As it turns out, nothing is readily available for this exact purpose, but another facetious colleague could have come up with a terse answer: {{There's a __visitor__ for that!}} Now, we can be a bit more helpful and actually write that visitor. Our end goal is to come up with a function -/// -fold_typ: (Cil_types.typ -> 'a -> 'a) -> 'a -> 'a -/// -so that @@fold_typ f init@@ will be @@f t_1 (f t_2 (... (f t_n init)...))@@, where the @@t_i@@ are all the C types appearing in a given C program (in no particular order). -!!! Frama-C's visitors -The [visitor pattern|http://en.wikipedia.org/wiki/Visitor_pattern] is a well-known object-oriented design pattern that can be used to perform a given action over all nodes of a complex data structure (in our case the Abstract Syntax Tree -AST for short- of a C program). Frama-C provides a generic visitor mechanism, built upon CIL's visitor, -whose entry points can be found in the aptly named @@src/kernel/visitor.mli@@ file. It is also documented in section 5.14 of [the developer manual|http://frama-c.com/download/plugin-development-guide-Nitrogen-20111001.pdf]. In summary, you first define a class that inherits from the generic visitor and overrides the methods corresponding to the nodes you're interested in (in our case, this will be @@vtype@@ for visiting uses of @@Cil_types.typ@@). Then you apply an object of this class to the function from the @@Visitor@@ module that correspond to the subpart of the AST that you want to inspect (in our case, this will be the whole AST). -!!! Basic version -The standard visitor does not provide anything to return a value outside of the AST. In fact, all the entry points in @@Visitor@@ return a node of the same type that the node in which the visit starts (for visitors that don't perform code transformation, this is in fact physically the same node). But if you accept to sneak in a little bit of imperative code into your development -and by using Frama-C you've already accepted that- there is an easy way out: pass to the visitor a reference -that it can update, and you just have to read the final value that reference is holding after the visit. The visitor then looks like the following: -/// -class fold_typ_basic f acc = -object - inherit Visitor.frama_c_inplace - method vtype ty = acc:= f ty !acc; Cil.DoChildren -end -/// -And that's it. Each time the visitor sees a type, it will apply @@f@@ to @@ty@@ and the result of the previous computations, stored in @@acc@@. @@fold_typ@@ then just needs to call the visitor over the whole AST and give it a reference initialized with @@init@@: -/// -let fold_typ f init = - let racc = ref init in - let vis = new fold_typ_basic f racc in - Visitor.visitFramacFileSameGlobals vis (Ast.get()); - !racc -/// -!!! Don't do the same work twice -This first version, that is barely more than 10 LoC, works, but we can do a little better. Indeed, @@f@@ will be called each time a type is encountered in the AST. In most cases, we want to call @@f@@ once for any given type. This can be done quite simply by memoizing in an instance variable of our visitor the set of types encountered thus far. Frama-C's @@Cil_datatype@@ module (@@cil/src/cil_datatype.mli@@) provides all the needed functions for that: -/// -class fold_typ f acc = -object - inherit Visitor.frama_c_inplace - val mutable known_types = Cil_datatype.Typ.Set.empty - method vtype ty = - if Cil_datatype.Typ.Set.mem ty known_types then Cil.DoChildren - else begin - known_types <- Cil_datatype.Typ.Set.add ty known_types; - acc:= f ty !acc; - Cil.DoChildren - end -end -/// -!!! Testing the infrastructure -It is now time to test if everything works smoothly. The following function will print the name and size of the type who has the biggest size in the analyzed program. -/// -let test () = - let f ty (maxty,maxsize as acc) = - try - let size = Cil.sizeOf_int ty in - if size > maxsize then (ty,size) else acc - with Cil.SizeOfError _ -> acc - in - let (ty,size) = fold_typ f (Cil.voidType,0) in - Format.printf \Biggest type is %a @ with size %d@." - !Ast_printer.d_type ty size -/// -Since it is only a quick test we don't do anything special if Cil complains that it cannot compute the size of a given type: we just stick to the maximal value computed -so far. -File [fold_typ.ml|/assets/img/blog/imported-posts/fold_typ.ml] provides the code for the visitor and the test function. @@frama-c -load-script fold_typ.ml file.c@@ should output something like -/// -[kernel] preprocessing with "gcc -C -E -I. file.c" -Biggest type is struct Ts -with size 44 -/// -!!! Exercises -# How can you use the @@fold_typ@@ class to define an @@iter_typ@@ function that apply a function @@f@@ returning @@unit@@ to each type of the AST (@@val iter_typ: (Cil_types.typ -> unit) -> unit@@)? -# Writing @@fold_typ@@ is a bit overkill if you're going to apply it once in your plug-in. Write a specialized visitor that will do the same thing as the @@test@@ function above." <h3>Context</h3> +<h3>Context</h3> <p>A facetious colleague who claims that he should be better writing his thesis but keeps committing Coq and OCaml files on Frama-C's repository, asked me the following question: <q>Is there a function in Frama-C's kernel that can fold<sup>[<a href="#pnote-144-1" id="rev-pnote-144-1">1</a>]</sup> a function over all types that appear in a C program?</q></p> <p>As it turns out nothing is readily available for this exact purpose but another facetious colleague could have come up with a terse answer: <q>There's a <strong>visitor</strong> for that!</q> Now we can be a bit more helpful and actually write that visitor. Our end goal is to come up with a function</p> <pre> diff --git a/_posts/2012-06-07-Verifying-the-termination-of-programs-with-value-analysis-option--obviously-terminates.html b/_posts/2012-06-07-Verifying-the-termination-of-programs-with-value-analysis-option--obviously-terminates.html index 933667b54eecda6262b9a1e93ce1c2430320076b..ef173088c69c022c5c64a95f2711c3ec456093ef 100644 --- a/_posts/2012-06-07-Verifying-the-termination-of-programs-with-value-analysis-option--obviously-terminates.html +++ b/_posts/2012-06-07-Verifying-the-termination-of-programs-with-value-analysis-option--obviously-terminates.html @@ -100,98 +100,5 @@ main(){ } } </pre> -<p>Again <code>frama-c -obviously-terminates -val</code> shows the termination of this program. It is very quick in this case since the interval for variable <code>x</code> is initially reduced by slices of 12 values at a time and then the value analysis carefully analyzes the tricky part which takes most of the time.</p> - <h2>What's old about option -obviously-terminates</h2> -<p>Option <code>-obviously-terminates</code> is a value analysis option, new in Nitrogen, with some of the same effects as using an infinite slevel. This option also disables fixpoint detection and the statement-wise memorisation of analysis results.</p> -<p>I briefly described this option in <a href="http://blog.frama-c.com/index.php?post/2012/03/12/Minimizing-alarms">a previous post</a> in section “Trying to improve results by doing things differentlyâ€. This option was originally intended for the <a href="http://blog.frama-c.com/index.php?pages/Csmith-testing">interpretation of Csmith-generated programs</a>. Csmith-generated programs are executable and it is possible to make sure that they terminate by simply letting them run for a few milliseconds. Once it is known that a Csmith-generated program terminates then the value analysis' job interpreting the program is much easier with option <code>-obviously-terminates</code>. This option tells it not to waste time looking for a fixpoint since in this case it could only find one if the program looped which we know it doesn't.</p> -<h2>What's new about option -obviously-terminates</h2> -<p><strong>Option <code>-obviously-terminates</code> can be used to verify the termination of C programs.</strong></p> -<p>Used this way it is sound—when it diagnoses the program as terminating then the program always terminates. It is not complete: it may fail to answer for programs that terminate. Actually it always either diagnoses the program as terminating or fails to answer: it must be used with a timeout. It tries to make the program terminate until the timeout and the timeout being reached must be interpreted as the answer “I don't knowâ€.</p> -<p>This new insight into an existing option is as new for me as it is for you: I genuinely did not realize that this option could do this until this morning's shower. I was close because in the previously linked blog post I had written:</p> -<p>“[Option <code>-obviously-terminates</code>] makes [the value analysis] loop forever on C programs that loop forever — like an interpreter doesâ€</p> -<p>But it did not occur to me to contrapose the above statement until I tried a few examples into the web interface for <a href="http://kaz.dsic.upv.es/sett/">sett</a> Germán Vidal's symbolic execution-based termination tool. I am extremely thankful to him for making this web interface available.</p> -<h2>Examples</h2> -<p>Here is a first example with non-obvious termination:</p> -<pre>char x y; -main() -{ - x = input(); - y = input(); - while (x>0 && y>0) - { - if (input() == 1) - { - x = x - 1; - y = input(); - } - else - y = y - 1; - } -} -</pre> -<p>Note the use of the (signed) type <code>char</code> for variables <code>x</code> and <code>y</code> to limit combinatorial explosion.</p> -<pre>$ frama-c -obviously-terminates -val t1.c -[kernel] preprocessing with "gcc -C -E -I. t1.c" -[value] Analyzing a complete application starting at main -[value] Computing initial state -[value] Initial state computed -[value] Values of globals at initialization - x ∈ {0} - y ∈ {0} -[value] computing for function input <- main. - Called from t1.c:5. -... - (several seconds here) -... -[value] Semantic level unrolling superposing up to 48100 states -... -[value] Done for function input -[value] Recording results for main -[value] done for function main -[value] ====== VALUES COMPUTED ====== -</pre> -<p>Frama-C's value analysis with option <code>-obviously-terminates</code> was able to finish its analysis of this example. This means that the program terminates for all possible integers returned by <code>input()</code>.</p> -<p>Another example:</p> -<pre>char x y; -main() -{ - x = input(); - y = input(); - while (x>0 && y>0) - { - // Frama_C_dump_each(); - if (input()) - { - x = x - 1; - y = x; - } - else - { - x = y - 2; - y = x + 1; - } - } -} -</pre> -<pre>$ frama-c -obviously-terminates -val t2.c -... -[value] ====== VALUES COMPUTED ====== -</pre> -<p>This means once again that the program terminates for all possible integers returned by <code>input()</code>.</p> -<p>I couldn't believe how fast the analysis of this second example was so I inserted the <code>Frama_C_dump_each();</code> call. If you uncomment it you can see the abstract states that have been considered during the analysis and how they become smaller and smaller until it becomes obvious that all execution paths eventually exit the loop.</p> -<p>The two above examples were taken from the sett website. They can be found in the sett input language syntax inside the PDF description of the tool. Here is a third example invented by me:</p> -<pre>char x; -main(){ - x = input(); - while (x > 0) - { - Frama_C_dump_each(); - if (x > 11) - x = x - 12; - else - x = x + 1; - } -} -</pre> <p>Again <code>frama-c -obviously-terminates -val</code> shows the termination of this program. It is very quick in this case since the interval for variable <code>x</code> is initially reduced by slices of 12 values at a time and then the value analysis carefully analyzes the tricky part which takes most of the time.</p> {% endraw %} diff --git a/_posts/2012-06-08-To-finish-on-termination.html b/_posts/2012-06-08-To-finish-on-termination.html index a9a7cbace17f0b960aa24c2c32e8c65fb6d989c1..6b6faaf3f42e2d48055ce2f4f2a0a48e9e0016a8 100644 --- a/_posts/2012-06-08-To-finish-on-termination.html +++ b/_posts/2012-06-08-To-finish-on-termination.html @@ -88,86 +88,5 @@ main(){ x ∈ {0; 1} __retres ∈ {0} </pre> -<p>Both attempts failed. Ah well at least we tried.</p> - <p>Enthusiastic reactions to the <a href="/index.php?post/2012/06/07/Verifying-the-termination-of-programs-with-value-analysis-option-obviously-terminates">previous post</a> about verifying the termination of a C program with Frama-C's value analysis lead me to write this post-scriptum.</p> -<h2>On detecting both termination and non-termination</h2> -<p>The scheme I outlined in the previous post can only confirm the termination of the program. If the program does not terminate the analysis method I outlined runs indefinitely. I recommended to use a timeout and to interpret reaching the timeout as the answer “I don't knowâ€. Off-line a colleague complained about this behavior.</p> -<p>This colleague was of course being facetious. Frama-C's value analysis when used normally (<strong>without</strong> option <code>-obviously-terminates</code>) is already a sound detector of non-termination. Consider the program below:</p> -<pre>unsigned char u = 1; -int main(){ - while (u) - { - u = u + 14; - } - return u; -} -</pre> -<p>If you can get Frama-C's value analysis to print that the function is a “NON TERMINATING FUNCTION†it means that the function is guaranteed not to have any defined terminating executions (to put it simply the function is guaranteed not to terminate). In this case it is easy:</p> -<pre>$ frama-c -val t4.c -[value] Values at end of function main: - NON TERMINATING FUNCTION -</pre> -<p>The values displayed as possible at the end of the function are sound over-approximations of the values that are possible in real (defined) executions. When the value analysis says that there are no possible values you can trust that there are no real executions that reach the end of the function.</p> -<p>For more difficult cases I recommend option <code>-slevel</code> to improve the chances that the analyzer will detect non-termination. The guarantees are the same as before: if the value analysis says “NON TERMINATING FUNCTION†no real execution reaches the end of the function. If it describes possible values for variables at the end of the function it mean that because of over-approximations it doesn't know whether the end of the function is reached at all.</p> -<pre>unsigned char u; -int main(){ - while (u * u != 17) - { - u = u + 1; - } - return u; -} -</pre> -<p>The program above looks for a number whose square is 17. With the default settings the value analysis is unable to decide whether the program terminates or not:</p> -<pre>$ frama-c -val t5.c -... -[value] Values at end of function main: - u ∈ [--..--] - __retres ∈ [0..255] -</pre> -<p>Let us now analyze the program more precisely with option <code>-slevel 300</code>:</p> -<pre>~ $ frama-c -slevel 300 -val t5.c -... -[value] Values at end of function main: - NON TERMINATING FUNCTION -</pre> -<p>That's better: the above result means that the value analysis can guarantee that the program will keep searching for an unsigned char whose square is 17 until the end of the world.</p> -<p>To summarize:</p> -<ul> -<li>If you want to verify non-termination you can hope to do so with Frama-C's value analysis in normal mode.</li> -<li>If you want to verify termination you can hope to do so with Frama-C's value analysis with option <code>-obviously-terminate</code>.</li> -<li>If you don't know whether the target program terminates or not and you want to chance to detect both then you can launch both <code>frama-c -val</code> and <code>frama-c -obviously-terminates -val</code> in parallel and see whether one of them is able to conclude one way or the other.</li> -<li>If you want an analyzer that always tells in finite time whether a given program terminates or not and although a C program without dynamic allocation is not exactly similar to a Turing machine you may be <a href="http://en.wikipedia.org/wiki/Halting_problem">asking too much</a>.</li> -</ul> -<h2>On the Collatz conjecture</h2> -<p>An expedient shortcut when trying to explain undecidability to non-computer scientists is to encode a famous well-researched mathematical conjecture into a computer program ideally one with a large monetary prize attached to it. It works well as an intuitive explanation of the difficulty of saying anything about the dynamic behavior of arbitrary programs. The argument is that if it was easy to tell whether an arbitrary program does something or the other some mathematician would have taken the opportunity to become famous and possibly rich by encoding the conjecture as a computer program and analyzing this program. This is of course an informal meta-argument. Perhaps all mathematicians are stupid; we don't know about that. But I find this explanation of undecidability works better than any other I have tried.</p> -<p>A long time ago I was using <a href="http://en.wikipedia.org/wiki/Fermat%27s_Last_Theorem">Fermat's last theorem</a> for the above purpose. When it started to be considered satisfactorily proved I switched to <a href="http://en.wikipedia.org/wiki/Goldbach%27s_conjecture">Goldbach's conjecture</a>. But Goldbach's conjecture requires enumerating prime numbers. To encode it into the simplest possible program for the purpose of an informal explanation one needs to write at least a function that recognizes a prime number and explain that this is good enough to encode the conjecture into a program.</p> -<p>All this time I should have been using the <a href="http://en.wikipedia.org/wiki/Collatz_conjecture">Collatz conjecture</a> (that you may also know as “Syracuse problemâ€). My facetious colleagues reminded me of this in the comments to the previous post.</p> -<p>Let us humor these colleagues:</p> -<pre>unsigned long long x; -unsigned long long input(); -main(){ - x = input(); - while (x > 1) - { - if (x%2 == 0) x = x/2; else x = 3*x + 1; - } -} -</pre> -<p>Trying to prove termination:</p> -<pre>$ frama-c -obviously-terminates -val syracuse.c -... -[value] Semantic level unrolling superposing up to 53600 states -[value] Semantic level unrolling superposing up to 53700 states -[value] Semantic level unrolling superposing up to 53800 states -^C[kernel] User Interruption (Ctrl-C) -</pre> -<p>Trying to prove non-termination:</p> -<pre>$ frama-c -slevel 44444 -val syracuse.c -... -[value] Values at end of function main: - x ∈ {0; 1} - __retres ∈ {0} -</pre> <p>Both attempts failed. Ah well at least we tried.</p> {% endraw %} diff --git a/_posts/2012-06-12-IOCCC.html b/_posts/2012-06-12-IOCCC.html index 1d849c789aae7ee23a302e213bb5767560c1ba0e..72ff9c8ea0103e79534cd4afb4e47cae1cfbdfaf 100644 --- a/_posts/2012-06-12-IOCCC.html +++ b/_posts/2012-06-12-IOCCC.html @@ -19,17 +19,5 @@ summary: <p>Just as I feel ready to start two gentlemen in front of me arrive to a pause in their discussion. I seize the opportunity to introduce myself and ask them both my carefully prepared first question. And it turns out one of them is a teaching assistant for a C programming class. Disappointing isn't it? Now I no longer have reason to continue my survey and although I have learnt something about this conference's attendees it will never be very statistically significant. I didn't even get to the “small world†part.</p> <p>But wait it does not end here! Just a little while later as we are still discussing C in relation to teaching a third person who knows us each interjects “oh have you two guys found each other?†and when it appears we did not even know we were looking for each other does some proper introductions. It turns out that I am talking to a <a href="http://www.ioccc.org/years.html#2011">2011 IOCCC</a> laureate.</p> <p>So at this conference I am at one attendee in two has written a winning IOCCC entry. With low confidence.</p> -<p>(*) many “introduction to programmingâ€-kind of classes have moved from C to Java apparently which would be a good thing if Java didn't have its own set of failures as a beginner's language. Anyway there is a work-related experiment I want to conduct and it only works with a C course.</p> - <p>So I am at this conference, right?</p> -<p>Having been looking, for a few months now, without luck, for someone who teaches C programming*, I figure this conference is as good an occasion to find <a href="http://en.wikipedia.org/wiki/Spivak_pronoun">em</a> as any. But it sounds kind of stupid to go to someone and just ask "excuse me but would you happen to teach C?"</p> -<p>Having reduced a problem I have been stuck with for a while to the easier problem of not looking stupid I find that if I augment my question a little it may just become weird enough as to look cute. And I can increase my chances at the same time. And learn something on the side. So I prepare a mini-survey that I feel scientific-minded people might receive positively:</p> -<ol> -<li>Do you happen to teach C?</li> -<li>If you do not do you know someone at this conference who might or who might recursively know someone who might?</li> -</ol> -<p>You will have recognized a “<a href="http://en.wikipedia.org/wiki/Small_world_experiment">small world</a>â€-type experiment one that could reveal something interesting about the connectedness of the graph whose nodes are the attendees of this particular conference.</p> -<p>Just as I feel ready to start two gentlemen in front of me arrive to a pause in their discussion. I seize the opportunity to introduce myself and ask them both my carefully prepared first question. And it turns out one of them is a teaching assistant for a C programming class. Disappointing isn't it? Now I no longer have reason to continue my survey and although I have learnt something about this conference's attendees it will never be very statistically significant. I didn't even get to the “small world†part.</p> -<p>But wait it does not end here! Just a little while later as we are still discussing C in relation to teaching a third person who knows us each interjects “oh have you two guys found each other?†and when it appears we did not even know we were looking for each other does some proper introductions. It turns out that I am talking to a <a href="http://www.ioccc.org/years.html#2011">2011 IOCCC</a> laureate.</p> -<p>So at this conference I am at one attendee in two has written a winning IOCCC entry. With low confidence.</p> <p>(*) many “introduction to programmingâ€-kind of classes have moved from C to Java apparently which would be a good thing if Java didn't have its own set of failures as a beginner's language. Anyway there is a work-related experiment I want to conduct and it only works with a C course.</p> {% endraw %} diff --git a/_posts/2012-06-28-Undefined-behavior-is-a-harsh-mistress.html b/_posts/2012-06-28-Undefined-behavior-is-a-harsh-mistress.html index e18d7bba3163ff422399c51a1d4bb84a59b6e902..617c9a8087c50c2ac5360ea31741f5dbd62bb092 100644 --- a/_posts/2012-06-28-Undefined-behavior-is-a-harsh-mistress.html +++ b/_posts/2012-06-28-Undefined-behavior-is-a-harsh-mistress.html @@ -17,15 +17,5 @@ summary: <blockquote><p>First you demonstrate ignorance talking about C language with the “bool†data type.</p> </blockquote> <p>Dude Mark demonstrates his mastery of C by properly using <code>stdbool.h</code> as part of a sound discussion of undefined behavior in a C program.</p> -<p>If you are in the Manchester area and are reading this please drop by on Saturday. Gate-crash the conference if you have to. You can always blame my bad influence if you get caught.</p> - <p>Mark Shroyer has discovered <a href="http://markshroyer.com/2012/06/c-both-true-and-false/">an interesting consequence</a> of undefined behavior in the compiled version of a C program: a variable behaves as both true and false as a result of being uninitialized.</p> -<p>The post is great and could not come at a better time. I needed for the talk I will give on Saturday morning at COMPARE2012 convincing examples that some undefined behaviors cannot be recovered from. For a long time I had wanted an example that “uninitialized†was not equivalent to “holding an unknown value†and this is just it. Once again procrastination wins!</p> -<blockquote><p>One a side note should I be worried that I am building tolerance to the panic of not having one's slides ready for an upcoming talk? If I can't even get in a frenzy in the last few days before the talk I may just become useless. Perhaps it's time for retirement.</p> -</blockquote> -<p>The only disappointing aspect of Mark's blog post is the general reaction to it in the blog's comments or elsewhere. Guys Mark obviously knows what undefined behavior is! He is not blaming GCC for not giving a consistent value to his variable <code>p</code>. Using uninitialized memory is a bug in his program; it's a bug he has been looking for and the consequences of it were funny so he shared. No need to get all professorial about it.</p> -<p>The so-stupid-it's-funny prize goes to the comment below.</p> -<blockquote><p>First you demonstrate ignorance talking about C language with the “bool†data type.</p> -</blockquote> -<p>Dude Mark demonstrates his mastery of C by properly using <code>stdbool.h</code> as part of a sound discussion of undefined behavior in a C program.</p> <p>If you are in the Manchester area and are reading this please drop by on Saturday. Gate-crash the conference if you have to. You can always blame my bad influence if you get caught.</p> {% endraw %} diff --git a/_posts/2012-07-17-Code-smells-smell.html b/_posts/2012-07-17-Code-smells-smell.html index 9dfb73bead1e71f0a913b931455c4a2b01b9d774..d0d4d2dfe658b6db3c0ad3ebadbb43d57172ea9f 100644 --- a/_posts/2012-07-17-Code-smells-smell.html +++ b/_posts/2012-07-17-Code-smells-smell.html @@ -16,13 +16,5 @@ I think however that there is something fundamentally wrong not with the defi <div class="footnotes"><h4>Notes</h4> <p>[<a href="#rev-pnote-149-1" id="pnote-149-1">1</a>] This post was crying so loud for moderation that it would have been a shame not to grant it</p> <p>[<a href="#rev-pnote-149-2" id="pnote-149-2">2</a>] a special kind of facetious colleague</p> -</div> <p>This blog post is on the subject of “code smells†and what is wrong with them. I initially wanted to go with the title “Code smells are crapâ€. That made it clearer that the title was grammatically a sentence, with “code smells†a nominal group followed by a verb. But there seems to be something in this blog's content management system that censors four-letter words in the title of articles, like some sort of <del>administrator or something</del><sup>[<a href="#pnote-149-1" id="rev-pnote-149-1">1</a>]</sup> friendly moderator<sup>[<a href="#pnote-149-2" id="rev-pnote-149-2">2</a>]</sup>.</p> -<p>At the time of this writing Wikipedia defines a code smell as “any symptom in the source code of a program that possibly indicates a deeper problemâ€. I do not challenge this definition. Indeed to the best of my knowledge this is exactly the meaning many researchers (and engineers) working in software engineering intend when they talk of “code smellsâ€. -I think however that there is something fundamentally wrong not with the definition but with scientific use of any notion accurately described by this definition. The issue I see in so many words is that it is not <a href="http://en.wikipedia.org/wiki/Precambrian_rabbit">falsifiable</a>.</p> -<p>Say that you build a tool that detects “code smellsâ€. You might even call your tool a “static analyzer†and there might be so many of you and of your tools that “static analysis†is understood by the majority as the craft of building code smell detectors. The tool flags as smelly a diligent implementation of a subtle but efficient computation taken from <a href="http://en.wikipedia.org/wiki/The_Art_of_Computer_Programming">The Art of Computer Programming</a>. This deserves the name “false positive†right? Surely your tool does not pretend to judge Knuth's carefully crafted state-of-the-art algorithms? Ah but no it is not a false positive because the notion is built right in the definition that a code smell only “possibly indicates a deeper problemâ€. Whatever the tool found <strong>is</strong> a code smell by virtue of having been flagged by the tool. It was not a problem but it was a code smell because it could have indicated a problem.</p> -<p>As scientists what the four-letter word are we supposed to do with such a notion?</p> -<div class="footnotes"><h4>Notes</h4> -<p>[<a href="#rev-pnote-149-1" id="pnote-149-1">1</a>] This post was crying so loud for moderation that it would have been a shame not to grant it</p> -<p>[<a href="#rev-pnote-149-2" id="pnote-149-2">2</a>] a special kind of facetious colleague</p> -</div> +</div> {% endraw %} diff --git a/_posts/2012-07-24-Results-are-in.html b/_posts/2012-07-24-Results-are-in.html index d44144ca8f473cc2c4796b3459c9579e69a215f7..eb3464154a368285a918ec780bd5e7e7a2eb10ae 100644 --- a/_posts/2012-07-24-Results-are-in.html +++ b/_posts/2012-07-24-Results-are-in.html @@ -63,61 +63,5 @@ The reason it finds* all undefined behaviors is not that it does well for a coup <p>Incidentally Frama-C's value analysis was tested on a lot more examples when working on <a href="http://www.cs.utah.edu/~regehr/papers/pldi12-preprint.pdf">this article on testcase reduction</a> and results were compared to <a href="http://code.google.com/p/c-semantics/">KCC</a>'s. The Csmith random C program generator produces only defined programs but C-Reduce one of the reducers described in the article produces tons of undefined behaviors. Although that was not a goal of the article the work also served as an application of differential testing to the detectors of undefined behaviors that are KCC and Frama-C's value analysis.</p> <p>There are problematic features of the C language that were left aside when initially designing the value analysis for its primary target of critical embedded code. This limits some uses but it remains possible to extract valuable information off a C program using the value analysis and the right methodology. One workaround is to use the value analysis as a C interpreter in which case standard library functions are easier to model. Many of them already are available in the unreleased value analysis.</p> <p>(*) when used properly. See Winner #1 and Winner #2 for examples of what “using properly†may entail.</p> -<p>My thanks to Sven Mattsen for proofreading this post.</p> - <h2>A contest and a self-pitying lament</h2> -<p>John Regehr was organizing a <a href="http://blog.regehr.org/archives/759">craziest undefined behavior contest</a> and the <a href="http://blog.regehr.org/archives/767">results are in</a>. I had an entry in the contest but I did not win. My entry apparently was too obviously dangerous. As John puts it “I would have expected a modern C compiler to exploit those undefined behaviorsâ€.</p> -<blockquote><p>I have explained the problem inherent to constructs of the kind <code>&a - 1 < &a</code> in several different sets of circumstances to different programmers for different projects and I was unable to convince any of them that the construct or a variant of it was <strong>not</strong> harmless and that the code <strong>should</strong> be changed. But for this contest the construct was too obviously wrong and too prone to be taken advantage of by an aggressive compiler to win. This is the story of my life really.</p> -</blockquote> -<h2>Notable entries</h2> -<p>The contest invited C++ entries as well but fortunately for this blog post most of the submissions were actually in C.</p> -<h3>Runner-up</h3> -<pre>int main (void) { - int x = 1; - while (x) x <<= 1; - return x; -} -$ bin/toplevel.opt -val t1.c | grep assert -t1.c:3:[kernel] warning: invalid LHS operand for left shift. assert x ≥ 0; -</pre> -<p>As shown above Frama-C's value analysis warns for the undefined behavior that made this entry a runner-up in the contest.</p> -<h3>Winner #1</h3> -<pre>enum {N = 32}; -int a[N] pfx[N]; -void prefix_sum (void) -{ - int i accum; - for (i = 0 accum = a[0]; i < N; i++ accum += a[i]) - pfx[i] = accum; -} -$ bin/toplevel.opt -val t2.c -main prefix_sum | grep assert -t2.c:6:[kernel] warning: accessing out of bounds index [1..32]. assert i < N; -</pre> -<p>In this second example you need to tell Frama-C to analyze the function <code>prefix_sum</code>. Otherwise it won't find the undefined behavior: the value analysis is <strong>not</strong> the sort of heuristic bug-finding tool that detects patterns in code regardless of calling contexts. For precision and soundness Frama-C's value analysis tries to determine whether <code>prefix_sum</code> is safe <strong>in the context(s) in which it is actually called during execution</strong>. Without option <code>-main prefix_sum</code> it looks like it is not called at all and therefore safe. Indeed if you try to compile and run the program the linker complains about a missing <code>main()</code> function meaning that the code cannot do harm.</p> -<p>Having to use option <code>-main</code> and others to describe your intentions is the sort of quirk you can pick up by going through <a href="/index.php?tag/skein">a tutorial</a> or <a href="http://frama-c.com/download/frama-c-value-analysis.pdf">the documentation</a>.</p> -<h3>Winner #2</h3> -<pre>#include <stdio.h> -#include <stdlib.h> -int main() { - int *p = (int*)malloc(sizeof(int)); - int *q = (int*)realloc(p sizeof(int)); - *p = 1; - *q = 2; - if (p == q) - printf("%d %d" *p *q); -} -</pre> -<p>This example involves dynamic allocation which is one of the C features that Frama-C's value analysis as a static analyzer does not claim to handle precisely in all cases.</p> -<p>Here however the program is completely deterministic: it does not have inputs of any kind. With an unreleased version of the value analysis it is possible to interpret such programs for the detection of undefined behaviors. In this interpreter mode the value analysis handles many more C constructs including <code>malloc()</code> and <code>realloc()</code> calls.</p> -<p>That version of the value analysis warns about the use of <code>p</code> in the line <code>if (p == q)</code> which is indeed the first use of <code>p</code> after its contents have become indeterminate (in the sense of the C99 standard). The issue here relates to <a href="/index.php?post/2012/01/05/Double-free">that post on the impossibility of freeing a pointer twice</a>.</p> -<h3>My entry</h3> -<p><a href="http://lwn.net/Articles/278137/">My entry</a> was on the subject of illegal pointer arithmetic which the value analysis does not warn about because there would be too many programs that it would (correctly) flag. It also involved comparisons of such illegal pointers which the value analysis <strong>does</strong> warn about. These comparisons are also commonly found in the wild but these are very very often actually dangerous and have security implications.</p> -<p>There is nothing much I can say on the subject that was not already in <a href="/index.php?post/2011/06/04/Valid-compare-pointers">a previous post on pointer comparisons</a>.</p> -<h2>Conclusion</h2> -<p>You might think I am going to end up with a statement like “Frama-C's value analysis detects* all undefined behaviors because it finds the undefined behaviors in all four examples illustrated in the contestâ€.</p> -<p>Perish the thought! That would be fallacious. My claim is that Frama-C's value analysis detects* all undefined behaviors that you may care about and even some you may think you do not need to care about but that might have surprising consequences as exemplified on some notable entries in John's contest. -The reason it finds* all undefined behaviors is not that it does well for a couple of examples but that it was designed to do so.</p> -<p>Incidentally Frama-C's value analysis was tested on a lot more examples when working on <a href="http://www.cs.utah.edu/~regehr/papers/pldi12-preprint.pdf">this article on testcase reduction</a> and results were compared to <a href="http://code.google.com/p/c-semantics/">KCC</a>'s. The Csmith random C program generator produces only defined programs but C-Reduce one of the reducers described in the article produces tons of undefined behaviors. Although that was not a goal of the article the work also served as an application of differential testing to the detectors of undefined behaviors that are KCC and Frama-C's value analysis.</p> -<p>There are problematic features of the C language that were left aside when initially designing the value analysis for its primary target of critical embedded code. This limits some uses but it remains possible to extract valuable information off a C program using the value analysis and the right methodology. One workaround is to use the value analysis as a C interpreter in which case standard library functions are easier to model. Many of them already are available in the unreleased value analysis.</p> -<p>(*) when used properly. See Winner #1 and Winner #2 for examples of what “using properly†may entail.</p> <p>My thanks to Sven Mattsen for proofreading this post.</p> {% endraw %} diff --git a/_posts/2012-07-25-On-the-redundancy-of-C99s-restrict.html b/_posts/2012-07-25-On-the-redundancy-of-C99s-restrict.html index f8afa72b4096d14c9d20ac52bb6006bc829d17d3..756418a8c232049ba5c2ab7b63ccf459acf6ac18 100644 --- a/_posts/2012-07-25-On-the-redundancy-of-C99s-restrict.html +++ b/_posts/2012-07-25-On-the-redundancy-of-C99s-restrict.html @@ -62,60 +62,5 @@ $ cat restr.s GCC does not generate efficient code for the function <code>f2()</code> above but it could. It generates the same code as for the plain function <code>f()</code> correctly compiling <code>(*p=*p) & (*q=*q);</code> to nothing but failing to take advantage of the freedom it provides to generate a function that does not work when <code>p</code> and <code>q</code> alias.</p> <h2>Wrapping up</h2> <p>My proposal is more flexible than <code>restrict</code> allowing to specify fine-grained non-aliasing relations between specific pointers. It is slightly more verbose especially when there are many pointers but this is a normal downside of allowing to specify aliasing relations pointer by pointer. Note that the pairwise absence of alias between <code>p</code> <code>q</code> and <code>r</code> can be specified with the compact <code>(*p=*p) & (*q=*q) & (*r=*r);</code></p> -<p>Compiler makers please support the <code>(*p=*p) & (*q=*q);</code> code annotation in your compilers.</p> - <h2>The restrict keyword in C99</h2> -<p>C99 introduced a <code>restrict</code> keyword. The intention is to let the programmer <a href="http://en.wikipedia.org/wiki/Restrict">specify the absence of alias between some inputs of a function ey is writing</a>.</p> -<p>Consider the function:</p> -<pre>int f1(int * restrict p int * restrict q) -{ - *p = 1; - *q = 2; - return *p + *q; -} -</pre> -<p>Thanks to the restrict keyword GCC can compile function <code>f1()</code> into the following assembly code:</p> -<pre>$ ~/gcc-172652/bin/gcc -O3 -std=c99 -S restr.c -$ cat restr.s -... - movl $1 (%rdi) - movl $2 (%rsi) - movl $3 %eax - ret -... -</pre> -<p>Note that the <code>-std=c99</code> is necessary. The code parsed as a C89 program is syntactically incorrect because <code>restrict</code> is not a keyword in C89.</p> -<p>In the generated x86_64 code <code>%rdi</code> is the first argument <code>p</code> <code>%rsi</code> is the second argument <code>q</code> the parentheses dereference and the dollar sign indicates constants. By convention register <code>%eax</code> contains the return value when the <code>ret</code> instruction is reached.</p> -<p>The above is pretty good code. Since the information is provided that pointers passed to function <code>f1</code> for <code>p</code> and <code>q</code> never alias the compiler knows that at the point of the return <code>*p</code> must be <code>1</code> and therefore the returned expression evaluates to <code>3</code>.</p> -<p>Contrast with the same function compiled without the <code>restrict</code> annotations say because all you have is a C89 compiler:</p> -<pre>int f(int * p int * q) -{ - *p = 1; - *q = 2; - return *p + *q; -} -... - movl $1 (%rdi) - movl $2 (%rsi) - movl (%rdi) %eax - addl $2 %eax - ret -</pre> -<p>This generated assembly code is not as good. The compiler knows that <code>*q</code> can only be <code>2</code> at the point of the <code>return</code> statement but it cannot be certain that <code>*p</code> contains <code>1</code> because the function could be passed the same address for both arguments. In order for the code to work in all cases the compiler decided to reload <code>*p</code> from memory for the addition.</p> -<h2>My proposal</h2> -<p>I claim that the <code>restrict</code> keyword in C99 both <strong>lacks expressive power</strong> and is <strong>redundant</strong> with constructs that already existed in C89. There was no need to encumber the language with a new construct especially a new keyword that breaks the compilation of existing code that uses a variable named <code>restrict</code>.</p> -<p>C89 already had <strong>undefined behavior</strong> a powerful tool for instructing the compiler that it does not have to generate code that handles special cases.</p> -<p>A function <code>f2()</code> that works under the same hypotheses as <code>f1()</code> can be written in C89:</p> -<pre>int f2(int * p int * q) -{ - (*p=*p) & (*q=*q); - *p = 1; - *q = 2; - return *p + *q; -} -</pre> -<p>The first statement in the body informs the compiler that <code>f2()</code> will never be called with aliasing arguments <code>p</code> and <code>q</code>. The compiler is then free to generate the same code as was generated for the <code>restrict</code>-using function <code>f1()</code>. It is completely legal for the compiler to assume that <code>*p + *q</code> at the <code>return</code> statement evaluates to <code>3</code> in the function above. -GCC does not generate efficient code for the function <code>f2()</code> above but it could. It generates the same code as for the plain function <code>f()</code> correctly compiling <code>(*p=*p) & (*q=*q);</code> to nothing but failing to take advantage of the freedom it provides to generate a function that does not work when <code>p</code> and <code>q</code> alias.</p> -<h2>Wrapping up</h2> -<p>My proposal is more flexible than <code>restrict</code> allowing to specify fine-grained non-aliasing relations between specific pointers. It is slightly more verbose especially when there are many pointers but this is a normal downside of allowing to specify aliasing relations pointer by pointer. Note that the pairwise absence of alias between <code>p</code> <code>q</code> and <code>r</code> can be specified with the compact <code>(*p=*p) & (*q=*q) & (*r=*r);</code></p> <p>Compiler makers please support the <code>(*p=*p) & (*q=*q);</code> code annotation in your compilers.</p> {% endraw %} diff --git a/_posts/2012-07-25-The-previous-post-was-written-in-jest.html b/_posts/2012-07-25-The-previous-post-was-written-in-jest.html index b7e822187767ca461014e991110a5df141121af4..15d9182d7d863eb89d35c227a03e5fbcf514e3ec 100644 --- a/_posts/2012-07-25-The-previous-post-was-written-in-jest.html +++ b/_posts/2012-07-25-The-previous-post-was-written-in-jest.html @@ -16,14 +16,5 @@ These days are gone. A few dedicated architectures (DSP) may give you saturating <p>The problem nowadays is that <a href="http://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html">compilers take advantage of undefined behavior for optimization</a>. An expression such as <code>X+1 > X</code> with <code>X</code> of type <code>int</code> may be optimized to <code>1</code> because the only case when it is not true is when <code>X+1</code> overflows which is undefined behavior and therefore the compiler can do what it wants then. Incidentally this means the same compiler compiles <code>X+1 > X</code> into code that produces different results for <code>INT_MAX</code> on different optimization levels.</p> <p>The previous post suggested to use a statement that is undefined when <code>p</code> and <code>q</code> alias in order to free the compiler of any constraints in these circumstances. The compiler can effectively do anything it wants including returning the incorrect result <code>3</code> if the same address is passed as both arguments of <code>f2()</code> because the function is undefined then. This was not a serious suggestion but should be understood as an argument in the debate about the exploitation of undefined behavior in compiler optimization.</p> <p>This debate is interesting to me as someone who works on the static analysis of critical embedded C because embedded code has constraints that make some kinds of undefined behaviors unavoidable. And critical code shouldn't use any of the dangerous undefined behaviors. And the frontier between the unavoidable undefined behaviors and the dangerous undefined behaviors is not written anywhere and it is always moving.</p> -<p>The previous post was largely written in jest. I was not suggesting to substitute the respected <code>restrict</code> keyword with an awkward replacement. All the arguments I put forward were in bad faith.</p> - <p>Just a quick update to provide context for the previous post.</p> -<p>The previous post assumes the reader is familiar with the notion of undefined behavior and how C compilers have started to justify their more aggressive optimizations along the lines of “this program has always been undefinedâ€.</p> -<p>Long ago, a C programmer trying to write a portable C program had to avoid signed overflows because different architectures could exhibit different behaviors depending on whether signed numbers were represented as sign-magnitude, in one's complement or in two's complement. -These days are gone. A few dedicated architectures (DSP) may give you saturating behavior for overflows, but mostly every architecture use two's complement.</p> -<p>A modern programmer might think “I know my target architecture uses two's complement representation, and I want wrap-around behavior here, so I will just use signed additionâ€.</p> -<p>The problem nowadays is that <a href="http://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html">compilers take advantage of undefined behavior for optimization</a>. An expression such as <code>X+1 > X</code> with <code>X</code> of type <code>int</code> may be optimized to <code>1</code> because the only case when it is not true is when <code>X+1</code> overflows which is undefined behavior and therefore the compiler can do what it wants then. Incidentally this means the same compiler compiles <code>X+1 > X</code> into code that produces different results for <code>INT_MAX</code> on different optimization levels.</p> -<p>The previous post suggested to use a statement that is undefined when <code>p</code> and <code>q</code> alias in order to free the compiler of any constraints in these circumstances. The compiler can effectively do anything it wants including returning the incorrect result <code>3</code> if the same address is passed as both arguments of <code>f2()</code> because the function is undefined then. This was not a serious suggestion but should be understood as an argument in the debate about the exploitation of undefined behavior in compiler optimization.</p> -<p>This debate is interesting to me as someone who works on the static analysis of critical embedded C because embedded code has constraints that make some kinds of undefined behaviors unavoidable. And critical code shouldn't use any of the dangerous undefined behaviors. And the frontier between the unavoidable undefined behaviors and the dangerous undefined behaviors is not written anywhere and it is always moving.</p> <p>The previous post was largely written in jest. I was not suggesting to substitute the respected <code>restrict</code> keyword with an awkward replacement. All the arguments I put forward were in bad faith.</p> {% endraw %} diff --git a/_posts/2012-07-25-The-restrict-qualifier-as-an-element-of-specification.html b/_posts/2012-07-25-The-restrict-qualifier-as-an-element-of-specification.html index c7f69dff6238a041dfbfffb74812efe61fc61353..4a6b38914bc77b15d66a6e57176924bec0fb258a 100644 --- a/_posts/2012-07-25-The-restrict-qualifier-as-an-element-of-specification.html +++ b/_posts/2012-07-25-The-restrict-qualifier-as-an-element-of-specification.html @@ -43,41 +43,5 @@ I can provide a neat trick for <a href="/derived/analysis/skein/2011/12/31/Do-no <pre>requires \separated(((char *)dest)+(0..n-1) ((char *)src)+(0..n-1)); </pre> <p>I might be biased but I think it is just as clear and separate concerns are better separated. The <code>\separated</code> predicate for instance is also useful for expressing exactly the conditions under which the statement <code>(*p=*p) & (*q=*q);</code> is defined.</p> -<p>The <a href="http://www.first.fraunhofer.de/fileadmin/FIRST/ACSL-by-Example.pdf">ACSL by example</a> library contains more examples of function contracts.</p> - <h2>An insightful interjection</h2> -<p>Stephen Canon, whose explanations about the fine points of floating-point I have appreciated on <a href="http://stackoverflow.com/users/142434/stephen-canon">StackOverflow</a> chimed in on the subject of the <code>restrict</code> qualifier. With minor edits for consistency with this blog's formatting:</p> -<blockquote><p>Consider <code>memcpy()</code>; its arguments are declared <code>restrict</code>. This not only means that the source and destination pointers cannot be the same (which is what Pascal's "replacement" says) but also means that the buffers cannot overlap at all (i.e. the src pointer cannot be anywhere in the range [dst-(length-1) dst+(length-1)]).</p> -<p> -<code>restrict</code> also has the virtue of making this contract apparent to your callers as it's part of the API. People should know that they can't call <code>memcpy()</code> with overlapping buffers and use <code>memmove()</code> instead. If the information is instead encoded in a cryptic line in the implementation then it isn't obvious to a developer who intends to use the function.</p> -</blockquote> -<h2>Non-aliasing granularity</h2> -<p>I noted that my not-really-serious proposal did not have the same granularity as the original with both good and bad consequences. An advantage of my proposal is that it is possible to specify <strong>only</strong> that <code>p</code> does not alias with <code>q</code> and that <code>r</code> does not alias with <code>t</code>. As defined in C99 <code>restrict</code> is more concise but this also means that there are some properties you might want to specify and that you cannot.</p> -<h2>restrict as an element of specification</h2> -<p>But I failed to realize that <code>restrict</code> being a type qualifier (for the casual C/C++ programmer: like <code>const</code>) is part of the function prototype. I was only thinking of the opportunity for better code generation inside <code>f()</code> but it would theoretically be possible to have compilers that warn about passing aliasing pointers to <code>f()</code>.</p> -<p>That's the theory anyway. In practice the situation is even worse than for <code>const</code>. For <code>const</code> you get type-system level warnings about casts discarding the qualifier. The warnings are sometimes useful and sometimes annoying. For <code>restrict</code> I do not know of any tool that makes any check of proper use at the call site.</p> -<h2>An alternative</h2> -<p>One tool that comes close to checking for proper use of functions with <code>const</code> and <code>restrict</code>-like specifications is developed nearby (have you heard of <a href="http://frama-c.com/">it</a>?). One drawback is that it is work in progress. And it uses its own syntax for function specifications.</p> -<p>Here is the specification for <code>memcpy()</code> in that system:</p> -<pre>/*@ requires \valid(((char*)dest)+(0..n-1)) - @ && \valid(((char*)src)+(0..n-1)); - @ requires \separated(((char *)dest)+(0..n-1) ((char *)src)+(0..n-1)); - @ assigns ((char*)dest)[0..n-1] \from ((char*)src)[0..n-1]; - @ ensures memcmp((char*)dest (char*)src n) == 0 && \esult == dest; - @*/ -extern void *memcpy(void *restrict dest - const void *restrict src size_t n); -</pre> -<p>Yes it is longer than just sprinkling the prototype with <code>const</code> and <code>restrict</code> and I did not even include the definition of the logic predicate <code>memcmp</code>. But on the other hand what you have here is a complete specification of <code>memcpy()</code>. You can ask your worst enemy to write a function to this specification and ey proves that eir implementation satisfies the specification you can rest assured that for all valid inputs the function terminates and computes the right result. The worst your enemy could do would be to provide you with a function that is arbitrarily slower than necessary.</p> -<blockquote><p>Side note: solutions to the problem of your worst enemy providing you with a function that is too slow are being researched but even researchers working on that would agree that this field has not reached the maturity of the solutions to the problem of your worst enemy providing you with a function that functionally does the wrong thing.</p> -<p> -I can provide a neat trick for <a href="/derived/analysis/skein/2011/12/31/Do-not-use-AES-in-a-context-where-timing-attacks-are-possible">verifying that a function executes in constant time</a> but this is only a <strong>very</strong> partial solution to the problem.</p> -</blockquote> -<p>Enough about this hypothetical worst enemy. The <code>const</code> part of <code>memcpy()</code>'s specification and more is contained in the clause:</p> -<pre>assigns ((char*)dest)[0..n-1] \from ((char*)src)[0..n-1]; -</pre> -<p>The <code>restrict</code> part is contained in:</p> -<pre>requires \separated(((char *)dest)+(0..n-1) ((char *)src)+(0..n-1)); -</pre> -<p>I might be biased but I think it is just as clear and separate concerns are better separated. The <code>\separated</code> predicate for instance is also useful for expressing exactly the conditions under which the statement <code>(*p=*p) & (*q=*q);</code> is defined.</p> <p>The <a href="http://www.first.fraunhofer.de/fileadmin/FIRST/ACSL-by-Example.pdf">ACSL by example</a> library contains more examples of function contracts.</p> {% endraw %} diff --git a/_posts/2012-07-27-Oxygen-is-stricter-about-types-and-why-you-should-get-used-to-it.html b/_posts/2012-07-27-Oxygen-is-stricter-about-types-and-why-you-should-get-used-to-it.html index 984d7f68af6d8b608feeb62363ae806cee483a71..615d2f78572e4ca6ce2ed91236ab7f5966e69765 100644 --- a/_posts/2012-07-27-Oxygen-is-stricter-about-types-and-why-you-should-get-used-to-it.html +++ b/_posts/2012-07-27-Oxygen-is-stricter-about-types-and-why-you-should-get-used-to-it.html @@ -22,20 +22,5 @@ A good number of these testcases are rejected by the current Frama-C. This is wh <p>The above is wise: to be maximally useful the static analyzer should choke on as few idiosyncrasies as possible. The analyzed code can be assumed to compile with some compiler and to go through some tests (there must still be a few of these right)? Why warn when a function is called without a prototype if the compiler accepted it? Why reject when the function's implementation has a type that is incompatible with the type that was inferred at the call site? This is probably not the issue the user is looking for (if it was the user would have fixed it when <a href="http://en.wikipedia.org/wiki/Spivak_pronoun">eir</a> compiler warned for it).</p> <h2>Oxygen is strict and that's it</h2> <p>Well our answer is that we tried and we found that it was too much work to try to be sound and precise with these constraints as exemplified by Virgile's blog post. Show us a tool that accepts your weakly typed program and we will show you a tool that probably isn't sound and precise at the same time (we have kept the examples that led to the decision. These examples demonstrate real issues masked by lenient typing. If you think you have found a sound analyzer that is at the same time conveniently permissive on typing it will be our pleasure to provide the examples for you to try).</p> -<p>We hope that Frama-C will still be useful with these new restrictions on typing. Fortunately for us there are more real worlds than the expression “the Real World†in the cited article's title might lead you to think (and this quip should not be taken as a reproach towards the authors of “A Few Billion Lines of Code Later: Using Static Analysis to Find Bugs in the Real World†a very useful document with an appropriately chosen title considering its intended public).</p> - <p>I have just sent a list of changewishes (<a href="https://groups.google.com/a/sosy-lab.org/forum/?fromgroups#!topic/sv-comp/W7amK63tbmE">1</a> <a href="https://groups.google.com/a/sosy-lab.org/forum/?fromgroups#!topic/sv-comp/AGSzHaoRv5E">2</a>) to a static analysis competition mailing-list and that reminded me of a blog post I had to write on the strictness of the type-checker in upcoming Frama-C release Oxygen. This is the blog post.</p> -<h2>This post is not about uninitialized variables</h2> -<p>The static analysis competition in question evaluates each participating tool on many testcases. -A good number of these testcases are rejected by the current Frama-C. This is why I was writing to the mailing-list: Frama-C cannot participate in the competition if the testcases are not changed (Frama-C does not <strong>have</strong> to participate of course. It's just that it looks fun and we would probably like to be in it).</p> -<p>In fact many of the testcases were already problematic for Frama-C version 20111001 (Nitrogen) the version in the current Debian Ubuntu FreeBSD NetBSD and other Unix distributions. Indeed a lot of the testcases rely on uninitialized variables for entropy which <a href="http://kqueue.org/blog/2012/06/25/more-randomness-or-less/">this</a> post by Xi Wang and <a href="http://markshroyer.com/2012/06/c-both-true-and-false/">this</a> post by Mark Shroyer show is wrong. Instead of the problem that is supposed to be detected (or not) Nitrogen detects the uninitialized use. I covered this already; this blog post is not about uninitialized variables (keep reading!).</p> -<h2>This post is about C type-checking</h2> -<p>While trying to get a list of uninitialized-variable-using testcases I realized that something had changed since my last evaluation of the competition's benchmarks. Many of them were now rejected at type-checking!</p> -<p>The new problem is many testcases in the benchmarks call functions without having provided a prototype and some ultimately define the called function with a type incompatible with the type inferred at the call site. Frama-C used to be lenient about typing issues but after fixing one soundness bug too many that was caused by the leniency we have decided to throw in the towel. Virgile <a href="/linking/type-checking/2012/04/19/On-arrays-vs.-pointers">described</a> one of the typing issues for which Frama-C used to be too lenient. It was not the only one.</p> -<p>This is an unusual position to take. In the article <a href="http://cacm.acm.org/magazines/2010/2/69354-a-few-billion-lines-of-code-later/fulltext">A Few Billion Lines of Code Later: Using Static Analysis to Find Bugs in the Real World</a> the makers of a commercially successful bug-finding tool state:</p> -<blockquote><p>Our product's requirements roughly form a "least common denominator" set needed by any tool that uses non-trivial analysis to check large amounts of code across many organizations; the tool must find and parse the code [...]</p> -</blockquote> -<p>The above is wise: to be maximally useful the static analyzer should choke on as few idiosyncrasies as possible. The analyzed code can be assumed to compile with some compiler and to go through some tests (there must still be a few of these right)? Why warn when a function is called without a prototype if the compiler accepted it? Why reject when the function's implementation has a type that is incompatible with the type that was inferred at the call site? This is probably not the issue the user is looking for (if it was the user would have fixed it when <a href="http://en.wikipedia.org/wiki/Spivak_pronoun">eir</a> compiler warned for it).</p> -<h2>Oxygen is strict and that's it</h2> -<p>Well our answer is that we tried and we found that it was too much work to try to be sound and precise with these constraints as exemplified by Virgile's blog post. Show us a tool that accepts your weakly typed program and we will show you a tool that probably isn't sound and precise at the same time (we have kept the examples that led to the decision. These examples demonstrate real issues masked by lenient typing. If you think you have found a sound analyzer that is at the same time conveniently permissive on typing it will be our pleasure to provide the examples for you to try).</p> <p>We hope that Frama-C will still be useful with these new restrictions on typing. Fortunately for us there are more real worlds than the expression “the Real World†in the cited article's title might lead you to think (and this quip should not be taken as a reproach towards the authors of “A Few Billion Lines of Code Later: Using Static Analysis to Find Bugs in the Real World†a very useful document with an appropriately chosen title considering its intended public).</p> {% endraw %} diff --git a/_posts/2012-07-31-On-arrays-vs.-pointer-the-ACSL-way.html b/_posts/2012-07-31-On-arrays-vs.-pointer-the-ACSL-way.html index 05e6126192fa192a93dff0b26a7c9fbb1fe95e12..5ccd6cd05f50c6ae8f290417188f33369361b4db 100644 --- a/_posts/2012-07-31-On-arrays-vs.-pointer-the-ACSL-way.html +++ b/_posts/2012-07-31-On-arrays-vs.-pointer-the-ACSL-way.html @@ -41,39 +41,5 @@ void f() { <p>This assertion is true for the same reason as the first one.</p> <pre>/*@ assert \at(p L1)[\at(i L0)] == 4; */ </pre> -<p>This assertion is false because the evaluation is slightly different than in the second case: This time we evaluate the pointer <code>p</code> in <code>L1</code> the offset <code>i</code> in <code>L0</code> and we dereference the result in <strong>the current state</strong> where <code>*(p+4)</code> is <code>6</code>.</p> - <p>Some time ago, <a href="/linking/type-checking/2012/04/19/On-arrays-vs.-pointers">we saw</a> that in C arrays and pointers have some subtle differences. A facetious colleague just remarked that this is also the case in ACSL especially if you use the <code>\at(e L)</code> construction which basically says that <code>e</code> is supposed to be evaluated in the state when the program reached label <code>L</code> for the last time. For instance let us consider the following function:</p> -<pre>int t[10]; -void f() { - int* p = t; - int i = 4; - L0: - t[i++] = 4; - L1: - t[i--] = 5; - L2: - t[i++] = 6; - return; -} -</pre> -<p>Can you decide which of the following assertions hold just before <code>f</code> returns?</p> -<ol> -<li><code>assert \at(t[\at(i L0)] L1) == 4;</code></li> -<li><code>assert \at(t L1)[\at(i L0)] == 4;</code></li> -<li><code>assert \at(p[\at(i L0)] L1) == 4;</code></li> -<li><code>assert \at(p L1)[\at(i L0)] == 4;</code></li> -</ol> -<h2>Answers</h2> -<pre> /*@ assert \at(t[\at(i L0)] L1) == 4; */ -</pre> -<p>This assertion is true: namely <code>i</code> is equal to <code>4</code> in <code>L0</code> so that we're evaluating <code>t[4]</code> in <code>L1</code> which is indeed equal to <code>4</code>.</p> -<pre>/*@ assert \at(t L1)[\at(i L0)] == 4; */ -</pre> -<p>This assertion is true but the evaluation is not that simple: according to ACSL's arrays semantics we convert <code>t</code> into a logic array whose cells have the same value as the one of <code>t</code> <strong>in the state <code>L1</code></strong>. Then we access the cell number <code>4</code> the value of <code>i</code> at <code>L0</code> that happens to contain <code>4</code>.</p> -<pre>/*@ assert \at(p[\at(i L0)] L1) == 4; */ -</pre> -<p>This assertion is true for the same reason as the first one.</p> -<pre>/*@ assert \at(p L1)[\at(i L0)] == 4; */ -</pre> <p>This assertion is false because the evaluation is slightly different than in the second case: This time we evaluate the pointer <code>p</code> in <code>L1</code> the offset <code>i</code> in <code>L0</code> and we dereference the result in <strong>the current state</strong> where <code>*(p+4)</code> is <code>6</code>.</p> {% endraw %} diff --git a/_posts/2012-08-02-restrict-is-not-good-for-modular-reasoning.html b/_posts/2012-08-02-restrict-is-not-good-for-modular-reasoning.html index 387ba3f19d74824e526bbb62598e7fbd33b9b4b0..b487e7abe51f6ecc4c4e9042a241209d8a204e5f 100644 --- a/_posts/2012-08-02-restrict-is-not-good-for-modular-reasoning.html +++ b/_posts/2012-08-02-restrict-is-not-good-for-modular-reasoning.html @@ -54,52 +54,5 @@ both <code>p</code> and <code>q</code>.</p> <p>The call <code>f(50 d + 50 d)</code> is valid because although offsets of <code>d+50</code> can obviously alias with offsets of <code>d</code> they do not alias inside the function for what the function does. When calling <code>f(50 d + 1 d);</code> offsets of the two <code>restrict</code>-qualified pointers do alias and the call invokes undefined behavior.</p> <h2>No modular reasoning</h2> <p>And this sums up why <code>restrict</code> alone would not be good for modular reasoning about programs. It is part of the prototype and the prototype is a kind of limited contract but the exact meaning of <code>restrict</code> depends on the function's implementation. If the function computes <code>p + 49</code> then <code>p + 49</code> is part of the offsets of <code>p</code> that must not alias with the rest of the memory locations accessed by <code>f</code>. If <code>f</code> accesses the global variable <code>G</code> by name then <code>p</code> must not point to <code>G</code>. if <code>f</code> does not access <code>G</code> by name then <code>p</code> is allowed to point to <code>G</code>. It is only one particular implementation of <code>f</code> that gives meaning to <code>restrict</code>.</p> -<p>By contrast a proper contract is supposed to be self-contained. The ACSL precondition <code>\separated(p+(0..n-1) q+(0..n-1));</code> tells the programmer exactly how the arguments <code>p</code> and <code>q</code> are allowed to alias. An implementation for <code>f</code> needs not exist for the programmer to start using it with the confidence that ey is calling <code>f</code> properly.</p> - <h2>ACSL</h2> -<p>There were quite a few posts recently that were concerned with ACSL, and a few more are planned for the near future. ACSL is a specification language for C (comparable with JML for Java, for those who know about JML). Some people call it a BISL, for “Behavioral Interface Specification Languageâ€, but considering that this acronym's definition needs to be introduced everytime, on account of nobody in the world having ever seen it before, and that it has very little reuse potential, please forget that we mentioned it.</p> -<p>ACSL is Frama-C's annotation language, and it is partially implemented in Frama-C, but it is not intended to be just Frama-C's. According to <a href="http://lists.gforge.inria.fr/pipermail/frama-c-acsl-discuss/2010-February/000012.html">this message</a> Microsoft Research's <a href="http://research.microsoft.com/en-us/projects/vcc/">VCC</a> now uses an annotation language with ACSL-like syntax and semantics.</p> -<p>ACSL allows to write <strong>function contracts</strong> the stuff that modular reasoning about programs is made of. A function contract is supposed to tell you everything you need to know about the function so that you do not need to look at its code. The function might still be unimplemented even.</p> -<blockquote><p>ACSL also allows to write annotations that go inside the function and are specific to one particular implementation. These annotations are typically hints to allow the verification that the specific implementation satisfies the contract. They can be for instance loop invariants or assertions.</p> -</blockquote> -<p>It is good on several levels to be able to write and read properties about a C program in a formal language with unambiguous meaning. A compiler could parse and interpret ACSL to obtain information about the programmer's intentions and take advantage of the opportunity to generate <strong>faster code</strong>. Hey compiler makers I said <strong>FASTER CODE</strong>.</p> -<h2>The restrict type qualifier again</h2> -<p>Recently Stephen Canon <a href="/acsl/memcpy/restrict/2012/07/25/The-restrict-qualifier-as-an-element-of-specification">reminded</a> me that the good thing about <code>restrict</code> is that it is part of the function prototype and I showed the differences with ACSL's approach.</p> -<p>Why does ACSL introduce an new notion the <code>\separated</code> predicate where C99 already has <code>restrict</code>? One reason that I pointed out is that while <code>restrict</code> offers a very concise syntax for some specialized uses <code>\separated</code> is useful for other things that are not convenient to express with <code>restrict</code>.</p> -<p>Another reason is that a C prototype with <code>restrict</code> annotations still does not work very well as a contract. The <code>restrict</code> qualifier in the prototype <strong>implicitly refers to the function's code.</strong> This blog post expands on this.</p> -<h2>The meaning of restrict</h2> -<p>The <code>restrict</code> qualifier applied to a pointer more or less means that any offset of the pointer can only alias with an offset of the pointer. Please read C99's 6.7.3.1 section for the exact definition. I will simply quote the example from paragraph 8 there:</p> -<p><br /> ----</p> -<p>The function parameter declarations in the following example</p> -<pre>void f(int n int * restrict p int * restrict q) -{ - while (n-- > 0) - *p++ = *q++; -} -</pre> -<p>assert that during each execution of the function if an object is accessed through one of the pointer -parameters then it is not also accessed through the other.</p> -<p>--- -</p> -<p>Note that the notion of any offset of a pointer <code>p</code> being separated from everything else that is not also an offset of <code>p</code> is a relative notion. In the absolute <code>p</code> has to point <em>somewhere</em>. If for instance <code>p</code> points inside a global array <code>t</code> then <code>p</code> aliases with <code>t</code>. The <code>restrict</code> qualifier only means that locally inside the function <code>f</code> <strong>for what <code>f</code> does</strong> an offset of <code>p</code> does not alias with any lvalue not based on <code>p</code>. As the next paragraph in the standard puts it:</p> -<p><br /> ----</p> -<p>The benefit of the <code>restrict</code> qualiï¬ers is that they enable a translator to make an effective dependence -analysis of function <code>f</code> without examining any of the calls of f in the program. The cost is that the -programmer has to examine all of those calls to ensure that none give undefined behavior. For example the -second call of <code>f</code> in <code>g</code> has undefined behavior because each of <code>d[1]</code> through <code>d[49]</code> is accessed through -both <code>p</code> and <code>q</code>.</p> -<pre>void g(void) -{ - extern int d[100]; - f(50 d + 50 d); //valid - f(50 d + 1 d); //undefined behavior -} -</pre> -<p>--- -</p> -<p>The call <code>f(50 d + 50 d)</code> is valid because although offsets of <code>d+50</code> can obviously alias with offsets of <code>d</code> they do not alias inside the function for what the function does. When calling <code>f(50 d + 1 d);</code> offsets of the two <code>restrict</code>-qualified pointers do alias and the call invokes undefined behavior.</p> -<h2>No modular reasoning</h2> -<p>And this sums up why <code>restrict</code> alone would not be good for modular reasoning about programs. It is part of the prototype and the prototype is a kind of limited contract but the exact meaning of <code>restrict</code> depends on the function's implementation. If the function computes <code>p + 49</code> then <code>p + 49</code> is part of the offsets of <code>p</code> that must not alias with the rest of the memory locations accessed by <code>f</code>. If <code>f</code> accesses the global variable <code>G</code> by name then <code>p</code> must not point to <code>G</code>. if <code>f</code> does not access <code>G</code> by name then <code>p</code> is allowed to point to <code>G</code>. It is only one particular implementation of <code>f</code> that gives meaning to <code>restrict</code>.</p> <p>By contrast a proper contract is supposed to be self-contained. The ACSL precondition <code>\separated(p+(0..n-1) q+(0..n-1));</code> tells the programmer exactly how the arguments <code>p</code> and <code>q</code> are allowed to alias. An implementation for <code>f</code> needs not exist for the programmer to start using it with the confidence that ey is calling <code>f</code> properly.</p> {% endraw %} diff --git a/_posts/2012-08-03-assume-and-assert.html b/_posts/2012-08-03-assume-and-assert.html index c7fdbb49f1a026a8ad913065d7dc6b551cd766a9..e79a2c65615efb9eb77096ad875720f330515f07 100644 --- a/_posts/2012-08-03-assume-and-assert.html +++ b/_posts/2012-08-03-assume-and-assert.html @@ -43,41 +43,5 @@ conveys both meanings. This may mean that a bit of redundant work is made but t <p>The devil is in the details of course and the details are in the article “Combining Analyses for C Program Verification†(FMICS2012) by my colleagues Loïc Correnson and Julien Signoles.</p> <blockquote><p>Trying to prove a goal can still be expensive and unnecessary. There will eventually be a way to mark a property as “assumed†in the Frama-C kernel for efficiency reasons. We are still thinking about the best way to do that.</p> </blockquote> -<p>Thanks to Julien Signoles Florent Kirchner Virgile Prevosto Sébastien Bardin and MichaÅ‚ Moskal for their remarks on earlier iterations of this blog post.</p> - <p>The <a href="/index.php?post/2012/08/02/restrict-not-modular">previous post</a> links to a <a href="http://lists.gforge.inria.fr/pipermail/frama-c-acsl-discuss/2010-February/000012.html">message</a> from MichaÅ‚ Moskal highlighting ACSL constructs that the VCC developers at Microsoft Research had either regretted the absence of or found superfluous while re-designing their own annotation language for VCC. -In that e-mail the third item in the “missing†list was:</p> -<blockquote><p>ACSL is surprisingly missing /*@ assume ... */ we've found it tremendously useful when debugging specifications.</p> -</blockquote> -<p>The feedback VCC developers sent us caused us to review our design choices and nudge ACSL a bit. Not having an <code>assume</code> annotation however was a conscious decision that remained. I am going to give an explanation that makes it look as if the exclusion is part of a larger well though-out plan. I did not think of this explanation at the time and it only came to me recently while talking about something else.</p> -<blockquote><p>I am not sure what this says about the plan. At some level the plan was there all along but for some reason we failed to explain it well perhaps especially in these circumstances when it would have been useful.</p> -</blockquote> -<h2>The assume annotation in VCC</h2> -<p>Design-by-contract is also sometimes called “assume-guarantee reasoning†(if you know the precise difference between these two please leave a comment. The only reason I see for separate denominations is that “Design by Contract†seems to be a registered trademark of Eiffel Software in the United States).</p> -<p>This is not the “assume†we are looking for. In ACSL and now in VCC the expectations of a function are introduced with the <code>requires</code> keyword. The keyword <code>assume</code> could have been used for that but this is not the choice that was made and MichaÅ‚'s e-mail is definitely not saying that ACSL is missing a keyword to introduce the precondition of a function.</p> -<p>Instead in VCC <code>assume</code> is the dual of <code>assert</code>. The <code>assert</code> annotation is attached to a specific point in a program and introduces a property that is supposed to hold (that the verifier should endeavor to verify) there:</p> -<pre> stuff; -/*@ assert property ; */ -// the verifier tries to prove that "stuff" makes "property" hold. -</pre> -<p>The <code>assume</code> keyword tells the verifier to take it as granted that a property holds somewhere and to use that for reasoning about the rest of the program:</p> -<pre>/*@ assume property ; */ -// "property" is useful to understand what "stuff" does. - stuff; -</pre> -<blockquote><p>Beware that ACSL since it does not use <code>assume</code> this way reserves the keyword <code>assumes</code> for something else entirely. When the rest of this post says that ACSL does not have <code>assume</code> it means that ACSL does not have a VCC-like <code>assume</code>.</p> -</blockquote> -<h2>Keyword minimalism</h2> -<p>It is a worthy goal to minimize the number of keywords forced on you by a BISL—Behavioral Interface Specification Language (the acronym is <a href="/index.php?post/2012/08/02/restrict-not-modular">catching on</a> already). One could argue that both the functionality of <code>assume</code> and <code>assert</code> above can be captured with a single keyword. The verifier when encountering that keyword should first try to establish the property as a consequence of the code above. Then regardless of whether it was able to establish it it should incorporate it in its hypotheses for the study of the code below it.</p> -<p>This is exactly how Frama-C approaches the issue. Plug-ins that understand ACSL at all both try to prove such properties and then use them as assumptions. The properties are introduced with the <code>assert</code> keyword which in ACSL -conveys both meanings. This may mean that a bit of redundant work is made but the resulting annotation language is so beautiful like a smartphone with <a href="http://www.youtube.com/watch?v=9BnLbv6QYcA">only</a> two hardware buttons that the sacrifice is worth it.</p> -<p>Well this explanation is not actually quite right. Please read on.</p> -<h2>Plug-in collaboration and property status management</h2> -<p>There is a deeper explanation than just “each plug-in can do the work both ways and that will save a keywordâ€. This other explanation is specific to what Frama-C is. Or rather what Frama-C intends to be for it is a long-term effort.</p> -<p>Frama-C is—or intends to be—a collaborative verification framework. Frama-C makes it convenient to seamlessly subject one same annotated program to different and complementary analysis techniques. In particular it was always the intention that whichever property was assumed by a plug-in could be proved by another. For the Frama-C platform to be usable this way it is necessary but not sufficient to have a single annotation language with a formal semantics that all plug-ins agree on to express properties like <code>\valid(p)</code>.</p> -<p>It is also necessary to use a single keyword for assumptions and goals because without that the user would need to go to the source code and change <code>assume</code> to <code>assert</code> or vice-versa when switching from a plug-in to another. In Frama-C <strong>a plug-in's assumption is another plug-in's goal</strong>.</p> -<p>The Frama-C kernel tracks each program property and its verification status. A property that was only ever assumed never proved is an assumption of the whole verification. A property that was assumed by a plug-in and proved by another is just like an intermediate lemma in a mathematical proof.</p> -<p>The devil is in the details of course and the details are in the article “Combining Analyses for C Program Verification†(FMICS2012) by my colleagues Loïc Correnson and Julien Signoles.</p> -<blockquote><p>Trying to prove a goal can still be expensive and unnecessary. There will eventually be a way to mark a property as “assumed†in the Frama-C kernel for efficiency reasons. We are still thinking about the best way to do that.</p> -</blockquote> <p>Thanks to Julien Signoles Florent Kirchner Virgile Prevosto Sébastien Bardin and MichaÅ‚ Moskal for their remarks on earlier iterations of this blog post.</p> {% endraw %} diff --git a/_posts/2012-08-06-Understand-LTL-Join-us.html b/_posts/2012-08-06-Understand-LTL-Join-us.html index 8cfc50e261e388f4466ae2ba4f67ed4ee5762fe8..e53e3d092680c8838a5ebc120cc2faa4589efb61 100644 --- a/_posts/2012-08-06-Understand-LTL-Join-us.html +++ b/_posts/2012-08-06-Understand-LTL-Join-us.html @@ -15,13 +15,5 @@ in the challenge to something that can be verified with the value analysis. We expect that part to be expensive so if you know how to do it we should get together and start on this as soon as possible.</p> <p>(*) I am not saying that a deep understanding of temporal properties would have helped you much in 2011 but it cannot hurt to be able to think clearly about these things</p> -<p>(**) No really 95%. We're almost there.</p> - <p>Here is yet another <a href="http://leo.cs.tu-dortmund.de:8100/isola2012/download.html">software verification competition</a>. If you are a specialist of the verification of temporal properties and you have been regretting not to <a href="/index.php?tag/icpc2011">snatch</a> that easy Xbox 360 (with Kinect!) in 2011* this is your chance to make up for it!</p> -<p>We have the reachability part of the problems nearly done** and we are -looking for someone who can reduce (at least some of) the temporal properties -in the challenge to something that can be verified with the value analysis. -We expect that part to be expensive so if you know how to do it we should -get together and start on this as soon as possible.</p> -<p>(*) I am not saying that a deep understanding of temporal properties would have helped you much in 2011 but it cannot hurt to be able to think clearly about these things</p> <p>(**) No really 95%. We're almost there.</p> {% endraw %} diff --git a/_posts/2012-08-20-Participating-in-the-RERS-2012-competition-liveness-questions.html b/_posts/2012-08-20-Participating-in-the-RERS-2012-competition-liveness-questions.html index 54adf09970a167b1168e71ef80514d5837157979..b78d38c65a9721fe066604dc616a42a494bb3904 100644 --- a/_posts/2012-08-20-Participating-in-the-RERS-2012-competition-liveness-questions.html +++ b/_posts/2012-08-20-Participating-in-the-RERS-2012-competition-liveness-questions.html @@ -70,68 +70,5 @@ With the toolset provided by Frama-C I only see the scheme below. We reduce the <li>Instrument the program as previously making execution terminate when W is emitted and also maintaining a transition counter (incremented at each iteration of the loop).</li> <li>Using sound and complete propagation on the instrumented program either reach a fixpoint (with a finite bound computed for the counter) or find an execution with N+1 transitions that does not emit <code>W</code>. The former case means that the program eventually emits <code>W</code>. The latter that in the transition graph there is a reachable cycle along which <code>W</code> is not emitted and therefore an infinite execution that does not output <code>W</code>.</li> </ol> -<p>This technique likely gets pretty heavy in practice. Adding a counter that may go up to N+1 to a system that already has N states can probably cause the new system to have of the order of N² states. This segues into at least one perhaps two more blog posts to answer the questions “what is the value analysis actually doing when it is applied on these questions?†“how much work would it be to do the same thing closer to the metal executing the C function as compiled instead of laboriously interpreting it?†and “why don't we make a C model checker while we are at it?â€</p> - <p>This third installment discusses the diagnosis of liveness properties of particular C programs, using Frama-C's value analysis, for the RERS 2012 competition.</p> -<p>[Note added in September 2012: the diagnostic found for the example in this post disagrees with the diagnostic found later and sent to the competition organizers. I am unable to reproduce the result obtained here. Perhaps it was obtain with a version of Frama-C that had a bug.]</p> -<h2>Liveness properties 101</h2> -<p>Here is another extract of two properties found in the <a href="http://leo.cs.tu-dortmund.de:8100/isola2012/examples/small-easy/properties.txt">property list</a> attached to Problem 1 in the competition:</p> -<pre>(G ! oW) -output W does never occur ----------------------------------------- -(F oW) -output W occurs eventually -</pre> -<p>To tell you how unaccustomed to temporal properties I am I first read the second formula as a negation of the first one. There are redundancies in the lists of formulas to evaluate and I thought this was one more of them. It is of course not the case: <code>(F oW)</code> is not the negation of <code>(G ! oW)</code>.</p> -<p><code>(G ! oW)</code> says that there is no execution path that leads to <code>W</code> being output; the negation of that is that there is at least one such execution path. -By contrast <code>(F oW)</code> expresses that all execution paths have a <code>W</code> being output at some point a much stronger property.</p> -<p>Indeed <code>(F oW)</code> expressing that a state in which <code>W</code> is output is eventually reached is a typical liveness property. Checking this kind of property is at odds with traditional abstract interpretation practices where the analysis is considered done when a fixpoint has been reached: the fixpoint does not tell whether all executions eventually leave the loop. It only tells what is guaranteed for those executions that leave the loop.</p> -<h2>Semi-solution: a simple program transformation</h2> -<p>Please bear with me and consider the simple modification of Problem1.c below applied on top of the <a href="/index.php?post/2012/08/20/Participating-in-the-RERS-2012-competition%3A-reachability-questions">previous</a> instrumentation:</p> -<pre>--- Problem1.c 2012-08-08 10:15:00.000000000 +0200 -+++ Problem1_terminate_at_W.c 2012-08-21 17:00:38.000000000 +0200 -@@ -1 9 +1 8 @@ - void assert(int x) - { - if (!x) - { -- Frama_C_show_each_assert_reached(); - /*@ assert \false; */ - } - } -@@ -594 6 +593 8 @@ - // operate eca engine - output = calculate_output(input); -+ // continue only if output not W yet -+ /*@ assert output != w ; */ - } - } -</pre> -<p>We remove the user message in our <code>assert()</code> function because we want to temporarily forget about assertions. Besides by instrumenting the main loop we make the program stop when the output is <code>W</code>.</p> -<p>You should be able to convince yourself that the modified program terminates if and only if the original program does not admit any infinite execution that never outputs <code>W</code> (for any infinite sequence of values assigned to variable <code>input</code>).</p> -<p>Earlier posts (<a href="/index.php?post/2012/06/07/Verifying-the-termination-of-programs-with-value-analysis-option-obviously-terminates">1</a> <a href="/facetious-colleagues/obviously-terminates/value/2012/06/08/To-finish-on-termination">2</a>) in this blog pointed out how Frama-C's value analysis could be made to forget that it was an abstract interpreter and verify the termination of programs.</p> -<h2>Application</h2> -<p>Since everything is ready for this particular property of Problem1.c let us run the verification. -The command to prove that the program terminates is as follows:</p> -<pre>$ frama-c -val -obviously-terminates -no-val-show-progress Problem1_terminate_at_W.c -... -[value] Semantic level unrolling superposing up to 400 states -[value] done for function main -[value] ====== VALUES COMPUTED ====== -</pre> -<p>We should have used a timeout because the analysis fails to terminate when the analyzer is unable to prove that the target program terminate. Nevertheless we were lucky the target program terminates the analyzer is able to verify that the program terminates and we can conclude that there are no infinite executions of the original Program1.c that fail to emit <code>W</code>.</p> -<h2>Assertions and consequences on liveness properties</h2> -<p>The previous section only tells us that there is no infinite execution that does not emit <code>W</code>. Depending on the organizers' intentions this may or may not answer the question of whether <code>(F oW)</code> holds.</p> -<p>It still depends whether you count an execution that reaches one of the <code>assert(0);</code> in the program as well an execution. If it count as an execution to which the formula should apply then an execution that does not emit <code>W</code> and terminates on such an <code>assert(0);</code> certainly does not eventually output <code>W</code>.</p> -<p>There is an argument to say that it shouldn't count however: although it is impossible to understand what these programs are supposed to do assertions usually characterize illegal behaviors. Perhaps the LTL formulas are to be evaluated only on the legal infinite behaviors of the system?</p> -<p>In the latter case we are done: <code>(F oW)</code> holds because <code>W</code> is eventually emitted in all legal executions. In the former case the additional question is whether an original <code>assert(0);</code> is reached before <code>W</code> is output which is a simple reachability question on the instrumented <code>Problem1_terminate_at_W.c</code>. The answer is then that <code>(F oW)</code> does not hold because there are plenty of <code>assert(0);</code> calls that are reached without <code>W</code> having been emitted.</p> -<p>We e-mailed the organizers and they said it was the first simpler case. Only infinite executions need be taken into account for evaluating LTL formulas and interrupted executions can be ignored. Our answer for the formula <code>(F oW)</code> of Problem 1 in the competition is therefore that the property holds.</p> -<h2>Proving that something does not eventually happen</h2> -<p>In the first part of the post we set out to prove that the liveness property <code>(F oW)</code> was true. Verifying that the property is false requires a different approach. -With the toolset provided by Frama-C I only see the scheme below. We reduce the problem to the seemingly harder but actually easier problem of computing the maximum number of iterations before W is emitted.</p> -<ol> -<li>Obtain the number N of reachable states for the system by running the value analysis on the original program.</li> -<li>Instrument the program as previously making execution terminate when W is emitted and also maintaining a transition counter (incremented at each iteration of the loop).</li> -<li>Using sound and complete propagation on the instrumented program either reach a fixpoint (with a finite bound computed for the counter) or find an execution with N+1 transitions that does not emit <code>W</code>. The former case means that the program eventually emits <code>W</code>. The latter that in the transition graph there is a reachable cycle along which <code>W</code> is not emitted and therefore an infinite execution that does not output <code>W</code>.</li> -</ol> <p>This technique likely gets pretty heavy in practice. Adding a counter that may go up to N+1 to a system that already has N states can probably cause the new system to have of the order of N² states. This segues into at least one perhaps two more blog posts to answer the questions “what is the value analysis actually doing when it is applied on these questions?†“how much work would it be to do the same thing closer to the metal executing the C function as compiled instead of laboriously interpreting it?†and “why don't we make a C model checker while we are at it?â€</p> {% endraw %} diff --git a/_posts/2012-08-20-Participating-in-the-RERS-2012-competition-reachability-questions.html b/_posts/2012-08-20-Participating-in-the-RERS-2012-competition-reachability-questions.html index bebde77315797add1d3380f049105aa1086e6bf4..8f43423dc1412e8954125a6f0b96d4ad54174909 100644 --- a/_posts/2012-08-20-Participating-in-the-RERS-2012-competition-reachability-questions.html +++ b/_posts/2012-08-20-Participating-in-the-RERS-2012-competition-reachability-questions.html @@ -73,70 +73,5 @@ output U does never occur before output Z <p><q>The weighting scheme gives you a way to express your personal confidence in your results. e.g. if you have found a feasable path to some error this is safe and you should weight it 10. Lifeness properties or stating that certain errors are non-feasible is of course more risky.</q></p> <p>Here we are using a sound analyzer to establish that certain errors are non-feasible so in our case there is little risk involved in attributing the maximum weight to these answers. There is in fact more risk when answering that some execution path leads to some error since the value analysis even when it happens to be complete is not designed to produce a trace that we could double-check. But we are confident for these errors too because of all the Csmith testing that we applied earlier in the year.</p> <blockquote><p>And by the way this blog post does not count as documentation: it is still undocumented in what circumstances Frama-C's value analysis is complete. The documentation is long enough trying to describe how to use the value analysis soundly; and this is despite soundness being its defining property. There is no point in enumerating the very specific circumstances in which it is complete. The conditions are unlikely to occur simultaneously in real life and if you think that this competition contradicts this statement have another look at the shape of the competition's target programs.</p> -</blockquote>" <p>This post is a follow-up to <a href="/benchmarks/link/rers2012/2012/08/06/Understand-LTL-Join-us%21">this one</a>. It begins to describe our participation using Frama-C's value analysis in the RERS 2012 competition.</p> -<h2>In theory</h2> -<p>The <a href="http://leo.cs.tu-dortmund.de:8100/isola2012/download.html">competition</a> features nine target programs of increasing difficulty. -Some of the questions to be answered about the target programs are reachability questions. This is the case for all calls to <code>assert(0);</code> in the program: for each call the question is exactly whether it can be reached in an execution.</p> -<p>In addition some LTL formulas are offered about each target program. The goal here is to individually diagnose each LTL formula as true or false when applied to the program. Some of the LTL formulas actually express reachability properties. Consider the following property from the list that applies to problem 1 (small-easy):</p> -<pre>(G ! oU) -output U does never occur -</pre> -<p>This formula holds if a program state in which <code>U</code> is output is never reached. It suffices to instrument the program a little bit to recognize when this happens and the problem is reduced to a reachability problem only in reverse: the property holds if the states are unreachable and does not hold if one of the states can be reached.</p> -<h2>In practice</h2> -<p>The good news is that the value analysis is at its core designed to answer reachability questions. More specifically it is designed to answer unreachability questions: it computes supersets of the values of variables that can reach each point in the target program and it warns if dangerous instructions can be reached. It can guarantee that an <code>assert(0);</code> call is not reached.</p> -<p>Preparing the program for analysis as described in the <a href="http://frama-c.com/download/frama-c-value-analysis.pdf">manual</a> and many times on this blog may result for instance in the following changes: removing the headers defining a function <code>assert()</code> removing the <code>printf()</code> calls so that one does not need to provide the function.</p> -<pre>--- Problem1.c~ 2012-07-31 01:32:42.000000000 +0200 -+++ Problem1.c 2012-08-08 10:15:00.000000000 +0200 -@@ -1 5 +1 12 @@ --#include <stdio.h> --#include <assert.h> -+void assert(int x) -+{ -+ if (!x) -+ { -+ Frama_C_show_each_assert_reached(); -+ /*@ assert \false; */ -+ } -+} -+ - // inputs - int a= 1; -@@ -582 14 +589 11 @@ - { - // read input - int input; -- scanf("%d" &input); -+ input = any_int(); -+/*@ assert input == 1 || input == 2 || input == 3 || input == 4 || input == 5 || input == 6 ; */ - // operate eca engine - output = calculate_output(input); -- if(output == -2) -- fprintf(stderr "Invalid input: %d" input); -- else if(output != -1) -- printf("%d" output); - } - } -</pre> -<p>We assume that an execution that reaches an <code>assert(0);</code> is interrupted and that <code>input</code> at each cycle is a number between 1 and 6. This corresponds to our understanding of the description of the programs in the competition.</p> -<p>As previously hinted the value analysis is designed to answer reachability questions negatively only. It is intended to guarantee that dangerous operations are unreachable (i.e. the program is safe). In doing so it computes whether any statement is reachable even non-dangerous ones and with what variable values each of these statement is reached.</p> -<p>In static analysis this is called “soundnessâ€. The value analysis does not in general guarantee that any statement is reachable. -However for the particular program above instrumented in this particular way with the right command-line options the value analysis is “complete†in addition to being sound: in addition to only diagnosing as unreachable statements that are actually unreachable it only diagnoses as reachable statements that are actually reachable.</p> -<p>Being complete in addition to being sound means that the value analysis is able to answer the question <code>(G ! oU)</code> negatively as well as positively. If the value analysis was only sound it could only guarantee that a particular <code>assert(0);</code> call is not reached or that <code>U</code> is never output. Being complete means that it can in addition guarantee that an <code>assert(0);</code> call is reached in some execution or that <code>U</code> is output in some execution.</p> -<h2>More formulas to evaluate</h2> -<p>There are more complex LTL formulas in <a href="http://leo.cs.tu-dortmund.de:8100/isola2012/examples/small-easy/properties.txt">the list</a> that express reachability properties sometimes modulo trivial instrumentation. Below are two of them:</p> -<pre>(! oZ WU (oZ WU (! oZ WU (oZ WU (G ! oZ))))) -output Z occurs at most twice ----------------------------------------- -(! oU WU oZ) -output U does never occur before output Z -</pre> -<p>The second formula expresses that a state where <code>U</code> is emitted without <code>Z</code> ever having been emitted is not reached. To verify this property one simply needs to add to the target program a boolean variable that remembers whether <code>Z</code> has been emitted before.</p> -<p>The first is a complex LTL formula with a simple English interpretation. The program can be instrumented with a counter for the number of times <code>Z</code> is output and the property to check is whether a state where <code>Z</code> has been emitted three times is reached.</p> -<h2>Do not make completeness claims about Frama-C's value analysis at home</h2> -<p>You may have noticed that the value analysis' manual rarely offers precision guarantees and in particular never describes the conditions in which it is complete.</p> -<p>Therefore an independent participant in the competition who wasn't a value analysis developer would not be able to assert that the value analysis is behaving completely. Such a participant could only hope to answer reachability questions negatively finding that <code>(G ! oU)</code> is true (when it is actually true) or finding that a particular assertion is never reached (when it is actually unreachable). This is the direction that matters when trying to establish that error states are unreachable to verify the safety of software. The competition organizers implicitly acknowledge that this kind of property can be difficult to establish otherwise when they say about weighting answers:</p> -<p><q>The weighting scheme gives you a way to express your personal confidence in your results. e.g. if you have found a feasable path to some error this is safe and you should weight it 10. Lifeness properties or stating that certain errors are non-feasible is of course more risky.</q></p> -<p>Here we are using a sound analyzer to establish that certain errors are non-feasible so in our case there is little risk involved in attributing the maximum weight to these answers. There is in fact more risk when answering that some execution path leads to some error since the value analysis even when it happens to be complete is not designed to produce a trace that we could double-check. But we are confident for these errors too because of all the Csmith testing that we applied earlier in the year.</p> -<blockquote><p>And by the way this blog post does not count as documentation: it is still undocumented in what circumstances Frama-C's value analysis is complete. The documentation is long enough trying to describe how to use the value analysis soundly; and this is despite soundness being its defining property. There is no point in enumerating the very specific circumstances in which it is complete. The conditions are unlikely to occur simultaneously in real life and if you think that this competition contradicts this statement have another look at the shape of the competition's target programs.</p> -</blockquote>" +</blockquote>" {% endraw %} diff --git a/_posts/2012-08-22-Interlude.html b/_posts/2012-08-22-Interlude.html index 4664a064e947394768a79dd71b7cad992cfa2e7b..3e0c9eecc6c15d84b9f42c3e100c1f71744903b5 100644 --- a/_posts/2012-08-22-Interlude.html +++ b/_posts/2012-08-22-Interlude.html @@ -9,5 +9,4 @@ summary: --- {% raw %} <p>The RERS competition series of posts is about to get more technical (yes, really). Here is a refreshing diversion, in the form of a <a href="http://www.seebs.net/log/articles/701/discrimination-a-quick-math-puzzle">link to a mathematical blog post</a>.</p> - <p>The RERS competition series of posts is about to get more technical (yes, really). Here is a refreshing diversion, in the form of a <a href="http://www.seebs.net/log/articles/701/discrimination-a-quick-math-puzzle">link to a mathematical blog post</a>.</p> {% endraw %} diff --git a/_posts/2012-08-22-Proving-F-oW-true-or-false-alternative-method.html b/_posts/2012-08-22-Proving-F-oW-true-or-false-alternative-method.html index 995baed59f0a8787442ffe2e1aa68391e89b42ed..1167aab6972a444be9fe4ccf236c97c590a1c35a 100644 --- a/_posts/2012-08-22-Proving-F-oW-true-or-false-alternative-method.html +++ b/_posts/2012-08-22-Proving-F-oW-true-or-false-alternative-method.html @@ -185,183 +185,5 @@ there is a cycle in the transition graph of the program instrumented to stop at [value] Called Frama_C_show_each_state({1} {1} {1} {1} {1} {1} {1} {1} {0} {0} {0} {0} {0} {0} {0} {0} {0} {1} {1} {1} {1} {1} {1} {1} {1} {1} {1} {1} {1} {1}) [value] Called Frama_C_show_each_state({1} {1} {1} {1} {1} {1} {1} {1} {0} {0} {0} {0} {0} {0} {0} {0} {0} {1} {1} {1} {1} {1} {1} {1} {1} {1} {2} {0} {1} {1}) </pre> -<p>This post benefited from discussions with Sébastien Bardin Sven Mattsen Benjamin Monate and Boris Yakobowski.</p> - <p>In the context of the <a href="http://leo.cs.tu-dortmund.de:8100/isola2012/problems.html">RERS 2012 competition</a> the <a href="/index.php?post/2012/08/20/Participating-in-the-RERS-2012-competition%3A-liveness-questions">previous post</a> points out that value analysis option <code>-obviously-terminates</code> can be used to prove the termination of an instrumented program created such that its termination implies that the property <code>(F oW)</code> is true of the original competition program. Unfortunately this only works in one direction. If the property <code>(F oW)</code> does not hold of the original competition program this approach cannot be used to prove that. The previous post continued to offer a method involving a counter that works in both directions.</p> -<h2>Preliminary remark regarding the counter method</h2> -<p>The second method proposed in the previous post requires a state count to use as bound. I suggested to use the number of reachable states of the original (uninstrumented) program obtained by running Frama-C's value analysis as a sound and complete abstract interpreter.</p> -<p>I would like to point out that instead of the state count of the original program it is possible to use the state count of the program instrumented to stop when <code>W</code> is emitted. This number is by definition lower. On the other hand the number of states of the uninstrumented program can be computed once and for all and then be used for all formulas of the form <code>(F oW)</code> that apply to that program in the competition. In fact we can obtain that number for free when we check the reachability of <code>assert(0);</code> statements for the competition. So there is a trade-off there.</p> -<h2>Applying the method of last post</h2> -<p>Let us now consider Problem3.c (small-hard). One of the properties to evaluate is <code>(F oY)</code>. The first method described in the previous post does not conclude rapidly so there is reason to suspect that perhaps the property is false for this program. But if this is going to be our answer in the competition we had better establish that the property is definitely false that is there exists an infinite execution along which <code>Y</code> is not emitted.</p> -<h3>Instrumenting with a counter</h3> -<p>To establish that the property is false using a counter we instrument Problem3.c thus:</p> -<pre>--- Problem3.c 2012-08-08 10:49:53.000000000 +0200 -+++ Problem3_terminate_at_Y_with_counter.c 2012-08-22 13:58:30.000000000 +0200 -@@ -1 9 +1 8 @@ - void assert(int x) - { - if (!x) - { -- Frama_C_show_each_assert_reached(); - /*@ assert \false; */ - } - } -@@ -1649 15 +1648 16 @@ - } - if((((((((!(a26==1)&&(a6==1))&&!(a27==1))&&(a12==1))&&(a3==0))&&(a11==1))&&(a5==1))&&(a18==1))){ - error_2: assert(0); - } -- return -2; -+ /*@ assert \false ; */ - } - int main() - { - // default output - int output = -1; -+ int counter = 0; - // main i/o-loop - while(1) - { -@@ -1668 6 +1668 10 @@ - // operate eca engine - output = calculate_output(input); -+ /*@ assert output != y ; */ -+ -+ counter++; -+ Frama_C_show_each_counter(counter); - } - } -</pre> -<h3>Obtaining a bound</h3> -<p>In order to obtain a bound we analyze the original program using the value analysis as a model-checker:</p> -<pre>$ frama-c -val -slevel 100000000 Problem3.c -... -[value] Semantic level unrolling superposing up to 200 states -... -</pre> -<p>This message means there are up to a number between 200 and 300 states attached to a single statement during the analysis of the program. That statement is probably the statement just after a new input has been picked non-deterministically between 1 and 6 and the number therefore six times higher than the number of states that interests us. The abstract interpreter also distinguishes states program that differ only for variable <code>output</code> again making the bound displayed in the “superposing up to†messages higher than the number we mean. But let us not try to compensate for that just to be on the safe side.</p> -<p>I kid I kid. Using the “superposing up to†message is not rigorous since this message was not designed for that (and the message is not documented at all I think). As a Frama-C developer with knowledge of value analysis internals I am tempted to use 300 as a safe bound but in order to obtain a rigorous number of states anyone can insert the following statement in the <code>while</code> loop of the program:</p> -<pre>Frama_C_show_each_state( a1 a4 a0 a15 a29 a10 a16 a22 a2 a17 a25 a7 a14 a19 a20 a8 a23 a21 a24 a13 a9 a28 a26 a6 a27 a12 a3 a11 a5 a18 ); -</pre> -<p>Once filtered sorted and de-duplicated the list of states is exactly 31 long. Once de-duplicated the messages printed by the call correspond exactly to unique states of the program. This method provides an exact number and it uses documented value analysis features only. -The list is provided at the end of the post for the doubters.</p> -<h3>Looking for an execution with more than 31 transitions</h3> -<p>Knowing that we are looking for an execution where counter goes higher than 31 we can now launch the analysis of the version instrumented with counter:</p> -<pre>$ frama-c -val -slevel 100000000 -no-val-show-progress Problem3_terminate_at_Y_with_counter.c -... -[value] Called Frama_C_show_each_counter({1}) -[value] Called Frama_C_show_each_counter({1}) -[value] Called Frama_C_show_each_counter({1}) -[value] Called Frama_C_show_each_counter({1}) -[value] Called Frama_C_show_each_counter({1}) -Problem3_terminate_at_Y_with_counter.c:5:[value] Assertion got status invalid (stopping propagation). -[value] Called Frama_C_show_each_counter({2}) -... -[value] Called Frama_C_show_each_counter({31}) -... -[value] Called Frama_C_show_each_counter({31}) -[value] Called Frama_C_show_each_counter({32}) -... -[value] Called Frama_C_show_each_counter({32}) -^C -</pre> -<p>This means that there is at least one infinite execution in the instrumented program which means that the original program can execute infinitely without emitting <code>Y</code>.</p> -<h2>A method not involving a transition counter</h2> -<p>An irritating feature of the previously described method is that it does not immediately detect infinite executions that are right under its nose. There could exist for a certain input a transition from the initial state to itself and the analyzer would still have to explore all other transitions breadth-first down to a depth of 31 before displaying the <code>Called Frama_C_show_each_counter({32})</code> message that confirms the existence of an infinite execution.</p> -<p>A method to look for this cycle of length one would be to instrument the program differently. This is what I describe now.</p> -<h3>Add variables to the program for the description of the predecessor state</h3> -<p>This means transforming the declarations</p> -<pre> int a1 = 1; - int a4 = 1; -... -</pre> -<p>into:</p> -<pre> int a1 = 1 p1 = -1; - int a4 = 1 p4 = -1; -... -</pre> -<p>This can be done with a regexp.</p> -<h3>Check whether a newly reached state coincides with its predecessor state</h3> -<p>At the end of a cycle we compare the new state with the predecessor state. -Again code doing this can be generated with a regexp:</p> -<pre> if - ((a1 == p1) && - (a4 == p4) && -... - (a18 == p18)) - Frama_C_show_each_cycle_found(1); -</pre> -<p>The above causes a message to be emitted by the analyzer as soon as a cycle is found.</p> -<h3>Update the predecessor state</h3> -<p>After checking whether the new state coincides with the predecessor state it is time to update the predecessor state. -Yada regexp yada:</p> -<pre> p1 = a1; - p4 = a4 ; -... - p18 = a18 ; -</pre> -<p>And presto: we detect all cycles. All cycles of length one that is.</p> -<h3>Maybe update the predecessor state</h3> -<p>Although it would work great on the example that motivated this new method detecting only cycles of length one is a little bit too specific. -Let us fix that.</p> -<p>At the end of a cycle instead of updating the predecessor state as above let us maybe update it as below:</p> -<pre> if (any_int()) - { - p1 = a1; - p4 = a4 ; -... - p18 = a18 ; - } -</pre> -<p>With the above non-deterministic update of the predecessor state for each vector <code>a1 a4 ...a18</code> of variables propagated by the value analysis the variables <code>p1 p4 ...p18</code> contain a nondeterministic superposition of all its predecessors. Think of it as programming a <a href="http://en.wikipedia.org/wiki/Quantum_computer">quantum computer</a> and if you think of it this way remember that the variables <code>p1 p4 ...p18</code> are <a href="http://en.wikipedia.org/wiki/Quantum_entanglement">entangled</a>: when observed they contain matching values from one specific predecessor. They are entangled because the conditional above either update variables <code>p1 p4 ...</code> all at once or leaves them all unchanged.</p> -<p>On the other hand different predecessors do not get mixed together because... well because the analyzer remains complete on this program even after it being instrumented thus for reasons I still do not want to document. Nevertheless the important part of the argument is that a sound and complete analyzer would find the <code>Frama_C_show_each_cycle_found(1);</code> statement above reachable if and only if in the program instrumented to stop at <code>Y</code> a state is identical to one of its predecessors. Hopefully it is possible to convince oneself of that much without being a value analysis expert—although I admit that programming nondeterministic machines is an unusual exercise.</p> -<p>Using Frama-C's value analysis as a sound and complete abstract interpreter the statement <code>Frama_C_show_each_cycle_found(1);</code> will be reached and a message be displayed exactly when a state is reached that is identical to one of its predecessors. This happens if and only if -there is a cycle in the transition graph of the program instrumented to stop at <code>Y</code>. In terms of the original program this corresponds to <code>(F oY)</code> being false.</p> -<h3>Putting the new method to the test</h3> -<p>Running the value analysis on the program instrumented as described:</p> -<pre>$ frama-c -val -slevel 100000000 -no-val-show-progress Problem3_terminate_at_Y_with_predecessor.c -... -[value] Semantic level unrolling superposing up to 100 states -[value] Semantic level unrolling superposing up to 200 states -[value] Called Frama_C_show_each_cycle_found({1}) -^C -</pre> -<p>Incidentally on this example this new method is much faster than the method involving a counter. It is not clear that it should always be the case and on difficult examples the two methods can perhaps be tried in parallel.</p> -<h2>Annex: an exhaustive list of states for Problem 3</h2> -<p>Below is the list of unique states displayed when the statement</p> -<pre>Frama_C_show_each_state( a1 a4 a0 a15 a29 a10 a16 a22 a2 a17 a25 a7 a14 a19 a20 a8 a23 a21 a24 a13 a9 a28 a26 a6 a27 a12 a3 a11 a5 a18 ); -</pre> -<p>is inserted in the <code>while</code> loop of <code>Program3.c</code>.</p> -<pre>[value] Called Frama_C_show_each_state({1} {1} {1} {1} {1} {1} {1} {1} {0} {0} {0} {0} {0} {0} {0} {0} {0} {1} {1} {1} {1} {1} {0} {0} {0} {0} {1} {0} {1} {1}) -[value] Called Frama_C_show_each_state({1} {1} {1} {1} {1} {1} {1} {1} {0} {0} {0} {0} {0} {0} {0} {0} {0} {1} {1} {1} {1} {1} {0} {0} {0} {0} {2} {1} {1} {1}) -[value] Called Frama_C_show_each_state({1} {1} {1} {1} {1} {1} {1} {1} {0} {0} {0} {0} {0} {0} {0} {0} {0} {1} {1} {1} {1} {1} {0} {0} {0} {1} {0} {0} {1} {1}) -[value] Called Frama_C_show_each_state({1} {1} {1} {1} {1} {1} {1} {1} {0} {0} {0} {0} {0} {0} {0} {0} {0} {1} {1} {1} {1} {1} {0} {0} {1} {0} {0} {0} {1} {1}) -[value] Called Frama_C_show_each_state({1} {1} {1} {1} {1} {1} {1} {1} {0} {0} {0} {0} {0} {0} {0} {0} {0} {1} {1} {1} {1} {1} {0} {0} {1} {0} {1} {0} {1} {1}) -[value] Called Frama_C_show_each_state({1} {1} {1} {1} {1} {1} {1} {1} {0} {0} {0} {0} {0} {0} {0} {0} {0} {1} {1} {1} {1} {1} {0} {0} {1} {0} {2} {1} {1} {1}) -[value] Called Frama_C_show_each_state({1} {1} {1} {1} {1} {1} {1} {1} {0} {0} {0} {0} {0} {0} {0} {0} {0} {1} {1} {1} {1} {1} {0} {1} {0} {1} {1} {0} {1} {1}) -[value] Called Frama_C_show_each_state({1} {1} {1} {1} {1} {1} {1} {1} {0} {0} {0} {0} {0} {0} {0} {0} {0} {1} {1} {1} {1} {1} {0} {1} {0} {1} {2} {0} {1} {1}) -[value] Called Frama_C_show_each_state({1} {1} {1} {1} {1} {1} {1} {1} {0} {0} {0} {0} {0} {0} {0} {0} {0} {1} {1} {1} {1} {1} {0} {1} {1} {0} {1} {0} {1} {1}) -[value] Called Frama_C_show_each_state({1} {1} {1} {1} {1} {1} {1} {1} {0} {0} {0} {0} {0} {0} {0} {0} {0} {1} {1} {1} {1} {1} {0} {1} {1} {0} {2} {0} {1} {1}) -[value] Called Frama_C_show_each_state({1} {1} {1} {1} {1} {1} {1} {1} {0} {0} {0} {0} {0} {0} {0} {0} {0} {1} {1} {1} {1} {1} {0} {1} {1} {1} {2} {1} {1} {1}) -[value] Called Frama_C_show_each_state({1} {1} {1} {1} {1} {1} {1} {1} {0} {0} {0} {0} {0} {0} {0} {0} {0} {1} {1} {1} {1} {1} {1} {0} {0} {0} {0} {1} {1} {1}) -[value] Called Frama_C_show_each_state({1} {1} {1} {1} {1} {1} {1} {1} {0} {0} {0} {0} {0} {0} {0} {0} {0} {1} {1} {1} {1} {1} {1} {0} {0} {0} {1} {0} {1} {1}) -[value] Called Frama_C_show_each_state({1} {1} {1} {1} {1} {1} {1} {1} {0} {0} {0} {0} {0} {0} {0} {0} {0} {1} {1} {1} {1} {1} {1} {0} {0} {0} {1} {1} {1} {1}) -[value] Called Frama_C_show_each_state({1} {1} {1} {1} {1} {1} {1} {1} {0} {0} {0} {0} {0} {0} {0} {0} {0} {1} {1} {1} {1} {1} {1} {0} {0} {1} {0} {1} {1} {1}) -[value] Called Frama_C_show_each_state({1} {1} {1} {1} {1} {1} {1} {1} {0} {0} {0} {0} {0} {0} {0} {0} {0} {1} {1} {1} {1} {1} {1} {0} {0} {1} {2} {1} {1} {1}) -[value] Called Frama_C_show_each_state({1} {1} {1} {1} {1} {1} {1} {1} {0} {0} {0} {0} {0} {0} {0} {0} {0} {1} {1} {1} {1} {1} {1} {0} {1} {0} {0} {0} {1} {1}) -[value] Called Frama_C_show_each_state({1} {1} {1} {1} {1} {1} {1} {1} {0} {0} {0} {0} {0} {0} {0} {0} {0} {1} {1} {1} {1} {1} {1} {0} {1} {0} {1} {1} {1} {1}) -[value] Called Frama_C_show_each_state({1} {1} {1} {1} {1} {1} {1} {1} {0} {0} {0} {0} {0} {0} {0} {0} {0} {1} {1} {1} {1} {1} {1} {0} {1} {0} {2} {1} {1} {1}) -[value] Called Frama_C_show_each_state({1} {1} {1} {1} {1} {1} {1} {1} {0} {0} {0} {0} {0} {0} {0} {0} {0} {1} {1} {1} {1} {1} {1} {0} {1} {1} {1} {1} {1} {1}) -[value] Called Frama_C_show_each_state({1} {1} {1} {1} {1} {1} {1} {1} {0} {0} {0} {0} {0} {0} {0} {0} {0} {1} {1} {1} {1} {1} {1} {0} {1} {1} {2} {1} {1} {1}) -[value] Called Frama_C_show_each_state({1} {1} {1} {1} {1} {1} {1} {1} {0} {0} {0} {0} {0} {0} {0} {0} {0} {1} {1} {1} {1} {1} {1} {1} {0} {0} {1} {1} {1} {1}) -[value] Called Frama_C_show_each_state({1} {1} {1} {1} {1} {1} {1} {1} {0} {0} {0} {0} {0} {0} {0} {0} {0} {1} {1} {1} {1} {1} {1} {1} {0} {0} {2} {0} {1} {1}) -[value] Called Frama_C_show_each_state({1} {1} {1} {1} {1} {1} {1} {1} {0} {0} {0} {0} {0} {0} {0} {0} {0} {1} {1} {1} {1} {1} {1} {1} {0} {0} {2} {1} {1} {1}) -[value] Called Frama_C_show_each_state({1} {1} {1} {1} {1} {1} {1} {1} {0} {0} {0} {0} {0} {0} {0} {0} {0} {1} {1} {1} {1} {1} {1} {1} {0} {1} {2} {0} {1} {1}) -[value] Called Frama_C_show_each_state({1} {1} {1} {1} {1} {1} {1} {1} {0} {0} {0} {0} {0} {0} {0} {0} {0} {1} {1} {1} {1} {1} {1} {1} {1} {0} {1} {1} {1} {1}) -[value] Called Frama_C_show_each_state({1} {1} {1} {1} {1} {1} {1} {1} {0} {0} {0} {0} {0} {0} {0} {0} {0} {1} {1} {1} {1} {1} {1} {1} {1} {0} {2} {0} {1} {1}) -[value] Called Frama_C_show_each_state({1} {1} {1} {1} {1} {1} {1} {1} {0} {0} {0} {0} {0} {0} {0} {0} {0} {1} {1} {1} {1} {1} {1} {1} {1} {0} {2} {1} {1} {1}) -[value] Called Frama_C_show_each_state({1} {1} {1} {1} {1} {1} {1} {1} {0} {0} {0} {0} {0} {0} {0} {0} {0} {1} {1} {1} {1} {1} {1} {1} {1} {1} {0} {1} {1} {1}) -[value] Called Frama_C_show_each_state({1} {1} {1} {1} {1} {1} {1} {1} {0} {0} {0} {0} {0} {0} {0} {0} {0} {1} {1} {1} {1} {1} {1} {1} {1} {1} {1} {1} {1} {1}) -[value] Called Frama_C_show_each_state({1} {1} {1} {1} {1} {1} {1} {1} {0} {0} {0} {0} {0} {0} {0} {0} {0} {1} {1} {1} {1} {1} {1} {1} {1} {1} {2} {0} {1} {1}) -</pre> <p>This post benefited from discussions with Sébastien Bardin Sven Mattsen Benjamin Monate and Boris Yakobowski.</p> {% endraw %} diff --git a/_posts/2012-08-23-Technical-interlude.html b/_posts/2012-08-23-Technical-interlude.html index 7babf2ec76d39e070614008bfffe01999241cfb2..64e0b5f5ca0ea48d7485bd339c8af50f810dda4c 100644 --- a/_posts/2012-08-23-Technical-interlude.html +++ b/_posts/2012-08-23-Technical-interlude.html @@ -63,61 +63,5 @@ summary: [kernel] Plug-in value aborted because of invalid user input. </pre> <p>This is convenient for timing the analyzer as it tackles some of the harder problems. In the case above the time was 5m35s answering a liveness question about Problem 6. It would have been a pain to watch the log for that long fingers poised to interrupt the analyzer.</p> -<p>That's all for this interlude. Expect exciting timings in the next post. There may also be talk of undocumented features that transcend the problem in the good sense of the word.</p> - <p>The current series of posts is pretty technical, huh? Here is a refreshing diversion in the form of a technical post that also touches on existential questions. What is this blog for? We don't know.</p> -<h2>Best solutions, or solutions anyone could have found</h2> -<p>If you have been following the current series of posts, you may have noticed that a recurring dilemma is whether the goal is to demonstrate the capabilities of the software tool under consideration (Frama-C's value analysis plug-in) when pushed to its limits by its authors, or to demonstrate what anyone could <strong>do without being a creator of the tool</strong>, taking advantage of Linux, Mac OS X and sometimes Windows packages for the software, and, most importantly, having only the available documentation to understand what the software makes possible.</p> -<p>The general goal of the blog is to empower users. In fact, much of the aforementioned documentation is available as posts in the blog itself. These posts sometimes describe techniques that were undocumented until then, but describe them so that they <strong>wouldn't be undocumented any more</strong>. Some of the posts even describe techniques that weren't undocumented at the time of writing. As my colleague Jean-Jacques Lévy would say, “repetition is the essence of teachingâ€.</p> -<p>However, I do not expect that most software tool competitions are about measuring the availability and learnability of tools. For instance, the <a href="http://www.sosy-lab.org/~dbeyer/Publications/2012-TACAS.Competition_on_Software_Verification.pdf">SV-COMP</a> competition explicitly <strong>forbids anyone other than the authors of the tool to participate</strong> with it:</p> -<p><q>A person (participant) was qualiï¬ed as competition contributor for a competition candidate if the person was a contributing designer/developer of the submitted competition candidate (witnessed by occurrence of the person’s name on the tool’s project web page a tool paper or in the revision logs).</q></p> -<p>Ostensibly the <strong>tools are the participants</strong> in the competition. Involving the authors is only a mean to make the competition as fair as possible for the tools. Some colleagues and I have <a href="https://www.dropbox.com/s/el2lidf5v71ogm6/p.pdf">expressed</a> the opinion that for static analysis at this time this was the right way:</p> -<p><q>In general the best way to make sure that a benchmark does not misrepresent the strengths and weaknesses of a tool is to include the toolmakers in the process.</q></p> -<p>Some competitions on the other hand acknowledge that a participant is a person(s)+tool hybrid and <a href="http://lists.csl.sri.com/pipermail/sal/2010-July/000135.html">welcome</a> entries from users that did not create the tools they used. This is perfectly fine especially for the very interactive tools involved in the cited competition as long as it is understood that it is not a tool alone but a hybrid participant that is being evaluated in such a competition. Some of the participating tools participated in several teams associated to several users (although the winning teams did tend to be composed of toolmakers using their respective tools).</p> -<p>It is not clear to me where on this axis the RERS competition falls. It is a “free-style†competition. The entries are largely evaluated on results with much freedom with respect to the way these were obtained. This definitely can also be fun(*).</p> -<p>The competition certainly does not require participating tools to be packaged and documented in such exquisite detail that anyone could have computed the same results. As such the best description to write is the description of what the authors of the value analysis can do with it with all the shortcuts they trust themselves to take. If some of the questions can be solved efficiently using undocumented features so be it. It is the free-style style.</p> -<p>But the mission of the blog remains to document and showing what we have done without explaining how to reproduce it sounds like boasting. I am torn.</p> -<p>(*) An untranslatable French idiom “bon public†literally “good audience†used in an adjective position conveys a number of subtle often humorous nuances. I think this applies to me and software competitions. They just all seem fun to me.</p> -<h2>A necessary built-in</h2> -<p>A value analysis built-in whose usefulness if it were available became apparent in the last post was a built-in that halts the analyzer.</p> -<p>Several analysis log snippets in the previous post show a <code>^C</code> as last line to indicate that the log already contains the answer to the question being investigated and that the user watching the analysis go by can freely interrupt it then.</p> -<blockquote><p>I cheated when editing the post by the way. I am not fast enough to interrupt the analysis just after the first conclusive log message. But I did interrupt these analyses which otherwise might have gone on for a long time for no purpose.</p> -</blockquote> -<p>I thought I would enjoy my colleagues' horrified reaction so I told everyone about my intention of writing a value analysis built-in like some already exist for <code>memcpy()</code> or <code>memset()</code> for halting the analyzer. Not halting the currently considered execution mind you. There is <code>/*@ assert \false; */</code> for that and if you need this functionality available as a C function you can put <code>/*@ assert \false; */</code> inside your own function like I did for <code>assert()</code> <a href="/index.php?post/2012/08/20/Participating-in-the-RERS-2012-competition%3A-reachability-questions">earlier</a> when prepping the competition programs for Frama-C.</p> -<p>Clearly such a built-in does not have a contract its effects are meta-effects that transcend the framework (in what would for these colleagues be the bad sense of the word).</p> -<h2>A time-saver</h2> -<p>Today I set out to write this built-in because I started to get serious about the competition and it would be convenient to just instrument the program with:</p> -<pre>if ( /* current state identical to predecessor state /* ) -{ - Frama_C_show_each_cycle_found(1); - Frama_C_halt_analysis(); -} -</pre> -<p>instead of having an operator or even a shell script watch the log for the <code>Frama_C_show_each_cycle_found</code> message and interrupt Frama-C then.</p> -<p>Soon after opening the file and finding my place I realized that this feature was already available. I am telling you this because this blog is for the benefit of transparency for documenting things and for empowering users but mostly because I want to see my colleagues' horrified reaction when they read about this trick. Actually I would not use it if I were you. It might cease to work in a future version.</p> -<pre>if ( /* current state identical to predecessor state /* ) -{ - Frama_C_show_each_cycle_found(1); - Frama_C_cos(0.0 0.0); -} -</pre> -<p>You see Frama-C value analysis built-ins such as <code>Frama_C_cos()</code> do not have an intrinsic type. You can include a header that will give them a type if you wish:</p> -<pre>double Frama_C_cos(double x); -</pre> -<p>Otherwise the old C89 rules for missing function prototypes apply. During parsing a type is inferred from the types of the arguments at the call site.</p> -<p>Only if and when the analysis actually reaches the <code>Frama_C_cos(0.0 0.0)</code> call the analyzer will realize that it is passed arguments that are incompatible with the OCaml function that implement the built-in. An exception will be raised. Since there is no reason to try to recover from a built-in misuse this exception is caught only at the highest level. It stops the entire analyzer (it marks the entire analysis results as unreliable as it should but of course it does not retroactively unemit the <code>Frama_C_show_each_cycle_found</code> message in the log that says a conclusion has been reached).</p> -<p>The result looks like this this time without cheating:</p> -<pre>[value] Called Frama_C_show_each_cycle_found({1}) -... -[value] computing for function any_int <- main. - Called from Problem6_terminateU_pred.c:9516. -[value] Done for function any_int -[value] Semantic level unrolling superposing up to 1400 states -[value] user error: Invalid argument for Frama_C_cos function -[value] user error: Degeneration occured: - results are not correct for lines of code - that can be reached from the degeneration point. -[kernel] Plug-in value aborted because of invalid user input. -</pre> -<p>This is convenient for timing the analyzer as it tackles some of the harder problems. In the case above the time was 5m35s answering a liveness question about Problem 6. It would have been a pain to watch the log for that long fingers poised to interrupt the analyzer.</p> <p>That's all for this interlude. Expect exciting timings in the next post. There may also be talk of undocumented features that transcend the problem in the good sense of the word.</p> {% endraw %} diff --git a/_posts/2012-08-24-On-writing-a-dedicated-model-checker-for-the-RERS-competition.html b/_posts/2012-08-24-On-writing-a-dedicated-model-checker-for-the-RERS-competition.html index 5411d9048b31ef914b85acc88b5109bdc463ebd8..002ca7449d1047b0565ece74c4a7573d44b3c9ec 100644 --- a/_posts/2012-08-24-On-writing-a-dedicated-model-checker-for-the-RERS-competition.html +++ b/_posts/2012-08-24-On-writing-a-dedicated-model-checker-for-the-RERS-competition.html @@ -33,31 +33,5 @@ Some of these improvements are too sophisticated to justify implementing in a ve more or less quickly; again when the infinite loop is detected it simply goes on to the next trace. With an ad-hoc verifier if you expect the verification to take days it may take days before you realize that the verifier is executing an infinite loop in its third considered transition.</p> <h2>Conclusion</h2> <p>In summary considering the general C verification framework we already have it looks like it wouldn't be a good investment of our time to develop a dedicated fast verifier for the competition—although it would provide an insightful datapoint if someone did.</p> -<p>Perhaps participating in the meeting will convince us that Event Condition Action (ECA) systems are more generally useful than our current experience has led us to believe. We could work on a verifier for them if there is a need. There is not much code to reuse from a general-purpose C abstract interpreter. There would be ideas to reuse certainly. I will come to one of them in the next post.</p> - <p>In recent <a href="/index.php?post/2012/08/20/Participating-in-the-RERS-2012-competition%3A-reachability-questions">posts</a> I have shown that Frama-C's value analysis could answer many reachability questions and some questions that weren't originally phrased as reachability questions about the programs in the <a href="http://leo.cs.tu-dortmund.de:8100/isola2012/challenge.html">RERS competition</a>.</p> -<p>If you are vaguely familiar with the internals of Frama-C's value analysis and if you tried analyzing some of the competition programs yourself you may have noticed that these analyses use only a small fraction of the plug-in's capabilities. The analyzer is only ever propagating abstract states that correspond to singletons. It does juggle with many program states but the programs here have small states that are encoded in just a few variables (the analyzer would have been able to manipulate the states encoded on a much larger number of variables and would efficiently share in memory the values common to several of the explored states). There are no bit-fields no structs with padding (both of which might make identical states look different if carelessly handled). The programs obviously do not execute any undefined behavior for lack of any operation that might introduce them. There is a single outermost loop. There is no arithmetic at all.</p> -<h2>In favor of the general verifier</h2> -<p>A specialized verifier that was designed for just these programs would have a huge opportunity to do a better job on them. On the other hand the advantage of working on a more general verifier is that it is <strong>useful for more tasks</strong>. This enables to spend more time improving it. Some of the improvements enhance the analysis of many programs including the specific programs built only from assignments equality tests and conditionals considered in the competition. -Some of these improvements are too sophisticated to justify implementing in a verifier that only handles programs with assignments equality tests and conditionals because such a verifier will never be usable to find that the SHA-3 candidate Skein's reference implementation <a href="/index.php?tag/skein">does not exhibit undefined behavior</a> that AES may be <a href="/derived/analysis/skein/2011/12/31/Do-not-use-AES-in-a-context-where-timing-attacks-are-possible">susceptible</a> to timing attacks (but Skein isn't) where <a href="/index.php?tag/icpc2011">a couple</a> of bugs are in an old undocumented piece of control software that there is a <a href="/index.php?tag/QuickLZ">subtle memory overflow in compression library QuickLZ</a> or that units of code have the <a href="http://www.erts2012.org/Site/0P2RUC89/5C-3.pdf">data and control flows mandated by specification</a>.</p> -<h2>What a dedicated verifier might look like</h2> -<p>In the particular case of these programs the same propagation done by the value analysis could be done in C by a program that would incorporate the transition function directly and execute it as compiled code. This would be much more efficient than what the value analysis does and in this particular case it would give the same results. From experiments <a href="/index.php?pages/Csmith-testing">interpreting Csmith programs</a> the value analysis slowdown with respect to compiled code can be expected to be of the order of 10000.</p> -<h3>Accumulating reachable states</h3> -<p>In order to reproduce what Frama-C's value analysis does a dedicated verifier would need to store states that have already been visited and to be able to recognize after applying the transition function once more whether the obtained state was one that was already visited.</p> -<p>In this particular case this could be done in constant time with a hashset. Note however that it is only possible to compute a hash in this specialized case because all states are “singleton†states. If some states represented several values at once e.g. a1 ∈ {1; 2} a2 ∈ {0; 1} the good criterion would then be whether the newly computed state is <strong>included</strong> in one of the previously propagated states. Testing inclusion in one of the previous states cannot be done in constant time with a hashset (hashsets only allow you to test whether the new state is <strong>equal</strong> to an existing state and you need to be careful to use compatible equality and hash functions).</p> -<p>Frama-C's value analysis uses a data structure that is generally as efficient as hashsets when the manipulated states are singletons and that often remains efficient when testing inclusion in one another of states that are not singletons.</p> -<h3>Storing states that remain to be propagated</h3> -<p>A small thing: the propagation algorithm also requires a workqueue. Any propagation order will do (Frama-C's value analysis propagation order is not specified either) but since C comes with so few data structures I just thought I would mention it. For a dedicated verifier in C one would need to find some linked list implementation or write <a href="http://en.wikipedia.org/wiki/Spivak_pronoun">eir</a> own. Frama-C's value analysis may interpret C slower than the code can be executed once compiled but it comes with ready to use data structures for the reached set and for the workqueue. One needs not even know they are there to use the analyzer.</p> -<h2>Specific drawbacks</h2> -<p>Obviously this ad-hoc verifier could be expected to be must faster than the value analysis. This makes the experiment tempting. What prevents me from starting work on it is the lack of generality of the resulting tool. Some examples follow.</p> -<h3>Undefined behavior</h3> -<p>Suppose that you had implemented such a specialized verifier for the competition's program and that you were looking for more transition functions written in C that the same verifier could apply to. You would certainly find some but would you in general be certain that the transition function never exhibits undefined behavior (not for the first transition and not for the transition from any reachable state to a successor)? If one isn't certain that the transition function does not cause undefined behavior from a formal verification point of view the tool is worthless. An undefined behavior can cause <strong>anything</strong> to happen. In particular an out-of-bounds memory access in the transition function can mess up the verifier's reached set or workqueue and compromise the results of the verification.</p> -<p>Any automatic verifier is susceptible to the caveat that a bug in the verifier can compromise results. This is different: your implementation could be flawless but it would still be susceptible to a bug in the transition function <strong>a bug in the system being verified</strong>.</p> -<p>Of course you could as a preliminary step in your verification check that the transition function does not have any undefined behavior for any input state. If you find that there are a lot of different undefined behaviors in C and that it's a bother to detect them all we have a tool that we have been working on. It also answers reachability questions.</p> -<h3>General interference between unrelated traces</h3> -<p>Even if you have only “frank†run-time errors to fear—undefined behavior that compilers kindly translate to run-time errors at least when optimizations are disabled— a run-time error in one transition will still interrupt the entire dedicated analyzer. You will notice when this happens and you can add a guard to the particular division by zero or NULL dereference but this iterative process may end up taking as long as the value analysis for the same result. The value analysis when encountering division by zero or NULL dereference makes a note of it considers the trace as terminated and goes on to the propagation of the next trace. The end result a list of run-time errors to worry about and a reachable states set is the same but it is obtained in a single pass.</p> -<p>There is also the issue of non-termination of the transition function. The value analysis detects cases of non-termination -more or less quickly; again when the infinite loop is detected it simply goes on to the next trace. With an ad-hoc verifier if you expect the verification to take days it may take days before you realize that the verifier is executing an infinite loop in its third considered transition.</p> -<h2>Conclusion</h2> -<p>In summary considering the general C verification framework we already have it looks like it wouldn't be a good investment of our time to develop a dedicated fast verifier for the competition—although it would provide an insightful datapoint if someone did.</p> <p>Perhaps participating in the meeting will convince us that Event Condition Action (ECA) systems are more generally useful than our current experience has led us to believe. We could work on a verifier for them if there is a need. There is not much code to reuse from a general-purpose C abstract interpreter. There would be ideas to reuse certainly. I will come to one of them in the next post.</p> {% endraw %} diff --git a/_posts/2012-09-04-Extracting-information-from-Frama-C-programmatically.html b/_posts/2012-09-04-Extracting-information-from-Frama-C-programmatically.html index ac7f1799822fd0f061b4c67ce2fd9452b7e7cd58..3357f5b798d7156f9d4315677ddef02c55dce02a 100644 --- a/_posts/2012-09-04-Extracting-information-from-Frama-C-programmatically.html +++ b/_posts/2012-09-04-Extracting-information-from-Frama-C-programmatically.html @@ -79,76 +79,5 @@ let () = Db.Main.extend run <li>For now the graphs are generated each time the script is explicitely loaded from the command line. One might eventually want to compile it as a proper plugin systematically loaded by Frama-C with the graph generation commanded by a proper command-line option</li> <li>Some other parameters might be interesting such as choosing the name of the output file including only the CFG of certain functions ...</li> <li>The script could interact with some plugins to give more information (e.g. showing dead paths for a given run of Value)</li> -</ul>" <h2>Extending the framework</h2> -<p>Some time ago, one of our fellow users asked us whether it was possible to extract the control-flow graph (CFG) of C functions from Frama-C. Fact is, although the CFG is computed during the elaboration of the AST, nothing exists currently to present the information to the user. But Frama-C is a Flexible framework, and a small (50 LoC) <a href="/assets/img/blog/imported-posts/cfg_print.ml">script</a> will provide this functionality albeit in a rather crude form. -More specifically we'll ask Frama-C to output a file in the <a href="http://en.wikipedia.org/wiki/DOT_language">dot format</a> that will contain a graph for each of the functions of the program under analysis. Basically our script is composed of three parts: a function to pretty-print the statements as node of the graph -a <a href="/cil/ocaml/developer/facetious-colleagues/visitor/2012/05/21/Iterating-over-the-AST">visitor</a> to create the graphs and the boilerplate code that takes care of registering the code into Frama-C kernel.</p> -<h2>Pretty-printing</h2> -<p>Frama-C already has a function to pretty-print statements but it is not suitable for us as it will recursively print substatements of compound statements (blocks if while ...) while we only want to have a label for the current statement: substatements will be represented by other nodes. We'll use thus the following small function:</p> -<pre>let print_stmt out = - function - | Instr i -> !Ast_printer.d_instr out i - | Return _ -> Format.pp_print_string out "<return>" - | Goto _ -> Format.pp_print_string out "<goto>" - | Break _ -> Format.pp_print_string out "<break>" - | Continue _ -> Format.pp_print_string out "<continue>" - | If (e _ _ _) -> Format.fprintf out "if %a" !Ast_printer.d_exp e - | Switch(e _ _ _) -> Format.fprintf out "switch %a" !Ast_printer.d_exp e - | Loop _ -> Format.fprintf out "<loop>" - | Block _ -> Format.fprintf out "<enter block>" - | UnspecifiedSequence _ -> Format.fprintf out "<enter unspecified sequence>" - | TryFinally _ | TryExcept _ -> Format.fprintf out "<try>" -</pre> -<h2>Creating the graphs</h2> -<p>In order to create our output we must make a pass through the whole AST. An easy way to do that is to use CIL's visitor mechanism. There are three kinds of nodes where we have something to do. -First at the <code>file</code> level we create the whole graph structure:</p> -<pre>method vfile f = - Format.fprintf out "@[<hov 2>digraph cfg {@"; - ChangeDoChildrenPost (f fun f -> Format.fprintf out "}@."; f) -</pre> -<p>Then for each function we encapsulate the CFG in a subgraph (and don't do anything for other globals hence the SkipChildren for the other branch of the pattern-matching).</p> -<pre> method vglob_aux g = - match g with - | GFun(f loc) -> - Format.fprintf out "@[<hov 2>subgraph cluster_%a {@\ -\ - graph [label=\"%a\"];@" - Cil_datatype.Varinfo.pretty f.svar - Cil_datatype.Varinfo.pretty f.svar; - ChangeDoChildrenPost([g] fun g -> Format.fprintf out "}@\ -@]"; g) - | _ -> SkipChildren -</pre> -<p>Last for each statement we have to create a node of the graph and create the edges toward its successors:</p> -<pre> method vstmt_aux s = - Format.fprintf out "s%d@[[label=\"%a\"]@];@" s.sid print_stmt s.skind; - List.iter - (fun succ -> Format.fprintf out "s%d -> s%d;@" s.sid succ.sid) - s.succs; - DoChildren -</pre> -<h2>Registration within Frama-C's main loop</h2> -<p>Now we want Frama-C to be aware of our script. Basically this amounts to write a driver function of type <code>unit -> unit</code> that will launch the visitor process and to tell Frama-C that this function should be run as an analysis:</p> -<pre>let run () = - let chan = open_out "cfg.out" in - let fmt = Format.formatter_of_out_channel chan in - Visitor.visitFramacFileSameGlobals (new print_cfg fmt) (Ast.get()) -let () = Db.Main.extend run -</pre> -<h2>Launching the script</h2> -<p>In order to obtain a <code>cfg.out</code> file with our graphs we simply have to call frama-c that way:</p> -<pre>frama-c -load-script cfg_print.ml [other_options] file.c [file2.c] -</pre> -<p>Then provided <a href="http://www.graphviz.org/">graphviz</a> is installed the command</p> -<pre>dot -Tpdf -o cfg.pdf cfg.out -</pre> -<p>will provide a pdf file similar to <a href="/assets/img/blog/imported-posts/cfg.pdf">this one</a></p> -<h2>What next?</h2> -<p>This script is very basic and should be improved in several ways in order to be useful beyond the point of showing how to interact with Frama-C's API (some of these might be the subject of new posts in the future)</p> -<ul> -<li>The graphs could be fancier in particular by distinguishing between branching nodes and plain ones or showing exit of blocks as well as their beginning</li> -<li>For now the graphs are generated each time the script is explicitely loaded from the command line. One might eventually want to compile it as a proper plugin systematically loaded by Frama-C with the graph generation commanded by a proper command-line option</li> -<li>Some other parameters might be interesting such as choosing the name of the output file including only the CFG of certain functions ...</li> -<li>The script could interact with some plugins to give more information (e.g. showing dead paths for a given run of Value)</li> -</ul>" +</ul>" {% endraw %} diff --git a/_posts/2012-09-06-A-value-analysis-option-to-reuse-previous-function-analyses.html b/_posts/2012-09-06-A-value-analysis-option-to-reuse-previous-function-analyses.html index a209193da769ac2e4b35071f129df284351093ed..b4297c2ebb43446a8f9503e6900b2e8467c05947 100644 --- a/_posts/2012-09-06-A-value-analysis-option-to-reuse-previous-function-analyses.html +++ b/_posts/2012-09-06-A-value-analysis-option-to-reuse-previous-function-analyses.html @@ -100,98 +100,5 @@ calc.c:40:[value] Reusing old results for call to calculate_output <p>The option alluded to in this post was not implemented for the purpose of the RERS 2012 competition. It was implemented earlier in the context of a large case study where it contributed to speed up the analysis greatly. A lot of work would be involved in making this option work well in all contexts (and actually in making sure that derived analyses that plug into the value analysis are not confused by bits of analysis being reused).</p> <blockquote><p>Still although it is unfinished the mysterious option is finished enough to be useful in the context of the RERS competition. It is particularly useful when determining the status of liveness properties such as (F oW). Whether infinite execution traces are detected with a <a href="/index.php?post/2012/08/20/Participating-in-the-RERS-2012-competition%3A-liveness-questions">counter</a> or with a <a href="/index.php?post/2012/08/22/Proving-%28F-oW%29-true-or-false%3A-alternative-method">quantum superposition of all previous states</a> the extra program state introduced by the instrumentation does not influence the behavior of function <code>calculate_output()</code>. In that context it is a huge gain to be able to re-use the analysis of <code>calculate_output()</code> which would otherwise for each state have to be duplicated for all possible predecessors.</p> </blockquote> -<p>Boris Yakobowski invented and implemented the option this post refers to without which the hardest properties in the RERS challenge would be intractable.</p> - <h2>A context-sensitive analysis</h2> -<p>Frama-C's value analysis is <a href="http://en.wikipedia.org/wiki/Data-flow_analysis#Sensitivities">context-sensitive</a>.</p> -<p>This means that when a function <code>f2()</code> is called from a caller <code>f1()</code> -function <code>f2()</code> is analyzed as many times as the analyzer goes over <code>f1()</code>. Function <code>f2()</code> is analyzed each time with a different program state—the program state corresponding to the specific call. If <code>f2()</code> is called from within a loop the analyzer may analyze it many times.</p> -<p>This is for the worthy cause of precision. Any attempt to summarize <code>f2()</code> so that it can be analyzed once and for all can only result in less precise analysis results.</p> -<h2>An example</h2> -<p>Consider the following program:</p> -<pre>int a1 = 1; -int a2 = 2; -int a3 = 3; -int p1 = -1; -int p2 = -1; -int p3 = -1; -void calculate_output(void) -{ - if (a1 == 1 && a2 == 2 && a3 == 3) - { - a1 = 2; - return; - } - if (a1 == 2 && a2 == 2 && a3 == 3) - { - a1 = 1; - return; - } -} -main() -{ - calculate_output(); - p1 = a1; - p2 = a2; - p3 = a3; - Frama_C_dump_each(); - calculate_output(); - p1 = a1; - p2 = a2; - p3 = a3; - Frama_C_dump_each(); - calculate_output(); - p1 = a1; - p2 = a2; - p3 = a3; - Frama_C_dump_each(); - calculate_output(); -} -</pre> -<p>For the reason stated above function <code>calculate_output()</code> is analyzed four times when this program is analyzed with the command <code>frama-c -val</code>:</p> -<pre>$ frama-c -val calc.c -... -[value] computing for function calculate_output <- main. - Called from calc.c:25. -... -[value] computing for function calculate_output <- main. - Called from calc.c:30. -... -[value] computing for function calculate_output <- main. - Called from calc.c:35. -... -[value] computing for function calculate_output <- main. - Called from calc.c:40. -... -[value] Values at end of function main: - a1 ∈ {1} - p1 ∈ {2} - p2 ∈ {2} - p3 ∈ {3} -... -</pre> -<h2>An unnamed option</h2> -<p>If you look at the program closely you may notice that the third call and the first call (and respectively the fourth and second call) have a lot in common. For each of these pairs the analysis follows the same paths inside the function and change the program state in the same way. This is because although the states differ in variables <code>p1 p2 p3</code> they are identical for the variables <code>a1 a2 a3</code> that are the only variables read.</p> -<p>There is an undocumented (and indeed unfinished) value analysis option to take advantage of previous analyses of a function call <strong>without loss of precision</strong>. It only reuses calls in circumstances similar to those that apply to the third and fourth call to <code>calculate_output()</code> above. When this option is enabled Frama-C after analyzing a function call computes the sets of locations that were effectively read and written <strong>for that specific call</strong> and records these inputs and outputs as well as the program state before and after the call in a cache for the purpose of later re-using the analysis just done.</p> -<p>With that option the log output during the analysis becomes:</p> -<pre>[value] computing for function calculate_output <- main. - Called from calc.c:25. -... -[value] computing for function calculate_output <- main. - Called from calc.c:30. -... -calc.c:35:[value] Reusing old results for call to calculate_output -... -calc.c:40:[value] Reusing old results for call to calculate_output -... -[value] Values at end of function main: - a1 ∈ {1} - p1 ∈ {2} - p2 ∈ {2} - p3 ∈ {3} -</pre> -<h2>History and application to the RERS challenge</h2> -<p>The option alluded to in this post was not implemented for the purpose of the RERS 2012 competition. It was implemented earlier in the context of a large case study where it contributed to speed up the analysis greatly. A lot of work would be involved in making this option work well in all contexts (and actually in making sure that derived analyses that plug into the value analysis are not confused by bits of analysis being reused).</p> -<blockquote><p>Still although it is unfinished the mysterious option is finished enough to be useful in the context of the RERS competition. It is particularly useful when determining the status of liveness properties such as (F oW). Whether infinite execution traces are detected with a <a href="/index.php?post/2012/08/20/Participating-in-the-RERS-2012-competition%3A-liveness-questions">counter</a> or with a <a href="/index.php?post/2012/08/22/Proving-%28F-oW%29-true-or-false%3A-alternative-method">quantum superposition of all previous states</a> the extra program state introduced by the instrumentation does not influence the behavior of function <code>calculate_output()</code>. In that context it is a huge gain to be able to re-use the analysis of <code>calculate_output()</code> which would otherwise for each state have to be duplicated for all possible predecessors.</p> -</blockquote> <p>Boris Yakobowski invented and implemented the option this post refers to without which the hardest properties in the RERS challenge would be intractable.</p> {% endraw %} diff --git a/_posts/2012-09-06-Crediting-where-credit-is-due.html b/_posts/2012-09-06-Crediting-where-credit-is-due.html index 7b563c885e766bea8813d4a9824df1f58490066d..0143ba283e5e0cf30f5861e0e1854d7ed075440a 100644 --- a/_posts/2012-09-06-Crediting-where-credit-is-due.html +++ b/_posts/2012-09-06-Crediting-where-credit-is-due.html @@ -9,7 +9,5 @@ summary: --- {% raw %} <p>In a <a href="/index.php?post/2012/08/22/Proving-%28F-oW%29-true-or-false%3A-alternative-method">recent post</a> I showed how to use Frama-C's value analysis to prove a particular liveness property true or false of a particular C program.</p> -<p>My colleague Sébastien Bardin reliably informs me that the ideas for reducing a liveness property to a reachability property were all in the article <a href="http://staff.aist.go.jp/c.artho/papers/BiereArthoSchuppan-FMICS02.pdf">Liveness Checking as Safety Checking</a>. I had read the article and the instrumentation I described was inspired by it but I wasn't sure I understood the article well enough to claim that I was using exactly Biere Artho and Schuppan's idea. It turns out I was pretty much.</p> - <p>In a <a href="/index.php?post/2012/08/22/Proving-%28F-oW%29-true-or-false%3A-alternative-method">recent post</a> I showed how to use Frama-C's value analysis to prove a particular liveness property true or false of a particular C program.</p> <p>My colleague Sébastien Bardin reliably informs me that the ideas for reducing a liveness property to a reachability property were all in the article <a href="http://staff.aist.go.jp/c.artho/papers/BiereArthoSchuppan-FMICS02.pdf">Liveness Checking as Safety Checking</a>. I had read the article and the instrumentation I described was inspired by it but I wasn't sure I understood the article well enough to claim that I was using exactly Biere Artho and Schuppan's idea. It turns out I was pretty much.</p> {% endraw %} diff --git a/_posts/2012-09-19-Never-forget-to-sanitize-your-input.html b/_posts/2012-09-19-Never-forget-to-sanitize-your-input.html index 5ab200763da5984daf5da5c9f19ce7d90a60071a..9333952354468dcf1e67b1e9228ebf96f3ce225c 100644 --- a/_posts/2012-09-19-Never-forget-to-sanitize-your-input.html +++ b/_posts/2012-09-19-Never-forget-to-sanitize-your-input.html @@ -38,36 +38,5 @@ void test(int c) { + (protect !Ast_printer.d_exp) e </pre> <p>Using this new version of the script <code>frama-c -load-script cfg_print_escape.ml test.c && dot -Tpng -O cfg.out</code> produces a better result: -<img src="/assets/img/blog/imported-posts/.cfg_string_cst_correct_m.jpg" alt="cfg_string_cst_correct.png" style="display:block; margin:0 auto;" title="cfg_string_cst_correct.png sept. 2012" /></p> - <p>This post is a follow up of this <a href="/cfg/developer/visitor/2012/09/04/Extracting-information-from-Frama-C-programmatically">one</a></p> -<p>A facetious colleague pointed out to me that the <code>print_stmt</code> function that is used to display the CFG in the post mentioned above behaves incorrectly when used over code that include string constants such as the one below:</p> -<pre>void f(const char *); -void test(int c) { - if ("A random string"[c]=='s') f("Hello world"); else f("Goodbye"); -} -</pre> -<p>Namely poor <code>dot</code> is a little bit confused by all these double quotes occurring in labels that are themselves delimited by double quotes. It manages to output something but the result is not really satisfying: -<img src="/assets/img/blog/imported-posts/.cfg_string_cst_m.jpg" alt="cfg_string_cst.png" style="display:block; margin:0 auto;" title="cfg_string_cst.png sept. 2012" /></p> -<p>Thus it looks as though the first improvement to our little script will be to have a more robust pretty-printing function for statements. Basically we have to escape those pesky double quotes that might appear when pretty-printing a C expression. Fortunately OCaml's Printf (hence Format) module does know how to do this with the <code>"%S"</code> directive. There's one drawback though: this directive will also put (unescaped) double quotes at the beginning and end of the result that we'll have to get rid of. In the end the escaping function is the following:</p> -<pre>let protect pretty chan v = - let s = Pretty_utils.sfprintf "%a" pretty v in - let s = Pretty_utils.sfprintf "%S" s in - Format.pp_print_string chan (String.sub s 1 (String.length s - 2)) -</pre> -<p>First we create a string containing the the unescaped output. <code>Pretty_utils.sfprintf</code> is a Frama-C function that is analogous to <code>Format.sprintf</code> except that 1) it can be fed with the same pretty-printing functions as <code>fprintf</code> when there is a custom <code>"%a"</code> directive and 2) each call uses its own internal buffer avoiding subtle flushing issues. Second we escape all the inner double quotes. Finally we output the result except for the first and last characters that by definition of <code>"%S"</code> are double quotes.</p> -<p>We can now use <code>protect</code> in <code>print_stmt</code> each time there might be an issue (the complete file is available <a href="/assets/img/blog/imported-posts/cfg_print_escape.ml">here</a>):</p> -<pre> let print_stmt out = - function -- | Instr i -> !Ast_printer.d_instr out i -+ | Instr i -> protect !Ast_printer.d_instr out i -... -- | If (e _ _ _) -> Format.fprintf out "if %a" !Ast_printer.d_exp e -- | Switch(e _ _ _) -> Format.fprintf out "switch %a" !Ast_printer.d_exp e -+ | If (e _ _ _) -> Format.fprintf out "if %a" (protect !Ast_printer.d_exp) e -+ | Switch(e _ _ _) -> -+ Format.fprintf out "switch %a" -+ (protect !Ast_printer.d_exp) e -</pre> -<p>Using this new version of the script <code>frama-c -load-script cfg_print_escape.ml test.c && dot -Tpng -O cfg.out</code> produces a better result: <img src="/assets/img/blog/imported-posts/.cfg_string_cst_correct_m.jpg" alt="cfg_string_cst_correct.png" style="display:block; margin:0 auto;" title="cfg_string_cst_correct.png sept. 2012" /></p> {% endraw %} diff --git a/_posts/2012-09-30-A-proposal-for-named-constants-in-C.html b/_posts/2012-09-30-A-proposal-for-named-constants-in-C.html index 36ea7f6e5dfd55c774154ece84a9349c44f73789..61eed76d01f89e9f51d553265585a0d77251349e 100644 --- a/_posts/2012-09-30-A-proposal-for-named-constants-in-C.html +++ b/_posts/2012-09-30-A-proposal-for-named-constants-in-C.html @@ -10,8 +10,5 @@ summary: {% raw %} <p>If you liked my earlier proposal for a finer-grained <code>restrict</code> (<a href="/index.php?post/2012/07/25/On-the-redundancy-of-C99-s-restrict">1</a> <a href="/undefined/behavior/2012/07/25/The-previous-post-was-written-in-jest">2</a> <a href="/acsl/memcpy/restrict/2012/07/25/The-restrict-qualifier-as-an-element-of-specification">3</a> <a href="/index.php?post/2012/08/02/restrict-not-modular">4</a>) you might like this slightly more serious <a href="https://gustedt.wordpress.com/2012/08/17/named-constants/">proposal for named constants in C</a> on Jens Gustedt's blog.</p> <p>Or not. -Here is a simple test to tell if you are likely to be interested: if you can readily discuss the relative advantages of <code>const int C=1;</code> <code>#define C 1</code> and <code>enum { C = 1 };</code> you will probably find Jens' proposal for arbitrary types fascinating.</p> - <p>If you liked my earlier proposal for a finer-grained <code>restrict</code> (<a href="/index.php?post/2012/07/25/On-the-redundancy-of-C99-s-restrict">1</a> <a href="/undefined/behavior/2012/07/25/The-previous-post-was-written-in-jest">2</a> <a href="/acsl/memcpy/restrict/2012/07/25/The-restrict-qualifier-as-an-element-of-specification">3</a> <a href="/index.php?post/2012/08/02/restrict-not-modular">4</a>) you might like this slightly more serious <a href="https://gustedt.wordpress.com/2012/08/17/named-constants/">proposal for named constants in C</a> on Jens Gustedt's blog.</p> -<p>Or not. Here is a simple test to tell if you are likely to be interested: if you can readily discuss the relative advantages of <code>const int C=1;</code> <code>#define C 1</code> and <code>enum { C = 1 };</code> you will probably find Jens' proposal for arbitrary types fascinating.</p> {% endraw %} diff --git a/_posts/2012-10-02-RERS-2012-competition-our-solutions-for-problems-1-9.html b/_posts/2012-10-02-RERS-2012-competition-our-solutions-for-problems-1-9.html index 1ef7ec42cb34cc3fbf5020f75435c56e4d1b77a8..d12b3e85fb58fc1ea203173b5a631d0e3b566cd6 100644 --- a/_posts/2012-10-02-RERS-2012-competition-our-solutions-for-problems-1-9.html +++ b/_posts/2012-10-02-RERS-2012-competition-our-solutions-for-problems-1-9.html @@ -124,122 +124,5 @@ we considered that input and corresponding output are simultaneous. Both are pas <blockquote><p>This discussion gives me an idea for a powerful static analysis tool. I will call it <a href="http://en.wikipedia.org/wiki/Marvin_the_Paranoid_Android">Marvin</a>. You ask it “Is this software safe? Can this dangerous angle be reached?†and it answers “Who cares? The Sun is going to blow up in five billion years. Good riddance if you ask me. Oh god I'm so depressed…â€</p> </blockquote> <h2>Thanks</h2> -<p>As the initiator of this attempt to participate to the competition I would like to thank my colleagues Virgile Prevosto Boris Yakobowski and Sébastien Bardin from whom I personally learnt a lot about various aspects of software verification; my warmest thanks are for the organizers of the 2012 RERS Grey Box Challenge.</p> - <h2>Previously on this blog</h2> -<p>Although it was so brief that you may have missed it, I previously mentioned here the <a href="http://leo.cs.tu-dortmund.de:8100/isola2012/index.php?page=home">2012 RERS Grey Box Challenge</a> an interesting competition where the questions involve programs in C syntax.</p> -<p>I pointed out that some questions were about the reachability of assertions in the programs. As it is documented Frama-C's value analysis can guarantee that some assertions are not reachable. When its authors are using it they can ascertain that no approximation is taking place and that for this reason any assertion that the analysis diagnoses as perhaps reachable is indeed reachable for some sequence of inputs. Because of the way it work the analysis is unable to exhibit the sequence of inputs but one such sequence definitely exist.</p> -<p>We then moved on to properties expressed as LTL formulas. Some of the LTL formulas in the competition <a href="/index.php?post/2012/08/20/Participating-in-the-RERS-2012-competition%3A-reachability-questions">expressed reachability properties</a>. It was easy to diagnose those by applying Frama-C's value analysis to an instrumented program. The other properties were more difficult liveness properties. With more instrumentation <a href="/index.php?post/2012/08/22/Proving-%28F-oW%29-true-or-false%3A-alternative-method">involving either a transition counter or a non-deterministic predecessor state</a> it was possible to diagnose these too using the value analysis.</p> -<blockquote><p>Colleagues and I have obtained solutions for all properties in the initial problems 1-9 of the competition. More information about these solutions is available in the last part of this post. First now that the exercise is done I would like to revisit its benefits.</p> -</blockquote> -<h2>Features gained bugs fixed</h2> -<h3>New built-in Frama_C_interval_split()</h3> -<p>A key part of the <code>main()</code> function used for the verification of any kind of property in the competition was:</p> -<pre> input = unknown_int(); - /*@ assert input == 1 || input == 2 || input == 3 || - input == 4 || input == 5 || input == 6 ; */ -</pre> -<p>These three lines are intended to replace the following one in the original <code>main()</code> function provided by the organizers. Their line works for interactive sessions where the operator inputs number in the range 1..6.</p> -<pre> scanf("%d" &input); -</pre> -<p>The call to <code>unknown_int()</code> could also have been <code>Frama_C_interval(1 6)</code>. Then the value analysis would be able to tell that the assertion is not an assumption only a hint. Regardless the assertion is there together with option <code>-slevel</code> to make the analyzer study separately what happens in executions where a different value is read for <code>input</code>.</p> -<p>This is a classic trick used in many earlier studies. It is mentioned in <a href="/index.php?post/2011/06/02/Skein-7">the study of the Skein-256 hash function</a> and in nearly all others since. Still these assertions do get tiring to write when many cases need to be listed. Until now there was no shortcut (I have been using Emacs macros myself).</p> -<p>Enter <code>Frama_C_interval_split(l u)</code>. It does the same thing that <code>Frama_C_interval(l u)</code> does but it automatically causes the individual values between <code>l</code> and <code>u</code> inclusive to be propagated separately without need for a laborious ACSL assertion. -The <code>Frama_C_interval_split()</code> built-in is available in Oxygen (I think) and since it is a true value analysis built-in the user does not need to remember to include file <code>builtin.c</code> to make it accessible. A simple prototype <code>int Frama_C_interval_split(int int);</code> will do.</p> -<h3>The informational message “unrolling up to ... states†could be off</h3> -<p>If you have used option <code>-slevel</code> (and as previously said if you use Frama-C's value analysis at all you should definitely use this option from time to time) you know that it sometimes logs a message to tell how much superposition has been done on a same program statement. It looks like:</p> -<pre>... -[value] Semantic level unrolling superposing up to 100 states -... -[value] Semantic level unrolling superposing up to 200 states -... -</pre> -<p>The algorithm that takes care of this message was like this:</p> -<pre> target := 100; - if new number of states attached to the statement ≥ target - then - print "Semantic level unrolling superposing up to " target " states" - target := target + 100 - endif -</pre> -<p>The intention was that the value displayed would indicate the maximum number of superposed states to the nearest hundred.</p> -<p>Suppose the first wave of propagated states to reach a statement contains a thousand of them. The algorithm displays “superposing up to 100 states†and updates the target to 200. If the second wave contains 2500 more states the algorithm then displays “superposing up to 200 states†and updates the target to 300. And so on. If states keep arriving in large numbers variable <code>target</code> gets irremediably behind.</p> -<p>This had not been noticed until this competition but in model-checking mode manipulating tons of states <code>target</code> never gets a chance to catch up and the number displayed can be much lower than the number of states actually superposed.</p> -<p>This bug is present in Frama_C Oxygen. It is fixed in the development version.</p> -<h3>An unnamed option was tested more thoroughly</h3> -<p>Last but proverbially not least thanks to this competition the value analysis option that <a href="/derived/analysis/rers2012/value/2012/09/06/A-value-analysis-option-to-reuse-previous-function-analyses">caches</a> previous analyses of a function call in order to re-use them without loss of precision has received more testing. Who knows someday we may even trust it enough to reveal its name.</p> -<h2>Conclusion</h2> -<p>The next section describes our solutions. If you did not at least attempt the competition yourself it is unlikely that you will find it interesting: you should stop reading now. Here is my personal conclusion before you go: case studies are fun and model-checking is a fun sub-field of computer science. At the same time a piece of software is not an automaton: if you try to specify one as if it was the other you will certainly make mistakes and verify something other than you intended. I think that our experience trying to participate in the competition demonstrates that. If you are not convinced please try to answer the competition's questions for yourself and then and only then read the next section.</p> -<h2>Our solutions to the 2012 RERS challenge</h2> -<h3>Description</h3> -<p>The reachability of assertions is straightforward to answer with the value analysis so I won't describe that. -Here is an <a href="/assets/img/blog/imported-posts/eca-automatic.tgz">archive</a> containing our answers for the LTL properties part. The archive contains mostly everything. Many files there were generated from others. In particular the *.log files are analysis log files that took about one core-month to generate on a 2.66 GHz Intel Xeon X5650 workstation. The last file to be generated was “resultsâ€. It contains the predicted statuses of properties as interpreted with the conventions that follow.</p> -<p>A specific LTL property for a specific problem is checked by putting together the problem's transition function (function <code>calculate_output()</code> and its callees) a file <code>buchimgt.c</code> specific to the problem (this file contains the definition of the predecessor state and functions that manipulate it) a file <code>main.c</code> that contains a generic main loop and a file such as <code>output Z occurs after output U until output W.c</code> that is specific to a property (but independent of the problem to which it is linked).</p> -<p>The problem-specific files are generated by the script <code>genallproblemfiles</code>.</p> -<p>The property-specific files such as <code>output Z occurs after output U until output W.c</code> were generated from templates such as <code>output _ occurs after output _ until output _.c</code>. The templates were hand-crafted by my colleague Sébastien Bardin to work together with the rest of the instrumentation.</p> -<p>The current status of the LTL property is maintained by an automaton designed for this kind of work (called a Büchi automaton). -The generic <code>main()</code> function describes our interpretation of the problem. In pseudo-code:</p> -<pre>forever - read input 1..6 - compute output from input and current state - compute transition in Büchi automaton from input and output - if the current trace can no longer fail to satisfy the property - prune - if the current trace can no longer satisfy the property - display current state for verification - abort analysis - non-deterministically update predecessor state -</pre> -<p>The actual C file is designed so that the value analysis will remain complete as well as sound when analyzing it with high <code>-slevel</code>. A secondary objective is for the analysis to be as fast as possible despite current limitations. Readability only ranks third as an objective.</p> -<p>Still regardless of the strange structure of the program it is basically C. Any C programmer can read the <code>main()</code> and understand what is being verified. The only non-standard function is <code>Frama_C_interval_split()</code>. The informal description of <code>Frama_C_interval_split()</code> is that the function returns a value between the bounds passed to it and that the results provided by the analyzer hold for all values that it can return. -If a simple Büchi automaton is plugged in that fails when output <code>Z</code> is emitted it is relatively easy to understand on the basis of this <code>main()</code> function what we mean by “<code>Z</code> is emitted†and that <code>Z</code> can never be emitted if the analysis passes without the automaton raising a flag. This is how we can verify as an example the LTL property <code>G !oZ</code>.</p> -<p>As you can see on the pseudo-code the Büchi automaton is updated with an input and the corresponding computed output which are considered simultaneous. When <code>calculate_output()</code> fails to return an output because of a failed assertion no pair <code>(input output)</code> is presented to the automaton. To illustrate consider the hypothetical property "output X occurs before -input A". This property is weird because each input A-F can happen at each instant including the first one. It may seem that the property is tautologically false. -With our interpretation this property would be true if the system always failed the instant it read A until it had output X. These inputs would not count because the Büchi automaton would not see them.</p> -<p>The above is what we considered the most reasonable interpretation of what the competition organizers intended at the time we sent our answers. On October 1 the organizers published example solutions that made us realize that they intended something else and we had to retract our participation.</p> -<h3>Differences with the official interpretation and remaining unknowns</h3> -<p>As the challenge period was coming to a close organizers published solutions to additional problems 10 and 11 (the challenge was supposed to close at the end of September. The solutions illustrating the semantics were published on October 1 and the deadline extended).</p> -<p>One can only assume that these solutions also define the semantics of LTL formulas for problems 1-9 since no example is available for these. Unfortunately there are subtle differences between the two families of programs.</p> -<h5>Outputs corresponding to invalid inputs</h5> -<p>The transition functions in problems 1-9 can return -1 or -2. They only return -2 when the rest of the program state was unchanged. The organizers communicated to us that traces in which -2 is emitted indefinitely should be ignored:</p> -<p><q>The same holds by the way for invalid inputs i.e. calculate_output returning 2 [sic]. They are not meant to be part of the traces that LTL properties talk about - a liveness property such as F oW hence does not become false alone by infinitely often executing an invalid input.</q></p> -<p>I did not see this last point made explicit on the website.</p> -<p>For problems 1-9 <strong>since the program state is unchanged when -2 is returned</strong> it seems that the easiest way to comply is to treat -2 as a fatal error that interrupts the trace. We do not lose much of importance in doing so because any trace with -2 outputs can be shortened into a trace without these outputs. We do lose some inputs during such a shortening so it is still slightly invasive and we would like to be sure that this is what the organizers intended. Indeed the <code>main()</code> function provided by the organizers does seem to treat -1 and -2 differently and does call the inputs that lead to -2 “invalidâ€.</p> -<pre> if(output == -2) - fprintf(stderr "Invalid input: %d" input); - else if(output != -1) - printf("%d" output); -</pre> -<p>The code above matches more or less the “if an unexpected input event is provided an error message is printed and the ECA system terminates†statement on the competition's <a href="http://leo.cs.tu-dortmund.de:8100/isola2012/index.php?page=problems">website</a>. The code above does not stop on -2 but it seems clear that the “unexpected input†from the explanation is the -2 from the code and that as informally stated it interrupts the current trace.</p> -<p>You might expect programs 10-13 to follow the same pattern but it turns out that instead of sometimes -1 and sometimes -2 they always return -2 both when the program state has been changed by the transition function and when it hasn't. You might still hope to interpret -2 as “error†but in programs 10 and 11 it happens in the middle of traces that are given as example for the questions on the reachability of assertions. -The <a href="http://leo.cs.tu-dortmund.de:8100/isola2012/examples/new/small-easy/Problem10-solutions.txt">solution page</a> says:</p> -<pre>error_46 reachable via input sequence -[E A] -</pre> -<p>And when you try it:</p> -<pre>$ gcc Problem10.c -$ ./a.out -5 -Invalid input: 5 -1 -Assertion failed: (0) function calculate_output file Problem10.c line 66. -Abort trap -</pre> -<p>So it does not look that -2 should be treated as an error after all. In the above organizer-provided trace the error caused by input 5 (E) does not make <code>error_46</code> unreachable (actually I have it on good authority that error_46 is unreachable when in the transition function <code>return -2;</code> is treated as a trace-interrupting error).</p> -<p>In conclusion for problems 1-9 we treated -1 as just another output letter and -2 as a trace-interrupting error. This does not correspond to what the organizers did in their example solutions to problem 10. We still do not know what the organizers intended. -The transition function returning -2 instead of -1 in problems 10-13 seems particularly inscrutable when the organizers have previously told us by e-mail to ignore the traces with finitely many non-(-2) outputs.</p> -<p>Our aforelinked solutions were computed with this convention. We provide them in case someone wants to use the same convention and compare their results to ours.</p> -<h5>Are inputs and outputs simultaneous or are they different events?</h5> -<p>Again we have no idea. In our modelization the output happens at the same time as the input it was computed from.</p> -<p>But in example traces provided by the organizers it looks like they are distinct events!! An example trace is <code>[iD oV iB] ([oY iC oV iB])*</code>.</p> -<p>But if input and output are separate events why is the first LTL formula for problem 10 expressed as <code>(! iA WU (oU & ! iA))</code> ? -The atom <code>(oU & ! iA)</code> makes no sense because if the event is any sort of output event (<code>U</code> or another) then it cannot be an input event. The atom <code>(oU & ! iA)</code> is just equivalent to <code>oU</code>. All LTL properties that talk about inputs and outputs in the same instant are similarly nonsensical.</p> -<p>In our solutions influenced by the shape of the competition's LTL formulas which talk about input and output in the same instant -we considered that input and corresponding output are simultaneous. Both are passed to the Büchi automaton at the time of computing a transition. An input can happen together with the output -1. If the transition function aborts because of an assertion or returns -2 then the input is not seen by the Büchi automaton (in the case of the -2 output this would be easy to change by modifying the <code>main()</code> function. The trace could be interrupted just after the Büchi automaton transition instead of just before).</p> -<h5>Is there any reachability LTL property at all in the competition?</h5> -<p>The example solutions all provide infinite traces as counter-examples. This is consistent with the explanation “an LTL property holds for a certain ECA program if and only if all possible runs which do not lead to an error satisfy the LTL property†but it is a very strange way to approach reachability questions (which indeed are no longer reachability questions at all). To answer a LTL question that would ordinarily have been a reachability question such as “output <code>W</code> occurs at most twice†in this setting one must when <code>W</code> has been encountered three times on a trace wonder whether this trace is the prefix of at least one infinite trace. If there is a sequence of inputs that keeps the trace alive then the trace is a counter-example. If all inputs that can be added to extend to this prefix eventually lead to an error even if it is at a very far horizon then the trace is not a counter-example (remember not to take into account the trace that indefinitely outputs -2 when trying to answer this sub-question).</p> -<p>In short in this setting no LTL formula ever expresses a reachability property. It does not prevent us to handle these LTL properties (Sébastien assures me that our method theoretically handles all liveness properties. We certainly handle those that are already liveness properties without the weird “all possible runs that do not lead to an error†quantification).</p> -<blockquote><p>This discussion gives me an idea for a powerful static analysis tool. I will call it <a href="http://en.wikipedia.org/wiki/Marvin_the_Paranoid_Android">Marvin</a>. You ask it “Is this software safe? Can this dangerous angle be reached?†and it answers “Who cares? The Sun is going to blow up in five billion years. Good riddance if you ask me. Oh god I'm so depressed…â€</p> -</blockquote> -<h2>Thanks</h2> <p>As the initiator of this attempt to participate to the competition I would like to thank my colleagues Virgile Prevosto Boris Yakobowski and Sébastien Bardin from whom I personally learnt a lot about various aspects of software verification; my warmest thanks are for the organizers of the 2012 RERS Grey Box Challenge.</p> {% endraw %} diff --git a/_posts/2012-10-02-StackOverflow-answers-everything.html b/_posts/2012-10-02-StackOverflow-answers-everything.html index 80465bd210174c26c083efddd2a4e7e55091102d..99a28323d63605ce6f05c0a960d070cba5b96981 100644 --- a/_posts/2012-10-02-StackOverflow-answers-everything.html +++ b/_posts/2012-10-02-StackOverflow-answers-everything.html @@ -14,12 +14,5 @@ summary: printf(\%p" p); </pre> <p>The programming Q&A website StackOverflow had never failed me before so I asked there. Lo and behold less than 24 hours later a very reasonable explanation <a href="http://stackoverflow.com/q/12676411/139746">appeared</a>.</p> -<p>I would like to thank my colleague Virgile Prevosto for answering my question on StackOverflow.</p> - <p>One thing leading to another, I recently ended up wondering why, according to an individual close to the situation, the C snippet below is considered defined in C99.</p> -<pre> struct X { int a[5]; } f(); - int *p = f().a; - printf(\%p" p); -</pre> -<p>The programming Q&A website StackOverflow had never failed me before so I asked there. Lo and behold less than 24 hours later a very reasonable explanation <a href="http://stackoverflow.com/q/12676411/139746">appeared</a>.</p> <p>I would like to thank my colleague Virgile Prevosto for answering my question on StackOverflow.</p> {% endraw %} diff --git a/_posts/2012-10-08-September-in-security.html b/_posts/2012-10-08-September-in-security.html index b7e2ceefd895d08bbe46efbd92ad28df79cc4271..7adc06853721e9ce8e7da13013adf3f489f3a506 100644 --- a/_posts/2012-10-08-September-in-security.html +++ b/_posts/2012-10-08-September-in-security.html @@ -15,13 +15,5 @@ summary: <li>Security <a href="http://www.zdnet.com/oracle-issues-major-java-security-fix-recommends-immediate-action-7000003517/">vulnerability</a> after security <a href="http://www.forbes.com/sites/andygreenberg/2012/08/31/oracles-java-security-woes-mount-as-researchers-spot-a-bug-in-its-critical-bug-fix/">vulnerability</a> were found in Oracle's Java. These appear to allow a malicious website to plant malware on an unsuspecting user's computer who navigates to the wrong webpage.</li> <li>Security vulnerabilities were <a href="http://www.theverge.com/2012/9/18/3351076/internet-explorer-zero-day-vulnerability">found</a> in various versions of Internet Explorer. Again navigate to the wrong webpage and malware gets installed on your computer.</li> </ol> -<p>What do all these items have in common? Firstly impact: many people have an iPhone or use Internet Explorer as web browser. They may not know what Java is but it is likely to be enabled in whatever browser they use—many internet banking sites rely on it for instance. Secondly the listed vulnerabilities all made headlines in September 2012.</p> - <p>October is <a href="http://en.wikipedia.org/wiki/National_Cyber_Security_Awareness_Month">National Cyber Security Awareness Month</a> (if you are in the United States; otherwise it is Another Country's Cyber Security Awareness Month).</p> -<p>In celebration here is a short list of recent cyber-security failures:</p> -<ol> -<li>An iPhone user navigating to a malicious webpage can see <a href="http://en.wikipedia.org/wiki/Spivak_pronoun">eir</a> personal information (address book browsing history photos …) <a href="http://thenextweb.com/apple/2012/09/19/dutch-security-researchers-hack-apple-iphone-4s-exploiting-safari/">revealed</a> to the attacker.</li> -<li>Security <a href="http://www.zdnet.com/oracle-issues-major-java-security-fix-recommends-immediate-action-7000003517/">vulnerability</a> after security <a href="http://www.forbes.com/sites/andygreenberg/2012/08/31/oracles-java-security-woes-mount-as-researchers-spot-a-bug-in-its-critical-bug-fix/">vulnerability</a> were found in Oracle's Java. These appear to allow a malicious website to plant malware on an unsuspecting user's computer who navigates to the wrong webpage.</li> -<li>Security vulnerabilities were <a href="http://www.theverge.com/2012/9/18/3351076/internet-explorer-zero-day-vulnerability">found</a> in various versions of Internet Explorer. Again navigate to the wrong webpage and malware gets installed on your computer.</li> -</ol> <p>What do all these items have in common? Firstly impact: many people have an iPhone or use Internet Explorer as web browser. They may not know what Java is but it is likely to be enabled in whatever browser they use—many internet banking sites rely on it for instance. Secondly the listed vulnerabilities all made headlines in September 2012.</p> {% endraw %} diff --git a/_posts/2012-10-16-Exact-Gap-Computation-for-Code-Coverage-Metrics-in-ISO-C.html b/_posts/2012-10-16-Exact-Gap-Computation-for-Code-Coverage-Metrics-in-ISO-C.html index 1ddf86b312ee86b3fb95fd5d7eeb48b176da5a86..301eb5af12a47f995c949d3ae32ca92eb991a391 100644 --- a/_posts/2012-10-16-Exact-Gap-Computation-for-Code-Coverage-Metrics-in-ISO-C.html +++ b/_posts/2012-10-16-Exact-Gap-Computation-for-Code-Coverage-Metrics-in-ISO-C.html @@ -224,221 +224,5 @@ error_56: assert(0); error_53: assert(0); error_47: assert(0); error_59: assert(0); -error_8: assert(0);</pre>" <h2>Comparing static analysis tools is (still) difficult</h2> -<p>Earlier this year of 2012, some of my colleagues and I took the opportunity to point out that, as a research community, we are not doing a satisfactory job of <a href="http://blog.frama-c.com/index.php?post/2012/04/29/Benchmarking">comparing static analysis tools</a>. This article and blog post were concerned with independent third-party comparisons. Another context in which each of us can be lead to do comparisons and to try to be as objective as possible is the “related work†section of any traditional non-benchmark article.</p> -<h2>“Related work†sections</h2> -<p>Dirk Richter and Christian Berg have designed a <a href="http://www.drgames.onpw.de/dl/mbt12.pdf" rel="nofollow">technique</a> that apparently it makes some sense to compare to what Frama-C's value analysis allows. Here is their summary of their comparison between their tool and the value analysis:</p> -<blockquote><p>No sophisticated examples can be handled by Frama-C’s value analysis. Some of the examples tested even cause runtime-errors in Frama-C itself thus it is not reliable.</p> -</blockquote> -<p>Richter and Berg's technique appears to tackle the problem of estimating how much code must actually be covered for all the code that can be covered to have been covered.</p> -<p>Frankly it seems to me that the researchers should be comparing their tool to existing test-generation tools. They are much closer in objectives and in the means deployed to reach these objectives. One such tool that I know of because it is developped locally is <a href="http://pathcrawler-online.com/">PathCrawler</a>. I am sure there are plenty of others. -I am not sure why they spend a paragraph on Frama-C's value analysis when it is absolutely not documented as trying to do this.</p> -<h2>Possible comparisons</h2> -<p>However I <strong>am</strong> interested in tool comparisons so this is a good opportunity to understand how these comparisons work and how we can make them better.</p> -<br /> -<p>First the claim “No sophisticated examples can be handled by Frama-C’s value analysis†is interesting because of course what really kills advanced techniques in practice is that they do not scale to even moderate size programs. The authors point out that their own work may only be “practical†for embedded systems. Coincidentally Frama-C's value analysis was designed to work well on embedded code too since we too felt this was a domain where practicality was within reach. This makes me curious as to what embedded code examples the authors experimented on before reaching their conclusion. If these examples reveal weaknesses in Frama-C's value analysis <strong>on embedded code</strong> we would definitely like to hear about them. I would summarize this into one additional item that we did not list in our “Benchmarking static analyzers†<a href="https://www.dropbox.com/s/el2lidf5v71ogm6/p.pdf">article</a> (although it was implict in other recommendations we did list): when doing comparisons conditions should be made explicit and input programs should be made available. Here this would mean providing the Frama-C version and commandline in addition to the test programs themselves. For such programs and commandline that “cause runtime-errors in Frama-C itself†a good place to provide them is our <a href="http://bts.frama-c.com/">Bug Tracking System</a>. Instructions for reporting a bug are displayed on crashes. Otherwise a tarball with all the embedded C code examples the authors used would be fine. A URL could be provided in the article.</p> -<br /> -<p>Second the authors claim that Frama-C is not reliable. This makes me want to investigate because precisely in 2012 we published a peer-reviewed <a href="/index.php?pages/Csmith-testing">article</a> on the subject “Frama-C is reliable here is how we used random program generation to make it soâ€. I am eager to get my paws on the authors' implementation so as to evaluate its reliability since this is supposed to be one aspect where it does better. Unfortunately the implementation does not appear to be available yet.</p> -<br /> -<p>Third it is always a difficult exercise to compare one's own tool to a different unfamiliar one. One risks ending up with a slightly unfair conclusion even if one tries one's hardest to be objective. I was remarking about the difficulty of finding “fair†inputs for the comparison of static analyzers in another <a href="/benchmarks/floating-point/position/value/2011/11/25/Static-analysis-tools-comparisons">previous post</a>. The difficulty for static analyzers is that inputs are programs: programming languages are so expressive that two programs even in the same language can differ widely.</p> -<p>There as a remedy I suggested tool authors first try their own tool on the programs that the other analyzer works well on. For someone working on another technique and unfamiliar with the strengths and weaknesses of Frama-C's value analysis Csmith-generated examples are one obvious possibility. Another possibility would be to use the programs in the <a href="http://leo.cs.tu-dortmund.de:8100/isola2012/index.php?page=download">2012 RERS challenge</a>. These programs contains <code>assert(0);</code> calls and for each an objective is to tell whether it is reachable. This seems to me to be the same question as whether a test suite needs to cover the <code>assert(0);</code> call. The good news is that both on Csmith-generated programs and in the RERS challenge Frama-C's value analysis can be made to be both sound and complete just like Richter and Berg claim their technique is. It should be simple and informative to compare the results of their tool to the results obtained with the value analysis then. Below are our solutions for problems 1-9.</p> -<h2>Reachable assertions in problems 1-9 of the RERS competition</h2> -<p>Below are a list of reachable lines for each problem. The assert(0) calls -not listed are unreachable.</p> -<p>Problem1.c</p> -<pre>error_20: assert(0); -error_47: assert(0); -error_32: assert(0); -error_37: assert(0); -error_56: assert(0); -error_33: assert(0); -error_57: assert(0); -error_50: assert(0); -error_35: assert(0); -error_15: assert(0); -error_38: assert(0); -error_21: assert(0); -error_44: assert(0); -globalError: assert(0);</pre> -<p>Problem2.c</p> -<pre>error_50: assert(0); -error_45: assert(0); -error_59: assert(0); -globalError: assert(0); -error_43: assert(0); -error_13: assert(0); -error_16: assert(0); -error_44: assert(0);</pre> -<p>Problem3.c</p> -<pre>error_45: assert(0); -error_35: assert(0); -error_52: assert(0); -error_39: assert(0); -error_9: assert(0); -error_37: assert(0); -error_43: assert(0); -error_31: assert(0); -error_28: assert(0); -error_27: assert(0); -error_50: assert(0); -error_13: assert(0); -error_26: assert(0); -globalError: assert(0);</pre> -<p>Problem4.c</p> -<pre>error_12: assert(0); -error_19: assert(0); -error_31: assert(0); -error_39: assert(0); -error_52: assert(0); -error_6: assert(0); -error_58: assert(0); -error_40: assert(0); -error_4: assert(0); -error_38: assert(0); -error_45: assert(0); -error_11: assert(0); -error_26: assert(0); -globalError: assert(0); -error_9: assert(0); -error_17: assert(0); -error_32: assert(0); -error_35: assert(0); -error_55: assert(0); -error_36: assert(0); -error_14: assert(0); -error_18: assert(0); -error_13: assert(0); -error_15: assert(0); -error_27: assert(0);</pre> -<p>Problem5.c</p> -<pre>error_0: assert(0); -error_38: assert(0); -error_57: assert(0); -error_55: assert(0); -error_58: assert(0); -error_32: assert(0); -error_13: assert(0); -error_51: assert(0); -error_33: assert(0); -error_48: assert(0); -error_18: assert(0); -error_39: assert(0); -error_1: assert(0); -error_41: assert(0); -error_37: assert(0); -globalError: assert(0); -error_11: assert(0); -error_26: assert(0); -error_15: assert(0); -error_40: assert(0); -error_36: assert(0); -error_44: assert(0); -error_30: assert(0); -error_47: assert(0); -error_24: assert(0);</pre> -<p>Problem6.c</p> -<pre>error_12: assert(0); -error_21: assert(0); -error_11: assert(0); -error_44: assert(0); -error_1: assert(0); -error_36: assert(0); -error_0: assert(0); -error_2: assert(0); -error_38: assert(0); -error_48: assert(0); -error_37: assert(0); -error_4: assert(0); -error_59: assert(0); -error_10: assert(0); -error_20: assert(0); -error_5: assert(0); -error_15: assert(0); -error_27: assert(0); -error_33: assert(0); -error_9: assert(0); -error_29: assert(0); -error_47: assert(0); -error_56: assert(0); -error_24: assert(0); -error_58: assert(0); -globalError: assert(0);</pre> -<p>Problem7.c</p> -<pre>error_58: assert(0); -error_47: assert(0); -error_5: assert(0); -error_48: assert(0); -error_19: assert(0); -error_39: assert(0); -error_36: assert(0); -error_40: assert(0); -error_35: assert(0); -error_31: assert(0); -error_9: assert(0); -error_42: assert(0); -error_7: assert(0); -globalError: assert(0); -error_11: assert(0); -error_20: assert(0); -error_44: assert(0); -error_46: assert(0); -error_18: assert(0); -error_6: assert(0); -error_23: assert(0); -error_30: assert(0); -error_3: assert(0); -error_37: assert(0); -error_15: assert(0);</pre> -<p>Problem8.c</p> -<pre>error_48: assert(0); -error_2: assert(0); -error_49: assert(0); -error_15: assert(0); -error_7: assert(0); -error_55: assert(0); -error_51: assert(0); -error_50: assert(0); -error_43: assert(0); -error_10: assert(0); -error_29: assert(0); -error_24: assert(0); -error_1: assert(0); -error_26: assert(0); -error_6: assert(0); -error_5: assert(0); -error_46: assert(0); -error_13: assert(0); -error_4: assert(0); -error_37: assert(0); -globalError: assert(0); -error_34: assert(0); -error_25: assert(0); -error_28: assert(0); -error_59: assert(0);</pre> -<p>Problem9.c:</p> -<pre>error_46: assert(0); -error_57: assert(0); -error_36: assert(0); -error_19: assert(0); -error_6: assert(0); -error_10: assert(0); -error_34: assert(0); -error_15: assert(0); -error_32: assert(0); -error_41: assert(0); -error_11: assert(0); -error_35: assert(0); -error_2: assert(0); -error_20: assert(0); -error_3: assert(0); -globalError: assert(0); -error_44: assert(0); -error_38: assert(0); -error_51: assert(0); -error_54: assert(0); -error_56: assert(0); -error_53: assert(0); -error_47: assert(0); -error_59: assert(0); -error_8: assert(0);</pre>" +error_8: assert(0);</pre>" {% endraw %} diff --git a/_posts/2012-10-30-October-in-security.html b/_posts/2012-10-30-October-in-security.html index 4dffb9866f4bf161e17e26b55cf4fb70745259ba..707fcbe4aaa1c512f004ada143342a19380182dd 100644 --- a/_posts/2012-10-30-October-in-security.html +++ b/_posts/2012-10-30-October-in-security.html @@ -13,11 +13,5 @@ summary: <p> For many of those years Dr. Neumann (pronounced NOY-man) has remained a voice in the wilderness tirelessly pointing out that the computer industry has a penchant for repeating the mistakes of the past. He has long been one of the nation’s leading specialists in computer security and early on he predicted that the security flaws that have accompanied the pell-mell explosion of the computer and Internet industries would have disastrous consequences.</p> </blockquote> -<p>In other news it appears that South Carolina's Department of Revenue has seen its computers <a href="http://arstechnica.com/security/2012/10/hack-of-south-carolina-network-exposes-ssns-for-3-6-million-taxpayers/">hacked</a> with 3.6 million social security numbers and 387 000 payment cards details leaked.</p> - <p>Today, the New York Times has an <a href="http://www.nytimes.com/2012/10/30/science/rethinking-the-computer-at-80.html?_r=0">homage</a> to Peter G. Neumann.</p> -<blockquote><p>Many people cite Albert Einstein’s aphorism “Everything should be made as simple as possible but no simpler.†Only a handful however have had the opportunity to discuss the concept with the physicist over breakfast. One of those is Peter G. Neumann now an 80-year-old computer scientist at SRI International […]</p> -<p> -For many of those years Dr. Neumann (pronounced NOY-man) has remained a voice in the wilderness tirelessly pointing out that the computer industry has a penchant for repeating the mistakes of the past. He has long been one of the nation’s leading specialists in computer security and early on he predicted that the security flaws that have accompanied the pell-mell explosion of the computer and Internet industries would have disastrous consequences.</p> -</blockquote> <p>In other news it appears that South Carolina's Department of Revenue has seen its computers <a href="http://arstechnica.com/security/2012/10/hack-of-south-carolina-network-exposes-ssns-for-3-6-million-taxpayers/">hacked</a> with 3.6 million social security numbers and 387 000 payment cards details leaked.</p> {% endraw %} diff --git a/_posts/2012-11-02-Short-difficult-programs.html b/_posts/2012-11-02-Short-difficult-programs.html index 2c9fbd485248c842b785896135c07f5f3feabd2f..6ea25bb3b5dc8fbd5c5092199147269b4f23c0f7 100644 --- a/_posts/2012-11-02-Short-difficult-programs.html +++ b/_posts/2012-11-02-Short-difficult-programs.html @@ -67,65 +67,5 @@ void sub(float x float y) <p>The target difference <code>0.1f</code> is larger than <code>0.09375f</code> so it should be easier to obtain as the difference of two floats from the prescribed range right? In fact it isn't. The numbers <code>0.099999904632568359375</code> and <code>0.10000002384185791015625</code> can be obtained as values of <code>x-y</code> in the above program for the former as the result of picking <code>1.099999904632568359375</code> for <code>x</code> and <code>1.0</code> for <code>y</code>. The value <code>0.1f</code> on the other hand cannot be obtained as the subtraction of two floats above <code>1.0</code> because some bits are set in its significand that cannot be set by subtracting floats that large.</p> <h2>Conclusion</h2> <p>I expect it will be some time before automatic analyzers can soundly and completely decide in all two-line programs whether the second line is reachable. Frama-C's value analysis does not detect unreachability in any of the programs above for instance (the value analysis is sound so it soundly detects that <code>L</code> may be reachable when it is). Please leave your own difficult two-line programs in the comments.</p> -<p>The floating-point examples in this post owe quite a bit to my colleague Bruno Marre explaining his article “Improving the Floating Point Addition and Subtraction Constraints†to me over lunch.</p> - <p>When researchers start claiming that they have a sound and complete analyzer for predicting whether a program statement is reachable, it is time to build a database of interesting programs.</p> -<h2>Goldbach's conjecture</h2> -<p>My long-time favorite is a C program that verifies <a href="http://en.wikipedia.org/wiki/Goldbach's_conjecture">Goldbach's conjecture</a> (actual program left as an exercise to the reader).</p> -<p>If the conjecture is true the program never terminates (ergo a statement placed after it is unreachable). If the conjecture is false the program terminates and moves on to the following statement. The program can be implemented using <code>unsigned long long</code> integers that should be good for counter-examples up to 18446744073709551615. It can alternately use dynamic allocation and multi-precision integers in which case depending whether your precise definition of “analyzing a C program†includes out-of-memory behaviors you could claim that the reachability of the statement after the counter-example-finding loop is equivalent to the resolution of “one of the oldest and best-known unsolved problems in number theory and in all of mathematicsâ€.</p> -<h2>Easier programs than that</h2> -<p>No-one expects the resolution of Goldbach's conjecture to come from a program analyzer. This example is too good because it is out of reach for everyone—it has eluded our best mathematicians for centuries. What I am looking for in this post is easier programs where the solution is just in reach. Examples that it would genuinely be informative to run these sound complete analyzers on. If they were made available.</p> -<h3>With integers</h3> -<p>For 32-bit ints and 64-bit long longs I know that the label <code>L</code> is unreachable in the program below but does your average sound and complete program analyzer do?</p> -<pre>/*@ requires 2 <= x ; - requires 2 <= y ; */ -void f(unsigned int x unsigned int y) -{ - if (x * (unsigned long long)y == 17) - L: return; -} -</pre> -<p>The key is that with the aforementioned platform hypotheses the multiplication does not overflow. Label <code>L</code> being reached would mean that the program has identified divisors of the prime number <code>17</code> which we don't expect it to.</p> -<p>In the program below the multiplication can overflow and not having tried it I have truly no idea whether the label <code>L</code> is reachable. I expect it is statistically but if you told me that it is unreachable because of a deep mathematical property of computations modulo a power of two I would not be shocked.</p> -<pre>/*@ requires 2 <= x ; - requires 2 <= y ; */ -void f(unsigned long long x unsigned long long y) -{ - if (x * y == 17) - L: return; -} -</pre> -<h3>With floating-point</h3> -<p>Floating-point is fun. Label <code>L</code> in the following program is unreachable:</p> -<pre>/*@ requires 10000000. <= x <= 200000000. ; - requires 10000000. <= y <= 200000000. ; */ -void sub(float x float y) -{ - if (x - y == 0.09375f) - L: return; -} -</pre> -<p>Frama-C's value analysis and most other analyzers will not tell you that label <code>L</code> is unreachable. It definitely looks reachable The difference between <code>x</code> and <code>y</code> can be zero and it can be <code>1.0</code>. It looks like it could be <code>0.09375</code> but it cannot: the subtracted numbers are too large for the difference if non-zero to be smaller than <code>1.0</code>.</p> -<p>So the subtlety in the example above is the magnitude of the arguments. What about smaller arguments then?</p> -<pre>/*@ requires 1.0 <= x <= 200000000. ; - requires 1.0 <= y <= 200000000. ; */ -void sub(float x float y) -{ - if (x - y == 0.09375f) - L: return; -} -</pre> -<p>This time the label <code>L</code> is easily reachable for instance with the inputs <code>2.09375</code> for <code>x</code> and <code>2.0</code> for <code>y</code>.</p> -<p>What about this third program?</p> -<pre>/*@ requires 1.0 <= x <= 200000000. ; - requires 1.0 <= y <= 200000000. ; */ -void sub(float x float y) -{ - if (x - y == 0.1f) - L: return; -} -</pre> -<p>The target difference <code>0.1f</code> is larger than <code>0.09375f</code> so it should be easier to obtain as the difference of two floats from the prescribed range right? In fact it isn't. The numbers <code>0.099999904632568359375</code> and <code>0.10000002384185791015625</code> can be obtained as values of <code>x-y</code> in the above program for the former as the result of picking <code>1.099999904632568359375</code> for <code>x</code> and <code>1.0</code> for <code>y</code>. The value <code>0.1f</code> on the other hand cannot be obtained as the subtraction of two floats above <code>1.0</code> because some bits are set in its significand that cannot be set by subtracting floats that large.</p> -<h2>Conclusion</h2> -<p>I expect it will be some time before automatic analyzers can soundly and completely decide in all two-line programs whether the second line is reachable. Frama-C's value analysis does not detect unreachability in any of the programs above for instance (the value analysis is sound so it soundly detects that <code>L</code> may be reachable when it is). Please leave your own difficult two-line programs in the comments.</p> <p>The floating-point examples in this post owe quite a bit to my colleague Bruno Marre explaining his article “Improving the Floating Point Addition and Subtraction Constraints†to me over lunch.</p> {% endraw %} diff --git a/_posts/2012-11-06-Debugging-with-WP.html b/_posts/2012-11-06-Debugging-with-WP.html index 4e53dafbd8adbed5f10f651cb96600d9057334f6..d21772626620020ef9f5ee6e201d370719643b76 100644 --- a/_posts/2012-11-06-Debugging-with-WP.html +++ b/_posts/2012-11-06-Debugging-with-WP.html @@ -78,76 +78,5 @@ unsigned int binary_search(int* a unsigned int length int key) { <pre>else { if med == 0 break; high = med - 1; } </pre> <h2>Getting a correct program</h2> -<p>This time all POs are discharged meaning that the program is correct with respect to its specification. I guess this was yet another example that no change in the code as small as it looks like can be considered harmless and that looking at the unproved POs of WP can be an effective way to catch those issues.</p> - <h2>Initial setting</h2> -<p>So, I was checking a small demo of the WP plug-in the other day, just before making a presentation of Frama-C to some future fellow user. This was the traditional <a href="http://frama-c.com/training/FindArray.zip">binary_search verification </a> presented in the Berlin training session in 2010 but using the <a href="http://frama-c.com/wp.html">WP plugin</a> instead of <a href="http://frama-c.com/jessie.html">Jessie</a>. For some reason I decided to change the type for all the offsets from <code>int</code> to <code>unsigned int</code>. After all we're morally dealing with array indexes and we want to search very big arrays (with <code>length > INT_MAX</code> don't we?) what can possibly go wrong?</p> -<p>The code and its contract then become the following:</p> -<pre>/*@ - requires length > 0; - requires \valid(a+(0..length - 1)); - requires sorted: \forall integer i j; 0<=i<=j<length ==> a[i]<=a[j]; - behavior find: - assumes \exists integer i; 0<=i<length && a[i] == key; - ensures 0<= \esult < length; - ensures a[\esult] == key; - behavior no_find: - assumes \forall integer i; 0<=i<length ==> a[i] != key; - ensures \esult == -1; - */ -unsigned int binary_search(int* a unsigned int length int key) { - unsigned int low high; - low = 0; high=length-1; - while (low <= high) { - unsigned int med = (high-low)/2U+low; - if (a[med] == key) return med; - if (a[med] < key) low = med+1; - else high = med-1; - } - return -1; -} -</pre> -<h2>Loop invariants</h2> -<p>As all of you know deductive verification require to write loop invariants to have a slight chance of proving something. An appropriate set of invariants for our case is the following:</p> -<ul> -<li><code>low</code> is between <code>0</code> and <code>high + 1</code> (at the loop exit)</li> -<li><code>high</code> is less than <code>length</code></li> -<li>all cells before <code>low</code> contain elements smaller than <code>key</code></li> -<li>all cells after <code>high</code> contain elements greater than <code>key</code></li> -</ul> -<p>and for the termination we have</p> -<ul> -<li>the difference between <code>high</code> and <code>low</code> strictly decreases.</li> -</ul> -<p>Translated into ACSL with named loop invariants in order to easily identify them in WP's output and without forgetting the <code>loop assigns</code> (WP is a bit picky about that) this becomes:</p> -<pre> /*@ - loop invariant low: 0<=low<=high+1; - loop invariant high: high < length; - loop invariant smaller: \forall integer i; 0<=i<low ==> a[i] < key; - loop invariant greater: - \forall integer i; high < i < length ==> a[i] > key; - loop assigns low high; - loop variant high - low; - */ -</pre> -<h2>A wrong specification!</h2> -<p>we launch Frama-C with the following command line:</p> -<pre>frama-c-gui -wp -wp-split -wp-rte binary_search.c -</pre> -<ul> -<li><code>-wp</code> asks WP to generate proof obligations (POs) and to launch the default prover (Alt-ergo) on them</li> -<li><code>-wp-split</code> splits POs that are conjunctions leading to smaller (and hopefully easier to prove) formulas to the provers</li> -<li><code>-wp-rte</code> asks RTE to generate all safety assertions before WP is launched. In other words we will get proof POs for potential run-time errors.</li> -</ul> -<p>The result is encouraging but not perfect: <code>behavior no_find</code> is not proved and if we dig a little bit in the <code>WP Proof Obligations</code> panel we see that the branch where the PO fails is the one where we return <code>-1</code> exactly what we specified:</p> -<p><img src="/assets/img/blog/imported-posts/debugging_with_WP.png" alt="debugging_with_WP.png" title="debugging_with_WP.png nov. 2012" /></p> -<p>Of course returning <code>-1</code> is sensible for indicating failure when we have <code>int</code>s not so with <code>unsigned</code>... In that case we can return <code>length</code> to indicate that no suitable index has been found</p> -<h2>Subtraction is not harmless</h2> -<p>We thus correct the <code>ensures</code> clause and the return <code>statement</code> according to our new error value and relaunch frama-c-gui. This time almost everything is fine except from some tiny assertion from RTE when assigning <code>med-1</code> to <code>high</code>:</p> -<pre>assert rte: med-(unsigned int)1 ≥ 0; -</pre> -<p>As a matter of fact if we think of it a little further if the <code>key</code> is less than all elements of the array <code>med</code> will become <code>0</code> at a certain point and we'll try to assign <code>-1</code> to <code>high</code> which is not exactly what we want (and is likely to result in a buffer overflow at the next loop step if <code>length<UINT_MAX/2</code>). We thus modify our <code>else</code> clause that way:</p> -<pre>else { if med == 0 break; high = med - 1; } -</pre> -<h2>Getting a correct program</h2> <p>This time all POs are discharged meaning that the program is correct with respect to its specification. I guess this was yet another example that no change in the code as small as it looks like can be considered harmless and that looking at the unproved POs of WP can be an effective way to catch those issues.</p> {% endraw %} diff --git a/_posts/2012-11-12-November-in-Security.html b/_posts/2012-11-12-November-in-Security.html index 64ad9c66f3ddb247ddb41e7f5eb5aeeddb6ed747..a0bbfc1e1c78276fb914ef097b778c5c822b80a7 100644 --- a/_posts/2012-11-12-November-in-Security.html +++ b/_posts/2012-11-12-November-in-Security.html @@ -12,10 +12,5 @@ summary: <blockquote><p>Key quote: The kind of defense I advocate (called "passive defense" or "protection" above) involves security engineering -- building security in as we create our systems knowing full well that they will be attacked in the future. One of the problems to overcome is that exploits are sexy and engineering is well not so sexy.</p> </blockquote> <p>Bruce in his typical fisheye approach to security also recently provided this other link about <a href="http://www.schneier.com/blog/archives/2012/11/fairy_wren_pass.html">security in fairy wren nests</a>. I thought this made a lot of sense but then again Hongseok Yang lent me a copy of Dawkins' <a href="http://en.wikipedia.org/wiki/The_Selfish_Gene">The Selfish Gene</a> when we were both post-doc students at KAIST so your mileage may vary.</p> -<p>Since I came back to France I bought my own copy of The Selfish Gene to lend others. If you are around and are curious just ask.</p> - <p>Bruce Schneier is, among other things, the author of the blog <a href="http://www.schneier.com">Schneier on Security</a>. He is also one of the co-authors of the Skein cryptographic hash function the SHA-3 contestant being verified in Frama-C's value analysis tutorial in the <a href="http://frama-c.com/download/frama-c-value-analysis.pdf">manual</a> and then on this <a href="/index.php?tag/skein">blog</a>. I feel silly introducing him considering he is rather on the “well-respected†side of the security researcher spectrum. But Bruce did <a href="http://www.schneier.com/blog/archives/2012/11/gary_mcgraw_on.html">provide</a> this month's cybersecurity link this <a href="http://searchsecurity.techtarget.com/news/2240169976/Gary-McGraw-Proactive-defense-prudent-alternative-to-cyberwarfare">essay</a> by Gary McGraw.</p> -<blockquote><p>Key quote: The kind of defense I advocate (called "passive defense" or "protection" above) involves security engineering -- building security in as we create our systems knowing full well that they will be attacked in the future. One of the problems to overcome is that exploits are sexy and engineering is well not so sexy.</p> -</blockquote> -<p>Bruce in his typical fisheye approach to security also recently provided this other link about <a href="http://www.schneier.com/blog/archives/2012/11/fairy_wren_pass.html">security in fairy wren nests</a>. I thought this made a lot of sense but then again Hongseok Yang lent me a copy of Dawkins' <a href="http://en.wikipedia.org/wiki/The_Selfish_Gene">The Selfish Gene</a> when we were both post-doc students at KAIST so your mileage may vary.</p> <p>Since I came back to France I bought my own copy of The Selfish Gene to lend others. If you are around and are curious just ask.</p> {% endraw %} diff --git a/_posts/2012-11-17-Compiler-driven-language-development.html b/_posts/2012-11-17-Compiler-driven-language-development.html index e5913e98beeeb57623f8c9e2dc5b192e5ecd1fa6..fa437c7f4f6d1efb65838533aa97122b83258981 100644 --- a/_posts/2012-11-17-Compiler-driven-language-development.html +++ b/_posts/2012-11-17-Compiler-driven-language-development.html @@ -36,33 +36,5 @@ Floating point exception <ol> <li>Revisions of the C standard are carefully crafted to allow as many compliant programs as possible to continue to be considered compliant, but this is only one of several conflicting objectives. My program is C99-compliant and is undefined in C11.</li> <li>Sometimes the standard defines the future direction of the language (e.g. the memory model part of C11) but sometimes it only ratifies whatever non-compliant semantics compilers have been implementing for years.</li> -</ol> <h2>A quiz</h2> -<p>What is pressing “return†next below going to reveal GCC has done wrong?</p> -<pre>$ cat t.c -#include <limits.h> -int x = -1; -int main(int c, char **v) { - x = INT_MIN % x; - return x; -} -~ $ gcc -std=c99 t.c -~ $ ./a.out -</pre> -<p>Answer:</p> -<pre>$ ./a.out -Floating point exception -</pre> -<h2>The programmer was using an x86_64 processor</h2> -<p>GCC has compiled a perfectly well-defined C99 program for returning 0 into binary code that makes an error. The error is misdiagnosed as a floating point exception but is actually a division overflow. It happens because computing the C99 remainder operation <code>%</code> on this computer invokes the x86_64 instruction <code>idivl</code>, which can raise this error when invoked with the arguments passed to it in this program. The <code>idivl</code> instruction computes a quotient and a remainder at the same time; the overflow error relates to the computation of the quotient, which my program was going to throw away anyway.</p> -<p>My program was well-defined in C90, too. In both these versions of the C standard, the semantics of <code>%</code>, like other arithmetic operations, are described informally as first computing the result as unbounded integer and then, since the result <code>0</code> fits the signed destination type <code>int</code>, the operation is defined and the result is <code>0</code>.</p> -<p>Over the period of time it has been generating code for x86 computers, GCC could have become standard-compliant by adding the couple of instructions necessary to compute the standard-mandated result. The most efficient sequence I see would be to test the divisor for equality with <code>-1</code> and to conditionally move if equal the divisor into the dividend. This would compute <code>-1 % -1</code> instead of <code>dividend % -1</code>, always producing the same result <code>0</code> without the need for an expensive branch.</p> -<p>GCC would not even have needed to generate this code all the time. Most of the times the divisor is statically known not to be <code>-1</code> or the dividend is statically known not to be <code>INT_MIN</code>. In either case the guarding test is unnecessary.</p> -<blockquote><p>To be fair, GCC can generate sophisticated assembly code when it exerts itself. If a program uses both <code>dividend % divisor</code> and <code>dividend / divisor</code> nearby in the same function, the generated assembly code is likely to call the division instruction <code>idivl</code> only once. My proposed conditional move would interfere with this optimization when it applies.</p> -</blockquote> -<h2>What it must be like to standardize a language like C</h2> -<p>Good news! GCC held out, and now (in the C11 standard), <code>INT_MIN % -1</code> is officially undefined behavior, so GCC is allowed to do what it wants. This goes to show two things:</p> -<ol> -<li>Revisions of the C standard are carefully crafted to allow as many compliant programs as possible to continue to be considered compliant, but this is only one of several conflicting objectives. My program is C99-compliant and is undefined in C11.</li> -<li>Sometimes the standard defines the future direction of the language (e.g. the memory model part of C11) but sometimes it only ratifies whatever non-compliant semantics compilers have been implementing for years.</li> -</ol> +</ol> {% endraw %} diff --git a/_posts/2012-11-18-About-the-rounding-error-in-these-Patriot-missiles.html b/_posts/2012-11-18-About-the-rounding-error-in-these-Patriot-missiles.html index c027732136478b494664d725458adbb90d12b76f..0236eb74bb9d009fc7d69a8e608ff2cfe3bfe303 100644 --- a/_posts/2012-11-18-About-the-rounding-error-in-these-Patriot-missiles.html +++ b/_posts/2012-11-18-About-the-rounding-error-in-these-Patriot-missiles.html @@ -29,27 +29,5 @@ Assuming that this summary is correct and it certainly looks more plausible tha <li>Will your system then detect the drift between the same computation having gone one path and the other?</li> </ol> <p>If your system is only practical in an alternate universe in which the Patriot missile software is cleanly implemented with good old IEEE 754 double-precision values: sorry but in that universe the Patriot missile does not exhibit the problem you are claiming to solve.</p> -<p>Thanks to Martin Jambon for proof-reading this post.</p> - <h2>An old rant: misusing Ariane 5 in motivation slides</h2> -<p>I was lucky to be an intern and then a PhD student at INRIA, while it was still called “INRIA†(it is now called “Inriaâ€). This was about when researchers at INRIA and elsewhere were taken to task to understand the unfortunate software failure of the Ariane 5 maiden flight. So I heard the story from people I respect and who knew at least a little bit about the subject.</p> -<p>Ever since, it has been irking me when this example is taken for the purpose of motivating some formal technique or other. Unless you attend this sort of CS conference, you might not believe the non-solutions that get motivated as getting us all closer to a world in which Ariane 5 rockets do not explode.</p> -<p>What irks me is this: even if the technique being motivated were comparably expensive to traditional testing, requiring comparable or a little less time for comparable or a little more confidence, that would not guarantee it would have been used to validate the component. The problem with Ariane 5 was not a failure of traditional tests. The problem was that, because of constraints of time and money, traditional tests were <strong>not applied</strong> to the component that eventually failed.</p> -<blockquote><p>If your method is not cheaper and faster than not doing the tests, do not imply that it would have saved Ariane 5. It might have been omitted too.</p> -</blockquote> -<p>The report is <a href="http://www.ima.umn.edu/~arnold/disasters/ariane5rep.html">online</a>. Key quote: “no test was performed to verify that the SRI would behave correctly when being subjected to the count-down and flight time sequence and the trajectory of Ariane 5.â€</p> -<h2>A new rant: the Patriot missile rounding error</h2> -<p>If you attend that sort of conference you have also heard about this other spectacular software failure the <a href="http://en.wikipedia.org/wiki/MIM-104_Patriot#Failure_at_Dhahran">Patriot</a> missile rounding error. This bug too is used to justify new techniques.</p> -<p>This one did not irk me until today. I did not happen to be in the right place to get the inside scoop by osmosis. Or at the wrong time.</p> -<p>I vaguely knew that it had something to do with a clock inside the Patriot missile measuring tenths of seconds and the constant 0.1 not being representable in binary. When researchers tell the story on a motivation slide it sounds like a stupid mistake.</p> -<blockquote><p>There is nothing reprehensible in calculating with constants that are not represented finitely in binary. Other computations inside the missile surely involved the number Ï€ which is not finitely representable in binary either. The designer of the system simply must understand what <a href="http://en.wikipedia.org/wiki/Spivak_pronoun">ey</a> is doing. It can get a little tricky especially when the software is evolved. Let me tell you about the single-precision <code>cosf()</code> function from the Glibc library in another rant.</p> -</blockquote> -<p>Similarly with the Ariane 5 case a rather good-looking <a href="http://mate.uprh.edu/~pnm/notas4061/patriot.htm">summary</a> of the issue is available. -Assuming that this summary is correct and it certainly looks more plausible than the rash explanations you get at motivation-slide time the next time I hear a researcher use the Patriot missile example to motivate eir talk I will ask the questions that follow.</p> -<ol> -<li>When are you adapting your system to ad-hoc 24-bit fixed-point computations (not whether it is theoretically possible but when you are doing it)?</li> -<li>When are you adapting your system to ad-hoc non-IEEE 754 48-bit floating-point computations?</li> -<li>Will your system then detect the drift between the same computation having gone one path and the other?</li> -</ol> -<p>If your system is only practical in an alternate universe in which the Patriot missile software is cleanly implemented with good old IEEE 754 double-precision values: sorry but in that universe the Patriot missile does not exhibit the problem you are claiming to solve.</p> <p>Thanks to Martin Jambon for proof-reading this post.</p> {% endraw %} diff --git a/_posts/2012-11-19-Funny-floating-point-bugs-in-Frama-C-Oxygens-front-end.html b/_posts/2012-11-19-Funny-floating-point-bugs-in-Frama-C-Oxygens-front-end.html index 46fcee877eceed5178cd426d7ed3adbe2fcdad6d..8731cad935bcb6bb02f6475092f743f4edfc2db7 100644 --- a/_posts/2012-11-19-Funny-floating-point-bugs-in-Frama-C-Oxygens-front-end.html +++ b/_posts/2012-11-19-Funny-floating-point-bugs-in-Frama-C-Oxygens-front-end.html @@ -48,46 +48,5 @@ is not represented exactly. Will use inf. See documentation for option -warn-decimal-float </pre> -<p>These two related bugs are fixed in the development version of Frama-C.</p> - <p>In a previous <a href="/ocaml/floating-point/2011/11/14/Analyzing-single-precision-floating-point-constants">post</a> almost exactly one year ago before Frama-C Oxygen was released I mentioned that the then future release would incorporate a custom decimal-to-binary floating-point conversion function. The reason was that the system's <code>strtof()</code> and <code>strtod()</code> functions could not be trusted.</p> -<p>This custom conversion function is written in OCaml. It can be found in src/kernel/floating_point.ml in the now available Oxygen <a href="http://frama-c.com/download.html">source tree</a>. This post is about a couple of funny bugs the function has.</p> -<h2>History</h2> -<p>There had been arguments about the inclusion of the “correct parsing of decimal constants†feature in Frama-C's front-end and about the best way to implement it. My colleague Claude Marché was in favor of using the reputable MPFR library. I thought that such an additional dependency was unacceptable and I was against the feature's inclusion as long as I could not see a way to implement it that did not involve such a dependency.</p> -<p>When I presented my dependency-avoiding solution to Claude he said: “But how do you know your function works? Did you prove it?â€. To which I replied that no I had not proved it but I had thoroughly tested it. I had written a quick generator of difficult-to-convert decimal numbers and I was rather happy with the confidence it gave me.</p> -<blockquote><p>My generator allowed me to find and fix a double rounding issue when the number to convert was a denormal: in this case the number would first be rounded at 52 significant digits and then at the lower number of significant digits implied by its denormal status.</p> -</blockquote> -<p>I owe Claude a beer though because there were two bugs in my function. The bugs were not found by my random testing but would indeed have been found by formal verification. If you want to identify them yourself stop reading now and start hunting because the bugs are explained below.</p> -<h2>Stop reading here for a difficult debugging exercise</h2> -<p>Say that the number being parsed is of the form <em>numopt1</em>.<em>numopt2</em>E<em>num3</em> where <em>numopt1</em> and <em>numopt2</em> expand to optional strings of digits and <em>num3</em> expands to a mandatory string of digits.</p> -<p>The sequences of digits <em>numopt1</em> and <em>numopt2</em> can be long. The string <em>numopt2</em> in particular should not be parsed as an integer because the leading zeroes it may have are significant.</p> -<p>At this point of the parsing of the input program we have already ensured that <em>num3</em> was a string of digits with an optional sign character at the beginning. In these conditions it is tempting to simply call the OCaml function <code>int_of_string</code>. -The function <code>int_of_string</code> may still fail and raise an exception if the string represents a number too large to be represented as a 31- or 63-bit OCaml <code>int</code>.</p> -<p>This is easy to fix: if the program contains a literal like <code>1.234E9999999999999999999</code> causing <code>int_of_string</code> to fail when parsing the exponent return infinity. A vicious programmer might have written <code>0.000…01E9999999999999999999</code> but this programmer's hard-drive is not large enough to contain all the digits that would prevent infinity to be the correct answer.</p> -<p>Similarly if <code>int_of_string</code> chokes because the programmer wrote <code>1.234E-9999999999999999999</code> the function can safely return <code>0.0</code> which for the same reason is always the correctly rounded floating-point representation.</p> -<p>Or so it would seem. The above logic is implemented in function <code>parse_float</code> inside Frama-C Oxygen and this is where the bugs are.</p> -<h2>Stop reading here for an easy debugging exercise</h2> -<p>During a code review my colleague Boris Yakobowski and I found that Oxygen had the following unwanted behaviors. Read on for the solution.</p> -<h3>Exhibit one: spurious warning</h3> -<pre>double d = 0.0E-9999999999999999999; -</pre> -<p>For the program above a warning is emitted whereas the constant is in fact exactly represented. The only issue here is the spurious warning:</p> -<pre>$ frama-c e1.c -[kernel] preprocessing with "gcc -C -E -I. e1.c" -e1.c:1:[kernel] warning: Floating-point constant 0.0E-9999999999999999999 -is not represented exactly. -Will use 0x0.0000000000000p-1022. -See documentation for option -warn-decimal-float -</pre> -<h3>Exhibit two: confusion between zero and infinity</h3> -<pre>double d = 0.0E9999999999999999999; -</pre> -<p>This bug is more serious:</p> -<pre>$ frama-c e2.c -[kernel] preprocessing with "gcc -C -E -I. e2.c" -e2.c:1:[kernel] warning: Floating-point constant 0.0E9999999999999999999 -is not represented exactly. -Will use inf. -See documentation for option -warn-decimal-float -</pre> <p>These two related bugs are fixed in the development version of Frama-C.</p> {% endraw %} diff --git a/_posts/2012-11-26-Debugging.html b/_posts/2012-11-26-Debugging.html index 6a4ce90296328a02c20cfa29f4a437a27d8917eb..03efe1738e9c8970d6857bc5fd9a980234ed40a3 100644 --- a/_posts/2012-11-26-Debugging.html +++ b/_posts/2012-11-26-Debugging.html @@ -13,11 +13,5 @@ summary: </blockquote> <p>My answer is twofold. First subscribers get the blog they deserve. If you cannot rail and mock such obvious contradictions what is to prevent me from putting them in? Also I was not advertising a particular OCaml formal verification tool. I do not know any that accepts the full language. It was fully confident in the absence of any such tool that I claimed that if it existed and was usable and automatic enough to have actually been used it could have found the bug disclaimed in the last post. If provided with an appropriate specification. Which in the case at hand could only be a decimal-to-floating-point implementation in itself.</p> <p>The truth is that Frama-C development involves a lot of old-fashioned testing and debugging. One factor is that available OCaml programmer-assistance tools do not always scale to projects the size of Frama-C. Another is that Frama-C uses some hard-to-get-right hard-to-diagnose techniques (for instance mixing data unmarshaling and hash-consing).</p> -<p>Speaking of which I think my Frama-C debugging colleagues will agree with me that this <a href="http://www.patriciashanahan.com/debug/index.html">introduction</a> to debugging is a nice read.</p> - <p>A remark I have not heard about the last two posts is the following.</p> -<blockquote><p>Pascal, how can you, in your <a href="/index.php?post/2012/11/19/Funny-floating-point-bugs-in-Frama-C-Oxygen-s-front-end">last</a> post claim that formal verification would have found the bug in your decimal-to-floating-point function? This is the kind of outrageous claim you rant against in your <a href="/rant/2011/09/27/About-the-rounding-error-in-these-Patriot-missiles">penultimate</a> post! Formal verification did <strong>not</strong> find the bug. A code review did.</p> -</blockquote> -<p>My answer is twofold. First subscribers get the blog they deserve. If you cannot rail and mock such obvious contradictions what is to prevent me from putting them in? Also I was not advertising a particular OCaml formal verification tool. I do not know any that accepts the full language. It was fully confident in the absence of any such tool that I claimed that if it existed and was usable and automatic enough to have actually been used it could have found the bug disclaimed in the last post. If provided with an appropriate specification. Which in the case at hand could only be a decimal-to-floating-point implementation in itself.</p> -<p>The truth is that Frama-C development involves a lot of old-fashioned testing and debugging. One factor is that available OCaml programmer-assistance tools do not always scale to projects the size of Frama-C. Another is that Frama-C uses some hard-to-get-right hard-to-diagnose techniques (for instance mixing data unmarshaling and hash-consing).</p> <p>Speaking of which I think my Frama-C debugging colleagues will agree with me that this <a href="http://www.patriciashanahan.com/debug/index.html">introduction</a> to debugging is a nice read.</p> {% endraw %} diff --git a/_posts/2012-11-28-C99-quiz.html b/_posts/2012-11-28-C99-quiz.html index 989c58bda3b9fd47c7b22ca5106e40199e5660f0..ae98f9f496f2047be6c87fb5f5d6328c9d30bab5 100644 --- a/_posts/2012-11-28-C99-quiz.html +++ b/_posts/2012-11-28-C99-quiz.html @@ -15,12 +15,5 @@ summary: } </pre> <p>What does it do on my faithful PowerMac?</p> -<p>The Intel version is not as nice. That's progress for you: <code>*(3+(char*)(float){x*x}) - 63</code></p> <p>Here is a convenient one-liner:</p> -<pre>int l(unsigned int x) -{ - return *(char*)(float[]){x*x} - 63; -} -</pre> -<p>What does it do on my faithful PowerMac?</p> -<p>The Intel version is not as nice. That's progress for you: <code>*(3+(char*)(float){x*x}) - 63</code></p> +<p>The Intel version is not as nice. That's progress for you: <code>*(3+(char*)(float){x*x}) - 63</code></p> {% endraw %} diff --git a/_posts/2012-11-29-Solution-to-yesterdays-quiz.html b/_posts/2012-11-29-Solution-to-yesterdays-quiz.html index c74d9edcf1766897ed1a6a38e59bbf65a58d6274..cbad543a9f06e8b3e450470087fd09876034ca55 100644 --- a/_posts/2012-11-29-Solution-to-yesterdays-quiz.html +++ b/_posts/2012-11-29-Solution-to-yesterdays-quiz.html @@ -42,40 +42,5 @@ l(20)=4 <p>In the case at hand the construct converts to float the contents of the braces and puts the result in memory. The function puts the float in memory in order to read its most significant byte. That's <code>*(char*)…</code> on a big-endian architecture and <code>*(3+(char*)…)</code> on a little-endian one.</p> <p>One reason to read a single char is to circumvent <a href="http://stackoverflow.com/q/98650/139746">strict aliasing rules</a>—which do not apply to type <code>char</code>. A simpler version of the same function would have been <code>(*(int*)(float[]){x} >> 23) - 127</code> but that version would break strict aliasing rules. Also it would be too obvious.</p> <p>The most significant bits of a single-precision IEEE 754 floating-point representation are in order one sign bit and eight exponent bits. By reading the most significant byte we get most of the exponent but one bit is lost. To compensate for this the operation is applied to <code>x*x</code> whose exponent is double the exponent of <code>x</code>.</p> -<p>In conclusion yesterday's one-liner returns an integer approximation of the base-2 logarithm of a reasonably small <code>unsigned int x</code>. On a typical 32-bit architecture it is exact for powers of two up to <code>2¹âµ</code>. If <code>x</code> is zero the function returns its best approximation of <code>-∞</code> that is <code>-63</code>.</p> - <p>Yesterday's quiz was about the expression <code>*(char*)(float[]){x*x} - 63</code> (for big-endian architectures) or <code>*(3+(char*)(float[]){x*x}) - 63</code> (for little-endian ones). This post provides an explanation.</p> -<p>First, let us try the function on a few values:</p> -<pre>int main(){ - for (unsigned int i=0; i<=20; i++) - printf(\l(%2u)=%d" i l(i)); -} -</pre> -<p>This may provide the beginning of a hint:</p> -<pre>l( 0)=-63 -l( 1)=0 -l( 2)=1 -l( 3)=2 -l( 4)=2 -l( 5)=2 -l( 6)=3 -l( 7)=3 -l( 8)=3 -l( 9)=3 -l(10)=3 -l(11)=3 -l(12)=4 -l(13)=4 -l(14)=4 -l(15)=4 -l(16)=4 -l(17)=4 -l(18)=4 -l(19)=4 -l(20)=4 -</pre> -<p>The construct <code>(float[]){…}</code> is C99's syntax for anonymous arrays a kickass programming technique. This is an <a href="http://www.run.montefiore.ulg.ac.be/~martin/resources/kung-f00.html">unabated</a> quote.</p> -<p>In the case at hand the construct converts to float the contents of the braces and puts the result in memory. The function puts the float in memory in order to read its most significant byte. That's <code>*(char*)…</code> on a big-endian architecture and <code>*(3+(char*)…)</code> on a little-endian one.</p> -<p>One reason to read a single char is to circumvent <a href="http://stackoverflow.com/q/98650/139746">strict aliasing rules</a>—which do not apply to type <code>char</code>. A simpler version of the same function would have been <code>(*(int*)(float[]){x} >> 23) - 127</code> but that version would break strict aliasing rules. Also it would be too obvious.</p> -<p>The most significant bits of a single-precision IEEE 754 floating-point representation are in order one sign bit and eight exponent bits. By reading the most significant byte we get most of the exponent but one bit is lost. To compensate for this the operation is applied to <code>x*x</code> whose exponent is double the exponent of <code>x</code>.</p> <p>In conclusion yesterday's one-liner returns an integer approximation of the base-2 logarithm of a reasonably small <code>unsigned int x</code>. On a typical 32-bit architecture it is exact for powers of two up to <code>2¹âµ</code>. If <code>x</code> is zero the function returns its best approximation of <code>-∞</code> that is <code>-63</code>.</p> {% endraw %} diff --git a/_posts/2012-12-01-Syntax-appropriateness.html b/_posts/2012-12-01-Syntax-appropriateness.html index 4f8c0916f73df47cf67cffc398adab5412ad3efd..a03a1e12266cde1d9f61dcd2a39504179275a72c 100644 --- a/_posts/2012-12-01-Syntax-appropriateness.html +++ b/_posts/2012-12-01-Syntax-appropriateness.html @@ -10,7 +10,5 @@ summary: {% raw %} <p><q>I know! Let us make [ and ] function as meta-characters when in code style. Users will surely love the ability to insert hyperlinks inside the code they are writing a blog post about.</q></p> <p>—The authors of the Content Management System this blog relies on</p> -<p>In the previous post, <code>(float){…}</code>, discussed as if it were the syntax for anonymous arrays, should have read <code>(float []){…}</code>.</p> <p><q>I know! Let us make [ and ] function as meta-characters when in code style. Users will surely love the ability to insert hyperlinks inside the code they are writing a blog post about.</q></p> -<p>—The authors of the Content Management System this blog relies on</p> -<p>In the previous post, <code>(float){…}</code>, discussed as if it were the syntax for anonymous arrays, should have read <code>(float []){…}</code>.</p> +<p>In the previous post, <code>(float){…}</code>, discussed as if it were the syntax for anonymous arrays, should have read <code>(float []){…}</code>.</p> {% endraw %} diff --git a/_posts/2012-12-06-Formally-verifying-zlib.html b/_posts/2012-12-06-Formally-verifying-zlib.html index eea2966b62adcae7475f231bc09e042fdfd1d45d..037a9d067569b4ab0c73ca4b5dfaeaa47672ca75 100644 --- a/_posts/2012-12-06-Formally-verifying-zlib.html +++ b/_posts/2012-12-06-Formally-verifying-zlib.html @@ -18,15 +18,5 @@ summary: <blockquote><p>Edited to add: too late Andrew Å veikauskas has already determined that our first alarm was a false positive as you can see on <a href="http://codereview.stackexchange.com/q/19368/20072">codereview.stackexchange.com</a>. Ah well… It would have been nice if out first alarm were a true positive but that was unlikely.</p> <p> In case you regret missing out on the fun here is another one: when reaching line inffast.c:269 where <code>from</code> is computed as <code>out - dist</code> to be accessed next what prevents variable <code>out</code> to point one byte into the output buffer and <code>dist</code> to be 2 or 3 or 19? I expect the library must guard against this in the code above but this is the end of a long day and I did not find where. Also this would typically be the kind of relational information that the value analysis fails to remember so I am not promising there is a bug to find here.</p> -</blockquote>" <p>In a blog post earlier this year, John Regehr wonders when software verification will finally matter. He means “formal verificationâ€, I am pretty sure. “Verification†is what practitioners of, say, the software development V-cycle have been doing for decades, and it has kept us safe for that long—at least, when it mattered most.</p> -<p>Formal verification on the other hand, despite having been used here and there, is not yet the big deal that it could be. You'd better read the <a href="http://blog.regehr.org/archives/710">post</a> I fear I may not be doing it justice.</p> -<p>In that post John writes:</p> -<p><q>For example I’d be happy to drop a proved-correct gzip into my Linux machine as long as it was respectably fast.</q></p> -<p>Okay John let us do this and see how far we can go.</p> -<p><a href="https://blog.frama-c.com/admin/post.php?id=187&xconv=1">Convertir en XHTML</a></p> -<p>We'll start with <a href="http://www.zlib.net">zlib</a> that we are going to approach like we did <a href="/index.php?post/2011/04/05/QuickLZ-1">QuickLZ</a> by verifying that the decompression feature is resilient to malicious inputs. I have described the first potential issue on <a href="http://codereview.stackexchange.com/q/19368/20072">this code review site</a>. If you have an opinion on this potential issue you can contribute by expressing it there (registering is a one-click process) or here in the comments if you prefer.</p> -<blockquote><p>Edited to add: too late Andrew Å veikauskas has already determined that our first alarm was a false positive as you can see on <a href="http://codereview.stackexchange.com/q/19368/20072">codereview.stackexchange.com</a>. Ah well… It would have been nice if out first alarm were a true positive but that was unlikely.</p> -<p> -In case you regret missing out on the fun here is another one: when reaching line inffast.c:269 where <code>from</code> is computed as <code>out - dist</code> to be accessed next what prevents variable <code>out</code> to point one byte into the output buffer and <code>dist</code> to be 2 or 3 or 19? I expect the library must guard against this in the code above but this is the end of a long day and I did not find where. Also this would typically be the kind of relational information that the value analysis fails to remember so I am not promising there is a bug to find here.</p> -</blockquote>" +</blockquote>" {% endraw %} diff --git a/_posts/2012-12-12-Seriously-Go.html b/_posts/2012-12-12-Seriously-Go.html index 6ae8de99658ad518a36bb81a576c39ebfe467c5a..099be799e22357251b3ba29aa32c41f8c4344500 100644 --- a/_posts/2012-12-12-Seriously-Go.html +++ b/_posts/2012-12-12-Seriously-Go.html @@ -18,16 +18,5 @@ summary: <li>If you write <code>var a = 0.0 * -1.0</code> variable <code>a</code> is still initialized to <code>+0.0</code>.</li> <li>But you can obtain <code>-0.0</code> if you write <code>var a = 0.0</code> followed by <code>a *= -1.0</code>.</li> </ol> -<p>So Go has egregious differences between the run-time and compile-time semantics used for floating-point computations but on the plus side it sucks at recognizing static floating-point computations.</p> - <p>I used to be curious about the <a href="http://en.wikipedia.org/wiki/D_(programming_language)">D programming language</a>. D had been pitched to me as “C done rightâ€. Even before I had time to look at it though someone on StackOverflow was having an issue that stemmed from constant floating-point expressions being evaluated at compile-time with different semantics than the run-time semantics.</p> -<blockquote><p>The C language has this problem too. But I do not see the point of switching to a similar supposedly improved language if it does not at least fix this sort of issue.</p> -</blockquote> -<p>History it turns out is cyclical modulo alpha-renaming. Today in <a href="http://stackoverflow.com/questions/13804255/negative-zero-literal-in-golang">another</a> question on StackOverflow someone was having a hard time writing the IEEE 754 constant <code>-0.0</code> as a literal in the new programming language Go.</p> -<p><a href="http://golang.org">Go</a> was not pitched to me as a better C but it is pitched as a good replacement for some of C's applications. I had been mildly curious since I heard about it. Call me easily disappointed but here is what I learned from today's question:</p> -<ol> -<li>In the current Go implementation if you write <code>-0.0</code> you get <code>+0.0</code>.</li> -<li>If you write <code>var a = 0.0 * -1.0</code> variable <code>a</code> is still initialized to <code>+0.0</code>.</li> -<li>But you can obtain <code>-0.0</code> if you write <code>var a = 0.0</code> followed by <code>a *= -1.0</code>.</li> -</ol> <p>So Go has egregious differences between the run-time and compile-time semantics used for floating-point computations but on the plus side it sucks at recognizing static floating-point computations.</p> {% endraw %} diff --git a/_posts/2012-12-18-zlib-progress-one-comma-misused.html b/_posts/2012-12-18-zlib-progress-one-comma-misused.html index 3a6641e680b85792bd4deb37a13c50a372529a92..720886dd8fa1d05c0b0f989a3f321f6119872c69 100644 --- a/_posts/2012-12-18-zlib-progress-one-comma-misused.html +++ b/_posts/2012-12-18-zlib-progress-one-comma-misused.html @@ -30,27 +30,4 @@ And I was pretty pleased with myself.</p> <p>It behaved exactly as the original statement in assigning non-zero values to the output buffer. I had instead intended:</p> <pre> *output_pointer++ = (expression_with_side_effects 0); -</pre>" <p>A <a href="/index.php?post/2012/12/06/Verifying-zlib">few days ago</a> I announced that the world had been using an unverified zlib library for too long and that we were going to fix this. This post is the first progress report. I have found a harmless undefined behavior in zlib and I have learnt something about the comma operator. This post only covers the latter aspect.</p> -<h2>The comma operator</h2> -<p>The comma operator can be used to build an expression <code>e1 e2</code>. When <code>e1 e2</code> is evaluated first <code>e1</code> is evaluated (for its result and side-effects) then the result is discarded and <code>e2</code> is evaluated.</p> -<blockquote><p>The comma counts as a <a href="http://en.wikipedia.org/wiki/Sequence_point">sequence point</a>. Sequence points are the points in a C program in-between which it is illegal to both read and write the same memory location; for instance <code>x++ + x</code> is undefined behavior because there is no sequence point between the post-incrementation <code>x++</code> and the use of the value of <code>x</code>. Coming back to the comma operator since it counts as a sequence point I thought this might allow writing <code>(x++ y) + (y++ x)</code> but I am not so sure about that now.</p> -</blockquote> -<h2>Easing the value analysis' job on zlib</h2> -<p>Formally verifying such a library as zlib is difficult. Indeed otherwise considering its usefulness and fame if it was easy someone would already have advertized that they had formally verified it.</p> -<p>One verification plan that I wanted to try out on this library is the model-checking approach that we first experimented with last <a href="/index.php?post/2012/08/20/Participating-in-the-RERS-2012-competition%3A-reachability-questions">summer</a>.</p> -<blockquote><p>The words “model-checking†may evoke different things to different people. In this context they mean the propagation of only unabstracted known-to-be-feasible states so that if a division by zero is reached in the program we know for sure that this dangerous division can be reached for some inputs. In other words we are talking here about a technique to avoid false positives in addition to avoiding false negatives as we always do.</p> -</blockquote> -<p>There is a catch: the propagation of unabstracted states does not really scale to a codebase the size and complexity of zlib. My plan was to ease the job of Frama-C's value analysis by carefully re-introducing a little bit of abstraction. I intended to modify the zlib library so that the modified version has all the same opportunities to do something wrong with pointers as the original version but the modified version always computes zero as output sequence. This would make many memory states that would otherwise have been different become identical something that the value analysis efficiently recognizes and takes advantage of.</p> -<h2>A beginner's mistake</h2> -<p>And this is how I found myself modifying <code>*output_pointer++ = expression_with_side_effects;</code> so that it would only write <code>0</code> to the output buffer but otherwise have all the same side-effects as the original. I chose to replace it with the statement below. -And I was pretty pleased with myself.</p> -<pre> *output_pointer++ = expression_with_side_effects 0; -</pre> -<p>Unfortunately after one additional cycle of verification it turned out that in the C syntax assignment has higher precedence than comma. My modified statement was parsed as:</p> -<pre> (*output_pointer++ = expression_with_side_effects) 0; -</pre> -<p>It behaved exactly as the original statement in assigning non-zero values to the output buffer. -I had instead intended:</p> -<pre> *output_pointer++ = (expression_with_side_effects 0); -</pre>" {% endraw %} diff --git a/_posts/2012-12-30-December-in-Security.html b/_posts/2012-12-30-December-in-Security.html index 124fe43e5098058429dfe5dfaad20c4f154a17a2..45d47d4e5b806a71d388c48c2b450a6b0a30a9a5 100644 --- a/_posts/2012-12-30-December-in-Security.html +++ b/_posts/2012-12-30-December-in-Security.html @@ -9,7 +9,5 @@ summary: --- {% raw %} <p>Robert Graham, of the blog Errata Security, <a href="http://erratasec.blogspot.fr/2012/12/predictions-for-2013.html">predicts</a> that “vulnerabilities in Acrobat Reader Adobe Flash and Java today […] will be announced and patched in 2013â€.</p> -<p>As fate would have it he could safely have <a href="https://community.rapid7.com/community/metasploit/blog/2012/12/29/microsoft-internet-explorer-0-day-marks-the-end-of-2012">included Internet Explorer 8</a> in his list of software products used by millions to process untrusted inputs.</p> - <p>Robert Graham, of the blog Errata Security, <a href="http://erratasec.blogspot.fr/2012/12/predictions-for-2013.html">predicts</a> that “vulnerabilities in Acrobat Reader Adobe Flash and Java today […] will be announced and patched in 2013â€.</p> <p>As fate would have it he could safely have <a href="https://community.rapid7.com/community/metasploit/blog/2012/12/29/microsoft-internet-explorer-0-day-marks-the-end-of-2012">included Internet Explorer 8</a> in his list of software products used by millions to process untrusted inputs.</p> {% endraw %} diff --git a/_posts/2013-01-01-Software-obsolescence-and-security.html b/_posts/2013-01-01-Software-obsolescence-and-security.html index 5e3f98699a1adb412dd55a3762120efb8ccf7098..7ec2fe1f81279e6b69efb3fbb915adeddfa3e3e0 100644 --- a/_posts/2013-01-01-Software-obsolescence-and-security.html +++ b/_posts/2013-01-01-Software-obsolescence-and-security.html @@ -17,15 +17,5 @@ summary: <p>Here is an idea for 2013: how about making software that works? Of course it would not automatically adapt to new protocols but as long as the user was satisfied with the old ones this software would simply keep working. It would not have to be constantly updated with security patches because it would have been made right the first time just like hardware sometimes is.</p> <blockquote><p>I would not want to give the impression that I am unfairly picking on the fine developers of Firefox. Firefox 3.6 continued to be maintained long after Safari for OS X 10.4 had ceased to receive security updates. In fact the <a href="http://en.wikipedia.org/wiki/TenFourFox">TenFourFox</a> project a maintained variant of Firefox for precisely the kind of computer I took to the basement is a testament to the power of Open Source Software. Unfortunately there is no Adobe Flash support in TenFourFox and I fear that this might complicate the life of a computerwise-unsophisticated user.</p> </blockquote> -<p>Acknowledgements: besides selling me his computer Damien Doligez officially owned the first OS X-able mac I used as a PhD student. Harry McCracken suggested to liven up this post with a picture. Gerhard Piezinger <a href="http://fr.wikipedia.org/wiki/Fichier:IMac.jpg">photographed</a> an iMac very much like mine and I used his picture.</p> - <p>A couple of months ago, I packed a computer into a brown plastic bag of the kind usually used for trash. I then carried the carefully packed computer down to the basement. Physically, the computer still works. It is still beautiful (it is <a href="http://www.everymac.com/systems/apple/imac/specs/imac_800_fp.html">an iMac G4</a>). It has been with me for the last ten years: I bought it second-hand in December 2002 from my friend Damien Doligez. I have used it for both work and entertainment for several years and then gave it to my computerwise-unsophisticated sister who has been using it since. The design much friendlier than later iMacs and even than earlier iMacs evokes the <a href="http://www.youtube.com/watch?v=Hrnz2pg3YPg">Luxo</a> Pixar character. This computer was built to last: after ten years the white plastics are still white. I pick this insignificant detail not because I particularly care about the tint of my computing devices but because I don't. This is not an accident. People took care of the details when designing this computer all the way down to how it would look as it aged.</p> -<p>The iMac G4 came with the cutest matched loudspeakers. The integrated modem would not find much use nowadays but the computer also has USB firewire and ethernet ports and Wi-Fi. The thinking behind the integrated modem remains avant-gardist even if the technology is now outdated: this computer was the hub of its buyer's future digital lifestyle. It was intended to be connected and it was intended not to look like an untidy mess in your living room.</p> -<p><img src="/assets/img/blog/imported-posts/300px-IMac.jpg" alt="300px-IMac.jpg" style="display:block; margin:0 auto;" title="300px-IMac.jpg janv. 2013" /></p> -<p>I opened it a couple of times to upgrade the hard disk and optical drive. It reminded me of the glimpse I once took as a student of the insides of a Sun workstation. I don't think I could explain this particular feeling to someone who did not see the inside of a Sun workstation—or of an iMac. As a concrete example that does not do justice to the experience the unused screw holes of the factory-installed optical drive I retrieved from the computer had been taped over so that air would not be sucked through the drive lest dust accumulate on the drive's door as years passed.</p> -<p>Unfortunately some functions mostly everyone expects from a computer nowadays is to display e-mail and web pages and this computer is no longer fit for this purpose. This isn't a case of running new software on old hardware. This has never worked but one used to be able to use loved hi-tech gadgets way past obsolescence as long as one avoided the mistake of installing new software on them. For lustra you could keep using the spreadsheet you were used to for accounting or your simple-but-sufficient word processor. Even games kept working!</p> -<p>The problem nowadays is that the option not to upgrade software is no longer available: software more than a few years old ceases to receive security patches. The iMac G4 in question cannot be upgraded past Mac OS X 10.4. On Mac OS X 10.4 Firefox cannot be upgraded past version 3.6. Firefox 3.6 received its last security update in March 2012 and has now joined the Great Repository in the Sky.</p> -<p>Here is an idea for 2013: how about making software that works? Of course it would not automatically adapt to new protocols but as long as the user was satisfied with the old ones this software would simply keep working. It would not have to be constantly updated with security patches because it would have been made right the first time just like hardware sometimes is.</p> -<blockquote><p>I would not want to give the impression that I am unfairly picking on the fine developers of Firefox. Firefox 3.6 continued to be maintained long after Safari for OS X 10.4 had ceased to receive security updates. In fact the <a href="http://en.wikipedia.org/wiki/TenFourFox">TenFourFox</a> project a maintained variant of Firefox for precisely the kind of computer I took to the basement is a testament to the power of Open Source Software. Unfortunately there is no Adobe Flash support in TenFourFox and I fear that this might complicate the life of a computerwise-unsophisticated user.</p> -</blockquote> <p>Acknowledgements: besides selling me his computer Damien Doligez officially owned the first OS X-able mac I used as a PhD student. Harry McCracken suggested to liven up this post with a picture. Gerhard Piezinger <a href="http://fr.wikipedia.org/wiki/Fichier:IMac.jpg">photographed</a> an iMac very much like mine and I used his picture.</p> {% endraw %} diff --git a/_posts/2013-01-10-Code-review-finds-minor-issue-in-Zlib.html b/_posts/2013-01-10-Code-review-finds-minor-issue-in-Zlib.html index 2697246d77f1e671da338bfce67c227ec8b95340..b774ab0cca627858b62a669de0c6a55f96ff0900 100644 --- a/_posts/2013-01-10-Code-review-finds-minor-issue-in-Zlib.html +++ b/_posts/2013-01-10-Code-review-finds-minor-issue-in-Zlib.html @@ -67,64 +67,5 @@ $ ./a.out out_buffer: 0x7fff59e83a34 strm->next_out=0x7fff59e83a34 and zlib is about to subtract one from it out=0x7fff59e83a33 end=0x7fff59e83a5e -</pre>" <p>In an article about <a href="https://www.dropbox.com/s/el2lidf5v71ogm6/p.pdf">comparing static analyzers</a> (long-time readers of the blog do not follow the link. It is still the same old article)…</p> -<p>Where was I? Ah yes. One reason why it is extremely tricky to compare static analyzers is that a static analyzer is for identifying <strong>undefined behavior</strong> in C programs but while some families of undefined behavior are extremely dangerous C has many families of undefined behaviors. Some of them have been rather harmless until now and programmers voluntarily use constructs that cause them. One example briefly alluded to in a certain article is the computation of an invalid offset of a pointer.</p> -<p>It is not alright for a C program to compute an invalid offset as in <code>char t[50]; ...(t-1)...</code>. This is technically undefined behavior. -Unfortunately it is not alright for a C static analyzer to warn for this either because the programmer is likely doing it on purpose. With some compilation options the QuickLZ compression library does it (on purpose).</p> -<p>Frama-C's value analysis choice is to remain silent for the computation of <code>t-1</code> but to warn if it is ultimately <a href="/index.php?post/2011/06/04/Valid-compare-pointers">compared</a> to another pointer—it could for instance equal <code>&c</code> against the programmer's expectations. Or of course the value analysis warns if the invalid pointer is dereferenced.</p> -<h2>Et tu zlib?</h2> -<p>Here is the beginning of file inffast.c in library zlib:</p> -<pre>#ifdef POSTINC -... -#else -# define OFF 1 -# define PUP(a) *++(a) -#endif -</pre> -<p>When you see <code>*++p</code> in a C program you can expect an invalid offset computation nearby. Indeed:</p> -<pre> in = strm->next_in - OFF; - ... - out = strm->next_out - OFF; -</pre> -<p>Zlib's documentation allows the user of the library to pass in <code>strm->next_in</code> and <code>strm->next_out</code> pointers to the beginning of allocated blocks. This can cause a minor undefined behavior for some inputs.</p> -<h2>A “bug†not found by static analysis</h2> -<p>Nothing would be easier than implementing the detection of this undefined behavior in Frama-C but seeing more and more code that invoke it does not convince me that programmers want to know about it. Anyway I just stumbled on macro <code>PUP</code> as I was analyzing zlib.</p> -<h2>Post-scriptum</h2> -<p>A way to exhibit the undefined behavior is to use the input vector in a <a href="/index.php?post/2013/01/16/Bad-zlib-bad">future post</a> together with a more stringent instrumentation:</p> -<pre>--- zlib-1.2.7/inffast.c 2010-04-19 06:16:23.000000000 +0200 -+++ zlib-modified/inffast.c 2013-01-21 00:56:25.000000000 +0100 -@@ -64 6 +64 9 @@ - requires strm->avail_out >= 258 for each loop to avoid checking for - output space. - */ -+ -+int printf(const char *fmt ...); -+ - void ZLIB_INTERNAL inflate_fast(strm start) - z_streamp strm; - unsigned start; /* inflate()'s starting value for strm->avail_out */ -@@ -98 6 +101 7 @@ - state = (struct inflate_state FAR *)strm->state; - in = strm->next_in - OFF; - last = in + (strm->avail_in - 5); -+ printf("strm->next_out=%p and zlib is about to subtract one from it" strm->next_out); - out = strm->next_out - OFF; - beg = out - (start - strm->avail_out); - end = out + (strm->avail_out - 257); -@@ -316 6 +320 7 @@ - strm->next_in = in + OFF; - strm->next_out = out + OFF; - strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); -+ printf("out=%p end=%p" out end); - strm->avail_out = (unsigned)(out < end ? - 257 + (end - out) : 257 - (out - end)); - state->hold = hold; -</pre> -<p>When I compile and execute I get:</p> -<pre>$ gcc -I Downloads/zlib-modified/ zlib_UB.c Downloads/zlib-modified/libz.a -$ ./a.out -out_buffer: 0x7fff59e83a34 -strm->next_out=0x7fff59e83a34 and zlib is about to subtract one from it -out=0x7fff59e83a33 end=0x7fff59e83a5e -</pre>" +</pre> {% endraw %} diff --git a/_posts/2013-01-14-Why-verify-zlib.html b/_posts/2013-01-14-Why-verify-zlib.html index eb8f558783c9da921d38f196dfb770a5619e30b4..d49edf95fc7246dfe191d3aef59003e5d68a2031 100644 --- a/_posts/2013-01-14-Why-verify-zlib.html +++ b/_posts/2013-01-14-Why-verify-zlib.html @@ -16,14 +16,5 @@ summary: <h2>Does it matter?</h2> <p>In 2005 people did think it <a href="http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2005-2096">mattered</a>. The CVE summary points out that zlib is involved when decompressing a PNG image (most users think of PNG images as innocuous objects that they should be allowed to look at regardless of origin without compromising the host computer). Other examples are the “Windows binary of Virtual Floppy Drive 2.1†and “Official Windows binaries of curlâ€. I do not think that list is exhaustive. Does the HTTP/1.1 protocol not allow for zlib-compressed data to be exchanged between client and server? A malicious client could cause a buffer overflow on the server with a simple request and/or a malicious server could cause a buffer overflow in the client by replying to a request with specially crafted pretend-compressed data.</p> <h2>And a benchmark for the future</h2> -<p>I am making a deliberate effort not to look at that bug now but it goes without saying that when the verification of zlib is done I will check that the same method find the bug that was in the pre-July-2005 version.</p> - <p>As an interlude in the zlib verification thread, this post asks two questions. Is there any chance of finding a bug in zlib, and does it matter?</p> -<h2>Could there be a bug in zlib?</h2> -<p>It is not entirely impossible. The previous post in this blog pointed to a relatively minor issue in the zlib source code, and the next post will show a more serious (albeit still minor) one.</p> -<p>In July of 2005, a buffer overflow in zlib was <a href="http://www.gentoo.org/security/en/glsa/glsa-200507-05.xml?style=printable">found</a> by Tavis Ormandy. Key quote: “An attacker could construct a malformed data stream embedding it within network communication or an application file format potentially resulting in the execution of arbitrary code when decoded by the application using the zlib library.â€</p> -<p>If you have been following the zlib thread this is exactly the context we are investigating: decompression of a maliciously crafted stream.</p> -<h2>Does it matter?</h2> -<p>In 2005 people did think it <a href="http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2005-2096">mattered</a>. The CVE summary points out that zlib is involved when decompressing a PNG image (most users think of PNG images as innocuous objects that they should be allowed to look at regardless of origin without compromising the host computer). Other examples are the “Windows binary of Virtual Floppy Drive 2.1†and “Official Windows binaries of curlâ€. I do not think that list is exhaustive. Does the HTTP/1.1 protocol not allow for zlib-compressed data to be exchanged between client and server? A malicious client could cause a buffer overflow on the server with a simple request and/or a malicious server could cause a buffer overflow in the client by replying to a request with specially crafted pretend-compressed data.</p> -<h2>And a benchmark for the future</h2> <p>I am making a deliberate effort not to look at that bug now but it goes without saying that when the verification of zlib is done I will check that the same method find the bug that was in the pre-July-2005 version.</p> {% endraw %} diff --git a/_posts/2013-01-16-Bad-zlib-bad-No-compare-pointer.html b/_posts/2013-01-16-Bad-zlib-bad-No-compare-pointer.html index 57d40c1162af3d91d8971b8c5a058c418fd87c5e..9ff13cd2c84c031b10839aa642666263d9a334f2 100644 --- a/_posts/2013-01-16-Bad-zlib-bad-No-compare-pointer.html +++ b/_posts/2013-01-16-Bad-zlib-bad-No-compare-pointer.html @@ -89,87 +89,5 @@ out=0x7fff5bd9fa33 end=0x7fff5bd9fa5e <p>Defining POSTINC makes both the minor issues go away.</p> <h2>Conclusion</h2> <p>The defect identified here is related to the previous one and like it it is probably innocuous. Nevertheless we initially set out to formally verify zlib so we should stick to it: a formally verified zlib wouldn't compute negative offsets of arrays much less compare them to valid offsets of the same array. So far I have not been able to confirm any of the potential issues listed by Frama-C's value analysis in zlib with POSTINC defined so that version of the library may reveal itself to be the formally verified version we are after.</p> -<p>This post was proofread by Fabrice Derepas and Olivier Gay.</p> - <p>In a <a href="/zlib/2013/01/10/Code-review-finds-minor-issue-in-Zlib">previous</a> post we remarked that the decompression function of zlib for some inputs computes an invalid pointer. But at least it neither dereferences it nor compares it to another pointer.</p> -<p>Or does it?</p> -<h2>Recipe for an invalid pointer comparison</h2> -<h3>Instrument</h3> -<p>Take an ordinary zlib library version 1.2.7 and instrument it according to the diff below.</p> -<pre>$ diff -u zlib-1.2.7/inffast.c zlib-modified/inffast.c ---- zlib-1.2.7/inffast.c 2010-04-19 06:16:23.000000000 +0200 -+++ zlib-modified/inffast.c 2013-01-16 23:37:55.000000000 +0100 -@@ -64 6 +64 9 @@ - requires strm->avail_out >= 258 for each loop to avoid checking for - output space. - */ -+ -+int printf(const char *fmt ...); -+ - void ZLIB_INTERNAL inflate_fast(strm start) - z_streamp strm; - unsigned start; /* inflate()'s starting value for strm->avail_out */ -@@ -316 6 +319 7 @@ - strm->next_in = in + OFF; - strm->next_out = out + OFF; - strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); -+ printf("out=%p end=%p" out end); - strm->avail_out = (unsigned)(out < end ? - 257 + (end - out) : 257 - (out - end)); - state->hold = hold; -</pre> -<p>This instrumentation causes two pointers <code>out</code> and <code>end</code> that are compared at that point of the library to be printed. Apart from that it does not change the behavior of the library. The library behaves the same when the <code>printf()</code> call is not there albeit less observably.</p> -<h3>Following the documentation write an ordinary main()</h3> -<p>Prepare a <code>main()</code> function that uncompresses a buffer <code>deflated_buffer</code> more or less according to the <a href="http://www.zlib.net/zlib_how.html">official tutorial</a>:</p> -<pre>main(){ - unsigned char out_buffer[CHUNK_OUT]; - printf("out_buffer: %p" out_buffer); - /* allocate inflate state */ - ... - ret = inflateInit(&my_strm); - if (ret != Z_OK) - return ret; - my_strm.next_in = deflated_buffer; - my_strm.avail_in = 40; - my_strm.next_out = out_buffer; - my_strm.avail_out = CHUNK_OUT; - ret = inflate(&my_strm Z_FINISH); - ... -} -</pre> -<p>You can download the file <a href="/assets/img/blog/imported-posts/zlib_UB.c">zlib_UB.c</a>.</p> -<h3>Secret ingredient</h3> -<p>Season with a specially crafted deflated buffer:</p> -<pre>unsigned char deflated_buffer[40] = { - 120 - 156 - 67 - 84 -... -</pre> -<h3>Test</h3> -<p>Having built the instrumented zlib you can compile and link the <code>main()</code> function:</p> -<pre>$ gcc -I Downloads/zlib-modified/ zlib_UB.c Downloads/zlib-modified/libz.a -$ ./a.out -out_buffer: 0x7fff5bd9fa34 -out=0x7fff5bd9fa33 end=0x7fff5bd9fa5e -</pre> -<p>Although we followed the documentation when writing the <code>main()</code> function that calls it zlib appears to be at inffast.c:320 comparing a pointer <code>out</code> that points before <code>out_buffer</code> to a pointer <code>end</code> that points inside <code>out_buffer</code>. In fact the pointer <code>out</code> has been computed as an offset of <code>out_buffer</code> namely <code>out_buffer - 1</code>. Zlib is not supposed to do this for two reasons:</p> -<ol> -<li>The compiler could place <code>out_buffer</code> at address <code>0</code> or at the beginning of a segment in a segmented architecture. Then <code>out_buffer - 1</code> would evaluate to <code>0xffffffffffff</code> and appear to be larger than <code>end</code> or cause a hardware exception. To be fair in general the same value still ends up being stored in <code>strm->avail_out</code> because both branches of the expression <code>(out < end ? 257 + (end - out) : 257 - (out - end))</code> <a href="http://stackoverflow.com/q/14374437/139746">compute</a> the same thing.</li> -<li>Even without the array <code>out_buffer</code> being placed at address 0—which is rather unlikely—the compiler could suddenly become too smart for its own good and generate code that treats the condition <code>out < end</code> as false in this case. This has <a href="http://lwn.net/Articles/278137/">happened</a> before. Key quote: “Some versions of gcc may silently discard certain checks for overflow. Applications compiled with these versions of gcc may be vulnerable to buffer overflows.†In this case the invalid pointer <code>out_buffer - 1</code> would be interfering with a compiler optimization so anything might happen. Since it is <code>strm->avail_out</code> the statement is computing a buffer overflow might result.</li> -</ol> -<h2>Fix</h2> -<p>This problem and the previously described one have the same cause; they stem from the following optimization in inffast.c:</p> -<pre>#ifdef POSTINC -# define OFF 0 -# define PUP(a) *(a)++ -#else -# define OFF 1 -# define PUP(a) *++(a) -#endif -</pre> -<p>Defining POSTINC makes both the minor issues go away.</p> -<h2>Conclusion</h2> -<p>The defect identified here is related to the previous one and like it it is probably innocuous. Nevertheless we initially set out to formally verify zlib so we should stick to it: a formally verified zlib wouldn't compute negative offsets of arrays much less compare them to valid offsets of the same array. So far I have not been able to confirm any of the potential issues listed by Frama-C's value analysis in zlib with POSTINC defined so that version of the library may reveal itself to be the formally verified version we are after.</p> <p>This post was proofread by Fabrice Derepas and Olivier Gay.</p> {% endraw %} diff --git a/_posts/2013-01-23-2000s.html b/_posts/2013-01-23-2000s.html index 7f30045d1eba5f76457529da8b63751aa413f532..f7a02bc48bdb591602a1cf369337427dd302b1d6 100644 --- a/_posts/2013-01-23-2000s.html +++ b/_posts/2013-01-23-2000s.html @@ -17,15 +17,5 @@ summary: <p>In 1996 I left France for a 2-and-a-half months internship at Indiana University. Before I left I taught my father to use the 28800 BPS external modem I was leaving him to dial long-distance to Lyon impersonate me on the ENSL's server upload a text file containing news of the family download a text file that might contain news from me and disconnect as soon as possible because heck that was expensive (although cheaper than any available alternative). This was done with software that was called either “<a href="http://en.wikipedia.org/wiki/Kermit_(protocol)">Kermit</a>†or “<a href="http://en.wikipedia.org/wiki/ZMODEM">ZMODEM</a>â€. Kermit I am pretty sure it was. You could not trust these new-fangled protocols then any more than you can now.</p> <p>Nowadays my father has his own e-mail address and he may write to anyone he likes as opposed to leaving messages in a dropbox for me. And he does not pay long-distance rates for it.</p> <p>But I can't help thinking that all progress that has occurred since then was incremental. Slightly better for much cheaper. There has been the iPhone. But then again the first PalmPilot was launched in 1997.</p> -<p>So what have we been doing during the years 2000? What technologies were so life-changing that we are going to take them for granted in the 2010s?</p> - <p>Blogger of multiple qualities <a href="http://techland.time.com/author/hmccracken/">Harry McCracken</a> was recently still looking for “an iPad PDF reader which can handle giant files which are 100s of pages long without chokingâ€. Sorry I meant “STILL lookingâ€.</p> -<p>PDF is a nineteen-nineties technology to display <a href="http://en.wikipedia.org/wiki/Portable_Document_Format">text and pictures</a>. Key quote: “Each PDF file encapsulates a complete description of a fixed-layout flat document including the text fonts graphics and other information needed to display itâ€.</p> -<p>Now you might think that any proposal made in 1991 to master the intricacies of displaying text and pictures would have succeeded by 2013 but apparently not according to Harry's call for help.</p> -<p>Fortunately another nineteen-nineties technology came to the rescue: the <a href="http://en.wikipedia.org/wiki/Djvu">Djvu format</a> was created in 1996 for the purpose I wish I was kidding to store text and images. Key quote: “a computer file format designed primarily to store scanned documents especially those containing a combination of text line drawings indexed color images and photographsâ€.</p> -<p>It is good to see progress at work. Even if we acknowledge that it takes years to get these things right and that a project started in 1996 is bound to be more technologically advanced than one started in 1991 there remains the question what the file have we been collectively doing during the years 2000?</p> -<p>This leads me into a personal anecdote. In 1995 I was admitted at the ENS of Lyon (and I may be thinking about it because I am visiting back there on January 29. Drop by if you are around…). These were interesting times: 1995 is more or less the year the internet slash the world wide web started to become widespread in the US and then in other parts of the world. We were privileged to have access to it already at the ENSL.</p> -<p>In 1996 I left France for a 2-and-a-half months internship at Indiana University. Before I left I taught my father to use the 28800 BPS external modem I was leaving him to dial long-distance to Lyon impersonate me on the ENSL's server upload a text file containing news of the family download a text file that might contain news from me and disconnect as soon as possible because heck that was expensive (although cheaper than any available alternative). This was done with software that was called either “<a href="http://en.wikipedia.org/wiki/Kermit_(protocol)">Kermit</a>†or “<a href="http://en.wikipedia.org/wiki/ZMODEM">ZMODEM</a>â€. Kermit I am pretty sure it was. You could not trust these new-fangled protocols then any more than you can now.</p> -<p>Nowadays my father has his own e-mail address and he may write to anyone he likes as opposed to leaving messages in a dropbox for me. And he does not pay long-distance rates for it.</p> -<p>But I can't help thinking that all progress that has occurred since then was incremental. Slightly better for much cheaper. There has been the iPhone. But then again the first PalmPilot was launched in 1997.</p> <p>So what have we been doing during the years 2000? What technologies were so life-changing that we are going to take them for granted in the 2010s?</p> {% endraw %} diff --git a/_posts/2013-01-24-Customers-customers-customers.html b/_posts/2013-01-24-Customers-customers-customers.html index 1e93c4bcfecb9c89e66cd8cd92116b2c5bfab2b2..3acb7d1e17715f24c2e5d1d196f8b3688bd16820 100644 --- a/_posts/2013-01-24-Customers-customers-customers.html +++ b/_posts/2013-01-24-Customers-customers-customers.html @@ -9,7 +9,5 @@ summary: --- {% raw %} <p>The recent posts on extremely minor <a href="/index.php?post/2013/01/16/Bad-zlib-bad">undefined behaviors in zlib</a> neatly tie in with a <a href="http://blog.regehr.org/archives/880">discussion</a> on John Regehr's blog about the future-proofitude of C and C++.</p> -<p>Another insightful post in this regard is <a href="http://shape-of-code.coding-guidelines.com/2013/01/23/only-compiler-vendor-customers-not-its-users-count/">this one</a> by Derek Jones. Derek claims that the situation is different for proprietary compilers with paying customers. The argument rings true to me. The only proprietary compiler I know that competes with GCC or Clang in terms of aggressive optimization (at the cost of breakage of existing code) is the Intel C++ compiler. But that is not a counter-example: I did not pay for icc nor do I know anyone who pays for it in order to use it in production.</p> - <p>The recent posts on extremely minor <a href="/index.php?post/2013/01/16/Bad-zlib-bad">undefined behaviors in zlib</a> neatly tie in with a <a href="http://blog.regehr.org/archives/880">discussion</a> on John Regehr's blog about the future-proofitude of C and C++.</p> <p>Another insightful post in this regard is <a href="http://shape-of-code.coding-guidelines.com/2013/01/23/only-compiler-vendor-customers-not-its-users-count/">this one</a> by Derek Jones. Derek claims that the situation is different for proprietary compilers with paying customers. The argument rings true to me. The only proprietary compiler I know that competes with GCC or Clang in terms of aggressive optimization (at the cost of breakage of existing code) is the Intel C++ compiler. But that is not a counter-example: I did not pay for icc nor do I know anyone who pays for it in order to use it in production.</p> {% endraw %} diff --git a/_posts/2013-02-01-ENSL-seminar.html b/_posts/2013-02-01-ENSL-seminar.html index b5b7d2a56126794ad0f15f87be916eb925b2211e..a7d898586883a042f4664fbd1f27f815bc9422de 100644 --- a/_posts/2013-02-01-ENSL-seminar.html +++ b/_posts/2013-02-01-ENSL-seminar.html @@ -22,19 +22,5 @@ summary: <h2>A reflexive illustration</h2> <p>One last thing: this blog post contains two links one that I expect to be to a Java web applet (my nephew was playing a game that I bought a license for and downloaded the old-fashioned way in the early 2000s but it always felt like Java especially at launch-time). The other is to a Flash video. If either of them worked for you you should seriously think about disabling plug-ins in your browser. Yes you will be missing out but frankly this is the only solution at this time.</p> <blockquote><p>Students from ENSL or elsewhere if you would like to help solve this problem (at least the part where embedded-like C code is concerned) and at the same time solve your problem of picking a first- or second-year internship e-mail addresses of Frama-C developers are either firstname dot lastname at inria dot fr for contributors from Inria or firstname dot lastname at cea dot fr for contributors from CEA (including me).</p> -</blockquote>" <h2>Seminar</h2> -<p>As anticipated, I was at my alma mater's student seminar last tuesday. School and seminar were very much like I remembered them. The latter was improved by orange juice and biscuits to chat around after the talk, that I do not think were part of the protocol when I was a student.</p> -<blockquote><p>My years at the ENS of Lyon were a good time, but I had forgotten the reasons that made them so. If any of the students from the seminar read this, I hope they will pass on my thanks to everyone for reminding me why. In one word, it is the company.</p> -</blockquote> -<p>The sort of discussion that emerges naturally in an open, low-stakes chat after a general presentation of Frama-C but is too open-ended to be part of the talk's questions is that of general usefulness.</p> -<p>Not every programmer is writing critical embedded code—in fact, most of us aren't. But in this day and age, many of us who program at all write code with mild to severe security implications, and I believe that with a reasonable amount of work, Frama-C can next help here.</p> -<h2>Video games, and software security in the news</h2> -<p>The seminar also gave me an excuse to visit my family that lives in the general area of Lyon. As a result, today, I was helping my nephew play Professor Fizzwizzle (now an <a href="http://www.heavygames.com/professorfizzwizzle/gameonline.asp">online game</a> apparently) after lunch when the 13:00 TV news announced that some webcams sold for the purpose of allowing homeowners to watch their living room remotely and reassure themselves that they are not being burgled instead allowed anyone with internet access to watch at any time.</p> -<p>This was not by design of course. This was the result of a security flaw. I am not saying that the security flaw was one of the kind Frama-C identifies say a buffer overflow in a C program: the <a href="http://pluzz.francetv.fr/videos/jt_13h_ 76414636.html">France 2 news report</a> (in French available for a week) did not go into such detail. But I am willing to bet that software was involved.</p> -<h2>The future</h2> -<p>So what world is my three-year-old nephew going to grow in? Either we collectively solve the software security problem and hopefully when he is in age of lending an ear to TV news while playing Professor Fizzwizzle there won't be any more of these spectacular failures to announce. Or we do not and then at the current rhythm TV news won't announce security failures because they will not be news any more.</p> -<h2>A reflexive illustration</h2> -<p>One last thing: this blog post contains two links one that I expect to be to a Java web applet (my nephew was playing a game that I bought a license for and downloaded the old-fashioned way in the early 2000s but it always felt like Java especially at launch-time). The other is to a Flash video. If either of them worked for you you should seriously think about disabling plug-ins in your browser. Yes you will be missing out but frankly this is the only solution at this time.</p> -<blockquote><p>Students from ENSL or elsewhere if you would like to help solve this problem (at least the part where embedded-like C code is concerned) and at the same time solve your problem of picking a first- or second-year internship e-mail addresses of Frama-C developers are either firstname dot lastname at inria dot fr for contributors from Inria or firstname dot lastname at cea dot fr for contributors from CEA (including me).</p> -</blockquote>" +</blockquote> {% endraw %} diff --git a/_posts/2013-02-16-From-Facebook-to-Silent-Circle-through-the-metrics-Frama-C-plug-in.html b/_posts/2013-02-16-From-Facebook-to-Silent-Circle-through-the-metrics-Frama-C-plug-in.html index 641b579d0ce10c9d3490f128d6a3c75082716eed..2234334afaf4080700e3723d3f4cdcafd64b3625 100644 --- a/_posts/2013-02-16-From-Facebook-to-Silent-Circle-through-the-metrics-Frama-C-plug-in.html +++ b/_posts/2013-02-16-From-Facebook-to-Silent-Circle-through-the-metrics-Frama-C-plug-in.html @@ -80,77 +80,5 @@ parseSDP.c:308:[kernel] warning: out of bounds read. assert \valid_read(buf); ... parseSDP.c:308:[kernel] warning: out of bounds read. assert \valid_read(buf); parseSDP.c:309:[kernel] warning: out of bounds read. assert \valid_read(buf); -</pre>" <h2>From Facebook to Silent Circle</h2> -<p>Some computers at Facebook were recently <a href="http://arstechnica.com/security/2013/02/facebook-computers-compromised-by-zero-day-java-exploit/">compromised</a> because of a zero-day in Java. Nothing unexpected. -Last december instead of writing a full blog post I <a href="/cybersecurity/link/2012/12/30/December-in-Security">lazily linked</a> to Robert Graham predicting this sort of thing for the year 2013.</p> -<p>Speaking of Facebook do you know who cares for your privacy? The good people at <a href="https://silentcircle.com">Silent Circle</a>. They provide end-to-end encryption to use on your mobile phone so that the only people to hear your discussions with your loved ones or business partners are you and them and perhaps passengers in the same compartment as you if you are this sort of sociopath.</p> -<p>Speaking of Robert Graham he has written another excellent post on the dangers of only focusing on the obviously important the hard-to-get-right but known-to-be-hard-to-get-right cryptographic stuff and neglecting the mundane such as parsing. He <a href="http://erratasec.blogspot.fr/2013/02/silent-circle-and-inexperienced.html">takes the example</a> of source code recently released by Silent Circle finding traces of amateurism in the implementation of <a href="http://en.wikipedia.org/wiki/Session_Description_Protocol">SDP</a>. This is not were the hard cryptographic stuff takes place. But because this is a C++ implementation any exploitable flaw at this level could have deep security implications. A buffer overflow could result in execution of code chosen by the attacker and the attacker-chosen code could disable the cryptography entirely or worse.</p> -<blockquote><p>An attack on the protocol implementation is the equivalent of a $5 wrench in a well-known cryptography-related XKCD comic that probably does not require linking to at this point.</p> -</blockquote> -<h2>A mysterious commit message</h2> -<blockquote><p>[Metrics] Fix most complicated plugin ever metrics (globals counted twice if declared and defined)</p> -</blockquote> -<p>The above is the message attached by a facetious colleague to commit 21435 during the just elapsed week. -After inquiry the message is at least one-third sarcastic. Still no-one ever said that the metrics plug-in should be simpler or easier to get right on first try than any of the other Frama-C plug-ins. And in fact this was neither the first nor the last minor issue fixed in that plug-in last week.</p> -<p>Frama-C's metrics plug-in gathers various measurements of a syntactic nature. The “metrics†plug-in can help check how much of an unfamiliar codebase has actually been analyzed with a plug-in of a more semantic flavor such as the value analysis. It is used in context in the next section of this post.</p> -<p>One reason “metrics†as hard to get right as any other Frama-C plug-in is that it deals with syntax. Semantic plug-ins such as the value analysis only need manipulate abstract objects such as functions and variables. In the metrics plug-in details matter such as the nuance between the declaration (in a <code>.h</code> header file) and the definition (in a <code>.c</code> file) of the same function (that was the bug being fixed in commit 21435) or the subtle difference between the source location of a variable and the source location of its initializer (that was another bug fixed this week).</p> -<p>Metaphorically the metrics plug-in is to the Frama-C platform what the SDP parser is to an end-to-end encryption solution. It is not sexy but it is just as hard to get right and as essential as the rest.</p> -<h2>Using the metrics plug-in</h2> -<p>Life being what it is we sometimes find ourselves analyzing very unfamiliar code. I am talking code without documentation here and often without either the hardware or a minimal description of the hardware that would be necessary to understand what behaviors can be exercised in the source code. This is one case when the metrics plug-in helps either anticipate how much work will be necessary or how much has already been done.</p> -<p>Inspired by Robert Graham's post I converted the Silent Circle SDP parser from C++ to C so as to see whether I could not find a bug in it using Frama-C's value analysis. -At some point I had this <a href="/assets/img/blog/imported-posts/parseSDP.c">modified parseSDP.c</a> file and this <a href="/assets/img/blog/imported-posts/sdp.h">modified sdp.h</a> file. The originals can be seen here for <a href="https://github.com/SilentCircle/silent-phone-base/blob/master/silentphone/sdp/parseSDP.cpp">parseSDP.c</a> and <a href="https://github.com/SilentCircle/silent-phone-base/blob/master/silentphone/sdp/sdp.h">sdp.h</a>.</p> -<pre>$ frama-c -cpp-command "gcc -C -E -I. -I `frama-c -print-share-path`/libc" parseSDP.c -metrics -[kernel] preprocessing with "gcc -C -E -I. -I /usr/local/share/frama-c/libc parseSDP.c" -parseSDP.c:120:[kernel] warning: Calling undeclared function ipstr2long. Old style K&R code? -parseSDP.c:121:[kernel] warning: Calling undeclared function reverseIP. Old style K&R code? -parseSDP.c:328:[kernel] warning: Calling undeclared function u. Old style K&R code? -[metrics] Defined functions (6) - ===================== - findMediaId (0 call); hasAttrib (0 call); findCrLf (4 calls); - findip (3 calls); getMediaParams (1 call); parseSDP (0 call); - Undefined functions (10) - ======================== - printf (1 call); strlen (1 call); strncmp (6 calls); atoi (2 calls); - isdigit (4 calls); islower (1 call); isxdigit (1 call); ipstr2long (1 call); - reverseIP (1 call); u (4 calls); - Potential entry points (3) - ========================== - findMediaId; hasAttrib; parseSDP; -... -</pre> -<p>This snapshot arrives at a good time to use the metric plug-in as above. -The plug-in says that good entry points to start the analysis from are <code>findMediaId()</code> <code>hasAttrib()</code> and <code>parseSDP()</code>. The heuristic here is that these functions are provided and aren't called so they are likely to be part of the API.</p> -<p>The metrics plug-in also says that the only missing functions are those from <code>printf()</code> to <code>isxdigit()</code> (these are part of the standard library) <code>u()</code> (I introduced this function myself when converting from C++ to C) and <code>ipstr2long()</code> and <code>reverseIP()</code> that are the only two that require digging up from elsewhere in the codebase. At that point I decided that the functions probably weren't important and that I could let Frama-C infer some sort of behavior for them based on their respective types.</p> -<blockquote><p>The $5-wrench kind of flaw in the verification process would be to fail to notice that an important function is missing. Then the value analysis might report few or no issues not because the code is safe but because the analysis failed to visit most of it. In another scenario the value analysis might fail to visit a large part of the code because there is an error early on that makes it look like the rest is unreachable. The “metrics†plug-in is the best safeguard we have against this kind of mistake which is easy to make when verifying unfamiliar code.</p> -</blockquote> -<h2>A quick look at function <code>parseSDP()</code></h2> -<p>I finally used the commandline:</p> -<pre>$ frama-c -cpp-command "gcc -C -E -I. -I `frama-c -print-share-path`/libc" parseSDP.c \ - -lib-entry -main parseSDP -context-valid-pointers -context-width 20 -val -</pre> -<p>Here are a few alarms found this way cherry-picked as interesting because they are caused directly from the contents of the buffer pointed to by <code>buf</code> that we assume to be under an attacker's control for this exercise.</p> -<blockquote><p>Some alarms seem by contrast to be caused by the contents of <code>*psdp</code>. These are not as interesting to investigate because that structure probably has some invariants it is supposed to satisfy so the alarms we get there are only caused by the lack of context.</p> -</blockquote> -<p>From the way it is handled inside <code>parseSDP()</code> it seems that <code>buf</code> is only assumed to point to a zero-terminated string. It is a good way to pass a Sunday afternoon to see whether these alarms correspond to a real danger of buffer overflow for some input.</p> -<pre>parseSDP.c:84:[kernel] warning: out of bounds read. assert \valid_read(buf+1); -parseSDP.c:82:[kernel] warning: out of bounds read. assert \valid_read(buf); -... -parseSDP.c:162:[kernel] warning: out of bounds read. assert \valid_read(buf); -parseSDP.c:165:[kernel] warning: out of bounds read. assert \valid_read(buf-2); -parseSDP.c:167:[kernel] warning: out of bounds read. assert \valid_read(buf+1); -... -parseSDP.c:262:[kernel] warning: out of bounds read. assert \valid_read(buf); -... -parseSDP.c:291:[kernel] warning: out of bounds read. assert \valid_read(buf); -parseSDP.c:294:[kernel] warning: out of bounds read. assert \valid_read(buf); -... -parseSDP.c:300:[kernel] warning: out of bounds read. assert \valid_read(buf); -... -parseSDP.c:303:[kernel] warning: out of bounds read. assert \valid_read(buf); -... -parseSDP.c:308:[kernel] warning: out of bounds read. assert \valid_read(buf); -... -parseSDP.c:308:[kernel] warning: out of bounds read. assert \valid_read(buf); -parseSDP.c:309:[kernel] warning: out of bounds read. assert \valid_read(buf); -</pre>" +</pre> {% endraw %} diff --git a/_posts/2013-02-26-Portable-modulo-signed-arithmetic-operations.html b/_posts/2013-02-26-Portable-modulo-signed-arithmetic-operations.html index 6ef74d7170bed8643f1e2e80f7bbeed21b20f5eb..b8eb83cc986880d7b251669931d49124e076a97b 100644 --- a/_posts/2013-02-26-Portable-modulo-signed-arithmetic-operations.html +++ b/_posts/2013-02-26-Portable-modulo-signed-arithmetic-operations.html @@ -42,40 +42,5 @@ summary: <p>Issues of the nature discussed here should be in the bytecode version of the OCaml compiler only. By contrast the native compiler should translate OCaml-level multiplication directly to assembly multiplication bypassing the portable^Wwoefully underspecified assembly that is the C language.</p> <blockquote><p>Even programs generated by the native compiler interface with bits of OCaml runtime written in C but this runtime is small.</p> </blockquote> -<p>So actually there is not much cause for worry. If you are using a C compiler or a <a href="http://frama-c.com/">static analysis platform</a> that involve OCaml code on a modern computer they are probably already compiled with the native OCaml compiler.</p> - <p>In a recent post, John Regehr <a href="http://blog.regehr.org/archives/903">reports</a> on undefined behaviors in Coq! In Coq! Coq! Exclamation point!</p> -<blockquote><p>Coq is a proof assistant. It looks over your shoulder and tells you what remains to be done while you are elaborating a mathematical proof. Coq has been used to check that the <a href="http://www.ucalgary.ca/rzach/blog/2005/04/four-color-theorem-verified-in-coq.html">4-color theorem really holds</a>. It would be supremely ironic if an undefined behavior in a bit of C code in the OCaml implementation used to compile Coq caused it to accept as valid some incorrect proofs for instance in the formally verified (in Coq) compiler <a href="http://compcert.inria.fr">CompCert</a>.</p> -</blockquote> -<h2>Your mission should you decide to accept it</h2> -<p>Where are these undefined behaviors? They are in several places but some of them are in the implementation of the bytecode arithmetic operations. In OCaml basic operations such as addition and multiplication are specified as returning the mathematical result modulo 2^31 2^32 2^63 or 2^64 depending on the compilation platform and the integer type.</p> -<p>The problem here is not limited to OCaml. The Java Virtual Machine too specifies that arithmetic operations on its 32-bit integer type return results modulo 2^32. Someone wishing to implement a JVM in portable C would face the same issues.</p> -<p>In fact this is just such a big issue that we should collectively try to work out a solution now.</p> -<h2>A safer signed addition instruction</h2> -<p>Let us assume a 32-bit platform. In this case values of the unboxed OCaml type <code>int</code> range between -2^30 and 2^30-1 (31 bits of information). They are stored at run-time in the 31 most significant bits of a machine word with the least significant bit set to one to distinguish it from a pointer. This representation is taken into account when applying arithmetic operations to machine words representing unboxed integers.</p> -<p>Here is an example in file interp.c in the OCaml implementation. We are in the middle of the large <code>switch</code> that decodes bytecode instructions:</p> -<pre> Instruct(ADDINT): - accu = (value)((intnat) accu + (intnat) *sp++ - 1); Next; -</pre> -<p>The <code>- 1</code> in this expression compensates for the fact that the least significant bit is set in both operands and we want it to be set in the result (and no carry to be propagated). But as written there is an undefined overflow in the C implementation of the bytecode interpreter when the unboxed integers in <code>accu</code> and <code>*sp</code> total more than <code>2^30-1</code>. In order to avoid a signed overflow here the instruction ADDINT could be written:</p> -<pre> accu = (value)((uintnat) accu + (uintnat) *sp++ - 1U); Next; -</pre> -<p>This solution takes advantage of the fact that unlike signed addition the behavior of unsigned addition when the result overflows the destination type is defined by the C standard. The solution above does make assumptions about the conversion from a signed to an unsigned type and vice versa but these are implementation-defined (and we are only targeting implementations that define these conversions as 2's-complement).</p> -<p>No overhead is involved in this approach: a half-decent C compiler should generate the same instruction sequence for the new version as it already generates for the old version.</p> -<h2>Multiplication</h2> -<p>You may be vaguely worried about multiplication. For instance you may remember that while in a typical instruction set there is only one addition instruction that works for both signed and unsigned operands there are dedicated signed multiplication and unsigned multiplication instructions. These are IMUL and MUL in the x86 family of processors.</p> -<p>Fear not! The two multiplications are only because on x86 and many other processors 32-bit multiplication returns a 64-bit result. If you want all 64 bits of the results to be what you expect you need to choose the instruction that interprets the operands' highest bit correctly. But if on the other hand you only care for the lowest 32 bits of the result (that is you only want a result modulo 2^32) then it does no matter that you use unsigned multiplication. Think of it as (x + k1 * 2^32) * (y + k2 * 2^32) for unknown k1 and k2.</p> -<p>And this is our case. Thus in interp.c the implementation for bytecode instruction MULINT could be changed from:</p> -<pre>Instruct(MULINT): - accu = Val_long(Long_val(accu) * Long_val(*sp++)); Next; -</pre> -<p>to:</p> -<pre>Instruct(MULINT): - accu = Val_long((intnat)((uintnat)Long_val(accu) * (uintnat)Long_val(*sp++))); Next; -</pre> -<h2>Conclusion</h2> -<p>As pointed out by John Regehr in the comments the two fixes above are appropriate because the OCaml language definition specifies wrap-around behavior for its (signed) arithmetic operations. One should not assume that all the warnings emitted by IOC have a similar cause. Some may be deeper bugs requiring the logic to be fixed instead of conversions to unsigned types that only ensure wrap-around behavior.</p> -<p>Issues of the nature discussed here should be in the bytecode version of the OCaml compiler only. By contrast the native compiler should translate OCaml-level multiplication directly to assembly multiplication bypassing the portable^Wwoefully underspecified assembly that is the C language.</p> -<blockquote><p>Even programs generated by the native compiler interface with bits of OCaml runtime written in C but this runtime is small.</p> -</blockquote> <p>So actually there is not much cause for worry. If you are using a C compiler or a <a href="http://frama-c.com/">static analysis platform</a> that involve OCaml code on a modern computer they are probably already compiled with the native OCaml compiler.</p> {% endraw %} diff --git a/_posts/2013-03-03-Correct-rounding-or-mathematically-correct-rounding.html b/_posts/2013-03-03-Correct-rounding-or-mathematically-correct-rounding.html index f72fe464c1f9b8e1ca4b82364e311a3cd73d4ab9..2ac62a2ea59e87b10e6fcb182f7b024302612f85 100644 --- a/_posts/2013-03-03-Correct-rounding-or-mathematically-correct-rounding.html +++ b/_posts/2013-03-03-Correct-rounding-or-mathematically-correct-rounding.html @@ -62,60 +62,5 @@ ld 3.14159265358979323851280895940618620443274267017841 <p>This assertion will never trigger! The function <code>atanf()</code> will indeed return at most the single-precision float <code>3.1415926535897932f/2.0f</code>. It does not matter that this number is actually slightly larger than Ï€/2. For all intents and purposes in the twisted world of single-precision floating-point this number is Ï€/2.</p> <h2>Conclusion</h2> <p>There are other scenarios in which the innocent user might genuinely have an unpleasant surprise. The result of a computation may be converted to decimal for humans to read and the user may be surprised to see a value outside the range ey expected. But this user would have the wrong expectations just as if ey expected <code>10.0 * atan(x)</code> to always be less than 5Ï€. Plenty of these users and developers can be found. But my opinion for what it is worth is that by making special cases you are not helping these users only feeding their delusions.</p> -<p>The correct way to set expectations regarding the results of a floating-point program is numerical analysis. Numerical analysis is hard. Special cases such as the authors of CRlibm threaten to implement only seem to make it harder.</p> - <p><a href="http://lipforge.ens-lyon.fr/www/crlibm/">CRlibm</a> is a high-quality library of floating-point elementary functions. We used it as reference a long time ago in this blog while looking at lesser elementary function implementations and the even lesser properties we could verify about them.</p> -<h2>A bold choice</h2> -<p>The CRlibm <a href="http://ftp.nluug.nl/pub/os/BSD/FreeBSD/distfiles/crlibm/crlibm-1.0beta3.pdf">documentation</a> contains this snippet:</p> -<blockquote><p>[…] it may happen that the requirement of correct rounding conflicts with a basic mathematical property of the function such as its domain and range. A typical example is the arctangent of a very large number which rounded up will be a number larger than Ï€/2 (fortunately â—¦(Ï€/2) < Ï€/2). The policy that will be implemented in crlibm will be</p> -<p> -• to give priority to the mathematical property in round to nearest mode (so as not to hurt the innocent user who may expect such a property to be respected) and</p> -<p> -• to give priority to correct rounding in the directed rounding modes in order to provide trustful bounds to interval arithmetic.</p> -</blockquote> -<p>The choice for directed rounding modes is obviously right. I am concerned about the choice made for round-to-nearest. -The documentation states the dilemma very well. One can imagine slightly out of range values causing out-of-bound indexes during table look-ups and worse things.</p> -<p>I seldom reason about floating-point programs. I work on static analysis and am only concerned about floating-point inasmuch as it is a requirement for writing a static analyzer correct for programs that include floating-point computations.</p> -<p>However when I do reason about floating-point programs I am more often compounding approximations starting from the base assumption that <strong>a correctly rounded function returns a result within 1/2ulp of the mathematical result</strong> than I am assuming that atan(x) ≤ Ï€/2. The choice the CRlibm implementors made means that suddenly the reasoning I often make is wrong. The value of <code>atan(x)</code> in the program may not be 1/2ulp from the real arctangent of the same <code>x</code>. It can be more when <code>x</code> is very large and mathematical-correctness overrode correct rounding.</p> -<blockquote><p>Truck drivers fall asleep at the wheel when they face long dull stretches of straight empty roads. Similarly it is good to have another special case to consider when reasoning about floating-point computations. With only infinites and denormals to worry about it can get you know a bit too easy.</p> -</blockquote> -<h2>Oh well it's only Ï€/2</h2> -<p>In this section I rhetorically assume that it is only Ï€/2 for which there is a problem. The CRlibm documentation reminds us that in the case of double precision we were lucky. Or perhaps it isn't luck and the IEEE 754 committee took the desirableness of the property (double)Ï€/2 < Ï€/2 into account when it chose the number of bits in the significand of the double-precision format.</p> -<p>How lucky (or careful) have we been exactly? Let us test it with the program below — assuming my compilation platform works as intended.</p> -<pre>#include <stdio.h> -#define PI(S) 3.1415926535897932384626433832795028841971693993751##S -float f = PI(f); -double d = PI(); -long double ld = PI(L); -int main(){ - printf(" 3.14159265358979323846264338327950288419716939937510"); - printf("f %.50f" f); - printf("d %.50f" d); - printf("ld %.50Lf" ld); -} -</pre> -<p>The result of compiling and executing the program is for me:</p> -<pre> 3.14159265358979323846264338327950288419716939937510 -f 3.14159274101257324218750000000000000000000000000000 -d 3.14159265358979311599796346854418516159057617187500 -ld 3.14159265358979323851280895940618620443274267017841 -</pre> -<p>As you can see the nearest single-precision float to Ï€ is above Ï€ as is the nearest 80-bit long double. The same goes for Ï€/2 because the floating-point representations for Ï€ and Ï€/2 only differ in the exponent. Consequently the issue raised by the CRlibm implementors will come up for both functions <code>atanf()</code> and <code>atanl()</code> when it is time to get them done. We were not very lucky after all (or careful when defining the IEEE 754 standard).</p> -<h2>A subjective notion</h2> -<p>But what exactly is the informal “mathematical correctness†notion that this post is predicated upon? Yes the “innocent user†may expect mathematical properties to be respected as much as possible but there are plenty of mathematical properties! Let us enumerate some more:</p> -<p>If <code>x ≤ 1</code> in a program then <code>exp(x)</code> should always be lower than the mathematical constant e.</p> -<p>So far so good. The above is a good rule for an exponential implementation to respect. We are making progress.</p> -<p>Here is another property:</p> -<p>If <code>x ≥ 1</code> in a program then <code>exp(x)</code> should always be greater than the mathematical constant e.</p> -<p>We are decidedly unlucky today because at most one of these is going to be true of any floating-point function <code>exp()</code>. The programmatic value <code>exp(1)</code> must be either above or below the mathematical constant e (it is never equal to it because the mathematical constant e does not have a finite representation in binary).</p> -<h2>Why does it matter anyway?</h2> -<p>Let us revisit the argument:</p> -<blockquote><p>to give priority to the mathematical property in round to nearest mode (so as not to hurt the innocent user who may expect such a property to be respected)</p> -</blockquote> -<p>I alluded to a possible problem with a programmer computing an array index from <code>atanf(x)</code> under the assumption that it is always lower than Ï€/2. But how exactly would an innocent user even notice that <code>atanf(1e30)</code> is not lower than Ï€/2? The value Ï€/2 cannot exist in eir program any more than e. The user might innocently write an assertion like:</p> -<pre>assert(atanf(x)<=(3.1415926535897932f/2.0f)); -</pre> -<p>This assertion will never trigger! The function <code>atanf()</code> will indeed return at most the single-precision float <code>3.1415926535897932f/2.0f</code>. It does not matter that this number is actually slightly larger than Ï€/2. For all intents and purposes in the twisted world of single-precision floating-point this number is Ï€/2.</p> -<h2>Conclusion</h2> -<p>There are other scenarios in which the innocent user might genuinely have an unpleasant surprise. The result of a computation may be converted to decimal for humans to read and the user may be surprised to see a value outside the range ey expected. But this user would have the wrong expectations just as if ey expected <code>10.0 * atan(x)</code> to always be less than 5Ï€. Plenty of these users and developers can be found. But my opinion for what it is worth is that by making special cases you are not helping these users only feeding their delusions.</p> <p>The correct way to set expectations regarding the results of a floating-point program is numerical analysis. Numerical analysis is hard. Special cases such as the authors of CRlibm threaten to implement only seem to make it harder.</p> {% endraw %} diff --git a/_posts/2013-03-13-Reading-indeterminate-contents-might-as-well-be-undefined.html b/_posts/2013-03-13-Reading-indeterminate-contents-might-as-well-be-undefined.html index 2424cca0190069c2473d345968b205f514e9c1b6..f6fd078e450f0ae2caf8ee5e57cf509b0c26dbea 100644 --- a/_posts/2013-03-13-Reading-indeterminate-contents-might-as-well-be-undefined.html +++ b/_posts/2013-03-13-Reading-indeterminate-contents-might-as-well-be-undefined.html @@ -97,95 +97,5 @@ j:1 c:1 <p>No GCC is still acting as if <code>j *= 2;</code> was undefined.</p> <h2>Conclusion</h2> <p>I am not saying that this is not a bug in GCC. Perhaps it was fixed in later versions (in fact that version does not accept <code>-std=c11</code> so it must be rather old). My thesis is that you might as well avoid reading from uninitialized variables <strong>as if it was undefined behavior</strong> because otherwise compilers will bite you. This statement holds even if what we have witnessed here is a bug in GCC version 4.4.3.</p> -<p>Also if this is a bug in GCC 4.4.3 this is the first time I identify a bug in GCC without the assistance of a random program generator. In other words compiler bugs are rare but they become surprisingly common if you stick to a strict interpretation of a necessarily ambiguous standard. And speaking of <a href="http://embed.cs.utah.edu/csmith/">Csmith</a> if there is indeed a GCC bug here said bug cannot be detected with Csmith which does not generate programs like mine.</p> - <p>Warning: on a punctiliousness scale ranging from zero to ten, this post is a good nine-and-a-half. There was no tag for that, so I tagged it both “C99†and “C11â€. The faithful reader will know what to expect. There is a bit of C90, too.</p> -<p>To summarize, it may appear that according to the letter of modern C standards, it is only dangerous to use uninitialized variables, instead of very dangerous. Nevertheless, this post shows that it does not matter what the standards say: compilers will bite you even when you are arguably right.</p> -<h2>Some context in the form of a link</h2> -<p>In 2012, Xi Wang wrote a nice blog post showing it is not a good idea to use an uninitialized variable as a source of additional entropy when trying to create a random seed.</p> -<p>“Xoring an uninitialized variable with whatever other source of entropy you already have cannot hurtâ€, the conventional thinking goes. Conventional thinking is wrong. Your typical modern compiler deletes the code that gathers the original entropy, since it is only going to be xored with an uninitialized variable. Hence the title of Xi Wang's blog post, <a href="http://kqueue.org/blog/2012/06/25/more-randomness-or-less/">More Randomness or Less</a>.</p> -<h2>In C90 “indeterminate†was simple</h2> -<p>In the nineties real men were real men C standards were short and reading indeterminate contents(such as uninitialized variables) was listed in the very definition of “undefined behaviorâ€:</p> -<blockquote><p>1.6 DEFINITIONS OF TERMS</p> -<p> -<strong>Unspecified behavior</strong> — behavior for a correct program construct and correct data for which the Standard imposes no requirements.</p> -<p> -<strong>Undefined behavior</strong> — behavior upon use of a nonportable or erroneous program construct of erroneous data or <strong>of indeterminately-valued objects</strong> for which the Standard imposes no requirements.</p> -</blockquote> -<p>“Undefined behavior†means the compiler can do what it wants so the behavior noticed by Xi Wang can in no way be held against a C90 compiler.</p> -<h2>In 1999 C standards became more complicated</h2> -<p>The C99 standard does not directly list “reading indeterminate contents†as undefined behavior. Instead it defines indeterminate contents as “either an unspecified value or a trap representationâ€. Reading a trap representation causes undefined behavior (6.2.6.1:5). The nuance here is that the type <code>unsigned char</code> is guaranteed not to have any trap representations (and thus can always be used to read indeterminate contents).</p> -<h3>Less randomness : the simplified version</h3> -<p>“But my compilation platform does not have trap representations for type <code>int</code> either therefore I can use an uninitialized <code>int</code> variable and expect an unspecified value (a much better prospect than undefined behavior)†one may think. This line of reasoning is attractive. It could even explain the behavior shown in Xi Wang's blog post and reproduced in simplified form below:</p> -<pre>$ cat i.c -int f(int x) -{ - int u; - return u ^ x; -} -$ gcc -O2 -std=c99 -S -fomit-frame-pointer i.c -$ cat i.s -… -_f: -Leh_func_begin1: - ret -… -</pre> -<p>On this 64-bit platform the argument <code>x</code> passed to <code>f()</code> is in register <code>%edi</code> and the result of <code>f()</code> is expected in register <code>%eax</code>. Thus by executing instruction <code>ret</code> directly function <code>f()</code> is not even giving us back the entropy we provided it. It is instead giving us the current contents of <code>%eax</code> which may not be random at all.</p> -<p>(Giving us back the entropy we passed to it would have been <code>mov %edi %eax</code> followed by <code>ret</code> a longer sequence.)</p> -<p>One may argue that the compiler has only opportunistically chosen the most convenient value for variable <code>u</code> that is <code>x</code> xored with the current contents of <code>%eax</code> so that <code>u</code> xored with <code>x</code> is just the current contents of register <code>%eax</code>. This fits the interpretation of “unspecified value†for C99's definition of “indeterminate contentsâ€. It is a good argument but just wait until you have seen the next example.</p> -<h3>The next example</h3> -<pre>#include <stdio.h> -int main(int c char **v) -{ - unsigned int j; - if (c==4) - j = 1; - else - j *= 2; - printf("j:%u " j); - printf("c:%d" c); -} -</pre> -<p>If fewer than three command-line arguments are passed to the program it should display an unspecified <strong>even</strong> number for <code>j</code> right?</p> -<pre>$ gcc -v -Using built-in specs. -Target: x86_64-linux-gnu -… -gcc version 4.4.3 (Ubuntu 4.4.3-4ubuntu5.1) -$ gcc -O2 t.c -$ ./a.out -j:1 c:1 -</pre> -<p>GCC version 4.4.3 has decided that since the “else†branch was reading from an uninitialized variable <code>j</code> only the “then†branch was worth compiling. This is acceptable if reading uninitialized variable <code>j</code> is <strong>undefined behavior</strong> but not if it is <strong>unspecified behavior</strong>. Let us insist:</p> -<pre>$ gcc -Wall -O2 -std=c99 t.c -$ ./a.out -j:1 c:1 -</pre> -<p>Although we are requesting the C99 standard to be followed by GCC the program is not printing for variable <code>j</code> the even unspecified value we are entitled to.</p> -<p>(In passing a proper static analyzer would know that if it is going to show variable <code>j</code> as containing <code>1</code> it might as well show <code>c</code> as containing <code>4</code>. Also a proper static analyzer would remind you that your program must in essence only be used with three command-line arguments. The reason compilers do not do this is covered <a href="http://blog.llvm.org/2011/05/what-every-c-programmer-should-know_21.html">elsewhere</a>)</p> -<h2>Between 1999 and 2011 C standards did not get shorter</h2> -<p>In 2007 Rich Peterson working at HP was disappointed to find that the “Not a Thing†(NaT) value that registers can have on the Itanium architecture could <a href="http://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_338.htm">not be used to implement an uninitialized unsigned char</a>.</p> -<p>One thing led to another and the C11 standard was amended with the phrase “If the lvalue designates an object of automatic storage duration that could have been declared with register storage class (never had its address taken) and that object is uninitialized (not declared with an initializer and no assignment to it has been performed prior to the use) the behavior is undefined.â€</p> -<p>That would have been my reaction too if I was paid by the word. Anyway this additional sentence re-introduces undefined behavior where there was none in C99.</p> -<p>In the example above the address of <code>j</code> was never taken so maybe that's GCC's excuse. Let us check:</p> -<pre>#include <stdio.h> -int main(int c char **v) -{ - unsigned int j; - unsigned int *p = &j; - if (c==4) - j = 1; - else - j *= 2; - printf("j:%u " j); - printf("c:%d" c); -} -$ gcc -O2 t.c -$ ./a.out -j:1 c:1 -</pre> -<p>No GCC is still acting as if <code>j *= 2;</code> was undefined.</p> -<h2>Conclusion</h2> -<p>I am not saying that this is not a bug in GCC. Perhaps it was fixed in later versions (in fact that version does not accept <code>-std=c11</code> so it must be rather old). My thesis is that you might as well avoid reading from uninitialized variables <strong>as if it was undefined behavior</strong> because otherwise compilers will bite you. This statement holds even if what we have witnessed here is a bug in GCC version 4.4.3.</p> <p>Also if this is a bug in GCC 4.4.3 this is the first time I identify a bug in GCC without the assistance of a random program generator. In other words compiler bugs are rare but they become surprisingly common if you stick to a strict interpretation of a necessarily ambiguous standard. And speaking of <a href="http://embed.cs.utah.edu/csmith/">Csmith</a> if there is indeed a GCC bug here said bug cannot be detected with Csmith which does not generate programs like mine.</p> {% endraw %} diff --git a/_posts/2013-03-19-Digital-Technologies-ANR-Awards.html b/_posts/2013-03-19-Digital-Technologies-ANR-Awards.html index def88aa3d270c2f737f727b841af15c5688dc094..dff5b51f977efc55cd9d80452b2f642a5afdd7b2 100644 --- a/_posts/2013-03-19-Digital-Technologies-ANR-Awards.html +++ b/_posts/2013-03-19-Digital-Technologies-ANR-Awards.html @@ -11,8 +11,5 @@ summary: <p>In about a month, on April 17 and 18, <a href="http://www.agence-nationale-recherche.fr/en/project-based-funding-to-advance-french-research/" hreflang="en">ANR</a> the French research agency will hold <a href="http://www.agence-nationale-recherche.fr/Colloques/RencontresduNumerique2013/en/" hreflang="en">a meeting on digital technologies</a>. On this occasion ANR will also give <a href="http://www.agence-nationale-recherche.fr/Colloques/RencontresduNumerique2013/en/prix.php" hreflang="en">5 awards</a> to projects it has funded in the previous years. It is my pleasure to announce here that <a href="http://frama-c.com/u3cat/" hreflang="en">U3CAT</a> which has fueled the development of Frama-C during the last 4 years is among the nominees. This is of course a great reward for all the partners that have been involved in the project (Airbus Atos CEA LIST CNAM CS Dassault Aviation Inria and Sagem) and we are very grateful to the ANR for that although we of course hope to be able to brag a bit more about it next month<sup>[<a href="#pnote-202-1" id="rev-pnote-202-1">1</a>]</sup>. In the meantime I guess that it is an excellent occasion to remind you that we are always open to collaborations to ensure that Frama-C keeps being headed in the good direction.</p> <div class="footnotes"><h4>Notes</h4> <p>[<a href="#rev-pnote-202-1" id="pnote-202-1">1</a>] If you haven't seen anything on this blog by April 19<sup>th</sup> I suppose that you'll understand yourselves what the outcome was regarding our project</p> -</div> <p>In about a month, on April 17 and 18, <a href="http://www.agence-nationale-recherche.fr/en/project-based-funding-to-advance-french-research/" hreflang="en">ANR</a> the French research agency will hold <a href="http://www.agence-nationale-recherche.fr/Colloques/RencontresduNumerique2013/en/" hreflang="en">a meeting on digital technologies</a>. On this occasion ANR will also give <a href="http://www.agence-nationale-recherche.fr/Colloques/RencontresduNumerique2013/en/prix.php" hreflang="en">5 awards</a> to projects it has funded in the previous years. It is my pleasure to announce here that <a href="http://frama-c.com/u3cat/" hreflang="en">U3CAT</a> which has fueled the development of Frama-C during the last 4 years is among the nominees. This is of course a great reward for all the partners that have been involved in the project (Airbus Atos CEA LIST CNAM CS Dassault Aviation Inria and Sagem) and we are very grateful to the ANR for that although we of course hope to be able to brag a bit more about it next month<sup>[<a href="#pnote-202-1" id="rev-pnote-202-1">1</a>]</sup>. In the meantime I guess that it is an excellent occasion to remind you that we are always open to collaborations to ensure that Frama-C keeps being headed in the good direction.</p> -<div class="footnotes"><h4>Notes</h4> -<p>[<a href="#rev-pnote-202-1" id="pnote-202-1">1</a>] If you haven't seen anything on this blog by April 19<sup>th</sup> I suppose that you'll understand yourselves what the outcome was regarding our project</p> -</div> +</div> {% endraw %} diff --git a/_posts/2013-03-20-str2long.html b/_posts/2013-03-20-str2long.html index eeecbaf341977979af01fc423bd22586f5ed48c0..f56b2d7c474dabf1ddcb0348c9bcc2c049afb676 100644 --- a/_posts/2013-03-20-str2long.html +++ b/_posts/2013-03-20-str2long.html @@ -57,55 +57,5 @@ I am not sure why that is. Other <a href="http://erratasec.blogspot.fr/2013/03/c <p>On a more serious note I am still unsure whether the confidence gained per unit of time was better or worse with reviewing than it would have been with testing. In this instance for a throwaway submission the tests of which I would never have a chance to reuse I was happy to forgo testing completely and simply read my function again and again.</p> <blockquote><p>If not having to write another unit test is like reaching the week-end not having to write any unit tests is like being on holidays.</p> </blockquote> -<p>Becoming serious again I think that similarly to the situation with static analysis and tests a comparison between reviewing code and tests does not make complete sense because different techniques are good at finding different issues. Rational developers use all available tools (and reviewing code as one such tool is probably underrated).</p> - <h2>A coding contest of weeks past</h2> -<p>A fortnight ago, I sent an entry in this <a href="http://blog.regehr.org/archives/909">Quick Coding Contest</a>. The objective of the contest is to produce a C function to convert a string to the integer it represents. Now it turns out that my submission <a href="http://blog.regehr.org/archives/914">generates</a> the shortest code after libc whatever that means. -I am not sure why that is. Other <a href="http://erratasec.blogspot.fr/2013/03/code-philosophy-integer-overflows.html">submissions</a> duplicate more code than mine but I read yet more submissions that felt just as short as mine.</p> -<p>Rather than the code duplication I could tease Robert Graham for using type <code>int</code> for indexes into a char array which can lead to incorrect behavior for strings of more than 2GiB on 64-bit and even on 32-bit architectures:</p> -<pre>long str2long_robert_2(const char *str) -{ - long result = 0; - int i; -… - for (i=1; str[i]; i++) { - int c = str[i]; -</pre> -<p>The proper type to use in C is <code>size_t</code> I think. In fact <code>ptrdiff_t</code> would feel just as natural to me although that would take us back to the issue with 2.5GiB strings and 32-bit architectures.</p> -<blockquote><p>There are good <a href="http://stackoverflow.com/questions/9537967/what-is-the-limit-on-malloc-parameter-of-type-size-t-in-c-docs-say-it-has-an-up/9538071#9538071">reasons</a> to forbid objects of more than 2GiB on 32-bit architectures (making the use of <code>int</code> as index in a char array safe in that case). But on my system <code>malloc()</code> still lets me allocate 2.5GiB without a peep. Actually I didn't change systems since the last time <code>ptrdiff_t</code> was discussed in this blog.</p> -</blockquote> -<p>I do not have the heart to tease because writing with high-level idioms portable across languages is a laudable goal. Still if I was going to use a higher-level language with no <code>unsigned</code> type I would compute using the multiprecision integer type that any high-level language should have. C does not have native multiprecision integers and it has unsigned types. I feel that using the latter is acceptable when it compensates for the absence of the former.</p> -<h2>Making an even shorter <code>str2long()</code> function</h2> -<p>My submission looks like this:</p> -<pre>long str2long_pascal (const char *p) -{ - unsigned long l = 0; - int neg = 0; - if (!*p) goto err; - if (*p == '-') - { - p++; - neg = 1; - } - loop: - if (*p < '0' || *p > '9') goto err; - … -</pre> -<p>One nice trick I saw in other submissions was to use <code>neg = (*p == '-');</code> instead of what I wrote. I do not know whether compilers when provided with my version are typically able to simplify it into this one. It would be a sophisticated optimization but sounds plausible.</p> -<p>I really wanted to remark that statement <code>if (!*p) goto err;</code> in my submission was completely useless. It is intended to ensure that the empty string input is mapped onto the error case. If the statement was removed in the case of the empty input the test for <code>'-'</code> would fail and next control would go to <code>if (*p < '0' || *p > '9') goto err;</code> which would send execution to label <code>err</code> just the same.</p> -<p>I am pretty sure that no compiler knows how to detect this second trick by itself.</p> -<p>What can I say in guise of excuse? I spend a lot of time writing in OCaml where recursion and pattern-matching are more idiomatic. Yes I think this is a good excuse and I will explain why at length in a subsequent blog post.</p> -<blockquote><p>Also I noticed the uselessness of the empty string test while the contest was still open but I wanted to keep my impressive score on metrics other than code size and speed as bragged about in the next section.</p> -</blockquote> -<h2>Other metrics the contest should definitely be judged on</h2> -<p>I was a little disappointed to see that code size and speed were used for the first evaluation of the submissions because I optimized for completely different criteria.</p> -<ul> -<li>Least number of structured loops: I hoped there would be a special prize for this easily measurable and totally objective criterion.</li> -<li>Time spent: I submitted my function after spending 27 minutes on it in total. This may seem like a lot for 20 lines of C. But it is actually fair for 20 lines of C code that do something and behave as intended. I achieved the 27 minutes time by :</li> -<li>Least quantity of compilation static analysis and general parsing not to mention testing of the submitted function : I did not compile or analyze my entry before sending it in. I was relieved to find out that it compiled at all after I sent the e-mail. I spent half of the working time proofreading my submission trying to think of all the ways I had written incorrect C programs in the past.</li> -</ul> -<h2>Conclusion</h2> -<p>On a more serious note I am still unsure whether the confidence gained per unit of time was better or worse with reviewing than it would have been with testing. In this instance for a throwaway submission the tests of which I would never have a chance to reuse I was happy to forgo testing completely and simply read my function again and again.</p> -<blockquote><p>If not having to write another unit test is like reaching the week-end not having to write any unit tests is like being on holidays.</p> -</blockquote> <p>Becoming serious again I think that similarly to the situation with static analysis and tests a comparison between reviewing code and tests does not make complete sense because different techniques are good at finding different issues. Rational developers use all available tools (and reviewing code as one such tool is probably underrated).</p> {% endraw %} diff --git a/_posts/2013-04-04-Google-forking-WebKit.html b/_posts/2013-04-04-Google-forking-WebKit.html index 565322d83d3e15df6f3033128128b29f0b2ba5f6..2f570b8a23c006e47849cad6df967bf8ae26432e 100644 --- a/_posts/2013-04-04-Google-forking-WebKit.html +++ b/_posts/2013-04-04-Google-forking-WebKit.html @@ -19,17 +19,5 @@ Despite this state of affair or because of it it can be difficult to get some <blockquote><p>[…] the Chrome security team has taken a very active role in WebKit security over the last several years and really led the pack in making Webkit more robust against exploits. We’ve fuzzed at previously unheard of scale <<a href="http://goo.gl/R718K">goo.gl/R718K</a>> paid out hundreds of thousands of dollars in bug bounties <<a href="http://goo.gl/PGr89">goo.gl/PGr89</a>> performed extensive code auditing fixed many hundreds of security bugs and introduced a slew of hardening measures. […]</p> </blockquote> <p>My point is only tangentially relevant to web rendering engines so I am taking the above list out of context and adding my own punchline: despite of all these efforts measured in millions of dollars it is likely that there is still one exploitable security flaw in Chrome and it is possible that as you read this someone somewhere is exploiting this flaw.</p> -<p>To be very clear I am not blaming Google here. Google allocates the millions of dollars that cybersecurity warrants. It is open about how it uses this money; <strong>Google uses all the techniques that have proved their worthiness: random testing bug bounties code reviews defensive programming</strong>. I am only saying that cybersecurity is difficult since even doing all this <strong>does not guarantee absolute confidence</strong>. If you were to embed Chromium on some kind of connected device even after doing all the above you had better leave room in the design for regular software updates.</p> - <h2>Blink as seen from the inside</h2> -<p>As you have undoubtedly heard if you follow at all this sort of thing, as of April 3, Google is forking WebKit. Its Chrome browser will henceforth rely on its own variation of the popular rendering engine, Blink. This is big news. If I were Google, I would have pulled a <a href="http://techland.time.com/2013/04/01/google-april-fools/">Gmail</a> and made this serious announcement two days earlier. -Google security engineer Justin Schuh gives the <a href="https://plus.google.com/u/0/116560594978217291380/posts/AeCnq76cAXb">inside scoop</a>.</p> -<p>Something particularly strikes me in Justin's post. This post reacts to that aspect of Justin's and to that aspect only.</p> -<h2>As of 2013 Cybersecurity is an unsolved problem</h2> -<p>Let us be honest cybersecurity in general in 2013 is a bit of an unsolved problem. -Despite this state of affair or because of it it can be difficult to get some of the concerned companies to recognize there exists a problem at all.</p> -<p>Fortunately some are more open than others regarding security. Google is more open than most and when an exceptional event such as the forking of WebKit justifies it someone there may remind us of all the Chrome team does for security in a convenient list:</p> -<blockquote><p>[…] the Chrome security team has taken a very active role in WebKit security over the last several years and really led the pack in making Webkit more robust against exploits. We’ve fuzzed at previously unheard of scale <<a href="http://goo.gl/R718K">goo.gl/R718K</a>> paid out hundreds of thousands of dollars in bug bounties <<a href="http://goo.gl/PGr89">goo.gl/PGr89</a>> performed extensive code auditing fixed many hundreds of security bugs and introduced a slew of hardening measures. […]</p> -</blockquote> -<p>My point is only tangentially relevant to web rendering engines so I am taking the above list out of context and adding my own punchline: despite of all these efforts measured in millions of dollars it is likely that there is still one exploitable security flaw in Chrome and it is possible that as you read this someone somewhere is exploiting this flaw.</p> <p>To be very clear I am not blaming Google here. Google allocates the millions of dollars that cybersecurity warrants. It is open about how it uses this money; <strong>Google uses all the techniques that have proved their worthiness: random testing bug bounties code reviews defensive programming</strong>. I am only saying that cybersecurity is difficult since even doing all this <strong>does not guarantee absolute confidence</strong>. If you were to embed Chromium on some kind of connected device even after doing all the above you had better leave room in the design for regular software updates.</p> {% endraw %} diff --git a/_posts/2013-04-06-Non-expert-floating-point-using-developers-need-accurate-floating-point-libraries-the-most.html b/_posts/2013-04-06-Non-expert-floating-point-using-developers-need-accurate-floating-point-libraries-the-most.html index d975769297c66991c5c977f45c7ce3361c925d78..d0ca2a4d90cbd17b27a618f835d5bf83983f014c 100644 --- a/_posts/2013-04-06-Non-expert-floating-point-using-developers-need-accurate-floating-point-libraries-the-most.html +++ b/_posts/2013-04-06-Non-expert-floating-point-using-developers-need-accurate-floating-point-libraries-the-most.html @@ -63,61 +63,5 @@ In reality, it’s exactly backwards: <strong>proficient users can deal with a c <p>This was so troubling that user1257 <a href="http://stackoverflow.com/q/15851636/139746">suspected a compiler bug</a>. The reality is more likely that on eir computer the statement <code>long pow10 = pow(10 2);</code> sets variable <code>pow10</code> to <code>99</code>. The function <code>pow()</code> only needs to be inaccurate by 1ULP for this result to come up because of C's truncation behavior (towards zero) when converting from floating-point to integer.</p> <h2>Conclusion</h2> <p>My <code>str2long()</code> function would fail just the same if it was run in user1257's compilation environment. I still think that my function is correct and that I should be able to expect results to the ULP from the math library's <code>pow()</code> function. A floating-point expert would never even encounter the issue at all. I might be able to diagnose it and to cope. But the floating-point beginner simply needs an environment in which <code>long pow10 = pow(10 2);</code> sets <code>pow10</code> to <code>100</code>.</p> -<p>If you program and if you use floating-point at all beware of relying on the math library equivalent of a crappy netbook.</p> - <h2>Quotes on the Internet</h2> -<p>In 2012, Lukas Mathis took a quote out of the context of a blog post by Marco Arment and ran with it. The result was a though-provoking essay. Key quote:</p> -<blockquote><p>This is a sentiment you often hear from people: casual users only need «entry-level» devices. Even casual users themselves perpetuate it: «Oh, I’m not doing much on my computer, so I always just go with the cheapest option.» And then they buy a horrid, underpowered netbook, find out that it has a tiny screen, is incredibly slow, the keyboard sucks, and they either never actually use it, or eventually come to the conclusion that they just hate computers.</p> -<p> -In reality, it’s exactly backwards: <strong>proficient users can deal with a crappy computer, but casual users need as good a computer as possible</strong>.</p> -</blockquote> -<p>Lukas fully develops the idea in his post, <a href="http://ignorethecode.net/blog/2012/11/04/crappy_computers/">Crappy Computers</a>. Go ahead and read it now if you haven't already. This blog will still be here when you come back.</p> -<h2>Floating-point libraries</h2> -<p>The idea expressed by Lukas Mathis applies identically in a much more specific setting: developing with floating-point computations. The developers who most need accurate floating-point libraries are those who least care about floating-point. These developers will themselves tell you that it is all the same to them. They do not know what an ULP (“unit in the last placeâ€) is so what difference is it to them if they get two of them as error where they could have had one or half of one?</p> -<p>In this they are just as wrong as the casual computer users who pick horrid netbooks for themselves.</p> -<h3>Floating-point-wise programming environments are not born equal</h3> -<p>All recent processors for desktop computers provide basic operations + - * / and square root for IEEE 754 single- and double-precision floating-point numbers. Each operation has its assembly instruction and since the assembly instruction is the fastest way to implement the operation compilers have no opportunity to mess things up in a misguided attempt at optimizing for speed.</p> -<p>Who am I kidding? Of course compilers have plenty of opportunities to mess things up.</p> -<ol> -<li>It may seem to a compiler that a compile-time computation is even faster than the assembly instruction provided by the processor so that if the program computes <code>x / 10.0</code> the compiler may compute <code>1 / 10.0</code> at compile-time and generate assembly code that multiplies <code>x</code> by this constant instead. This transformation causes the result to be less accurate in some rare cases.</li> -<li>Or a compiler may simplify source-code expressions as if floating-point operations were associative when they aren't. It may for instance optimize a carefully crafted floating-point expression such as <code>a + b - a - b</code> into <code>0</code>.</li> -</ol> -<p>Nevertheless there has been much progress recently in standard compliance for compilers' implementations of floating-point. Overall for programs that only use the basic operators the situation has never been better.</p> -<p>The situation is not as bright-looking when it comes to mathematical libraries. These libraries provide conversion to and from decimal and transcendental elementary functions implemented on top of the basic operations. They are typically part of the operating system. Implementations vary wildly in quality from an operating system to the next.</p> -<p>Expert developers know exactly what compromise between accuracy and speed they need and they typically use their own functions instead of the operating system's. By way of illustration a famous super-fast pretty-accurate implementation of the <a href="http://en.wikipedia.org/wiki/Fast_inverse_square_root">inverse square root</a> function is used in Quake III and has been much <a href="http://blog.quenta.org/2012/09/0x5f3759df.html">analyzed</a>.</p> -<p>The casual developer of floating-point programs on the other hand will certainly use the functions provided by the system. Some of <a href="http://en.wikipedia.org/wiki/Spivak_pronoun">eir</a> expectations may be naive or altogether impossible to reconcile with the constraints imposed by the IEEE 754 standard. Other expectations may be common sense such as a <code>sin()</code> function that does not <a href="/index.php?post/2011/09/14/Linux-and-floating-point%3a-nearly-there">return</a> <code>-2.76</code>.</p> -<p>For such a developer the mathematical libraries should strive to be as accommodating and standard-compliant as possible because ey needs it regardless of what ey thinks.</p> -<h2>An example</h2> -<p>To illustrate I have written a string-to-long conversion function. It could have been an entry in John Regehr's contest but since the deadline is passed I have allowed the function to expect only positive numbers and to fail miserably when the input is ill-formed.</p> -<p>The function looks like this:</p> -<pre>long str2long(char *p) -{ - size_t l = strlen(p); - long acc = 0; - for (size_t i=0; i<l; i++) - { - int digit = p[i] - '0'; - long pow10 = pow(10 l - 1U - i); - acc += digit * pow10;; - } - return acc; -} -</pre> -<p>Neat huh?</p> -<p>I tested this function more than the <a href="//2013/03/20/str2long">last function</a>. This time I compiled it and invoked it on a few strings:</p> -<pre> printf("%ld %ld %ld %ld" - str2long("0") - str2long("123") - str2long("999") - str2long("123456789123456789")); -</pre> -<p>You can <a href="/assets/img/blog/imported-posts/float_str2long.c">download the entire C code</a> for yourself. If you run it you should get:</p> -<pre>0 123 999 123456789123456789 -</pre> -<p>I wrote my function to work for all well-formed inputs that fit in a <code>long</code> (but I only tested it for four values so do not embed it in your space shuttle please). Some of the reasons why I expect it to work are implicit: for one powers of ten up to 10^22 <a href="http://www.exploringbinary.com/why-powers-of-ten-up-to-10-to-the-22-are-exact-as-doubles/">are exactly representable as double-precision floating-point numbers</a>. Also I happen to know that on the system I use the mathematical library is one of the best available.</p> -<p>I am not in fact a floating-point expert. I could be completely illiterate with respect to floating-point and have written the exact same function. In fact this happened to StackOverflow user1257. (I am not saying that StackOverflow user1257 is illiterate with respect to floating-point either. Ey wrote a function similar to mine after all.)</p> -<p><strong>User1257's function returned <code>122</code> when applied to the string <code>"123"</code> !!!</strong></p> -<p>This was so troubling that user1257 <a href="http://stackoverflow.com/q/15851636/139746">suspected a compiler bug</a>. The reality is more likely that on eir computer the statement <code>long pow10 = pow(10 2);</code> sets variable <code>pow10</code> to <code>99</code>. The function <code>pow()</code> only needs to be inaccurate by 1ULP for this result to come up because of C's truncation behavior (towards zero) when converting from floating-point to integer.</p> -<h2>Conclusion</h2> -<p>My <code>str2long()</code> function would fail just the same if it was run in user1257's compilation environment. I still think that my function is correct and that I should be able to expect results to the ULP from the math library's <code>pow()</code> function. A floating-point expert would never even encounter the issue at all. I might be able to diagnose it and to cope. But the floating-point beginner simply needs an environment in which <code>long pow10 = pow(10 2);</code> sets <code>pow10</code> to <code>100</code>.</p> <p>If you program and if you use floating-point at all beware of relying on the math library equivalent of a crappy netbook.</p> {% endraw %} diff --git a/_posts/2013-04-13-Making-oughts-from-ises.html b/_posts/2013-04-13-Making-oughts-from-ises.html index b6a65234001cbb3d42af15b4b423563c86ea7398..70e3788fc3ca2d385667b459ddcca4d5437f8b3c 100644 --- a/_posts/2013-04-13-Making-oughts-from-ises.html +++ b/_posts/2013-04-13-Making-oughts-from-ises.html @@ -55,53 +55,5 @@ $ ./a.out <p>Nevertheless this does not detract from the point I intended to make which is that it is bad engineering practice to take the current behavior of popular compilers as language definition. If the C99 language allows to “miscompile†<code>(0 i++ j) + (0 j++ i)</code> so be it. But having read the relevant parts of the standard (6.5.2.2:10 6.5.2.2:12 and 5.1.2.3:2 in addition to the previously mentioned clauses) it seems to me that if the standard allows to miscompile the above it also allows to miscompile <code>f(1) + f(2)</code> for any function <code>f()</code> with global side-effects.</p> <blockquote><p>Global side-effects include temporarily modifying the FPU rounding mode using a statically allocated scratch buffer initializing a table of constants at first call calling <code>malloc()</code> and <code>free()</code> or even <code>random()</code>. All these examples are intended to be invisible to the caller and lots of library functions you routinely use may be doing them.</p> </blockquote> -<p>So in this case my argument remains very much the same: that compilers are not implementing aggressive optimizations (yet) in presence of <code>f(1) + f(2)</code> should be no excuse for not clarifying whether the standard allows them.</p> - <p>A previous post discussed the nature of uninitialized and indeterminate memory throughout the C standards. The argument was “<a href="/index.php?post/2013/03/13/indeterminate-undefined">avoid using uninitialized data</a> even if you think you know what you are doing; you may be right but regardless your compiler might think <strong>it knows</strong> what you are doing and be wrong about itâ€. I tried to strengthen this argument by claiming that writing the example for that post was how I found my first compiler bug “by handâ€.</p> -<h2>An example involving unsequenced addition and sequenced comma operators</h2> -<p>That bit about a compiler bug being my first I now fear was an exaggeration. I had found and forgotten another arguable GCC bug in 2012 while investigating sequence points. First consider the program below.</p> -<pre>#include <stdio.h> -int i j; -int f(void) -{ - i++; - return j; -} -int g(void) -{ - j++; - return i; -} -int main() -{ - printf("%d" f() + g()); -} -</pre> -<p>Although functions <code>f()</code> and <code>g()</code> may be called in an unspecified order calling a function and returning from it are sequence points. The program therefore avoids the sin of undefined behavior caused by C99's clause 6.5:2.</p> -<blockquote><p>6.5:2 Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression. Furthermore the prior value shall be read only to determine the value to be stored.</p> -</blockquote> -<p>The program can only print an unspecified choice of either <code>f() + g()</code> when calling <code>f()</code> first or <code>f() + g()</code> when calling <code>g()</code> first the two of which happen to result in the same value <code>1</code>.</p> -<p>The same reasoning that makes the C program above always print <code>1</code> should make the program below always print <code>1</code> too:</p> -<pre>$ cat t2.c -#include <stdio.h> -int i j; -int main() -{ - printf("%d" (0 i++ j) + (0 j++ i)); -} -</pre> -<p>But unfortunately:</p> -<pre>$ gcc t2.c -$ ./a.out -2 -</pre> -<p>This program should print the same result as the previous program (the one with <code>f()</code> and <code>g()</code>) because the modifications of <code>j</code> are sequenced by <code>0 </code> on the left and <code> i</code> on the right and similarly for <code>i</code>. In C99 at least the compiler must pick a choice between adding an incremented <code>i</code> to the initial value of <code>j</code> or the other way round. This example should print <code>1</code> in short for the same reason that the first example in this post could be expected to print <code>1</code> or that an example that prints <code>cos(x) * cos(x) + sin(x) * sin(x)</code> with MT-unsafe functions <code>cos()</code> and <code>sin()</code> can still be expected to print a floating-point value close to <code>1.0</code>.</p> -<h2>Pet peeve: guessing at what the standard ought to say from what compilers do</h2> -<p>This anecdote slowly but surely brings us to the annoyance I intended to denounce all along and this annoyance is when programmers infer what the standard ought to be saying from what compilers do. Any discussion of the kind of corner cases I described recently invite arguments about how compilers want to optimize the generated code as if uninitialized data could not be used or as if the two operands of <code>+</code> were evaluated in parallel.</p> -<p>This is backwards. Yes compilers want to optimize. But <strong>compilers are supposed to follow the standard</strong> not the other way round. And section 6 of the C99 standard does not once use the word “parallelâ€. It says that the evaluation order of sub-expressions is unspecified (6.5:3) and that unsequenced side-effects cause undefined behavior (6.5:2) but nothing about parallel evaluation.</p> -<h2>Never mind the example</h2> -<p>Actually C99's 6.5:3 clause really says “[…] the order of evaluation of subexpressions and the order in which side effects take place are both unspecifiedâ€. I am unsure about the implications of this thing about the order of side-effects. I might even and the long-time reader of this blog will savor this uncharacteristic admission be wrong: perhaps a compiler is allowed to generate code that prints 2 for t2.c after all.</p> -<p>Nevertheless this does not detract from the point I intended to make which is that it is bad engineering practice to take the current behavior of popular compilers as language definition. If the C99 language allows to “miscompile†<code>(0 i++ j) + (0 j++ i)</code> so be it. But having read the relevant parts of the standard (6.5.2.2:10 6.5.2.2:12 and 5.1.2.3:2 in addition to the previously mentioned clauses) it seems to me that if the standard allows to miscompile the above it also allows to miscompile <code>f(1) + f(2)</code> for any function <code>f()</code> with global side-effects.</p> -<blockquote><p>Global side-effects include temporarily modifying the FPU rounding mode using a statically allocated scratch buffer initializing a table of constants at first call calling <code>malloc()</code> and <code>free()</code> or even <code>random()</code>. All these examples are intended to be invisible to the caller and lots of library functions you routinely use may be doing them.</p> -</blockquote> <p>So in this case my argument remains very much the same: that compilers are not implementing aggressive optimizations (yet) in presence of <code>f(1) + f(2)</code> should be no excuse for not clarifying whether the standard allows them.</p> {% endraw %} diff --git a/_posts/2013-04-25-Sign-extension.html b/_posts/2013-04-25-Sign-extension.html index 132a6694dc09b99282cea59197e513516f5c4806..34d92bc8989a7600b4ba2d3751163aac83a5028e 100644 --- a/_posts/2013-04-25-Sign-extension.html +++ b/_posts/2013-04-25-Sign-extension.html @@ -17,15 +17,5 @@ summary: </pre> <p>Variable <code>i</code> receives <code>-3</code>. That's it. That's “sign extensionâ€.</p> <p>It's an assignment and in this particular case a <em>promotion</em>. With other types it could have been a <em>conversion</em>. The target wide variable receives the value that was contained in the narrow variable. Why would this operation need a name and such an ugly name as “sign extension†at that?</p> -<p>The name for “sign extension†in C is “getting the valueâ€. Variable <code>i</code> receives the value of <code>s</code>. That's it. That is all there is.</p> - <p>There is no “sign extension†in C. Please stop referring to “sign extension†in C programs.</p> -<h2>In assembly, there is such a thing as “sign extensionâ€</h2> -<p>Sign-extend is <a href="http://en.wikipedia.org/wiki/MOV_(x86_instruction)#Zero_extend">an assembly instruction</a> say <code>movsx %al %ebx</code> to transfer the contents of a narrow register say <code>%al</code> to a wide register say <code>%ebx</code> copying the most significant bit of the narrow register all over the unoccupied bits of the wide register.</p> -<h2>In C there is no “sign extensionâ€. Really.</h2> -<p>In C a <code>short</code> variable <code>s</code> contains <code>-3</code> and the contents of that variable is transferred to another variable of type <code>int</code> like so:</p> -<pre>int i = s; -</pre> -<p>Variable <code>i</code> receives <code>-3</code>. That's it. That's “sign extensionâ€.</p> -<p>It's an assignment and in this particular case a <em>promotion</em>. With other types it could have been a <em>conversion</em>. The target wide variable receives the value that was contained in the narrow variable. Why would this operation need a name and such an ugly name as “sign extension†at that?</p> <p>The name for “sign extension†in C is “getting the valueâ€. Variable <code>i</code> receives the value of <code>s</code>. That's it. That is all there is.</p> {% endraw %} diff --git a/_posts/2013-04-26-Of-compiler-warnings-discussions.html b/_posts/2013-04-26-Of-compiler-warnings-discussions.html index 14728db20111ced00eed1fc5f05789c10f0c6984..63eadc42ee456c4ff99626bdbde3033e9e1d2d1e 100644 --- a/_posts/2013-04-26-Of-compiler-warnings-discussions.html +++ b/_posts/2013-04-26-Of-compiler-warnings-discussions.html @@ -51,49 +51,5 @@ t.c:10:[kernel] warning: accessing out of bounds index [-1..255]. assert 0 ≤ i <blockquote><p>Speaking of which these four lines are not a very good modelisation of function <code>getchar()</code>. It is possible to do better than this and the above is only an example simplified for clarity but best not re-used.</p> </blockquote> <h2>Conclusion</h2> -<p>In conclusion it is possible to make sound static analyzers because theoretical undecidability results are about Turing machines because people are not interested in arbitrary programs and because a couple false positives once in a while do not necessarily make a sound analyzer unusable. The theoretical counter-arguments apply to binary code to concurrent programs and when reversing the use of the “sound†and “complete†adjective but I only have examples for the static analysis of sequential C source code.</p> - <p>A discussion I often have addresses the question of whether a compiler¹ can warn for all possible illegal actions a program could take at run-time within a specific, well-understood family² .</p> -<p>(1) or some other piece of software that receives a program as input and, in finite time, does something with it, for example a static analyzer</p> -<p>(2) for example the family of out-of-bounds memory accesses</p> -<p>For some reason my opinion differs significantly from the consensus opinion, but since this is my^H^H the Frama-C blog, I thought I would nevertheless put it here for exposure.</p> -<h2>The Halting problem is only relevant as a metaphor</h2> -<p>The <a href="http://en.wikipedia.org/wiki/Halting_problem">Halting problem</a> is defined for Turing machines. A computer is not a Turing machine. A Turing machine has an infinite ribbon whereas a real computer has finite memory.</p> -<p>Imagine a real physical computer running a program. Imagine that you sit at the keyboard typing new inputs indefinitely swapping the keyboard for a new one when wear and tear make it unusable putting the computer on a <a href="http://www.youtube.com/watch?v=vAMPFesqEmw">battery</a> and moving it to another planet when the Sun explodes rigging your will to ensure your descendants will carry on the typing this sort of thing.</p> -<p>Seems like a glimpse of infinity right? But the mathematical abstraction for this computer is not a Turing machine it is a boring <a href="http://en.wikipedia.org/wiki/Mealy_machine">Mealy machine</a> (an automaton with inputs and outputs). A Turing machine has an infinite ribbon it can write to and read from again. The above set-up does not. It is a Mealy machine with 256^(10^9) states (assuming a 1TB hard-drive).</p> -<h2>A sound analyzer is not impossible</h2> -<p>A <em>sound</em> analyzer for out-of-bounds accesses is an analyzer that warns for every out-of-bounds access. Making one is easier than it seems. There is always the solution of warning for every dereferencing construct in the program (in C these would be <code>*</code> <code>[]</code> and <code>-></code>).</p> -<h2>A useful sound analyzer is not impossible</h2> -<p>That last analyzer although sound was pretty useless was it not? General theoretical results on the undecidability of deciding of the run-time behavior of Turing machine would predict —if allowed to be intrapolated to computers and programs— that it is impossible to build a sound and <em>complete</em> analyzer.</p> -<blockquote><p>A <em>complete</em> analyzer for out-of-bounds accesses warns only for accesses that can really be out-of-bounds for some program inputs.</p> -</blockquote> -<p>Indeed a sound and complete analyzer is difficult. It is impossible for Turing machines and it is hard even for mere computers and programs.</p> -<p>Luckily the theoretical difficulty is only in reference to arbitrary programs. It is theoretically difficult to make the promise to warn for all out-of-bounds accesses and to warn only for real out-of-bound accesses for arbitrary programs but an analyzer does not have to do that to be useful. It only needs to deal with programs people are actually interested in (an excessively small subset of all programs).</p> -<p>And it does not even need to be sound and complete to be useful. An analyzer that warns for all out-of-bounds accesses with only a few false positives is still useful (and still sound. “Complete†is what it is not).</p> -<blockquote><p>Conversely an analyzer that warns only for actual out-of-bounds accesses and only omits a few is still useful and complete although it is not sound. But I have not spent the last 8 years working on such an analyzer so it is not my job to advertise one. Whoever wrote one can tout it in its own blog.</p> -</blockquote> -<p>This blog contains examples of analyses made using a sound analyzer. The analyzer does not emit so many false positives that it is unusable. The analyses involve a variety of real programs: QuickLZ (there were a few false positives but a bug was found and was fixed) the reference implementation for Skein (no bug was found but there were no false positives) Zlib (in this ongoing analysis there are plenty of false positives but one extremely minor issue has already been found) …</p> -<h2>But this cannot work in presence of dynamically loaded libraries!</h2> -<p>Well yes in order to do “program analysis†the program must be available. It is in the name.</p> -<p>Speaking of binary-only libraries or programs the counter-arguments I have written above apply the same to the analysis of a program in binary form. Analyzing a binary program is significantly harder than analyzing source code but a binary analyzer does not have to be unsound it does not have to be incomplete and it does not have to decide the Halting problem. The examples I have provided are for analyses of source code because that's what I work on but look for the blog of a binary static analyzer and there is <strong>no theoretical reason</strong> you won't be pleasantly surprised.</p> -<h2>But this cannot work if there are inputs from the user / from a file!</h2> -<p>Of course it can. The more you know and don't tell to the analyzer the more its warnings may subjectively feel like false positives to you but the analyzer can always assume the worst about any inputs:</p> -<pre>#define EOF (-1) -/*@ ensures \esult == EOF || 0 <= \esult <= 255 ; */ -int getchar(void); -int main(int c char **v) -{ - int a[5] i; - i = getchar(); - a[i] = 6; -} -</pre> -<pre>$ frama-c -pp-annot t.c -val -... -t.c:10:[kernel] warning: accessing out of bounds index [-1..255]. assert 0 ≤ i < 5; -</pre> -<p>The first four lines would not have to be written everytime. They model a function from the standard library and would only need to be updated when the specification of the standard C library changes.</p> -<blockquote><p>Speaking of which these four lines are not a very good modelisation of function <code>getchar()</code>. It is possible to do better than this and the above is only an example simplified for clarity but best not re-used.</p> -</blockquote> -<h2>Conclusion</h2> <p>In conclusion it is possible to make sound static analyzers because theoretical undecidability results are about Turing machines because people are not interested in arbitrary programs and because a couple false positives once in a while do not necessarily make a sound analyzer unusable. The theoretical counter-arguments apply to binary code to concurrent programs and when reversing the use of the “sound†and “complete†adjective but I only have examples for the static analysis of sequential C source code.</p> {% endraw %} diff --git a/_posts/2013-05-01-A-conversionless-conversion-function.html b/_posts/2013-05-01-A-conversionless-conversion-function.html index 64cb01878e47db6dae111af0afc5abef692eeca2..4be937c2f778f38c9eeb783a0121a9ed029580a9 100644 --- a/_posts/2013-05-01-A-conversionless-conversion-function.html +++ b/_posts/2013-05-01-A-conversionless-conversion-function.html @@ -60,58 +60,5 @@ int main() result:1.82622766329724559e+19 18262276632972455936 rounding:0 1 1 1 </pre> -<p>Incidentally does anyone know how to write a correctness proof for this function? A formal proof would be nice but just an informal explanation of how one convinces oneself that <code>o = f - t + t - f</code> is the right formula would already be something.</p> - <h2>A rant about programming interview questions</h2> -<p>Software development is a peculiar field. An applicant for a more traditionally artistic position would bring a portfolio to eir job interview: a selection of creations ey deems representative of eir work and wants to be judged by. -But in the field of software development, candidates are often asked to solve a programming problem live, the equivalent of telling a candidate for a photography job “these are nice photographs you have brought, but could you take a picture for me, right now, with this unfamiliar equipment?â€</p> -<p>Lots have already been written on programming job interview questions. Googling “fizzbuzz†alone reveals plenty of positions taken, reacted to, and counter-argumented. I do not intend to add to the edifice. Taking a step back, however, I notice that many of these posts do not tackle the question of why what works for the traditional arts should not be appropriate for the art of programming.</p> -<p>What I intend to discuss is the poor quality of “do this simple task, but avoid this simple construct that makes it trivial†interview questions. I hate those. Everytime I hear a new one it seems to reach a new high in sheer stupidity. The questions are usually very poorly specified, too. One such question might be to convert a floating-point value to integer without using a cast. Is <code>floor()</code> or <code>ceil()</code> allowed? Are other library functions than these ones that solve the problem too directly allowed? May I use a union to access the bits of the floating-point representation? Or <code>memcpy()</code>?</p> -<p>Well, I have solved this particular question once and for all. The conversion function makes up the second part of this post. It uses only floating-point computations, no tricks. Now, one just needs to learn it and to regurgitate it as appropriate at interview time (there is no way one can write a working version of this program on blackboard, too). Who is hiring?</p> -<h2>A program</h2> -<p>The function below requires a strict IEEE 754 implementation. If your GCC is generating x87 instructions, options <code>-msse2 -mfpmath=sse</code> should prevent it from doing so and allow you to run the program:</p> -<pre>#include <math.h> -#include <float.h> -#include <stdio.h> -#include <limits.h> -/*@ requires 0 <= f < ULLONG_MAX + 1 ; */ -unsigned long long dbl2ulonglong(double f) -{ - if (f < 1) return 0; - unsigned long long l = 0; - for (double coef = 3; coef != 0x1.0p53; coef = 2 * coef - 1, l >>= 1) - { - double t = coef * f; - double o = f - t + t - f; - if (o != 0) - { - l |= 0x8000000000000000ULL; - f -= fabs(o); - } - } - l |= 0x8000000000000000ULL; - for ( ; f != 0x1.0p63; f *= 2) l>>=1; - return l; -} -int main() -{ - double f = 123456.; - unsigned long long l = dbl2ulonglong(f); - printf(esult:%.18g %llu" f l); - f = ULLONG_MAX * 0.99; - l = dbl2ulonglong(f); - printf("result:%.18g %llu" f l); - printf("rounding:%llu %llu %llu %llu" - dbl2ulonglong(DBL_MIN) - dbl2ulonglong(1.4) - dbl2ulonglong(1.5) - dbl2ulonglong(1.6)); - return 0; -} -</pre> -<p>The expected result is:</p> -<pre>result:123456 123456 -result:1.82622766329724559e+19 18262276632972455936 -rounding:0 1 1 1 -</pre> <p>Incidentally does anyone know how to write a correctness proof for this function? A formal proof would be nice but just an informal explanation of how one convinces oneself that <code>o = f - t + t - f</code> is the right formula would already be something.</p> {% endraw %} diff --git a/_posts/2013-05-02-Harder-than-it-looks-rounding-float-to-nearest-integer-part-1.html b/_posts/2013-05-02-Harder-than-it-looks-rounding-float-to-nearest-integer-part-1.html index 254887e443afddd048e739ed52349269f28a507d..dd203e67a6491bb63866317c41f1e7a798c8f532 100644 --- a/_posts/2013-05-02-Harder-than-it-looks-rounding-float-to-nearest-integer-part-1.html +++ b/_posts/2013-05-02-Harder-than-it-looks-rounding-float-to-nearest-integer-part-1.html @@ -95,93 +95,5 @@ r.c:9:[kernel] warning: overflow in conversion of f ([-0. .. 3.40282346639e+38]) </pre> <p>It turns out that this works too. It solves the problem with the input <code>0.49999997f</code> without making the function fail its specification for other inputs.</p> <h2>To be continued</h2> -<p>The next post will approach the same question from a different angle. It should not be without its difficulties either.</p> - <p>This post is the first in a series on the difficult task of rounding a floating-point number to an integer. Laugh not! -The easiest-looking questions can hide unforeseen difficulties, and the most widely accepted solutions can be wrong.</p> -<h2>Problem</h2> -<p>Consider the task of rounding a <code>float</code> to the nearest integer. The answer is expected as a <code>float</code>, same as the input. In other words, we are looking at the work done by standard C99 function <code>nearbyintf()</code> when the rounding mode is the default round-to-nearest.</p> -<p>For the sake of simplicity, in this series of posts, we assume that the argument is positive and we allow the function to round any which way if the float argument is exactly in-between two integers. In other words, we are looking at the ACSL specification below.</p> -<pre>/*@ requires 0 ≤ f ≤ FLT_MAX ; - ensures -0.5 ≤ \esult - f ≤ 0.5 ; - ensures \exists integer n; \esult == n; -*/ -float myround(float f); -</pre> -<p>In the second <code>ensures</code> clause, <code>integer</code> is an ACSL type (think of it as a super-long <code>long long</code>). The formula <code>\exists integer n; \esult == n</code> simply means that <code>\esult</code>, the <code>float</code> returned by function <code>myround()</code>, is a mathematical integer.</p> -<h2>Via truncation</h2> -<p>A first idea is to convert the argument <code>f</code> to <code>unsigned int</code>, and then again to <code>float</code>, since that's the expected type for the result:</p> -<pre>float myround(float f) -{ - return (float) (unsigned int) f; -} -</pre> -<h3>Obvious overflow issue</h3> -<p>One does not need Frama-C's value analysis to spot the very first issue, an overflow for large <code>float</code> arguments, but it's there, so we might as well use it:</p> -<pre>$ frama-c -pp-annot -val r.c -lib-entry -main myround -... -r.c:9:[kernel] warning: overflow in conversion of f ([-0. .. 3.40282346639e+38]) - from floating-point to integer. assert -1 < f < 4294967296; -</pre> -<p>This overflow can be fixed by testing for large arguments. Large floats are all integers, so the function can simply return <code>f</code> in this case.</p> -<pre>float myround(float f) -{ - if (f >= UINT_MAX) return f; - return (float) (unsigned int) f; -} -</pre> -<h3>Obvious rounding issue</h3> -<p>The cast from <code>float</code> to <code>unsigned int</code> does not round to the nearest integer. It “truncatesâ€, that is, it rounds towards zero. And if you already know this, you probably know too the universally used trick to obtain the nearest integer instead of the immediately smaller one, adding 0.5:</p> -<pre>float myround(float f) -{ - if (f >= UINT_MAX) return f; - return (float) (unsigned int) (f + 0.5f); -} -</pre> -<p><strong>This universally used trick is wrong.</strong></p> -<h3>An issue when the ULP of the argument is exactly one</h3> -<p>The Unit in the Last Place, or ULP for short, of a floating-point number is its distance to the floats immediately above and immediately below it. For large enough floats, this distance is one. In that range, floats behave as integers.</p> -<blockquote><p>There is an ambiguity in the above definition for powers of two: the distances to the float immediately above and the float immediately below are not the same. If you know of a usual convention for which one is called the ULP of a power of two, please leave a note in the comments.</p> -</blockquote> -<pre>int main() -{ - f = 8388609.0f; - printf(\%f -> %f" f myround(f)); -} -</pre> -<p>With a strict IEEE 754 compiler the simple test above produces the result below:</p> -<pre>8388609.000000 -> 8388610.000000 -</pre> -<p>The value passed as argument is obviously representable as a float since that's the type of <code>f</code>. However the mathematical sum <code>f + 0.5</code> does not have to be representable as a float. In the worst case for us when the argument is in a range of floats separated by exactly one the floating-point sum <code>f + 0.5</code> falls exactly in-between the two representable floats <code>f</code> and <code>f + 1</code>. Half the time it is rounded to the latter although <code>f</code> was already an integer and was the correct answer for function <code>myround()</code>. This causes bugs as the one displayed above.</p> -<p>The range of floating-point numbers spaced every 1.0 goes from 2^23 to 2^24. Half these 2^23 values that is nearly 4 millions of them exhibit the problem.</p> -<p>Since the 0.5 trick is nearly universally accepted as the solution to implement rounding to nearest from truncation this bug is likely to be found in lots of places. Nicolas Cellier <a href="http://bugs.squeak.org/view.php?id=7134">identified it in Squeak</a>. He offered a solution too: switch the FPU to round-downward for the time of the addition <code>f + 0.5</code>. But let us not fix the problem just yet there is another interesting input for the function as it currently stands.</p> -<h3>An issue when the argument is exactly the predecessor of 0.5f</h3> -<pre>int main() -{ - f = 0.49999997f; - printf("%.9f -> %.9f" f myround(f)); -} -</pre> -<p>This test produces the output <code>0.499999970 -> 1.000000000</code> although the input <code>0.49999997</code> is clearly closer to <code>0</code> than to <code>1</code>.</p> -<p>Again the issue is that the floating-point addition is not exact. The argument <code>0.49999997f</code> is the last <code>float</code> of the interval <code>[0.25 … 0.5)</code>. The mathematical result of <code>f + 0.5</code> falls exactly midway between the last float of the interval <code>[0.5 … 1.0)</code> and <code>1.0</code>. The rule that ties must be rounded to the even choice means that <code>1.0</code> is chosen.</p> -<h3>A function that works</h3> -<p>The overflow issue and the first non-obvious issue (when ulp(f)=1) can be fixed by the same test: as soon as the ULP of the argument is one the argument is an integer and can be returned as-is.</p> -<p>The second non-obvious issue with input <code>0.49999997f</code> can be fixed similarly.</p> -<pre>float myround(float f) -{ - if (f >= 0x1.0p23) return f; - if (f <= 0.5) return 0; - return (float) (unsigned int) (f + 0.5f); -} -</pre> -<h3>A better function that works</h3> -<p>Changing the FPU rounding mode the suggestion in the Squeak bug report is slightly unpalatable for such a simple function but it suggests to add the predecessor of <code>0.5f</code> instead of <code>0.5f</code> to avoid the sum rounding up when it shouldn't:</p> -<pre>float myround(float f) -{ - if (f >= 0x1.0p23) return f; - return (float) (unsigned int) (f + 0.49999997f); -} -</pre> -<p>It turns out that this works too. It solves the problem with the input <code>0.49999997f</code> without making the function fail its specification for other inputs.</p> -<h2>To be continued</h2> <p>The next post will approach the same question from a different angle. It should not be without its difficulties either.</p> {% endraw %} diff --git a/_posts/2013-05-03-Rounding-float-to-nearest-integer-part-2.html b/_posts/2013-05-03-Rounding-float-to-nearest-integer-part-2.html index 14a9849d3df8c9c337b29d2e9e5e90d1659e4067..2665bf79996adc24b29b4d901c8b9227a7be6ec7 100644 --- a/_posts/2013-05-03-Rounding-float-to-nearest-integer-part-2.html +++ b/_posts/2013-05-03-Rounding-float-to-nearest-integer-part-2.html @@ -74,72 +74,5 @@ there is not need to take them out: we will manipulate them directly inside <cod } </pre> <h2>To be continued again</h2> -<p>The only salient point in the method in this post is how we pretend not to notice when significand arithmetic overflows over the exponent for inputs between 1.5 and 2.0 3.5 and 4.0 and so on. The method in next post will be so much more fun than this.</p> - <p>The <a href="/index.php?post/2013/05/02/nearbyintf1">previous post</a> offered to round a positive float to the nearest integer represented as a float through a conversion back and forth to 32-bit unsigned int. There was also the promise of at least another method. Thanks to reader feedback there will be two. What was intended to be the second post in the series is hereby relegated to third post.</p> -<h2>Rounding through bit-twiddling</h2> -<p>Several readers seemed disappointed that the implementation proposed in the last post was not accessing the bits of float <code>f</code> directly. This is possible of course:</p> -<pre> assert (sizeof(unsigned int) == sizeof(float)); - unsigned int u; - memcpy(&u &f sizeof(float)); -</pre> -<p>In the previous post I forgot to say that we were assuming 32-bit unsigned ints. From now on we are in addition assuming that floats and unsigned ints have the same endianness so that it is convenient to work on the bit representation of one by using the other.</p> -<p>Let us special-case the inputs that can mapped to zero or one immediately. We are going to need it. We could do the comparisons to 0.5 and 1.5 on <code>u</code> because positive floats increase with their unsigned integer representation but there is no reason to: it is more readable to work on <code>f</code>:</p> -<pre> if (f <= 0.5) return 0.; - if (f <= 1.5) return 1.; -</pre> -<p>Now to business. The actual exponent of <code>f</code> is:</p> -<pre> int exp = ((u>>23) & 255) - 127; -</pre> -<p>The explicit bits of <code>f</code>'s significand are <code>u & 0x7fffff</code> but -there is not need to take them out: we will manipulate them directly inside <code>u</code>. Actually at one point we will cheat and manipulate a bit of the exponent at the same time but it will all be for the best.</p> -<p>A hypothetical significand for the number 1 aligned with the existing significand for <code>f</code> would be <code>1U << (23 - exp)</code>. But this is hypothetical because <code>23 - exp</code> can be negative. If this happens it means that <code>f</code> is in a range where all floating-point numbers are integers.</p> -<pre> if (23 - exp < 0) return f; - unsigned int one = 1U << (23 - exp); -</pre> -<p>You may have noticed that since we special-cased the inputs below <code>1.5</code> variable <code>one</code> may be up to <code>1 << 23</code> and almost but not quite align with the explicit bits of <code>f</code>'s significand. Let us make a note of this for later. For now we are interested in the bits that represent the fractional part of <code>f</code> and these are always:</p> -<pre> unsigned int mask = one - 1; - unsigned int frac = u & mask; -</pre> -<p>If these bits represent less than one half the function must round down. If this is the case we can zero all the bits that represent the fractional part of <code>f</code> to obtain the integer immediately below <code>f</code>.</p> -<pre> if (frac <= one / 2) - { - u &= ~mask; - float r; - memcpy(&r &u sizeof(float)); - return r; - } -</pre> -<p>And we are left with the difficult exercise of finding the integer immediately above <code>f</code>. If this computation stays in the same binade this means finding the multiple of <code>one</code> immediately above <code>u</code>.</p> -<blockquote><p>“binade†is not a word according to my dictionary. It should be one. It designates a range of floating-point numbers such as [0.25 … 0.5) or [0.5 … 1.0). I needed it in the last post but I made do without it. I shouldn't have. Having words to designate things is the most important wossname towards clear thinking.</p> -</blockquote> -<p>And if the computation does not stay in the same binade such as 3.75 rounding up to 4.0? Well in this case it seems we again only need to find the multiple of <code>one</code> immediately above <code>u</code> which is in this case the power of two immediately above <code>f</code> and more to the point the number the function must return.</p> -<pre> u = (u + mask) & ~mask; - float r; - memcpy(&r &u sizeof(float)); - return r; -</pre> -<p>To summarize a function for rounding a float to the nearest integer by bit-twiddling is as follows. I am not sure what is so interesting about that. I like the function in the previous post or the function in the next post better.</p> -<pre>float myround(float f) -{ - assert (sizeof(unsigned int) == sizeof(float)); - unsigned int u; - memcpy(&u &f sizeof(float)); - if (f <= 0.5) return 0.; - if (f <= 1.5) return 1.; - int exp = ((u>>23) & 255) - 127; - if (23 - exp < 0) return f; - unsigned int one = 1U << (23 - exp); - unsigned int mask = one - 1; - unsigned int frac = u & mask; - if (frac <= one / 2) - u &= ~mask; - else - u = (u + mask) & ~mask; - float r; - memcpy(&r &u sizeof(float)); - return r; -} -</pre> -<h2>To be continued again</h2> <p>The only salient point in the method in this post is how we pretend not to notice when significand arithmetic overflows over the exponent for inputs between 1.5 and 2.0 3.5 and 4.0 and so on. The method in next post will be so much more fun than this.</p> {% endraw %} diff --git a/_posts/2013-05-04-Rounding-float-to-nearest-integer-part-3.html b/_posts/2013-05-04-Rounding-float-to-nearest-integer-part-3.html index 8e0a87768815e93b063f8d6945cf2649e1586117..840f569f42f2271e6a07c63e4fb2066c2d1d9f25 100644 --- a/_posts/2013-05-04-Rounding-float-to-nearest-integer-part-3.html +++ b/_posts/2013-05-04-Rounding-float-to-nearest-integer-part-3.html @@ -83,81 +83,5 @@ ____________________________________________________________________ <p>For instance if the FPU is set to round downwards and the argument <code>f</code> is <code>0.9f</code> then <code>f + 8388608.0f</code> produces <code>8388608.0f</code> and <code>f + 8388608.0f - 8388608.0f</code> produces zero.</p> <h2>Conclusion</h2> <p>This post concludes the “rounding float to nearest integer†series. The method highlighted in this third post is actually the method generally used for function <code>rintf()</code> because the floating-point addition has the effect of setting the “inexact†FPU flag when it is inexact which is exactly when the function returns an output other than its input which is when <code>rintf()</code> is specified as setting the “inexact†flag.</p> -<p>Function <code>nearbyintf()</code> is specified as not touching the FPU flags and would typically be implemented with the method from the second post.</p> - <p>Two earlier posts showed two different approaches in order to round a float to the nearest integer. The <a href="/index.php?post/2013/05/02/nearbyintf1">first</a> was to truncate to integer after having added the right quantity (either 0.5 if the programmer is willing to take care of a few dangerous inputs beforehand or the predecessor of 0.5 so as to have fewer dangerous inputs to watch for).</p> -<p>The <a href="/index.php?post/2013/05/03/nearbyintf2">second approach</a> was to mess with the representation of the <code>float</code> input trying to recognize where the bits for the fractional part were deciding whether they represented less or more than one half and either zeroing them (in the first case) or sending the float up to the nearest integer (in the second case) which was simple for complicated reasons.</p> -<h2>Variations on the first method</h2> -<p>Several persons have suggested smart variations on the first theme included here for the sake of completeness. -The first suggestion is as follows (remembering that the input <code>f</code> is assumed to be positive and ignoring overflow issues for simplicity):</p> -<pre>float myround(float f) -{ - float candidate = (float) (unsigned int) f; - if (f - candidate <= 0.5) return candidate; - return candidate + 1.0f; -} -</pre> -<p>Other suggestions were to use <code>modff()</code> that separates a floating-point number into its integral and fractional components or <code>fmodf(f 1.0f)</code> that computes the remainder of <code>f</code> in the division by 1.</p> -<p>These three solutions work better than adding 0.5 for a reason that is simple if one only looks at it superficially: floating-point numbers are denser around zero. Adding 0.5 takes us away from zero whereas operations <code>f - candidate</code> <code>modff(f iptr)</code> and <code>fmodf(f 1.0)</code> take us closer to zero in a range where the answer can be exactly represented so it is. (Note: this is a super-superficial explanation.)</p> -<h2>A third method</h2> -<h3>General idea: the power of two giveth and the power of two taketh away</h3> -<p>The third and generally most efficient method for rounding <code>f</code> to the nearest integer is to take advantage of this marvelous rounding machine that is IEEE 754 arithmetic. But for this to work the exact right machine is needed that is a C compiler that implements strict IEEE 754 arithmetic and rounds each operation to the precision of the type. If you are using GCC consider using options <code>-msse2 -mfpmath=sse</code>.</p> -<p>We already noticed that single-precision floats between 2^23 and 2^24 are all the integers in this range. If we add some quantity to <code>f</code> so that the result ends up in this range wouldn't it follow that the result obtained will be rounded to the integer? And it would be rounded in round-to-nearest. Exactly what we are looking for:</p> -<pre> f f + 8388608.0f -_____________________________ -0.0f 8388608.0f -0.1f 8388608.0f -0.5f 8388608.0f -0.9f 8388609.0f -1.0f 8388609.0f -1.1f 8388609.0f -1.5f 8388610.0f -1.9f 8388610.0f -2.0f 8388610.0f -2.1f 8388610.0f -</pre> -<p>The rounding part goes well but now we are stuck with large numbers far from the input and from the expected output. Let us try to get back close to zero by subtracting <code>8388608.0f</code> again:</p> -<pre> f f + 8388608.0f f + 8388608.0f - 8388608.0f -____________________________________________________________________ -0.0f 8388608.0f 0.0f -0.1f 8388608.0f 0.0f -0.5f 8388608.0f 0.0f -0.9f 8388609.0f 1.0f -1.0f 8388609.0f 1.0f -1.1f 8388609.0f 1.0f -1.5f 8388610.0f 2.0f -1.9f 8388610.0f 2.0f -2.0f 8388610.0f 2.0f -2.1f 8388610.0f 2.0f -</pre> -<p>It works! The subtraction is exact for the same kind of reason that was informally sketched for <code>f - candidate</code>. Adding <code>8388608.0f</code> causes the result to be rounded to the unit and then subtracting it is exact producing a <code>float</code> that is exactly the original rounded to the nearest integer.</p> -<p>For these inputs anyway. For very large inputs the situation is different.</p> -<h3>Very large inputs: absorption</h3> -<pre> f f + 8388608.0f f + 8388608.0f - 8388608.0f -____________________________________________________________________ -1e28f 1e28f 1e28f -1e29f 1e29f 1e29f -1e30f 1e30f 1e30f -1e31f 1e31f 1e31f -</pre> -<p>When <code>f</code> is large enough adding <code>8388608.0f</code> to it does nothing and then subtracting <code>8388608.0f</code> from it does nothing again. This is good news because we are dealing with very large single-precision floats that are already integers and can be returned directly as the result of our function <code>myround()</code>.</p> -<p>In fact since we entirely avoided converting to a range-challenged integer type and since adding <code>8388608.0f</code> to <code>FLT_MAX</code> does not make it overflow (we have been assuming the FPU was in round-to-nearest mode all this time remember?) we could even caress the dream of a straightforward <code>myround()</code> with a single execution path. Small floats rounded to the nearest integer and taken back near zero where they belong large floats returned unchanged by the addition and the subtraction of a comparatively small quantity (with respect to them).</p> -<h3>Dreams crushed</h3> -<p>Unfortunately although adding and subtracting 2^23 almost always does what we expect (it does for inputs up to 2^23 and above 2^47) there is a range of values for which it does not work. An example:</p> -<pre> f f + 8388608.0f f + 8388608.0f - 8388608.0f -____________________________________________________________________ -8388609.0f 16777216.0f 8388608.0f -</pre> -<p>In order for function <code>myround()</code> to work correctly for all inputs it still needs a conditional. The simplest is to put aside inputs larger than 2^23 that are all integers and to use the addition-subtraction trick for the others:</p> -<pre>float myround(float f) -{ - if (f >= 0x1.0p23) - return f; - return f + 0x1.0p23f - 0x1.0p23f; -} -</pre> -<p>The function above in round-to-nearest mode satisfies the contract we initially set out to fulfill. Interestingly if the rounding mode is other than round-to-nearest then it still rounds to a nearby integer but according to the FPU rounding mode. This is a consequence of the fact that the only inexact operation is the addition. The subtraction being exact is not affected by the rounding mode.</p> -<p>For instance if the FPU is set to round downwards and the argument <code>f</code> is <code>0.9f</code> then <code>f + 8388608.0f</code> produces <code>8388608.0f</code> and <code>f + 8388608.0f - 8388608.0f</code> produces zero.</p> -<h2>Conclusion</h2> -<p>This post concludes the “rounding float to nearest integer†series. The method highlighted in this third post is actually the method generally used for function <code>rintf()</code> because the floating-point addition has the effect of setting the “inexact†FPU flag when it is inexact which is exactly when the function returns an output other than its input which is when <code>rintf()</code> is specified as setting the “inexact†flag.</p> <p>Function <code>nearbyintf()</code> is specified as not touching the FPU flags and would typically be implemented with the method from the second post.</p> {% endraw %} diff --git a/_posts/2013-05-09-A-63-bit-floating-point-type-for-64-bit-OCaml.html b/_posts/2013-05-09-A-63-bit-floating-point-type-for-64-bit-OCaml.html index ed769fb7445baee242c8f84861f7ebc385fc5c21..0ea8e738236e86350a0946eacc7f421fe72297d3 100644 --- a/_posts/2013-05-09-A-63-bit-floating-point-type-for-64-bit-OCaml.html +++ b/_posts/2013-05-09-A-63-bit-floating-point-type-for-64-bit-OCaml.html @@ -42,40 +42,5 @@ As someone who has to deal with the consequences of hardware computing 64-bit ma <h3>Implementation</h3> <p>A quick and dirty implementation only tested as much as shown is available from <a href="http://ideone.com/Ev5uIP">ideone</a>. Now I would love for someone who actually uses floating-point in OCaml to finish integrating this in the OCaml runtime and do some benchmarks. Not that I expect it will be very fast: the 63-bit representation involves a lot of bit-shuffling and OCaml uses its own tricks such as unboxing floats inside arrays so that it will be hard to compete.</p> <h2>Credits</h2> -<p>I should note that I have been reading a report on implementing a perfect emulation of IEEE 754 double-precision using x87 hardware and that the idea presented here was likely to be contained there. Google which is prompt to point to the wrong definition of FLT_EPSILON has been no help in finding this report again.</p> - <h2>The OCaml runtime</h2> -<p>The OCaml runtime allows polymorphism through the uniform representation of types. Every OCaml value is represented as a single word, so that it is possible to have a single implementation for, say, “list of thingsâ€, with functions to access (e.g. <code>List.length</code>) and build (e.g. <code>List.map</code>) these lists that work just the same whether they are lists of ints, of floats, or of lists of sets of integers.</p> -<p>Anything that does not fit in in a word is allocated in a block in the heap. The word representing this data is then a pointer to the block. Since the heap contains only blocks of words, all these pointers are aligned: their few least significants bits are always unset.</p> -<p>Argumentless constructors (like this: <code>type fruit = Apple | Orange | Banana</code>) and integers do not represent so much information that they need to be allocated in the heap. Their representation is <em>unboxed</em>. The data is directly inside the word that would otherwise have been a pointer. So while a list of lists is actually a list of pointers, a list of ints contains the ints with one less indirection. The functions accessing and building lists do not notice because ints and pointers have the same size.</p> -<p>Still, the Garbage Collector needs to be able to recognize pointers from integers. A pointer points to a well-formed block in the heap that is by definition alive (since it is being visited by the GC) and should be marked so. An integer can have any value and could, if precautions were not taken, accidentally look like a pointer. This could cause dead blocks to look alive, but much worse, it would also cause the GC to change bits in what it thinks is the header of a live block, when it is actually following an integer that looks like a pointer and messing up user data.</p> -<p>This is why unboxed integers provide 31 bits (for 32-bit OCaml) or 63 bits (for 64-bit OCaml) to the OCaml programmer. In the representation, behind the scenes, the least significant bit of a word containing an integer is always set, to distinguish it from a pointer. 31- or 63-bit integers are rather unusual, so anyone who uses OCaml at all knows this. What users of OCaml do not usually know is why there isn't a 63-bit unboxed float type for 64-bit OCaml.</p> -<h2>There is no unboxed 63-bit floating-point type in OCaml</h2> -<p>And the answer to this last question is that there is no particular reason one shouldn't have a 63-bit unboxed float type in OCaml. Defining one only requires carefully answering two more intricately related questions:</p> -<ul> -<li>What 63-bit floating-point format should be used?</li> -<li>How will the OCaml interpreter compute values in this format?</li> -</ul> -<p>In 1990, when 64-bit computers were few, Xavier Leroy <a href="http://gallium.inria.fr/~xleroy/publi/ZINC.pdf">decided</a> that in his (then future) Caml-light system the type for floating-point would be 64-bit double precision. The double precision floating-point format did not come close to fitting in the then-prevalent 32-bit word:</p> -<blockquote><p>Floating-point numbers are allocated in the heap as unstructured blocks of length one two or three words depending on the possibilities of the hardware and on the required precision. An unboxed representation is possible using the 10 suffix for instance but this gives only 30 bits to represent floating-point numbers. Such a format lacks precision and does not correspond to any standard format so it involves fairly brutal truncations. Good old 64-bit IEEE-standard floating point numbers seem more useful even if they have to be allocated.</p> -</blockquote> -<p>First a remark: it is not necessary to distinguish floats from ints: that is what the static type-system is for. From the point of view of the GC they are all non-pointers and that's the only important thing. So if we decide to unbox floats we can take advantage of the same representation as for integers a word with the least significant bit set. And nowadays even the proverbial grandmother has a 64-bit computer to read e-mail on hence the temptation to unbox floats.</p> -<p>Second the reticence to truncate the mantissa of any existing format remains well-founded. Suppose that we defined a format with 51 explicit mantissa bits as opposed to double-precision's 52. We could use the double-precision hardware for computations and then round to 51 bits of mantissa but the sizes are so close that this would introduced plenty of <em>double rounding errors</em> where the result is less precise than if it had been rounded directly to 51 bits. -As someone who has to deal with the consequences of hardware computing 64-bit mantissas that are then rounded a second time to 52-bit I feel dirty just imagining this possibility. If we went for 1 sign bit 11 exponent bits 51 explicit mantissa bits we would have to use software emulation to round directly to the correct result.</p> -<p>This post is about another idea to take advantage of the double-precision hardware to implement a 63-bit floating-point type.</p> -<h2>A truncationless 63-bit floating-point format</h2> -<h3>Borrow a bit from the exponent</h3> -<p>Taking one of the bits from the 11 reserved for the exponent in the IEEE 754 double-precision format does not have such noticeable consequences. At the top of the scale it is easy to map values above a threshold to infinity. This does not involve double-rouding error. At the bottom of the scale things are more complicated. The very smallest floating-point numbers of a proper floating-point format called subnormals have an effective precision of less than the nominal 52 bits. Computing with full-range double-precision and then rounding to reduced-range 63-bit means that the result of a computation can be computed as a normal double-precision number with 52-bit mantissa say 1.324867e-168 and then rounded to the narrower effective precision of a 63-bit subnormal float.</p> -<blockquote><p>Incidentally this sort of issue is the sort that remains even after you have configured an x87 to use only the 53 or 24 mantissa bits that make sense to compute with the precision of double- or single-precision. Only the range of the mantissa is reduced not that of the exponent so numbers that would be subnormals in the targeted type are normal when represented in a x87 register. You could hope to fix them after each computation with an option such as GCC's -ffloat-store but then they are double-rounded. The first rounding is at 53 or 24 bits and the second to the effective precision of the subnormal.</p> -</blockquote> -<h3>Double-rounding Never!</h3> -<p>But since overflows are much easier to handle we can cheat. In order to make sure that subnormal results are rounded directly to the effective precision we can bias the computations so that if the result is going to be a 63-bit subnormal the double-precision operation produces a subnormal result already.</p> -<p>In practice this means that when the OCaml program is adding numbers 1.00000000001e-152 and -1.0e-152 we do not show these numbers to the double-precision hardware. What we show to the hardware instead is these numbers multiplied by 2^-512 so that if the result need to be subnormal in the 63-bit format and in this example it needs then a subnormal double-precision will be computed with the same number of bits of precision.</p> -<p>In fact we can maintain this “store numbers as 2^-512 times their intended value†convention all the time and only come out of it at the time of calling library functions such as <code>printf()</code>.</p> -<p>For multiplication of two operands represented as 2^-512 times their real value one of the arguments needs to be unbiased (or rebiased: if you have a trick to remember which is which please share) before the hardware multiplication by multiplying it by 2^512.</p> -<p>For division the result must be rebiased after it is computed.</p> -<p>The implementation of the correctly-rounded function <code>sqrt()</code> for 63-bit floats is left as an exercise to the reader.</p> -<h3>Implementation</h3> -<p>A quick and dirty implementation only tested as much as shown is available from <a href="http://ideone.com/Ev5uIP">ideone</a>. Now I would love for someone who actually uses floating-point in OCaml to finish integrating this in the OCaml runtime and do some benchmarks. Not that I expect it will be very fast: the 63-bit representation involves a lot of bit-shuffling and OCaml uses its own tricks such as unboxing floats inside arrays so that it will be hard to compete.</p> -<h2>Credits</h2> <p>I should note that I have been reading a report on implementing a perfect emulation of IEEE 754 double-precision using x87 hardware and that the idea presented here was likely to be contained there. Google which is prompt to point to the wrong definition of FLT_EPSILON has been no help in finding this report again.</p> {% endraw %} diff --git a/_posts/2013-05-09-Definition-of-FLT_EPSILON.html b/_posts/2013-05-09-Definition-of-FLT_EPSILON.html index a27c5132ae5ff981fa2e7962211527e821df0f1f..b0e7961cb471c7bd9de524bc033b90e919a933bb 100644 --- a/_posts/2013-05-09-Definition-of-FLT_EPSILON.html +++ b/_posts/2013-05-09-Definition-of-FLT_EPSILON.html @@ -50,48 +50,5 @@ candidate: 0x1.000000p-24 candidate+1.0f: 0x1.000000p+0 <p>Fortunately in the file that initiated this rant the value for FLT_EPSILON is correct:</p> <pre>#define FLT_EPSILON 1.19209290E-07F // decimal constant </pre> -<p>This is the decimal representation of <code>0x0.000002p0</code>. Code compiled against this header will work. It is only the comment that's wrong.</p> - <h2>Correct and wrong definitions for the constant FLT_EPSILON</h2> -<p>If I google “FLT_EPSILONâ€, the topmost result is <a href="http://www.rowleydownload.co.uk/avr/documentation/index.htm?http://www.rowleydownload.co.uk/avr/documentation/FLT_EPSILON.htm">this page</a> with this definition:</p> -<pre>FLT_EPSILON the minimum positive number such that 1.0 + FLT_EPSILON != 1.0. -</pre> -<p>No no no no no.</p> -<p>I don't know where this definition originates from but it is obviously from some sort of standard C library and it is wrong wrong wrong wrong wrong. -The definition of the C99 standard is:</p> -<blockquote><p>the difference between 1 and the least value greater than 1 that is representable in the given floating point type b^(1−p)</p> -</blockquote> -<p>The GNU C library gets it right:</p> -<blockquote><p>FLT_EPSILON: This is the difference between 1 and the smallest floating point number of type float that is greater than 1.</p> -</blockquote> -<h2>The difference</h2> -<p>On any usual architecture with the correct definition FLT_EPSILON is <code>0x0.000002p0</code> the difference between <code>0x1.000000p0</code> and the smallest float above it <code>0x1.000002p0</code>.</p> -<p>The notation <code>0x1.000002p0</code> is a convenient <a href="https://blogs.oracle.com/darcy/entry/hexadecimal_floating_point_literals">hexadecimal input format</a> introduced in C99 for floating-point numbers. The last digit is a <code>2</code> where one might have expected a <code>1</code> because single-precision floats have 23 explicit bits of mantissa and 23 is not a multiple of 4. So the <code>2</code> in <code>0x1.000002p0</code> represents the last bit that can be set in a single-precision floating-point number in the interval [1…2).</p> -<p>If one adds FLT_EPSILON to <code>1.0f</code> one does obtain <code>0x1.000002p0</code>. But is it the smallest <code>float</code> with this property?</p> -<pre>#include <stdio.h> -void pr_candidate(float f) -{ - printf("candidate: %.6a\tcandidate+1.0f: %.6a" f 1.0f + f); -} -int main(){ - pr_candidate(0x0.000002p0); - pr_candidate(0x0.000001fffffep0); - pr_candidate(0x0.0000018p0); - pr_candidate(0x0.000001000002p0); - pr_candidate(0x0.000001p0); -} -</pre> -<p>This program compiled and executed produces:</p> -<pre>candidate: 0x1.000000p-23 candidate+1.0f: 0x1.000002p+0 -candidate: 0x1.fffffep-24 candidate+1.0f: 0x1.000002p+0 -candidate: 0x1.800000p-24 candidate+1.0f: 0x1.000002p+0 -candidate: 0x1.000002p-24 candidate+1.0f: 0x1.000002p+0 -candidate: 0x1.000000p-24 candidate+1.0f: 0x1.000000p+0 -</pre> -<p>No <code>0x0.000002p0</code> is not the smallest number that added to <code>1.0f</code> causes the result to be above <code>1.0f</code>. This honor goes to <code>0x0.000001000002p0</code> the smallest float above half FLT_EPSILON.</p> -<p>Exactly half FLT_EPSILON the number <code>0x0.000001p0</code> or <code>0x1.0p-24</code> as you might prefer to call it causes the result of the addition to be exactly midway between <code>1.0f</code> and its successor. The rule says that the “even†one has to be picked in this case. The “even†one is <code>1.0f</code>.</p> -<h2>Conclusion</h2> -<p>Fortunately in the file that initiated this rant the value for FLT_EPSILON is correct:</p> -<pre>#define FLT_EPSILON 1.19209290E-07F // decimal constant -</pre> <p>This is the decimal representation of <code>0x0.000002p0</code>. Code compiled against this header will work. It is only the comment that's wrong.</p> {% endraw %} diff --git a/_posts/2013-05-11-Big-round-numbers-and-a-book-review.html b/_posts/2013-05-11-Big-round-numbers-and-a-book-review.html index fa1e6f91d1a1b89b975ba90d7f1ce7900f8f1c13..07a77eb26ec4da0afbc3e47713aeadca4b00784d 100644 --- a/_posts/2013-05-11-Big-round-numbers-and-a-book-review.html +++ b/_posts/2013-05-11-Big-round-numbers-and-a-book-review.html @@ -13,11 +13,5 @@ summary: <p>A lot of recent posts have been related to floating-point arithmetic. I would like to reassure everyone that this was only a fluke. Floating-point correctness became one of the Frama-C tenets with our involvement in two collaborative projects U3CAT and Hisseo now both completed. Very recently something must have clicked for me and I became quite engrossed by the subject.</p> <p>As a result of this recent passion in the last few days I started reading the “Handbook of Floating-Point Arithmetic†by Jean-Michel Muller et al. This book is both thick and dense but fortunately well organized so that it is easy to skip over sections you do not feel concerned with such as decimal floating-point or hardware implementation details. This book is an amazing overview. It contains cristal-clear explanations of floating-point idioms that I was until then painstakingly reverse-engineering from library code. Fifteen years from now people will say “… and you should read the Handbook of Floating-Point Arithmetic. It is a bit dated now but it is still the best reference just complete it with this one and that one†just like people might say now about Aho Sethi and Ullman's Dragon book for compilation.</p> <p>Except that right now the book is current. The references to hardware are references to hardware that you might still have or certainly remember having had. The open questions are still open. If you were offered the chance to read the Dragon book when it came out and was all shiny and new would you pass? If not and if there is the slightest chance that you might hold an interest in the mysteries of floating-point computation in the foreseeable future read this book now for the bragging rights.</p> -<p>In addition the book goes down to the lowest levels of detail with occasional snippets of programs to make it clear what is meant. The snippets are C code and irreproachable C code.</p> - <p>Nearly 15 months ago, according to a past article, this blog celebrated its 15-month anniversary, and celebrated with the announcement of minor milestones having been reached: 100 articles and 50 comments.</p> -<p>Fifteen months after that, the current count is nearly 200 articles and 200 comments. Also, the blog managed to get 100 subscribers in Google's centralized service for never having to mark the same post as read twice, Reader. This was a <a href="http://lifehacker.com/5990456/google-reader-is-getting-shut-down-here-are-the-best-alternatives">close call</a>.</p> -<p>A lot of recent posts have been related to floating-point arithmetic. I would like to reassure everyone that this was only a fluke. Floating-point correctness became one of the Frama-C tenets with our involvement in two collaborative projects U3CAT and Hisseo now both completed. Very recently something must have clicked for me and I became quite engrossed by the subject.</p> -<p>As a result of this recent passion in the last few days I started reading the “Handbook of Floating-Point Arithmetic†by Jean-Michel Muller et al. This book is both thick and dense but fortunately well organized so that it is easy to skip over sections you do not feel concerned with such as decimal floating-point or hardware implementation details. This book is an amazing overview. It contains cristal-clear explanations of floating-point idioms that I was until then painstakingly reverse-engineering from library code. Fifteen years from now people will say “… and you should read the Handbook of Floating-Point Arithmetic. It is a bit dated now but it is still the best reference just complete it with this one and that one†just like people might say now about Aho Sethi and Ullman's Dragon book for compilation.</p> -<p>Except that right now the book is current. The references to hardware are references to hardware that you might still have or certainly remember having had. The open questions are still open. If you were offered the chance to read the Dragon book when it came out and was all shiny and new would you pass? If not and if there is the slightest chance that you might hold an interest in the mysteries of floating-point computation in the foreseeable future read this book now for the bragging rights.</p> <p>In addition the book goes down to the lowest levels of detail with occasional snippets of programs to make it clear what is meant. The snippets are C code and irreproachable C code.</p> {% endraw %} diff --git a/_posts/2013-05-14-Contrarianism.html b/_posts/2013-05-14-Contrarianism.html index dcfcf15ad06a33fa976477824cd5750551f5e52e..ffdcf6292be398aff20d603bb691a38867f73eba 100644 --- a/_posts/2013-05-14-Contrarianism.html +++ b/_posts/2013-05-14-Contrarianism.html @@ -11,8 +11,5 @@ summary: <p>If I told you that when <code>n</code> is a positive power of two and <code>d</code> an arbitrary number, both represented as <code>double</code>, the condition <code>(n - 1) * d + d == n * d</code> in strictly-IEEE-754-implementing C is always true, would you start looking for a counter-example, or start looking for a convincing argument that this property may hold?</p> <p>If you started looking for counter-examples, would you start with the vicious values? Trying to see if <code>NaN</code> or <code>+inf</code> can be interpreted as “a positive power of two†or “an arbitrary number†represented “as <code>double</code>â€? A subnormal value for <code>d</code>? A subnormal value such that <code>n*d</code> is normal? A subnormal value such that <code>(n - 1) * d</code> is subnormal and <code>n * d</code> is normal?</p> <p>Or would you try your luck with ordinary values such as <code>0.1</code> for <code>d</code> and <code>4</code> for <code>n</code>?</p> -<p>This post is based on a remark by Stephen Canon. Also, I have discovered a truly remarkable proof of the property which this quick post is too small to contain.</p> <p>If I told you that when <code>n</code> is a positive power of two and <code>d</code> an arbitrary number, both represented as <code>double</code>, the condition <code>(n - 1) * d + d == n * d</code> in strictly-IEEE-754-implementing C is always true, would you start looking for a counter-example, or start looking for a convincing argument that this property may hold?</p> -<p>If you started looking for counter-examples, would you start with the vicious values? Trying to see if <code>NaN</code> or <code>+inf</code> can be interpreted as “a positive power of two†or “an arbitrary number†represented “as <code>double</code>â€? A subnormal value for <code>d</code>? A subnormal value such that <code>n*d</code> is normal? A subnormal value such that <code>(n - 1) * d</code> is subnormal and <code>n * d</code> is normal?</p> -<p>Or would you try your luck with ordinary values such as <code>0.1</code> for <code>d</code> and <code>4</code> for <code>n</code>?</p> -<p>This post is based on a remark by Stephen Canon. Also, I have discovered a truly remarkable proof of the property which this quick post is too small to contain.</p> +<p>This post is based on a remark by Stephen Canon. Also, I have discovered a truly remarkable proof of the property which this quick post is too small to contain.</p> {% endraw %} diff --git a/_posts/2013-05-20-Attack-by-Compiler.html b/_posts/2013-05-20-Attack-by-Compiler.html index 6383c751bbdc4f312de313ab01c3241e0bb2e020..a8ad4c61fb9d890cfc6e36c1ea96a5a63fbcb0b4 100644 --- a/_posts/2013-05-20-Attack-by-Compiler.html +++ b/_posts/2013-05-20-Attack-by-Compiler.html @@ -41,39 +41,5 @@ summary: <p>Nothing in the C language definition forces a compiler to compile the above function into a function that does not return as soon as variable <code>res</code> contains <code>(unsigned char)-1</code> not to mention the possibilities if the compiler first inlines the function in a site where its result is only compared to 0 and then optimizes the code for early termination. If I was trying to sneak in a compiler change that defeats the purpose of this <code>memcmp_nta()</code> function I would bundle it with auto-vectorization improvements. It is a fashionable topic and quite exciting if one does not care about non-functional properties such as execution time.</p> <h2>Conclusion</h2> <p>The impracticability of the described attack is counter-balanced by some unusual benefits: at the time of the attack someone may already have audited the pseudo-random number generator or function <code>memcmp_nta()</code> we used as examples. The audit may have considered both source and generated assembly code and involved actual tests at a time when the code was “safely†compiled. But the auditor is not going to come back to the review again and again each time a new compiler comes out. Like Monty Python's <a href="http://www.youtube.com/watch?v=Tym0MObFpTI">Spanish Inquisition</a> nobody expects the compiler-generated backdoor.</p> -<p>Three of my four examples involve undefined behavior. More generally my examples all involve unwarranted programmer expectations about C idioms. This is the key to plausibly deniable compiler changes that reveal latent security flaws. What other unwarranted expectations should we take advantage of for an “attack by compilerâ€?</p> - <p>The title of this post, “Attack by Compilerâ€, has been at the back of my mind for several weeks. It started with a comment by jduck on a post earlier this year. The post's topic, the practical undefinedness of reading from uninitialized memory, and jduck's comment, awakened memories from a 2008 incident with the random number generator in OpenSSL.</p> -<p>As I am writing this, if I google “attack by compilerâ€, the first page of results include the classic essay <a href="http://cm.bell-labs.com/who/ken/trust.html">Reflections on Trusting Trust</a> by Ken Thompson Wikipedia's definition of a <a href="http://en.wikipedia.org/wiki/Backdoor_(computing)">backdoor in computing</a> an <a href="http://www.acsa-admin.org/2005/abstracts/47.html">article</a> by David A. Wheeler for countering the attack described by Thompson a <a href="http://www.schneier.com/blog/archives/2006/01/countering_trus.html">commentary</a> by Bruce Schneier on Wheeler's article and a Linux Journal <a href="http://www.linuxjournal.com/article/7929">article</a> by David Maynor on the practicality of the attack described by Thompson on the widespread GNU/Linux platform.</p> -<p>This post is about a slightly different idea.</p> -<h2>Initial conditions: trustworthy compiler peer-reviewed changes</h2> -<p>Suppose that we start with a trustworthy compiler widely distributed in both source and binary form. Some people are in the position to make changes to the compiler's source code and could like Thompson in his essay attempt to insert a backdoor in the compiler itself.</p> -<p>But now each change is scrutinized by innumerable witnesses from the Open-Source community. I say “witnesses†in fact they are mostly students but we will probably be forced to assume that they can't all be mischievous.</p> -<p>The attackers could try to obfuscate the backdoor as they insert it but the problem is that some of the witnesses are bound to possess this character trait that the less they understand a change the more they investigate it. Furthermore once these witnesses have uncovered the truth loss of credibility will ensue for the person who tried to sneak the backdoor in. This person will lose eir commit privilege to the compiler's sources and people will recover untainted compilers in source and binary form from their archives. This kind of approach is risky and may only result in a temporary advantage—which may still be enough.</p> -<h2>The underhanded approach</h2> -<p>The 2013 edition of the <a href="http://underhanded.xcott.com">Underhanded C Contest</a> is under way. The contest defines underhanded code as:</p> -<blockquote><p>code that is as readable clear innocent and straightforward as possible and yet [fails] to perform at its apparent function</p> -</blockquote> -<p>Underhandedness is exactly what an attacker with commit access to the source code of the widely used compiler should aim for. If the commit is underhanded enough the committer may not only enjoy full <strong>deniability</strong> but ey may obtain that the incriminating change <strong>stays in ulterior versions</strong> of the compiler as a “good†change. This implies that all affected security-sensitive applications like the “login†program in Thompson's essay must be updated to work around the now official backdoor in the compiler. In this scenario even after the attack has been discovered anytime someone unknowingly compiles an old version of “login†with a recent compiler it's another win for the attacker.</p> -<p>Fortunately we agree with Scott Craver that the C programming language is a very good context to be underhanded in and a C compiler is even better. How about the following ideas?</p> -<ol> -<li>making pseudo-random number generators that rely on uninitialized memory <strong>less random</strong> in the hope that this will result in weaker cryptographic keys for those who do not know about the flaw;</li> -<li>optimizing a NULL test out of kernel code when it is one of several <strong>defenses that need to be bypassed</strong>;</li> -<li>optimizing <code>buffer + len >= buffer_end || buffer + len < buffer</code> overflow tests out from application code so that <strong>buffer overflows do take place</strong> in code that is guarded thus;</li> -<li>optimizing source code that was written to take constant-time into binary code that <strong>reveals secrets by terminating early</strong>.</li> -</ol> -<p>I am not being very original. According to this <a href="http://kqueue.org/blog/2012/06/25/more-randomness-or-less/">post</a> by Xi Wang idea (1) is only waiting for someone to give the compiler one last well-calibrated shove. The NULL test optimization was already implemented in the compiler when it was needed for a famous Linux kernel <a href="http://lwn.net/Articles/342330/">exploit</a>. The interesting scenario would have been if someone had found that the code in <code>tun_chr_poll()</code> was almost exploitable and had submitted the GCC optimization to activate the problem but it did not happen in this order. Idea (3) really <a href="http://lwn.net/Articles/278137/">happened</a>.</p> -<p>Idea (4) has not been exploited that I know of but it is only only a matter of time. If I google for “constant-time memcmp†I may <a href="http://www.serverphorums.com/read.php?12 650482">find</a> an implementation such as follows:</p> -<pre>int memcmp_nta(const void *cs const void *ct size_t count) -{ - const unsigned char *su1 *su2; - int res = 0; - for (su1 = cs su2 = ct; 0 < count; ++su1 ++su2 count--) - res |= (*su1 ^ *su2); - return res; -} -</pre> -<p>Nothing in the C language definition forces a compiler to compile the above function into a function that does not return as soon as variable <code>res</code> contains <code>(unsigned char)-1</code> not to mention the possibilities if the compiler first inlines the function in a site where its result is only compared to 0 and then optimizes the code for early termination. If I was trying to sneak in a compiler change that defeats the purpose of this <code>memcmp_nta()</code> function I would bundle it with auto-vectorization improvements. It is a fashionable topic and quite exciting if one does not care about non-functional properties such as execution time.</p> -<h2>Conclusion</h2> -<p>The impracticability of the described attack is counter-balanced by some unusual benefits: at the time of the attack someone may already have audited the pseudo-random number generator or function <code>memcmp_nta()</code> we used as examples. The audit may have considered both source and generated assembly code and involved actual tests at a time when the code was “safely†compiled. But the auditor is not going to come back to the review again and again each time a new compiler comes out. Like Monty Python's <a href="http://www.youtube.com/watch?v=Tym0MObFpTI">Spanish Inquisition</a> nobody expects the compiler-generated backdoor.</p> <p>Three of my four examples involve undefined behavior. More generally my examples all involve unwarranted programmer expectations about C idioms. This is the key to plausibly deniable compiler changes that reveal latent security flaws. What other unwarranted expectations should we take advantage of for an “attack by compilerâ€?</p> {% endraw %} diff --git a/_posts/2013-06-19-Microsofts-bug-bounty-program.html b/_posts/2013-06-19-Microsofts-bug-bounty-program.html index bba47cb3e4d31ef1799196680a5cea488d25246c..f87d8b35f2448aacc2d0a727878e6dc6310c8a1c 100644 --- a/_posts/2013-06-19-Microsofts-bug-bounty-program.html +++ b/_posts/2013-06-19-Microsofts-bug-bounty-program.html @@ -10,8 +10,5 @@ summary: {% raw %} <p>I like Robert Graham's <a href="http://erratasec.blogspot.fr/2013/06/even-microsoft-has-to-pay-for-it.html#.UcIBJZWBK2w">analysis</a> on Microsoft's new bug bounty program.</p> <p>I would never have thought of selling vulnerabilities to the NSA (but then I am not American and not a security researcher). Does the NSA not employ qualified people to look for vulnerabilities as their day job? Is that not like trying to sell a loaf of bread to a company whose business is to make bread?</p> -<p>Sometimes you have a really good loaf of bread but still… Regardless of whether the NSA already owns your particular loaf of bread and independently of the payment-by-carrot-or-stick discussion you are a competitor not a provider.</p> - <p>I like Robert Graham's <a href="http://erratasec.blogspot.fr/2013/06/even-microsoft-has-to-pay-for-it.html#.UcIBJZWBK2w">analysis</a> on Microsoft's new bug bounty program.</p> -<p>I would never have thought of selling vulnerabilities to the NSA (but then I am not American and not a security researcher). Does the NSA not employ qualified people to look for vulnerabilities as their day job? Is that not like trying to sell a loaf of bread to a company whose business is to make bread?</p> <p>Sometimes you have a really good loaf of bread but still… Regardless of whether the NSA already owns your particular loaf of bread and independently of the payment-by-carrot-or-stick discussion you are a competitor not a provider.</p> {% endraw %} diff --git a/_posts/2013-06-20-On-the-prototype-of-recv.html b/_posts/2013-06-20-On-the-prototype-of-recv.html index 66ef2b60fef0c3cb128662193e863a99ae86702f..bf5cefd4d09aaabf03daaeed65357ad4cfcdaf15 100644 --- a/_posts/2013-06-20-On-the-prototype-of-recv.html +++ b/_posts/2013-06-20-On-the-prototype-of-recv.html @@ -20,18 +20,5 @@ recv(int socket, void *buffer, size_t length, int flags); Fair enough. Now let us write a bit of formal specification to go with <code>recv()</code>'s prototype:</p> <pre> /*@ … ensures -1 <= \esult <= length ; */</pre> <p>The unimpeachable logic here is that since function <code>recv()</code> is well-written not to overflow the buffer passed to it the number of bytes received can only be lower than the number of bytes it was allowed to write. Or naturally it can be <code>-1</code> in case of error.</p> -<p>Question: what is strange about the above post-condition?</p> - <p>Typing <code>man recv</code> on my system, I get:</p> -<pre>ssize_t -recv(int socket, void *buffer, size_t length, int flags); -</pre> -<p>The man page contains this additional bit of specification: -“These calls return the number of bytes received, or -1 if an error occurred.â€</p> -<blockquote><p>The type <code>ssize_t</code> is defined as a signed variant of <code>size_t</code>. “Is that not what <code>ptrdiff_t</code> is for?â€, you may ask. Jonathan Leffler was wondering about <a href="http://stackoverflow.com/q/8649018/139746">this very question</a> during the last days of 2011. I am unsure of the answers conclusiveness: on 32-bit platforms that let <code>malloc()</code> create objects of more than 2GiB <code>ptrdiff_t</code> is generally 32-bit wide although it should be wider by the same reasoning applied in the accepted answer and in some of its comments.</p> -</blockquote> -<p>That function <code>recv()</code> may return <code>-1</code> in case of error is probably the reason for the result of <code>recv()</code> being of the signed type <code>ssize_t</code>. -Fair enough. Now let us write a bit of formal specification to go with <code>recv()</code>'s prototype:</p> -<pre> /*@ … ensures -1 <= \esult <= length ; */</pre> -<p>The unimpeachable logic here is that since function <code>recv()</code> is well-written not to overflow the buffer passed to it the number of bytes received can only be lower than the number of bytes it was allowed to write. Or naturally it can be <code>-1</code> in case of error.</p> <p>Question: what is strange about the above post-condition?</p> {% endraw %} diff --git a/_posts/2013-07-06-On-the-precise-analysis-of-C-programs-for-FLT_EVAL_METHOD--2.html b/_posts/2013-07-06-On-the-precise-analysis-of-C-programs-for-FLT_EVAL_METHOD--2.html index c06b7501fa7328295fc817079048d984936c4679..c57b6ba1ffa44c962f1668525f737074aeb53311 100644 --- a/_posts/2013-07-06-On-the-precise-analysis-of-C-programs-for-FLT_EVAL_METHOD--2.html +++ b/_posts/2013-07-06-On-the-precise-analysis-of-C-programs-for-FLT_EVAL_METHOD--2.html @@ -75,73 +75,5 @@ t.c:9:[kernel] warning: Floating-point constant 0.1 is not represented exactly. <blockquote><p>The above example command-lines are for Frama-C's value analysis but during her PhD Thi Minh Tuyen Nguyen has shown that the same kind of approach could be applied to source-level Hoare-style verification of floating-point C programs. The relevant articles can be found in the <a href="http://hisseo.saclay.inria.fr/documents.html">results of the Hisseo project</a>.</p> </blockquote> <h2>To be continued</h2> -<p>In the next post we will find more pitfalls revisit a post by Joseph S. Myers in the GCC mailing list and conclude that implementing a precise static analyzer for this sort of compilation platform is a lot of work.</p> - <p>There has been talk recently amongst my colleagues of Frama-C-wide support for compilation platforms that define <code>FLT_EVAL_METHOD</code> as 2. Remember that this compiler-set value, introduced in C99, means that all floating-point computations in the C program are made with <code>long double</code> precision, even if the type of the expressions they correspond to is <code>float</code> or <code>double</code>. This post is a reminder, to the attention of these colleagues and myself, of pitfalls to be anticipated in this endeavor.</p> -<p>We are talking of C programs like the one below.</p> -<pre>#include <stdio.h> -int r1; -double ten = 10.0; -int main(int c, char **v) -{ - r1 = 0.1 == (1.0 / ten); - printf(1=%d" r1); -} -</pre> -<p>With a C99 compilation platform that defines <code>FLT_EVAL_METHOD</code> as 0 this program prints "r1=1" but with a compilation platform that sets <code>FLT_EVAL_METHOD</code> to 2 it prints “r1=0â€.</p> -<p>Although we are discussing non-strictly-IEEE 754 compilers we are assuming IEEE 754-like floating-point: we're not in 1980 any more. -Also we are assuming that <code>long double</code> has more precision than <code>double</code> because the opposite situation would make any discussion specifically about <code>FLT_EVAL_METHOD == 2</code> quite moot. In fact we are precisely thinking of compilation platforms where <code>float</code> is IEEE 754 single-precision (now called binary32) <code>double</code> is IEEE 754 double-precision (binary64) and <code>long double</code> is the 8087 80-bit double-extended format.</p> -<p>Let us find ourselves a compiler with the right properties :</p> -<pre>$ gcc -v -Using built-in specs. -Target: x86_64-linux-gnu -… -gcc version 4.4.3 (Ubuntu 4.4.3-4ubuntu5.1) -$ gcc -mfpmath=387 -std=c99 t.c && ./a.out -r1=0 -</pre> -<p>Good! (it seems)</p> -<blockquote><p>The test program sets <code>r1</code> to 0 because the left-hand side <code>0.1</code> of the equality test is the double-precision constant 0.1 whereas the right-hand side is the double-extended precision result of the division of 1 by 10. The two differ because 0.1 cannot be represented exactly in binary floating-point so the <code>long double</code> representation is closer to the mathematical value and thus different from the <code>double</code> representation. We can make sure this is the right explanation by changing the expression for <code>r1</code> to <code>0.1L == (1.0 / ten)</code> in which the division is typed as <code>double</code> but computed as <code>long double</code> then promoted to <code>long double</code> in order to be compared to <code>0.1L</code> the <code>long double</code> representation of the mathematical constant <code>0.1</code>. This change causes <code>r1</code> to receive the value 1 with our test compiler whereas the change would make <code>r1</code> receive 0 if the program was compiled with a strict IEEE 754 C compiler.</p> -</blockquote> -<h2>Pitfall 1: Constant expressions</h2> -<p>Let us test the augmented program below:</p> -<pre>#include <stdio.h> -int r1 r2; -double ten = 10.0; -int main(int c char **v) -{ - r1 = 0.1 == (1.0 / ten); - r2 = 0.1 == (1.0 / 10.0); - printf("r1=%d r2=%d" r1 r2); -} -</pre> -<p>In our first setback the program prints “r1=0 r2=1â€. The assignment to <code>r2</code> has been compiled into a straight constant-to-register move based on a constant evaluation algorithm that does not obey the same rules that execution does. If we are to write a <strong>precise</strong> static analyzer that corresponds to this GCC-4.4.3 this issue is going to seriously complicate our task. We will have to delineate a notion of “constant expressions†that the analyzer with evaluate with the same rules as GCC's rules for evaluating constant expressions and then implement GCC's semantics for run-time evaluation of floating-point expressions for non-constant expressions. And our notion of “constant expression†will have to exactly match GCC's notion of “constant expression†lest our analyzer be unsound.</p> -<h2>Clarification: What is a “precise†static analyzer?</h2> -<p>This is as good a time as any to point out that Frama-C's value analysis plug-in for instance is already able to analyze programs destined to be compiled with <code>FLT_EVAL_METHOD</code> as 2. By default the value analysis plug-in assumes IEEE 754 and <code>FLT_EVAL_METHOD == 0</code>:</p> -<pre>$ frama-c -val t.c -… -t.c:9:[kernel] warning: Floating-point constant 0.1 is not represented exactly. - Will use 0x1.999999999999ap-4. - See documentation for option -warn-decimal-float -… -[value] Values at end of function main: - r1 ∈ {1} - r2 ∈ {1} -</pre> -<p>The possibility of <code>FLT_EVAL_METHOD</code> being set to 2 is captured by the option <code>-all-rounding-modes</code>:</p> -<pre>$ frama-c -val -all-rounding-modes t.c -… -t.c:9:[kernel] warning: Floating-point constant 0.1 is not represented exactly. - Will use 0x1.999999999999ap-4. - See documentation for option -warn-decimal-float -… -[value] Values at end of function main: - r1 ∈ {0; 1} - r2 ∈ {0; 1} -</pre> -<p>The sets of values predicted for variables <code>r1</code> and <code>r2</code> at the end of <code>main()</code> each contain the value given by the program as compiled by GCC-4.4.3 but these sets are not precise. If the program then went on to divide <code>r1</code> by <code>r2</code> Frama-C's value analysis would warn about a possible division by zero whereas we know that with our compiler the division is safe. The warning would be a false positive.</p> -<p>We are talking here about making a static analyzer with the ability to conclude that <code>r1</code> is 0 and <code>r2</code> is 1 because we told it that we are targeting a compiler that makes it so.</p> -<blockquote><p>The above example command-lines are for Frama-C's value analysis but during her PhD Thi Minh Tuyen Nguyen has shown that the same kind of approach could be applied to source-level Hoare-style verification of floating-point C programs. The relevant articles can be found in the <a href="http://hisseo.saclay.inria.fr/documents.html">results of the Hisseo project</a>.</p> -</blockquote> -<h2>To be continued</h2> <p>In the next post we will find more pitfalls revisit a post by Joseph S. Myers in the GCC mailing list and conclude that implementing a precise static analyzer for this sort of compilation platform is a lot of work.</p> {% endraw %} diff --git a/_posts/2013-07-09-Arithmetic-overflows-in-Fluorine.html b/_posts/2013-07-09-Arithmetic-overflows-in-Fluorine.html index 675eb8cab6256ddc8fc7bea7f097a0c86c40fffe..26a785ea8c664bcd1a8bad80e5ba733973864afd 100644 --- a/_posts/2013-07-09-Arithmetic-overflows-in-Fluorine.html +++ b/_posts/2013-07-09-Arithmetic-overflows-in-Fluorine.html @@ -75,73 +75,5 @@ unsigned int r = a * b; <p>Incidentally things would be completely different in this last example if <code>int</code> and <code>short</code> were the same size say if <code>int</code> was 16-bit. In this case the third line would be equivalent to <code>unsigned int r = (unsigned int) a * (unsigned int) b;</code> and would only contain an unsigned innocuous overflow.</p> <h2>Wrapping up</h2> <p>In Fluorine the option to activate or deactivate the emission of these undefined arithmetic overflow alarms is called <code>-warn-signed-overflow</code> (the opposite version for no alarms being <code>-no-warn-signed-overflow</code>). I felt that providing this piece of information earlier would have rendered the quiz too easy.</p> -<p>Although Frama-C's value analysis adheres to the semantics of C and only warns for undefined overflows it is possible to use Frama-C to check for the other kinds of overflows by <a href="/index.php?post/2012/02/04/Using-Rte-and-Value-to-detect-overflows">using another plug-in Rte</a> to automatically annotate the target C program with ACSL assertions that express the conditions for overflows. Note that that post pre-dates the Fluorine release and is written in terms of the old options.</p> - <p>There is a C quiz in the middle of this post, lost in the middle of all the reminiscing.</p> -<h2>A history of arithmetic overflows in Frama-C</h2> -<p>From the very beginnings in 2005, until after the first Open Source release in 2008, Frama-C's value analysis was assuming that all arithmetic overflows produced two's complement results. This seemed the right thing to do at the time.</p> -<p>Then an option was introduced to emit alarms on undefined overflows. John Regehr suggested it after testing one of the Open Source versions. The option was turned off by default. If a value analysis user turned the option on, any undefined arithmetic overflow in the program would be detected and reported as a possible error, with the same gravity as dereferencing NULL or accessing an array out of its bounds.</p> -<p>Later, a helpful reminder was added to the value analysis' output: in the default behavior of not emitting alarms, an informative message was emitted instead—if such an overflow was detected—about two's complement being assumed.</p> -<p>There was one last change in the last release, Fluorine. Actually, two changes: the name of the option for emitting alarms on undefined overflows changed, and the default value changed. The setting is now to emit alarms by default, and can be changed to not emitting them, for instance if the target code is destined to be compiled with <code>gcc -fno-strict-overflow -fwrapv</code>, in which case all overflows happening during execution can be expected to produce two's complement results.</p> -<p>One aspect remains unchanged in the above evolution: the discussion only applies to undefined overflows.</p> -<p>The philosophy was always to analyze programs as they were written, and not to force any change of habit on software developers. The initial choice not to warn about overflows was because we knew there were so many of these—most of them intentional—that we would be deluging the user with what would feel like a flood of false positives.</p> -<p>The gradual shift towards more arithmetic overflow awareness is a consequence of the fact that in C, some arithmetic overflows are undefined behavior. Compilers display increasing sophistication when optimizing the defined behaviors to the detriment of the predictability of undefined ones. To make a long story short, the “overflows produce 2's complement results†heuristic was wrong for some programs as compiled by some optimizing compilers.</p> -<p>In keeping with the same philosophy, “overflows†that are defined according to the C99 standard have always been treated by the value analysis plug-in with the semantics mandated by the standard. Those overflows that the standard says must have “implementation-defined†results are treated with the semantics that the overwhelming majority of compilation platforms give them (and it remains possible to model other architectures as the need arises).</p> -<h2>A quiz</h2> -<p>Other static analyzers may also warn for arithmetic overflows, but the philosophy can be different. The philosophy may for instance be that any overflow, regardless of whether it is defined or implementation-defined according to the letter of the standard, might be unintentional and should be brought to the attention of the developer.</p> -<p>In the few examples below, the goal is to predict whether Frama-C's value analysis with its new default setting in Fluorine would emit an alarm for an overflow. For extra credit, a secondary goal is to predict whether another static analyzer that warns for all overflows would warn. We assume a 32-bit <code>int</code> and a 16-bit <code>short</code>, same as (almost) everybody has.</p> -<pre>int a = 50000; -int b = 50000; -int r = a * b; -</pre> -<pre>unsigned int a = 50000; -unsigned int b = 50000; -unsigned int r = a * b; -</pre> -<pre>int a = 50000; -int b = 50000; -unsigned int r = a * b; -</pre> -<pre>short a = 30000; -short b = 30000; -short r = a * b; -</pre> -<pre>unsigned short a = 50000; -unsigned short b = 50000; -unsigned int r = a * b; -</pre> -<h2>Answers</h2> -<pre>int a = 50000; -int b = 50000; -int r = a * b; -</pre> -<p>There is an overflow in this snippet (mathematically, 50000 * 50000 is 2500000000, which does not fit in an <code>int</code>). This overflow is undefined, so the value analysis warns about it.</p> -<pre>unsigned int a = 50000; -unsigned int b = 50000; -unsigned int r = a * b; -</pre> -<p>The multiplication is an <code>unsigned int</code> multiplication, and when the mathematical result of unsigned operations is out of range, the C99 standard mandates that overflows wrap around. Technically, the C99 standard says “A computation involving unsigned operands can never overflow, …†(6.2.5:9) but we are using the word “overflow†with the same meaning as everyone outside the C standardization committee <a href="http://en.wikipedia.org/wiki/Integer_overflow#Origin">including Wikipedia editors</a>.</p> -<p>To sum up in the C99 standard overflows in signed arithmetic are undefined and there are no overflows in unsigned arithmetic (meaning that unsigned overflows wrap around).</p> -<pre>int a = 50000; -int b = 50000; -unsigned int r = a * b; -</pre> -<p>The multiplication is again a signed multiplication. It does not matter that the result is destined to an <code>unsigned int</code> variable because in C types are inferred bottom-up. So the value analysis warns about an undefined overflow in the multiplication here.</p> -<pre>short a = 30000; -short b = 30000; -short r = a * b; -</pre> -<p>There is no overflow here in the multiplication because the last line behaves as <code>short r = (short) ((int) a * (int) b);</code>. The justification for this behavior can be found in clause 6.3.1 of the C99 standard about conversions and promotions (the general idea is that arithmetic never operates on types smaller than <code>int</code> or <code>unsigned int</code>. Smaller types are implicitly promoted before arithmetic takes place). -The product 900000000 does fit in the type <code>int</code> of the multiplication. But then there is a conversion when the <code>int</code> result is assigned to the <code>short</code> variable <code>r</code>. This conversion is implementation-defined so the value analysis does not warn about it but another static analyzer may choose to warn about this conversion.</p> -<pre>unsigned short a = 50000; -unsigned short b = 50000; -unsigned int r = a * b; -</pre> -<p>Perhaps contrary to expectations there is an undefined overflow in the multiplication <code>a * b</code> in this example. Right in the middle of the aforementioned 6.3.1 clause in the C99 standard on the subject of the promotion of operands with smaller types than <code>int</code> the following sentence can be found:</p> -<blockquote><p>If an <code>int</code> can represent all values of the original type the value is converted to an <code>int</code>; otherwise it is converted to an <code>unsigned int</code>.</p> -</blockquote> -<p>All values of a 16-bit <code>unsigned short</code> fit a 32-bit <code>int</code> so the third line is interpreted as <code>unsigned int r = (unsigned int) ((int) a * (int) b);</code>.</p> -<p>Incidentally things would be completely different in this last example if <code>int</code> and <code>short</code> were the same size say if <code>int</code> was 16-bit. In this case the third line would be equivalent to <code>unsigned int r = (unsigned int) a * (unsigned int) b;</code> and would only contain an unsigned innocuous overflow.</p> -<h2>Wrapping up</h2> -<p>In Fluorine the option to activate or deactivate the emission of these undefined arithmetic overflow alarms is called <code>-warn-signed-overflow</code> (the opposite version for no alarms being <code>-no-warn-signed-overflow</code>). I felt that providing this piece of information earlier would have rendered the quiz too easy.</p> <p>Although Frama-C's value analysis adheres to the semantics of C and only warns for undefined overflows it is possible to use Frama-C to check for the other kinds of overflows by <a href="/index.php?post/2012/02/04/Using-Rte-and-Value-to-detect-overflows">using another plug-in Rte</a> to automatically annotate the target C program with ACSL assertions that express the conditions for overflows. Note that that post pre-dates the Fluorine release and is written in terms of the old options.</p> {% endraw %} diff --git a/_posts/2013-07-15-More-on-the-precise-analysis-of-C-programs-for-FLT_EVAL_METHOD--2.html b/_posts/2013-07-15-More-on-the-precise-analysis-of-C-programs-for-FLT_EVAL_METHOD--2.html index b5c12ba8b09ae408e53b5b7cfc8f732b54aa4fc6..06468209becb5aeeb02064aa90d104b9d8461819 100644 --- a/_posts/2013-07-15-More-on-the-precise-analysis-of-C-programs-for-FLT_EVAL_METHOD--2.html +++ b/_posts/2013-07-15-More-on-the-precise-analysis-of-C-programs-for-FLT_EVAL_METHOD--2.html @@ -182,179 +182,5 @@ r1=0 r2=1 r3=0 r4=1 r5=1 r6=1 r7=1 <p>In conclusion it would be possible and only quite a lot of hard work to make a precise static analyzer for programs destined to be compiled to x87 instructions by a modern GCC. But for most other compilers even including recent ones it is simply impossible: the compiler gives floating-point operations a meaning that only it knows.</p> <p>This is the sort of problem we tackled in the <a href="http://hisseo.saclay.inria.fr">Hisseo project</a> mentioned last time. One of the solutions we researched was “Just do not make a <strong>precise</strong> static analyzer†and another was “Just analyze the generated assembly code where the meaning of floating-point operations has been fixedâ€. A couple of years later the third solution “Just use a proper compiler†is looking better and better. It could even be a <a href="http://compcert.inria.fr">certified one</a> although it does not have to. Both Clang and GCC when targeting the SSE2 instruction set give perfect FLT_EVAL_METHOD==0 results. We should all enjoy this period of temporary sanity until x86-64 processors all sport a <a href="http://en.wikipedia.org/wiki/FMA_instruction_set">fused-multiply-add instruction</a>.</p> <blockquote><p>Two things I should point out as this conclusion's conclusion. First with the introduction of SSE2 the IA-32 platform (and its x86-64 cousin) has gone from the worst platform still in existence for predictable floating-point results to the best. It has correctly rounded operations for the standard single-precision and double-precision formats and it retains hardware support for an often convenient extended precision format. Second the fused-multiply-add instruction is a great addition to the instruction set and I for one cannot wait until I get my paws on a processor that supports it but it is going to be misused by compilers to compile source-level multiplications and additions. Compilers have not become wiser. The SSE2 instruction set has only made it more costly for them to do the wrong thing than to do the right one. They will break predictability again as soon as the opportunity comes and the opportunity is already in Intel and AMD's product pipelines.</p> -</blockquote>" <h2>Introduction</h2> -<p>It started innocently enough. My colleagues were talking of supporting target compilers with excess floating-point precision. -<a href="/index.php?post/2013/07/06/On-the-precise-analysis-of-C-programs-for-FLT_EVAL_METHOD-2">We saw</a> that if analyzing programs destined to be compiled with strict IEEE 754 compilers was a lovely Spring day at the beach analyzing for compilers that allow excess precision was Normandy in June 1944. But we had not seen anything yet.</p> -<h2>The notion of compile-time computation depends on the optimization level</h2> -<p>One first obvious problem was that of constant expressions that were evaluated at compile-time following rules that differed from run-time ones. -And who is to say what is evaluated at compile-time and at run-time? Why it even depends for one same compiler on the optimization level:</p> -<pre>#include <stdio.h> -int r1 r2; -double ten = 10.0; -int main(int c char **v) -{ - ten = 10.0; - r1 = 0.1 == (1.0 / ten); - r2 = 0.1 == (1.0 / 10.0); - printf("r1=%d r2=%d" r1 r2); -} -</pre> -<p>Note how compared to last time we make the vicious one-line change of assigning variable <code>ten</code> again inside function <code>main()</code>.</p> -<pre>$ gcc -v -Target: x86_64-linux-gnu -… -gcc version 4.4.3 (Ubuntu 4.4.3-4ubuntu5.1) -$ gcc -mno-sse2 -mfpmath=387 -std=c99 -O2 s.c && ./a.out -r1=1 r2=1 -$ gcc -mno-sse2 -mfpmath=387 -std=c99 s.c && ./a.out -r1=0 r2=1 -</pre> -<p>So the problem is not just that the static analyzer must be able to recognize the computations that are done at compile-time. A precise static analyzer that went this path would in addition have to model each of the tens of optimization flags of the target compiler and their effects on the definition of constant expression.</p> -<p>Fortunately for us after <a href="http://gcc.gnu.org/bugzilla/show_bug.cgi?id=323">many varied complaints</a> from GCC users Joseph S. Myers decided that 387 floating-point math in GCC was at least going to be <a href="http://gcc.gnu.org/ml/gcc-patches/2008-11/msg00105.html">predictable</a>. That would not solve all the issues that had been marked as duplicates of the infamous bug 323 over its lifetime but it would answer the valid ones.</p> -<h2>A ray of hope</h2> -<p>Joseph S. Myers provided a reasonable interpretation of the effects of -FLT_EVAL_METHOD in the C99 standard. The comparatively old compiler -we used in the previous post and in the first section of this one does not contain the patch from that -discussion but recent compilers do. The most recent GCC I have available is -SVN snapshot 172652 from 2011. It includes the patch. With this version of -GCC we compile and execute the test program below.</p> -<pre>#include <stdio.h> -int r1 r2 r3 r4 r5 r6 r7; -double ten = 10.0; -int main(int c char **v) -{ - r1 = 0.1 == (1.0 / ten); - r2 = 0.1 == (1.0 / 10.0); - r3 = 0.1 == (double) (1.0 / ten); - r4 = 0.1 == (double) (1.0 / 10.0); - ten = 10.0; - r5 = 0.1 == (1.0 / ten); - r6 = 0.1 == (double) (1.0 / ten); - r7 = ((double) 0.1) == (1.0 / 10.0); - printf("r1=%d r2=%d r3=%d r4=%d r5=%d r6=%d r7=%d" r1 r2 r3 r4 r5 r6 r7); -} -</pre> -<p>We obtain the following results different from the results of the earlier -version of GCC but independent of the optimization level and understandable -(all computations are done with FLT_EVAL_METHOD==2 semantics):</p> -<pre>$ ./gcc-172652/bin/gcc -mno-sse2 -mfpmath=387 -std=c99 t.c && ./a.out -r1=1 r2=1 r3=0 r4=0 r5=1 r6=0 r7=0 -</pre> -<p>As per the C99 standard the choice was made to give the literal <code>0.1</code> the value of <code>0.1L</code>. I am happy to report that this simple explanation for the values of <code>r2</code> and <code>r7</code> can be inferred directly from the assembly code. Indeed the corresponding constant is declared in assembly as:</p> -<pre>.LC1: - .long 3435973837 - .long 3435973836 - .long 16379 - .long 0 -</pre> -<p><strong>Quiz:</strong> why is it obvious in the above assembly code for a <code>long double</code> constant that the compiler used the <code>long double</code> approximation for <code>0.1</code> instead of the <code>double</code> one?</p> -<p>As described the semantics of C programs compiled with FLT_EVAL_METHOD==2 are just as -deterministic as if they were compiled with FLT_EVAL_METHOD==0. They -give different results from the latter but always the same -ones regardless of optimization level interference from unrelated -statements and even regardless of the particular compiler generating -code with FLT_EVAL_METHOD==2. In the discussion that followed between -Joseph Myers and Ian Lance Taylor this is called “predictable semantics†-and it is a boon to anyone who whishes to tell what a program ought -to do when executed (including but not limited to precise static analyzers).</p> -<h2>Implementation detail: source-to-source transformation or architecture option?</h2> -<p>Now that at least one C compiler can be said to have predictable behavior -with respect to excess precision the question arises of supporting -FLT_EVAL_METHOD==2 in Frama-C. This could be one more of the architecture-dependent parameters such as the size of type <code>int</code> and the endianness.</p> -<p>The rules are subtle however and rather than letting each Frama-C plug-in implement them and get them slightly wrong it would be less error-prone to implement -these rules once and for all as a source-to-source translation from a program -with FLT_EVAL_METHOD==2 semantics to a program that when compiled or -analyzed with FLT_EVAL_METHOD==0 semantics computes the same thing as the -first one.</p> -<h3>The destination of the transformation can be a Frama-C AST</h3> -<p>A translated program giving when compiled with strict IEEE 754 semantics -the FLT_EVAL_METHOD==2 semantics of an existing program -can be represented as an AST in Frama-C. Here is how the translation would work on an example:</p> -<pre>double interpol(double u1 double u2 double u3) -{ - return u2 * (1.0 - u1) + u1 * u3; -} -</pre> -<p>Function <code>interpol()</code> above can be compiled with either <code>FLT_EVAL_METHOD==0</code> or -with <code>FLT_EVAL_METHOD==2</code>. In the second case it actually appears to have slightly better properties than in the first case but the differences are minor.</p> -<p>A source-to-source translation could transform the function into that below:</p> -<pre>double interpol_80(double u1 double u2 double u3) -{ - return u2 * (1.0L - (long double)u1) + u1 * (long double)u3; -} -</pre> -<p>This transformed function <code>interpol_80()</code> when compiled or analyzed with <code>FLT_EVAL_METHOD==0</code> behaves exactly identical to function <code>interpol()</code> compiled or analyzed -with <code>FLT_EVAL_METHOD==2</code>. I made an effort here to insert only the minimum number of explicit conversions but a Frama-C transformation plug-in would not need to be so punctilious.</p> -<h3>The source of the transformation cannot be a Frama-C AST</h3> -<p>There is however a problem with the implementation of the transformation as a traditional Frama-C transformation plug-in. -It turns out that the translation cannot use the normalized Frama-C AST as source. Indeed if we use a Frama-C command to print the AST of the previous example in textual form:</p> -<pre>~ $ frama-c -print -kernel-debug 1 t.c -… -/* Generated by Frama-C */ -int main(int c char **v) -{ - /* Locals: __retres */ - int __retres; - /* sid:18 */ - r1 = 0.1 == 1.0 / ten; - /* sid:19 */ - r2 = 0.1 == 1.0 / 10.0; - /* sid:20 */ - r3 = 0.1 == 1.0 / ten; - /* sid:21 */ - r4 = 0.1 == 1.0 / 10.0; - … -} -</pre> -<p>Explicit casts to a type that an expression already has such as the casts to <code>double</code> in the assignments to variables <code>r3</code> and <code>r4</code> are erased by the Frama-C front-end as part of its normalization. For us this will not do: these casts although they convert a <code>double</code> expression to <code>double</code> change the meaning of the program as shown by the differences between the values of <code>r1</code> and <code>r3</code> and respectively or <code>r2</code> and <code>r4</code> when one executes our example.</p> -<p>This setback would not be insurmountable but it means complications. It also implies that FLT_EVAL_METHOD==2 semantics cannot be implemented by individual plug-ins which looked like a possible alternative.</p> -<p>To conclude this section on a positive note if the goal is to analyze a C program destined to be compiled to the -thirty-year old 8087 instructions with a recent GCC compiler we can -build the version of Frama-C that will produce results precise to the last bit. -The amount of work is not inconsiderable but it is possible.</p> -<h2>But wait!</h2> -<p>But what about a recent version of Clang? Let us see using the -same C program as previously:</p> -<pre>#include <stdio.h> -int r1 r2 r3 r4 r5 r6 r7; -double ten = 10.0; -int main(int c char **v) -{ - r1 = 0.1 == (1.0 / ten); - r2 = 0.1 == (1.0 / 10.0); - r3 = 0.1 == (double) (1.0 / ten); - r4 = 0.1 == (double) (1.0 / 10.0); - ten = 10.0; - r5 = 0.1 == (1.0 / ten); - r6 = 0.1 == (double) (1.0 / ten); - r7 = ((double) 0.1) == (1.0 / 10.0); - printf("r1=%d r2=%d r3=%d r4=%d r5=%d r6=%d r7=%d" r1 r2 r3 r4 r5 r6 r7); -} -</pre> -<pre>$ clang -v -Apple LLVM version 4.2 (clang-425.0.24) (based on LLVM 3.2svn) -$ clang -mno-sse2 -std=c99 t.c && ./a.out -r1=0 r2=1 r3=0 r4=1 r5=1 r6=0 r7=1 -</pre> -<p>Oh no! Everything is to be done again… Some expressions are evaluated -as compile-time with different results than the run-time ones as shown -by the difference between <code>r1</code> and <code>r2</code>. The explicit cast to <code>double</code> -does not seem to have an effect for <code>r3</code> and <code>r4</code> as compared to <code>r1</code> and -<code>r2</code>. This is different from Joseph Myers's interpretation but if it is because floating-point expressions are always converted to their nominal types before being compared it may be a good astonishment-lowering move. The value of <code>r5</code> differs from that of <code>r1</code> -pointing to a non-obvious demarcation line between compile-time -evaluation and run-time evaluation. And the values of <code>r5</code> and <code>r6</code> differ -meaning that -our interpretation “explicit casts to <code>double</code> have no effects†-based on the comparison of the values of <code>r1</code> and <code>r3</code> on the one hand -and r2 and r4 on the other hand is wrong or that some other -compilation pass can interfere.</p> -<p>What a mess! There is no way a precise static analyzer can be made for this recent version of Clang (with these unfashionable options). Plus the results depend on optimizations:</p> -<pre>$ clang -mno-sse2 -std=c99 -O2 t.c && ./a.out -r1=0 r2=1 r3=0 r4=1 r5=1 r6=1 r7=1 -</pre> -<h2>FLT_EVAL_METHOD is not ready for precise static analysis</h2> -<p>In conclusion it would be possible and only quite a lot of hard work to make a precise static analyzer for programs destined to be compiled to x87 instructions by a modern GCC. But for most other compilers even including recent ones it is simply impossible: the compiler gives floating-point operations a meaning that only it knows.</p> -<p>This is the sort of problem we tackled in the <a href="http://hisseo.saclay.inria.fr">Hisseo project</a> mentioned last time. One of the solutions we researched was “Just do not make a <strong>precise</strong> static analyzer†and another was “Just analyze the generated assembly code where the meaning of floating-point operations has been fixedâ€. A couple of years later the third solution “Just use a proper compiler†is looking better and better. It could even be a <a href="http://compcert.inria.fr">certified one</a> although it does not have to. Both Clang and GCC when targeting the SSE2 instruction set give perfect FLT_EVAL_METHOD==0 results. We should all enjoy this period of temporary sanity until x86-64 processors all sport a <a href="http://en.wikipedia.org/wiki/FMA_instruction_set">fused-multiply-add instruction</a>.</p> -<blockquote><p>Two things I should point out as this conclusion's conclusion. First with the introduction of SSE2 the IA-32 platform (and its x86-64 cousin) has gone from the worst platform still in existence for predictable floating-point results to the best. It has correctly rounded operations for the standard single-precision and double-precision formats and it retains hardware support for an often convenient extended precision format. Second the fused-multiply-add instruction is a great addition to the instruction set and I for one cannot wait until I get my paws on a processor that supports it but it is going to be misused by compilers to compile source-level multiplications and additions. Compilers have not become wiser. The SSE2 instruction set has only made it more costly for them to do the wrong thing than to do the right one. They will break predictability again as soon as the opportunity comes and the opportunity is already in Intel and AMD's product pipelines.</p> -</blockquote>" +</blockquote> {% endraw %} diff --git a/_posts/2013-07-19-The-word-binade-now-has-its-Wikipedia-page.html b/_posts/2013-07-19-The-word-binade-now-has-its-Wikipedia-page.html index 5479e5267a9d02443bc3c1ce9f19620f9a5c123b..eeaff81ca7c580de424bc3fbe2fcb4c393e7de52 100644 --- a/_posts/2013-07-19-The-word-binade-now-has-its-Wikipedia-page.html +++ b/_posts/2013-07-19-The-word-binade-now-has-its-Wikipedia-page.html @@ -9,7 +9,5 @@ summary: --- {% raw %} <p>… but that's only because I <a href="http://en.wikipedia.org/wiki/Binade">created it</a>.</p> -<p>If you are more familiar than me with Wikipedia etiquette feel free to adjust edit or delete this page. Also although a Wikipedia account is necessary to create a page I think it is not required for editing so you can add to the story too (but if you do not have an account you are perhaps no more familiar than me with Wikipedia etiquette).</p> - <p>… but that's only because I <a href="http://en.wikipedia.org/wiki/Binade">created it</a>.</p> <p>If you are more familiar than me with Wikipedia etiquette feel free to adjust edit or delete this page. Also although a Wikipedia account is necessary to create a page I think it is not required for editing so you can add to the story too (but if you do not have an account you are perhaps no more familiar than me with Wikipedia etiquette).</p> {% endraw %} diff --git a/_posts/2013-07-31-From-Pascal-strings-to-Python-tuples.html b/_posts/2013-07-31-From-Pascal-strings-to-Python-tuples.html index 7785f9cb0499ad727f32e2c531b5a08d5eab1c23..7ad91518e5f6997a8b2c6481f0061850783b93cb 100644 --- a/_posts/2013-07-31-From-Pascal-strings-to-Python-tuples.html +++ b/_posts/2013-07-31-From-Pascal-strings-to-Python-tuples.html @@ -75,73 +75,5 @@ int main() { … </pre> <h2>Conclusion</h2> -<p>I have encouraged my colleague Bernard to report the above as a bug in Python. This kind of bug report is usually ignored because it denounces idioms that programmers have used for a long time and that they think they understand. Just remember: if you think you can predict what the program in the second quiz does you should be able to predict what the program in the first quiz does (or explain what is different about it).</p> - <h2>Quiz time</h2> -<p>What does the program below do?</p> -<pre>#include <stdio.h> -int main(){ - struct { - int t[4]; - int u; - } v; - v.u = 3; - v.t[4] = 4; - printf(\v.u=%d" v.u); - return 0; -} -</pre> -<p>Two answers are “it prints <code>v.u=4</code>†and “it prints <code>v.u=3</code>â€:</p> -<pre>$ gcc t.c && ./a.out -v.u=4 -$ gcc -O2 t.c && ./a.out -v.u=3 -</pre> -<p>The correct answer is of course that the program invokes undefined behavior. It is not that we are using at any time an lvalue of the wrong type to access memory breaking the so-called “strict aliasing rulesâ€. -It is not that <code>v.t+4</code> is outside of object <code>v</code>. The problem is that <code>v.t+4</code> is outside object <code>v.t</code>. So GCC does what it pleases and when compiling with <code>-O2</code> optimizes brutally:</p> -<pre>$ gcc -S -O2 t.c && cat t.s -.LC0: - .string "v.u=%d" -… - movl $3 %edx - movl $.LC0 %esi - movl $1 %edi - xorl %eax %eax - call __printf_chk -</pre> -<p>Frama-C's value analysis warns for the above program:</p> -<pre>$ frama-c -val t.c -t.c:9:[kernel] warning: accessing out of bounds index {4}. assert 4 < 4; -</pre> -<p>In general accessing <code>t[i]</code> when <code>t</code> is an array of size <code>4</code> is only valid when <code>i < 4</code> but here the index is hard-coded as <code>4</code> so line 9 is only valid when <code>4 < 4</code>. That is never: all executions that reach line 9 encounter undefined behavior there.</p> -<h2>Second quiz same as the first quiz</h2> -<p>What does the program below do?</p> -<pre>#include "stdlib.h" -typedef struct{ - int tab[1]; -} ts; -int main() { - ts *q = malloc(5*sizeof(int)); - q->tab[2]= 5; - return 1; -} -</pre> -<p>If you guessed “invoke undefined behavior†well done!</p> -<p>The program above was shown to me by facetious colleague Bernard Botella who is hard at work analyzing Python 2.7.4's runtime in the context of a project named SafePython. The snippet above is his reduced version of a larger piece of C code he found there. The issue Bernard was having started with the type definition below and I will let you guess the rest:</p> -<pre>typedef struct { - PyObject_VAR_HEAD - PyObject *ob_item[1]; - /* ob_item contains space for 'ob_size' elements. - * Items must normally not be NULL except during construction when - * the tuple is not yet visible outside the function that builds it. - */ -} PyTupleObject; -</pre> -<p>In C90 the “array of size 1 as last member of a struct†was a common idiom for implementing things like Pascal strings. And of course it is just as valid for variable-length tuples. The problem is that this is not 1990 any more: compilers now use undefined behavior as an excuse to optimize aggressively and the idiom is no longer valid at all for either tuples or Pascal strings. On the plus side in the C99 standard we got “incomplete types†a safe way to implement tuples and Pascal strings:</p> -<pre>typedef struct { - PyObject_VAR_HEAD - PyObject *ob_item[]; -… -</pre> -<h2>Conclusion</h2> <p>I have encouraged my colleague Bernard to report the above as a bug in Python. This kind of bug report is usually ignored because it denounces idioms that programmers have used for a long time and that they think they understand. Just remember: if you think you can predict what the program in the second quiz does you should be able to predict what the program in the first quiz does (or explain what is different about it).</p> {% endraw %} diff --git a/_posts/2013-08-05-Exact-case-management-in-floating-point-library-functions.html b/_posts/2013-08-05-Exact-case-management-in-floating-point-library-functions.html index ce7a34bb59e804970a5dadeb6d6e048962e28591..09057c5b658995c6cb1f5516cc760345060a385c 100644 --- a/_posts/2013-08-05-Exact-case-management-in-floating-point-library-functions.html +++ b/_posts/2013-08-05-Exact-case-management-in-floating-point-library-functions.html @@ -13,11 +13,5 @@ summary: </blockquote> <p>The phrase “exact case†refers to inputs that need to be treated specially because no number of “Ziv iterations†at increasing precisions can ever resolve which way the rounding should go.</p> <p>Quiz: Isn't an exact case an exact case independently of the rounding mode? How can exact cases vary with the rounding mode?</p> -<p>If you can answer the above quiz without having to <a href="https://en.wikipedia.org/wiki/Rubber_duck_debugging">rubber duck</a> through the entire question on an internet forum you have me beat.</p> - <p>The <a href="http://lipforge.ens-lyon.fr/frs/download.php/153/crlibm-1.0beta3.pdf">documentation</a> of the correctly-rounded <a href="http://lipforge.ens-lyon.fr/www/crlibm/">CRlibm</a> floating-point library states for the difficult <code>pow()</code> function (p. 159):</p> -<blockquote><p>Directed rounding requires additional work in particular in subnormal handling and in exact case management. There are more exact cases in directed rounding modes therefore the performance should also be inferior.</p> -</blockquote> -<p>The phrase “exact case†refers to inputs that need to be treated specially because no number of “Ziv iterations†at increasing precisions can ever resolve which way the rounding should go.</p> -<p>Quiz: Isn't an exact case an exact case independently of the rounding mode? How can exact cases vary with the rounding mode?</p> <p>If you can answer the above quiz without having to <a href="https://en.wikipedia.org/wiki/Rubber_duck_debugging">rubber duck</a> through the entire question on an internet forum you have me beat.</p> {% endraw %} diff --git a/_posts/2013-08-24-Function-pointers-in-C.html b/_posts/2013-08-24-Function-pointers-in-C.html index a78efdbbdbcb4f3d2d0067e092ffafdc0a5f2b92..ca1b6e432f01d088a6d8dde38b072b81727e7e8e 100644 --- a/_posts/2013-08-24-Function-pointers-in-C.html +++ b/_posts/2013-08-24-Function-pointers-in-C.html @@ -86,84 +86,5 @@ t.c:3:[value] warning: Function pointer and pointed function 'fun' have incompa <h2>Conclusion</h2> <p>There is almost nothing you can do in C with a function pointer. The feature is still very useful and instills a bit of genericity in an otherwise decidedly low-level language.</p> <p>Function pointers are not often used in the standard library considering: <code>qsort()</code> is with <code>pthread_create()</code> another of the few functions that requires a function pointer. Like it it is often misused: it has its own <a href="http://c-faq.com/lib/qsort2.html">entry in the C FAQ</a>.</p> -<p>Jens Gustedt provided advice in the writing of this post.</p> - <p>This post contains a complete list of everything a C program can do with a function pointer, for a rather reasonable definition of “doâ€. Examples of things not to do with a function pointer are also provided. That list, in contrast, is in no way exhaustive.</p> -<h2>What a C program can do with a function pointer</h2> -<h3>Convert it to a different <em>function</em> pointer type</h3> -<p>A function pointer can be converted to a different function pointer type. The C99 standard's clause 6.3.2.3:8 starts:</p> -<p>“A pointer to a function of one type may be converted to a pointer to a function of another type and back again; the result shall compare equal to the original pointer.â€</p> -<h3>Call the pointed function <em>with the original type</em></h3> -<p>Clause 6.3.2.3:8 continues:</p> -<p>“If a converted pointer is used to call a function whose type is not compatible with the pointed-to type, the behavior is undefined.â€</p> -<p>Alright, so the above title is slightly sensationalistic: the pointed function can be called with a <em>compatible</em> type. After <code>typedef int t;</code>, the types <code>t</code> and <code>int</code> are compatible, and so are <code>t (*)(t)</code> and <code>int (*)(int)</code>, the types of functions taking a <code>t</code> and returning a <code>t</code> and of functions taking an <code>int</code> and returning an <code>int</code>, respectively.</p> -<h3>There is no third thing a C program can do with a function pointer</h3> -<p>Seriously. The C99 standard has <code>uintptr_t</code>, a recommended integer type to convert data pointers to, but there is not even an equivalent integer type to store function pointers.</p> -<h2>What a C program cannot do with a function pointer</h2> -<h3>Convert it to an ordinary pointer</h3> -<p>Function pointers should not be converted to <code>char *</code> or <code>void *</code>, both of which are intended for pointers to data (“objects†in the vocabulary of the C standard). Historically, there has been plenty of reasons why pointers to functions and pointers to data might not have the same representation. With 64-bit architectures, the same reasons continue to apply nowadays.</p> -<h3>Call the pointed function with an incompatible type</h3> -<p>Even if you know that type <code>float</code> is 32-bit, the same as <code>int</code> on your platform, the following is undefined:</p> -<pre>void f(int x); -int main(){ - void (*p)(float) = f; - (*p)(3); -} -</pre> -<p>The line <code>void (*p)(float) = f;</code>, which defines a variable <code>p</code> of type “pointer to function that takes a floatâ€, and initializes it with the conversion of <code>f</code>, is legal as per 6.3.2.3:8. However, the following statement, <code>(*p)(3);</code> is actually equivalent to <code>(*p)((float)3);</code>, because the type of <code>p</code> is used to decide how to convert the argument prior to the call, and it is undefined because <code>p</code> points to a function that requires an <code>int</code> as argument.</p> -<p>Even if you know that the types <code>int</code> and <code>long</code> are both 32-bit and virtually indistinguishable on your platform (you may be using an ILP32 or an IL32P64 platform), the types <code>int</code> and <code>long</code> are not compatible. Josh Haberman has written <a href="http://blog.reverberate.org/2013_03_01_archive.html">a nice essay on this precise topic</a>.</p> -<p>Consider the program:</p> -<pre>void f(int x); -int main(){ - void (*p)(long) = f; - (*p)(3); -} -</pre> -<p>This time the statement is equivalent to <code>(*p)((long)3);</code> and it is undefined even if <code>long</code> and <code>int</code> are both 32-bit (substitute <code>long</code> and <code>long long</code> if you have a typical I32LP64 platform).</p> -<p>Lastly the example that prompted this post was in a bit of Open-Source code the creation of a new execution thread. The example can be simplified into:</p> -<pre>void apply(void (*f)(void*) void *arg) -{ - f(arg); -} -void fun(int *x){ - // work work - *x = 1; -} -int data; -int main(){ - apply(fun &data); -} -</pre> -<p>The undefined behavior is not visible: it takes place inside function <code>apply()</code> which is a standard library function (it was <code>pthread_create()</code> in the original example). But it is there: the function <code>apply()</code> expects a pointer to function that takes a <code>void*</code> and applies it as such. The types <code>int *</code> and <code>void *</code> are not compatible and neither are the types of functions that take these arguments.</p> -<p>Note that <code>gcc -Wall</code> warns about the conversion when passing <code>fun</code> to <code>apply()</code>:</p> -<pre>t.c:11: warning: passing argument 1 of ‘apply’ from incompatible pointer type -</pre> -<p>Fixing this warning with a cast to <code>void (*)(void*)</code> is a programmer mistake. The bug indicated by the warning is that there is a risk that <code>fun()</code> will be applied with the wrong type and this warning is justified here since <code>fun()</code> will be applied with the wrong type inside function <code>apply()</code>. If we “fix†the program this way:</p> -<pre>$ tail -3 t.c -int main(){ - apply((void (*)(void*))fun &data); -} -$ gcc -std=c99 -Wall t.c -$ -</pre> -<p>The explicit cast to <code>(void (*)(void*)</code> silences the compiler but the bug is still in the same place in function <code>apply()</code>.</p> -<p>Fortunately <code>gcc -std=c99 -Wall</code> is not the only static analyzer we can rely on. Frama-C's value analysis warns where the problem really is in function <code>apply()</code> and it warns for both the version with implicit conversion and the version with explicit cast:</p> -<pre>$ frama-c -val t.c -… -[value] computing for function apply <- main. - Called from t.c:14. -t.c:3:[value] warning: Function pointer and pointed function 'fun' have incompatible types: - void (void *) vs. void (int *x). assert(function type matches) -</pre> -<p>The correct way to use function <code>apply()</code> without changing it is to make a function with the correct type for it and to pass that function to <code>apply()</code>:</p> -<pre>void stub(void *x){ - fun(x); -} -… - apply(stub &data); -</pre> -<p>Note that in the above <code>x</code> is implicitly converted when passed to function <code>fun()</code> the same way that <code>&data</code> is implicitly converted to <code>void*</code> when passed to <code>apply()</code>.</p> -<h2>Conclusion</h2> -<p>There is almost nothing you can do in C with a function pointer. The feature is still very useful and instills a bit of genericity in an otherwise decidedly low-level language.</p> -<p>Function pointers are not often used in the standard library considering: <code>qsort()</code> is with <code>pthread_create()</code> another of the few functions that requires a function pointer. Like it it is often misused: it has its own <a href="http://c-faq.com/lib/qsort2.html">entry in the C FAQ</a>.</p> <p>Jens Gustedt provided advice in the writing of this post.</p> {% endraw %} diff --git a/_posts/2013-09-02-The-case-for-formal-verification-of-existing-software.html b/_posts/2013-09-02-The-case-for-formal-verification-of-existing-software.html index aa8362c87ccb188483d30bd4ff2d3ce746b3ce6a..ddee8072907ed9b3d8dd27b52768a01ab84fdcd9 100644 --- a/_posts/2013-09-02-The-case-for-formal-verification-of-existing-software.html +++ b/_posts/2013-09-02-The-case-for-formal-verification-of-existing-software.html @@ -16,14 +16,5 @@ summary: <p>The bonus is that the formally verified PolarSSL can be compiled and embedded with all the same compilers and into all the same firmwares as the earlier non-verified version. It is the same as the non-verified version except maybe for a couple of bugfixes and the confidence that for an identified usage pattern no more undefined behavior bugs will ever need to be fixed.</p> <p>All in all the formal verification of existing code despite its differences from its “from scratch†counterpart has too become a force to be reckoned with.</p> <p>(*) translation: I use Frama-C option <code>-deps</code> and I compare the result to what I expected</p> -<p>Acknowledgement: I got the link to Perry E. Metzger's post through Toby Murray.</p> - <p>Perry E. Metzger <a href="http://permalink.gmane.org/gmane.comp.encryption.general/14818">takes a look at formal verification</a>. This is good stuff; there is a lot to agree with here.</p> -<p>However agreeing with Perry's post alone would not make a very interesting counterpoint. If agreeing was the only thing I intended to do I might even not have written this post. Instead I intended to add and I apologize in advance for the predictability of my views that while creating formally verified software from scratch is useful verifying existing software is useful too.</p> -<p>Yes formally verified software written from scratch can now be large enough in scope to be a compiler or a microkernel but when verifying existing software we can tackle the problem from the other end: we can pick any useful software component and verify that. We can pick a software component so useful that it is already <em>used</em> by millions. If we succeed in verifying it we have put formally verified software in the hands of millions of satisfied users. Transparently.</p> -<p>Take the example of the <a href="https://polarssl.org">SSL implementation</a> I am taking a couple of weeks to finish massaging through Frama-C. It is not as wide in scope as Quark seL4 or CompCert. Neither am I aiming for the same kind of functional correctness as these projects are: I am only verifying the absence of undefined behaviors in the component and verifying the functional dependencies of the cryptographic primitives(*).</p> -<p>But PolarSSL is useful. Plus by its very nature it is exposed to security attacks (SSL is the protocol behind HTTPS). And the former three examples are full-blown research projects in contrast to my single person.month effort.</p> -<p>The bonus is that the formally verified PolarSSL can be compiled and embedded with all the same compilers and into all the same firmwares as the earlier non-verified version. It is the same as the non-verified version except maybe for a couple of bugfixes and the confidence that for an identified usage pattern no more undefined behavior bugs will ever need to be fixed.</p> -<p>All in all the formal verification of existing code despite its differences from its “from scratch†counterpart has too become a force to be reckoned with.</p> -<p>(*) translation: I use Frama-C option <code>-deps</code> and I compare the result to what I expected</p> <p>Acknowledgement: I got the link to Perry E. Metzger's post through Toby Murray.</p> {% endraw %} diff --git a/_posts/2013-09-25-The-problem-with-differential-testing-is-that-at-least-one-of-the-compilers-must-get-it-right.html b/_posts/2013-09-25-The-problem-with-differential-testing-is-that-at-least-one-of-the-compilers-must-get-it-right.html index 3ed5b082b0bd69e6bd4ddd0a76fb65fbb8afdc9a..0bcec34c182214ee863d61aeb6f538cb55c98576 100644 --- a/_posts/2013-09-25-The-problem-with-differential-testing-is-that-at-least-one-of-the-compilers-must-get-it-right.html +++ b/_posts/2013-09-25-The-problem-with-differential-testing-is-that-at-least-one-of-the-compilers-must-get-it-right.html @@ -74,72 +74,5 @@ $ clang -std=c99 -O2 -Wall dr.c && ./a.out ... </pre> <p>And GCC had done the same. Although to be fair the two compilers appear to be using LLVM as back-end so this could be the result of a single bug. But this would remove all the salt of the anecdote so let us hope it isn't.</p> -<p>It is high time that someone used fuzz-testing to debug floating-point arithmetic in compilers. Hopefully one compiler will get it right sometimes and we can work from there.</p> - <p>A long time ago, John Regehr wrote a blog post about <a href="http://blog.regehr.org/archives/558">a 3-3 split vote</a> that occurred while he was finding bugs in C compilers through differential testing. John could have included Frama-C's value analysis in his set of C implementations and then the vote would have been 4-3 for the correct interpretation (Frama-C's value analysis predicts the correct value on the particular C program that was the subject of the post). But self-congratulatory remarks are not the subject of today's post. Non-split votes in differential testing where all compilers get it wrong are.</p> -<h2>A simple program to find double-rounding examples</h2> -<p>The program below looks for examples of harmful double-rounding in floating-point multiplication. Harmful double-rounding occurs when the result of the multiplication of two <code>double</code> operands differs between the double-precision multiplication (the result is rounded directly to what fits the <code>double</code> format) and the extended-double multiplication (the mathematical result of multiplying two <code>double</code> numbers may not be representable exactly even with extended-double precision so it is rounded to extended-double and then rounded again to <code>double</code> which changes the result).</p> -<pre>$ cat dr.c -#include <stdio.h> -#include <stdlib.h> -#include <math.h> -#include <float.h> -#include <limits.h> -int main(){ - printf("%d %a %La" FLT_EVAL_METHOD DBL_MAX LDBL_MAX); - while(1){ - double d1 = ((unsigned long)rand()<<32) + - ((unsigned long)rand()<<16) + rand() ; - double d2 = ((unsigned long)rand()<<32) + - ((unsigned long)rand()<<16) + rand() ; - long double ld1 = d1; - long double ld2 = d2; - if (d1 * d2 != (double)(ld1 * ld2)) - printf("%a*%a=%a but (double)((long double) %a * %a))=%a" - d1 d2 d1*d2 - d1 d2 (double)(ld1 * ld2)); - } -} -</pre> -<p>The program is platform-dependent but if it starts printing something like below then a long list of double-rounding examples should immediately follow:</p> -<pre>0 0x1.fffffffffffffp+1023 0xf.fffffffffffffffp+16380 -</pre> -<h2>Results</h2> -<p>In my case what happened was:</p> -<pre>$ gcc -v -Using built-in specs. -Target: i686-apple-darwin11 -... -gcc version 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2336.11.00) -$ gcc -std=c99 -O2 -Wall dr.c && ./a.out -0 0x1.fffffffffffffp+1023 0xf.fffffffffffffffp+16380 -^C -</pre> -<p>I immediately blamed myself for miscalculating the probability of easily finding such examples getting a conversion wrong or following <code>while (1)</code> with a semicolon. But it turned out I had not done any of those things. I turned to Clang for a second opinion:</p> -<pre>$ clang -v -Apple clang version 4.1 (tags/Apple/clang-421.11.66) (based on LLVM 3.1svn) -Target: x86_64-apple-darwin12.4.0 -Thread model: posix -$ clang -std=c99 -O2 -Wall dr.c && ./a.out -0 0x1.fffffffffffffp+1023 0xf.fffffffffffffffp+16380 -^C -</pre> -<h2>Conclusion</h2> -<p>It became clear what had happened when looking at the assembly code:</p> -<pre>$ clang -std=c99 -O2 -Wall -S dr.c && cat dr.s -... - mulsd %xmm4 %xmm5 - ucomisd %xmm5 %xmm5 - jnp LBB0_1 -... -</pre> -<p>Clang had compiled the test for deciding whether to call <code>printf()</code> into <code>if (xmm5 != xmm5)</code> for some register <code>xmm5</code>.</p> -<pre>$ gcc -std=c99 -O2 -Wall -S dr.c && cat dr.s -... - mulsd %xmm1 %xmm2 - ucomisd %xmm2 %xmm2 - jnp LBB1_1 -... -</pre> -<p>And GCC had done the same. Although to be fair the two compilers appear to be using LLVM as back-end so this could be the result of a single bug. But this would remove all the salt of the anecdote so let us hope it isn't.</p> <p>It is high time that someone used fuzz-testing to debug floating-point arithmetic in compilers. Hopefully one compiler will get it right sometimes and we can work from there.</p> {% endraw %} diff --git a/_posts/2013-10-09-The-overflow-when-converting-from-float-to-integer-is-undefined-behavior.html b/_posts/2013-10-09-The-overflow-when-converting-from-float-to-integer-is-undefined-behavior.html index 03c40e9c66c63cbb57960ab8f7e7c850c81550e6..559292345d56e81cfc5933ab51bc5fff2a8f674d 100644 --- a/_posts/2013-10-09-The-overflow-when-converting-from-float-to-integer-is-undefined-behavior.html +++ b/_posts/2013-10-09-The-overflow-when-converting-from-float-to-integer-is-undefined-behavior.html @@ -142,140 +142,5 @@ int main(int c char **v) <h2>Conclusion</h2> <p>In conclusion the overflow in the conversion from floating-point to integer is rather on the nasty side of C's undefined behavior spectrum. It may appear to behave consistently if the compilation targets an architecture where the underlying assembly instruction(s) saturate. Saturation is the behavior that compilers GCC and Clang implement when they are able to evaluate the conversion at compile-time. In these conditions a lucky programmer may not actually observe anything strange.</p> <p>The idiosyncrasies of other architectures may lead to very different results for overflowing conversions depending on parameters outside the programmer's control (constant propagation for instance is more or less efficient depending on the optimization level and may be difficult to predict as we already <a href="/index.php?post/2013/07/24/More-on-FLT_EVAL_METHOD_2">complained about when discussing Clang targeting the 387 FPU</a>).</p> -<p>Acknowledgements: In addition to Dillon Pariente I discussed this topic with Boris Yakobowski John Regehr Stephen Canon and StackOverflow users tenos Sander De Dycker and Mike Seymour prior to writing this blog post.</p> - <h2>Integer overflows in C</h2> -<p>A <a href="/conversions-and-promotions/fluorine/position/value/2013/07/09/Arithmetic-overflows-in-Fluorine">previous post</a> on this blog was a reminder that in C signed integer arithmetic overflow is undefined behavior. In contrast the behavior of overflows in conversions from integer type to signed integer type is implementation-defined. The C99 standard allows for an implementation-defined signal to be raised but in practice the widespread compilation platforms provide two's complement behavior. And you can trust that they will continue to do so because it's implementation-defined. Compiler makers cannot change their mind willy-nilly as if it was undefined behavior:</p> -<blockquote><p><strong>6.3.1.3</strong> Signed and unsigned integers</p> -<p> -<strong>1</strong> When a value with integer type is converted to another integer type other than <code>_Bool</code> if the value can be represented by the new type it is unchanged.</p> -<p> -<strong>2</strong> Otherwise if the new type is unsigned the value is converted by repeatedly adding or subtracting one more than the maximum value that can be represented in the new type until the value is in the range of the new type.</p> -<p> -<strong>3</strong> Otherwise the new type is signed and the value cannot be represented in it; either the result is implementation-defined or an implementation-defined signal is raised.</p> -</blockquote> -<h2>Floating-point overflows in C</h2> -<p>The C standard does not mandate IEEE 754 floating-point arithmetic. Still in practice modern compilation platforms if they provide floating-point features at all provide either exactly IEEE 754 binary32 and binary64 formats and computations or the same formats and a close approximation of the same computations.</p> -<p>IEEE 754 floating-point defines <code>+inf</code> and <code>-inf</code> values so that any real number can be approximated in the target IEEE 754 format (albeit when it ends up represented as an infinity not precisely). This means that for C compilation platforms that implement IEEE 754 for floating-point the condition “the value can be represented in the new type†is always true. There is no reason to worry of undefined behavior caused by overflow in either floating-point arithmetic or in the conversion of a <code>double</code> to a <code>float</code>.</p> -<p>Or indeed in a constant. Consider GCC's warning here:</p> -<pre>$ cat t.c -#include <stdio.h> -int main() -{ - double big = 0x1.0p5000; - printf("%f" big); -} -$ gcc-172652/bin/gcc -std=c99 -Wall t.c && ./a.out -t.c: In function ‘main’: -t.c:5:3: warning: floating constant exceeds range of ‘double’ [-Woverflow] -inf -</pre> -<p>The number 2^5000 represented in C as <code>0x1.0p5000</code> is totally in the range of <code>double</code> which goes up to <code>inf</code>. Clang similarly warns that “magnitude of floating-point constant too large for type doubleâ€. A proper warning message would be that 2^5000 cannot be represented precisely instead of implying that it cannot be represented at all.</p> -<h2>Floating-point ↔ integer conversion overflows in C</h2> -<p>But enough pedantry contests with compilers. -The range of floating-point representations being what it is we are left with only overflows in conversions from floating-point to integer to consider.</p> -<p>Suspense… (for the reader who did not pay attention to the title)</p> -<p>Overflows in conversions from floating-point to integer are undefined behavior. Clause 6.3.1.4 in the C99 standard make them so:</p> -<blockquote><p><strong>6.3.1.4</strong> Real floating and integer</p> -<p> -<strong>1</strong> When a finite value of real floating type is converted to an integer type other than <code>_Bool</code> the fractional part is discarded (i.e. the value is truncated toward zero). If the value of the integral part cannot be represented by the integer type the behavior is undefined.</p> -</blockquote> -<p>What can happen in practice when a C program invokes this particular flavor of undefined behavior? It is as bad as dereferencing an invalid address mostly harmless like signed integer arithmetic overflow or what? Let us find out.</p> -<p>The following program converts the <code>double</code> representation of 2^31 the smallest positive integer that does not fit a 32-bit <code>int</code> to <code>int</code>.</p> -<pre>int printf(const char * ...); -int main() -{ - int i = 0x1.0p31; - printf("%d" i); -} -</pre> -<p>Frama-C's value analysis warns about undefined behavior in this program:</p> -<pre>$ frama-c -val t.c -warning: overflow in conversion of 0x1.0p31 (2147483648.) - from floating-point to integer. - assert -2147483649 < 0x1.0p31 < 2147483648; -</pre> -<blockquote><p>Fine-tuning the assertion <code>-2147483649 < 0x1.0p31 < 2147483648</code> was a riot by the way. Do you see why?</p> -</blockquote> -<p>My aging (but still valiant) PowerPC-based Mac appears to think that saturation is the way to go: the variable <code>i</code> is set to <code>INT_MAX</code>:</p> -<pre>$ gcc -std=c99 t.c && ./a.out -2147483647 -</pre> -<p>Dillon Pariente was first to draw our attention to overflow in floating-point-to-integer conversions which caused CPU exceptions on the target CPU for the code he was analyzing. I understood that target CPU to also be a PowerPC so I suspect the behavior must be configurable on that architecture.</p> -<blockquote><p>Dillon Pariente's example was along the lines of <code>float f = INT_MAX; int i = f;</code> which is also hilarious if you are into that sort of humor.</p> -</blockquote> -<p>In order to really show how weird things can get on Intel processors I need to modify the test program a bit:</p> -<pre>int printf(const char * ...); -volatile double v = 0; -int main() -{ - int i1 = 0x1.0p31; - int i2 = 0x1.0p31 + v; - printf("%d %d" i1 i2); -} -</pre> -<p>The <code>volatile</code> type qualifier precludes optimization but there is no hardware or thread to change the value of variable <code>v</code>. The two expressions <code>0x1.0p31</code> and <code>0x1.0p31 + v</code> are both expressions of type <code>double</code> that evaluate to 2^31.</p> -<p>Still GCC and Clang like a single compiler think that these two expressions needn't result in the same value when converted to <code>int</code>:</p> -<pre>$ gcc t.c && ./a.out -2147483647 -2147483648 -$ clang t.c && ./a.out -2147483647 -2147483648 -</pre> -<p>The results are different because one conversion was evaluated statically to be placed in <code>%esi</code> (2147483647) whereas the other was evaluated at run-time in <code>%edx</code> with the <code>cvttsd2si</code> instruction:</p> -<pre>$ clang -S -O t.c && cat t.s -... -_main: ## @main -... - movsd _v(%rip) %xmm0 - addsd LCPI0_0(%rip) %xmm0 - cvttsd2si %xmm0 %edx - leaq L_.str(%rip) %rdi - movl $2147483647 %esi ## imm = 0x7FFFFFFF - xorb %al %al - callq _printf -... -L_.str: ## @.str - .asciz "%d %d" -</pre> -<p>Only undefined behavior allows GCC and Clang to produce different values for <code>i1</code> and <code>i2</code> here: the values of these two variables are computed by applying the same conversion to the same original <code>double</code> number and should be identical if the program was defined.</p> -<p>Generally speaking <code>cvttsd2si</code> always produces <code>-0x80000000</code> in cases of overflow. That is almost like saturation except that floating-point numbers that are too positive are wrapped to <code>INT_MIN</code>. One may think of it as saturating to either <code>-0x80000000</code> or <code>0x80000000</code> and in the latter case wrapping around to <code>-0x80000000</code> because of two's complement. I do not know whether this rationale bears any resemblance to the one Intel's engineers used to justify their choice.</p> -<p>So one might think that this is the end of the story: as long as the conversion is done at run-time on an Intel platform the compiler uses the <code>cvttsd2si</code> instruction. Overflows if overflows there are “saturate to INT_MIN†as the convention is on this platform. This can be confirmed experimentally with the following program variant:</p> -<pre>#include <stdio.h> -#include <stdlib.h> -int main(int c char **v) -{ - int i = 0x1.0p31 + strtod(v[1] 0); - printf("%d" i); -} -</pre> -<p>This new program takes a number from the command-line and adds it to 2^31 so that there is no opportunity for compile-time evaluation. We expect the conversion to saturate to <code>INT_MIN</code> and it does:</p> -<pre>$ gcc -std=c99 t.c && ./a.out 1234 && ./a.out 12345 && ./a.out 123456 --2147483648 --2147483648 --2147483648 -</pre> -<p>Wait! It gets more amusing still. Let us change the program imperceptibly:</p> -<pre>int main(int c char **v) -{ - unsigned int i = 0x1.0p32 + strtod(v[1] 0); - printf("%u" i); -} -</pre> -<p>The behavior of run-time overflow in the conversion from <code>double</code> to integer changes completely:</p> -<pre>$ gcc -m64 -std=c99 t.c && ./a.out 1234 && ./a.out 123456 && ./a.out 12345678999 -1234 -123456 -3755744407 -</pre> -<p>But conversion saturates again at zero this time for the same program when targeting IA-32:</p> -<pre>$ gcc -m32 -std=c99 t.c && ./a.out 1234 && ./a.out 123456 && ./a.out 12345678999 -0 -0 -0 -</pre> -<blockquote><p>Do you have an explanation for this one? Leave a message in the comments section below. The fastest author of a complete explanation wins a static analyzer license.</p> -</blockquote> -<h2>Conclusion</h2> -<p>In conclusion the overflow in the conversion from floating-point to integer is rather on the nasty side of C's undefined behavior spectrum. It may appear to behave consistently if the compilation targets an architecture where the underlying assembly instruction(s) saturate. Saturation is the behavior that compilers GCC and Clang implement when they are able to evaluate the conversion at compile-time. In these conditions a lucky programmer may not actually observe anything strange.</p> -<p>The idiosyncrasies of other architectures may lead to very different results for overflowing conversions depending on parameters outside the programmer's control (constant propagation for instance is more or less efficient depending on the optimization level and may be difficult to predict as we already <a href="/index.php?post/2013/07/24/More-on-FLT_EVAL_METHOD_2">complained about when discussing Clang targeting the 387 FPU</a>).</p> <p>Acknowledgements: In addition to Dillon Pariente I discussed this topic with Boris Yakobowski John Regehr Stephen Canon and StackOverflow users tenos Sander De Dycker and Mike Seymour prior to writing this blog post.</p> {% endraw %} diff --git a/_posts/2013-10-11-OCamls-option--compact-can-optimize-for-code-size-and-speed.html b/_posts/2013-10-11-OCamls-option--compact-can-optimize-for-code-size-and-speed.html index d9b6a100dca2e3464cde6f2249db8b98bd37623b..b79323c8bcb330844a2415ee70e4ff9fa6f16f03 100644 --- a/_posts/2013-10-11-OCamls-option--compact-can-optimize-for-code-size-and-speed.html +++ b/_posts/2013-10-11-OCamls-option--compact-can-optimize-for-code-size-and-speed.html @@ -46,44 +46,5 @@ user 0m0.856s <h2>Conclusion</h2> <p>It is not easy to try to predict performance on modern out-of-order architectures but if I had to hazard an explanation I would say that besides the obvious cache concerns having many scattered predictable conditional branches may be a losing proposition compared to one single conditional branch visited from many places with <code>call</code> and <code>ret</code>. Every conditional branch that isn't in the branch prediction buffer is at risk of being mispredicted. In addition each entry taken by the branches that have recently been visited is an entry that isn't available for branches translated from conditionals in the source code.</p> <p>In contrast the execution of the <code>call</code> and <code>ret</code> instructions has been optimized over the years. The target of the <code>ret</code> instruction is predicted with a Return Stack Buffer that has a conceptually simpler job than the Branch Predictor (although it is clearly possible to write code for which the <code>ret</code> instructions cause a stall which could re-establish an advantage for the partially inlined version).</p> -<p>The conclusion is that everyone who uses OCaml should try the native compiler's option <code>-compact</code> and that perhaps the default should be for this option to be on.</p> - <p>The OCaml compiler can generate native code for various architectures. One of the few code generation options is named <code>-compact</code>:</p> -<pre>$ ocamlopt -help -Usage: ocamlopt <options> <files> -Options are: - ... - -compact Optimize code size rather than speed - ... -</pre> -<p>One of the effects, perhaps the only effect(?), of this option is on the code generated for allocation. In OCaml, a small block typically gets allocated from the minor heap. When all goes well, allocating in the minor heap means simply decrementing the pointer that separates the already-allocated top of the minor heap from the still-available bottom of the minor heap. Eventually the minor heap becomes full; what happens then is complicated. But the fast path is basically a subtraction and a conditional branch (usually not taken) to the complicated stuff.</p> -<p>With option <code>-compact</code>, an allocation simply calls a routine that does all the above. Without it, the subtraction and conditional jump are inlined at the site where the allocation is requested. OCaml being a typical functional language, there are plenty of these. Inlining a couple of instructions makes the code bigger, but when execution stays on the fast path, which is often, a routine call is avoided completely.</p> -<h2>A small example</h2> -<p>Consider the one-line OCaml function <code>let f i = Some i</code>. This function takes a value <code>i</code> and returns a <code>Some</code> memory cell that points to <code>i</code>. I intended <code>i</code> to be an integer, but I inadvertently wrote code that works for any type of <code>i</code>. This was possible because in OCaml, all types of values share a uniform representation, as discussed in the introduction of a <a href="/ocaml/floating-point/2013/05/09/A-63-bit-floating-point-type-for-64-bit-OCaml">previous post</a>.</p> -<p>A <code>Some</code> cell occupies 16 bytes (yes this is huge. Blame 64-bit computing). The fast code generated by <code>ocamlopt -S t.ml</code> where L102 is the label at which selcom-called code manages the case when the minor heap is full:</p> -<pre> ... - subq $16 %r15 - movq _caml_young_limit@GOTPCREL(%rip) %rax - cmpq (%rax) %r15 - jb L102 - ... -</pre> -<p>The <code>-compact</code> option causes more compact code to be emitted for the allocation. When our function <code>f</code> is compiled with <code>ocamlopt -S -compact t.ml</code> the sequence generated for the allocation is much shorter indeed. There is even a specialized allocation function for allocating 16-byte blocs so no arguments need to be set up:</p> -<pre> ... - call _caml_alloc1 - ... -</pre> -<h2>Effects of option -compact in the large</h2> -<p>When the development version of Frama-C is compiled with option <code>-compact</code> the binary takes 14.4MB.</p> -<p>Without option -compact the Frama-C binary weights in at 15.4MB.</p> -<p>One additional megabyte of code is not going to hurt us at this point right? It is not as if the Frama-C binary had to fit exactly in a box of ten floppy disks. As long as the larger code is faster it is worth it…</p> -<pre>$ time bin/toplevel.lean_and_mean tests/test/adpcm.c -sparecode > /dev/null -user 0m0.843s -$ time bin/toplevel.big_and_slow tests/test/adpcm.c -sparecode > /dev/null -user 0m0.856s -</pre> -<p>… but it turns out that the larger code isn't faster. In the case of Frama-C and of the computer I am typing on at least the code generated with option <code>-compact</code> is smaller <strong>and</strong> faster.</p> -<h2>Conclusion</h2> -<p>It is not easy to try to predict performance on modern out-of-order architectures but if I had to hazard an explanation I would say that besides the obvious cache concerns having many scattered predictable conditional branches may be a losing proposition compared to one single conditional branch visited from many places with <code>call</code> and <code>ret</code>. Every conditional branch that isn't in the branch prediction buffer is at risk of being mispredicted. In addition each entry taken by the branches that have recently been visited is an entry that isn't available for branches translated from conditionals in the source code.</p> -<p>In contrast the execution of the <code>call</code> and <code>ret</code> instructions has been optimized over the years. The target of the <code>ret</code> instruction is predicted with a Return Stack Buffer that has a conceptually simpler job than the Branch Predictor (although it is clearly possible to write code for which the <code>ret</code> instructions cause a stall which could re-establish an advantage for the partially inlined version).</p> <p>The conclusion is that everyone who uses OCaml should try the native compiler's option <code>-compact</code> and that perhaps the default should be for this option to be on.</p> {% endraw %} diff --git a/_posts/2013-10-21-Bruce-Dawson-on-compiler-bugs.html b/_posts/2013-10-21-Bruce-Dawson-on-compiler-bugs.html index 2ea5ea781149a1206e4806381dcb01789ece9002..7fa4917164fe451a15208fee1184a694e3c55dd1 100644 --- a/_posts/2013-10-21-Bruce-Dawson-on-compiler-bugs.html +++ b/_posts/2013-10-21-Bruce-Dawson-on-compiler-bugs.html @@ -18,16 +18,5 @@ This bug is probably not security related but security is another reason to ens </blockquote> <p>Bruce's post also illustrates the “most compiler bugs aren't†problem and provides a step-by-step tutorial on manual bug reduction. Regarding the latter my reaction to Bruce's post was to bring up automatic testcase reduction with “delta debugging†but <a href="http://randomascii.wordpress.com/2013/10/14/how-to-report-a-vc-code-gen-bug/#comment-8630">Gravatar user jrrr beat me to it</a>.</p> -<p>Frama-C contributes to making automatic testcase reduction work in practice for C compiler bugs by providing a reference C implementation that detects the undefined behaviors that could make the (original or reduced) bug reports invalid. We also use delta debugging internally to simplify our own reports of bugs in Frama-C. The next post in this blog will illustrate this use of delta debugging on a concrete example.</p> - <p>Bruce Dawson has written <a href="http://randomascii.wordpress.com/2013/10/14/how-to-report-a-vc-code-gen-bug/">a superb blog post</a> on a Visual C++ compiler bug (now fixed) covering every aspect an essay on compiler bugs should cover.</p> -<p>I really like one section that I am going to quote in full:</p> -<blockquote><p><strong>Security</strong></p> -<p> -In these paranoid days of the NSA subverting every computer system available every bug is a possible security flaw. This bug seems curiously commonplace – why wasn’t it discovered when building Windows or other 64-bit products? The most likely explanation is chance and happenstance but compiler bugs can be used to make innocuous source code do surprising things. Maybe this bug is used as part of a back door to let code execution go in a direction that the source code says is impossible. This happened accidentally on the Xbox 360 where the low 32 bits of r0 were checked and then all 64 bits were used. This inconsistency allowed a <a href="http://cxsecurity.com/issue/WLB-2007030065">hypervisor privilege escalation</a> that led to arbitrary code execution.</p> -<p> -This bug is probably not security related but security is another reason to ensure that compiler bugs get fixed.</p> -</blockquote> -<p>Bruce's post also illustrates the “most compiler bugs aren't†problem and provides a step-by-step tutorial on manual bug reduction. -Regarding the latter my reaction to Bruce's post was to bring up automatic testcase reduction with “delta debugging†but <a href="http://randomascii.wordpress.com/2013/10/14/how-to-report-a-vc-code-gen-bug/#comment-8630">Gravatar user jrrr beat me to it</a>.</p> <p>Frama-C contributes to making automatic testcase reduction work in practice for C compiler bugs by providing a reference C implementation that detects the undefined behaviors that could make the (original or reduced) bug reports invalid. We also use delta debugging internally to simplify our own reports of bugs in Frama-C. The next post in this blog will illustrate this use of delta debugging on a concrete example.</p> {% endraw %} diff --git a/_posts/2013-10-26-Jakob-Engblom-on-the-Toyota-Acceleration-Case.html b/_posts/2013-10-26-Jakob-Engblom-on-the-Toyota-Acceleration-Case.html index 155747eb467b0f440c3ad321e06c4a9fdc11ba41..698ca825906a910bce9521cd916636c519cb76ac 100644 --- a/_posts/2013-10-26-Jakob-Engblom-on-the-Toyota-Acceleration-Case.html +++ b/_posts/2013-10-26-Jakob-Engblom-on-the-Toyota-Acceleration-Case.html @@ -9,5 +9,4 @@ summary: --- {% raw %} <p>We interrupt our regularly scheduled program to link to <a href="http://jakob.engbloms.se/archives/1956">this post</a> by Jakob Engblom. The post was prompted by the jury's conclusion in a lawsuit over what appears to be an automotive software glitch that the carmaker is liable.</p> - <p>We interrupt our regularly scheduled program to link to <a href="http://jakob.engbloms.se/archives/1956">this post</a> by Jakob Engblom. The post was prompted by the jury's conclusion in a lawsuit over what appears to be an automotive software glitch that the carmaker is liable.</p> {% endraw %} diff --git a/_posts/2013-11-03-C-Reduce-and-Frama-C.html b/_posts/2013-11-03-C-Reduce-and-Frama-C.html index 61c3c419692a10e2886579c750ef0e834974bf28..9382d90650e84904e99d3b16df63168f2145590a 100644 --- a/_posts/2013-11-03-C-Reduce-and-Frama-C.html +++ b/_posts/2013-11-03-C-Reduce-and-Frama-C.html @@ -114,112 +114,5 @@ To limit the risk of breaking internal C-Reduce assertions the time the initial <li>Still it would be a useful feature if the reducer could detect that a niceness property has appeared during reduction and strove to preserve it from there on. This was perhaps easy to implement in the early non-parallel version of C-Reduce: it looks like it could be done entirely by side-effects in the interestingness test. Since C-Reduce has been parallelized which greatly helps with reduction speed but means that implementing this feature becomes more complicated if it is at all desirable.</li> </ol> <h2>Conclusion</h2> -<p>This post collects a number of useful tricks for using C-Reduce in particular when reducing bugs for Frama-C. C-Reduce is already immensely useful as it is but this post also indicates some future work directions to make its use more automatic and more convenient yet.</p> - <h2>Automatic testcase reduction for compilers: the story so far</h2> -<p>A <a href="/cybersecurity/link/c-reduce/2013/10/21/Bruce-Dawson-on-compiler-bugs">previous post</a> linked to a discussion of manual testcase reduction when the program being debugged is a compiler (and the input demonstrating the faulty behavior is thus a C program). Since then quite a few related events took place:</p> -<p>In a comment to the linked post someone mentioned automatic testcase reduction with “delta debugging†and Bruce Dawson the author of the original post replied:</p> -<blockquote><p>Given that the compiler sometimes changed what register it was using I’m not sure that the effort of writing an accurate test for this bug would be worthwhile. It really didn’t take me much time to reduce this bug — half an hour perhaps? Once you don’t need to link the code you can slash-and-burn at a fearsome rate and my brain is more flexible at recognizing legitimate variations of the bug than any script would be.</p> -</blockquote> -<p>And I further commented that on the other hand a generic “accurate [automatic] test†only needs to be written once and can serve multiple times. This post intends to show how right Bruce is: subtle pitfalls lurk when writing the acceptance test for automatically reducing a C program. Some of the dangers are theoretical enough when the program being debugged is a compiler but become more annoying in practice when it is say a static analysis framework.</p> -<p>Meanwhile John Regehr wrote a <a href="http://blog.regehr.org/archives/1047">blog post of his own</a> about the automatic reduction of testcases for compilers. The remarks in his post are quite orthogonal to the remarks in this one. My remarks are in the context of reducing testcases for Frama-C which is a bit of a misappropriation and reveals specific issues in the same way that <a href="/index.php?pages/Csmith-testing">using Csmith to find bugs in Frama-C</a> provided some new insights.</p> -<h2>The general idea explained on an example</h2> -<p>Consider the example of a file from the Linux kernel that Frama-C's front-end chokes on. The original file causing the problem is 1.5MiB large after pre-processing and we would like automatic reduction to produce a smaller file that exhibits the same problem so that we can show it to our Frama-C front-end expert.</p> -<p>The symptom of the problem is the error message below:</p> -<pre>include/linux/delay.h:39:[kernel] failure: invalid implicit conversion from void to int -</pre> -<p>We can build a script that tests for the presence of this line in Frama-C's output. This script will then tell the reducer whether the latter is still on the right path or accidentally erased the interesting behavior.</p> -<p>A first obvious remark is that the test should not check for the presence of “include/linux/delay.h:39:[kernel] failure: invalid implicit conversion from void to int†exactly. If it does then a reduced program can only pass the test by making it look as if the problem is at that file and line which will prevent removal of <code>#line file</code> directives in the testcase and also hinder the removal of irrelevant lines that only seem useful because they happen to make the error message come from the expected line.</p> -<p>Instead the test should be only the presence of “failure: invalid implicit conversion from void to int†in the output of Frama-C. We think we will be happy with any testcase that produces this output so we should configure the reducer with a test that detects this output and this output only. This idea will be a recurring theme in this post.</p> -<p><a href="http://embed.cs.utah.edu/creduce/">C-Reduce</a> is the best reducer of C programs out there. C-Reduce takes as input a C program to reduce and a script implementing the interestingness test. A pre-condition is that the initial program has to be interesting. In exchange C-Reduce produces the smallest interesting program that it can removing and moving around bits of the original program and checking that the result remains interesting. When applied with the aforementioned 1.5MiB file from the Linux kernel and with the interestingness test <code>frama-c t.i | grep "failure: invalid implicit conversion…"</code> C-Reduce produces the minimal file below:</p> -<pre>fn1 () -{ - 0 ? 0 * 0 ? : 0 : 0; -} -</pre> -<p>This superficially looks like something that we could show to our Frama-C front-end expert although we will generate a better reduced program later in the post. If we make the mistake of grepping for <code>"delay.h:39:[[]kernel[]] failure: invalid implicit conversion…"</code> instead C-Reduce still does a good job preserving only a single additional line that happens to cause the warning to be localized where the interestingness test expects it:</p> -<pre>#37 "include/linux/delay.h" -fn1 () -{ - 0 ? 0 * 0 ? : 0 : 0; -} -</pre> -<p>C-Reduce's only quirk may be that it sometimes reduces too much. In both reduced programs above the function <code>fn1()</code> is implicitly typed as returning <code>int</code> according to now obsolescent C90 rules. In addition the syntax <code>e1 ? : e2</code> is not standard C but a GCC extension that happens to be accepted by the Frama-C front-end.</p> -<h2>We have been lucky</h2> -<p>We have in fact been lucky in the above reduction: the reduced program looks like something that should be accepted by Frama-C (despite the <code>int</code> ellipsis and the strange <code>? :</code> syntax) and instead of accepting it Frama-C emits an error message. This is exactly what we were hoping to obtain from the reduction process.</p> -<p>Consider the eventuality of the reduced program being an invalid program incorrectly converting a <code>void</code> expression to <code>int</code>. Frama-C would be behaving correctly by emitting its warning on the reduced program. C-Reduce would have behaved according to specification but we would be left without anything to show our front-end expert. We would have been had.</p> -<p>This is not a problem in C-Reduce but a problem with us not using it properly. The reason the original 1.5MiB program is interesting is that it is accepted by GCC and rejected by Frama-C. This is the criterion the interestingness test should implement. When the interestingness test passed to C-Reduce implements an approximation of the notion of interestingness we really desire we have only ourselves to blame if C-Reduce turns up an invalid reduced file that Frama-C correctly rejects.</p> -<h2>Stop reducing so much C-Reduce!</h2> -<p>We do not want the Frama-C front-end expert we report the bug to to be sidetracked by considerations on obsolete syntax or strange extensions. The best testcase to show <a href="http://en.wikipedia.org/wiki/Spivak_pronoun">em</a> is a short but perfectly standard C program. We can make this preference part of our interestingness test.</p> -<p>The first idea may be to reject any file that is not strictly C99-compliant. That would be a file that <code>gcc -std=c99 -pedantic</code> accepts to compile I think. However the unreduced testcase here is a file from the Linux kernel. The unreduced testcase does not pass this test.</p> -<p>Delta debugging is for preserving interestingness along size-reduction steps not for making interestingness appear. Therefore we cannot demand a reduced file that passes <code>gcc -std=c99 -pedantic</code> if the original file to start from does not pass it either.</p> -<blockquote><p>Note: techniques borrowed from C-Reduce and from genetic programming might make interestingness appear out of uninteresting C files. Structural coverage of the program under test beyond the ability to crash it may make a useful non-boolean fitness function. Or better for a chosen assertion inside the program under test coverage of the statements that lead to the assertion. This process would be different from delta debugging but might generate files that reveal bugs in static analysis frameworks. I hope someone will look into it someday.</p> -</blockquote> -<p>However simply compiling the tentative reduced file we already have with well-chosen compiler options reveals that GCC can already tell this file is not perfect. It emits the warnings snippets <code>forbids omitting the middle term</code> (regarding the syntax extension for <code>? :</code>) and <code>warning: return type defaults to</code> (regarding implicit return types of functions). Our original file although it originates from the Linux kernel is not so ugly that it causes these warnings. Consequently we can test for these warnings in an interestingness test that accepts the original file and will guide C-Reduce towards a clean reduced file.</p> -<p>If we do this we obtain:</p> -<pre>/* */ void -fn1 () -{ - 0 ? 0 * 0 ? 0 : 0 : 0; -} -</pre> -<p>The Frama-C issue at hand <a href="http://bts.frama-c.com/view.php?id=1503">was reported</a> using the reduced C program as evidence and was promptly fixed by Virgile Prevosto Frama-C front-end expert extraordinaire.</p> -<h2>C-Reduce is now parallel</h2> -<p>The latest version of C-Reduce can explore several possible reductions in parallel. This is particularly interesting when the program under test takes a long time. A bug deep into the value analysis plug-in may take minutes to occur in the original program and C-Reduce typically launches thousands of instances in the process of reducing a large program to a small one.</p> -<p>However it does not pay to run too many instances of memory-bandwidth-limited programs in parallel. The computer I ran this example on has 4 cores and two execution threads by core (it relies on <a href="http://en.wikipedia.org/wiki/Hyper-threading" hreflang="en">hyper-threading</a>). The system thus sees 8 processors. By default C-Reduce launches up to 8 instances in parallel. Is this the best choice?</p> -<p>If I use option C-Reduce's option <code>-n</code> to choose different levels of parallelism instead I obtain for this particular memory-intensive(*) program being debugged (Frama-C) and this particular initial C program the following timings:</p> -<pre># instances Time (s) - 1 620 - 2 375 - 3 346 - 4 367 - 5 396 - 8 492 -</pre> -<p>For this particular use C-Reduce's default of using all available execution threads is faster than using only one execution thread. It is also slower than all other parallelization choices. The fastest reduction is obtained for 3 parallel instances and it is almost twice faster than the non-parallel version.</p> -<p>There is some randomness to the reduction algorithm however and the experiment should be repeated with varying initial programs before conclusions are drawn.</p> -<p>(*) Frama-C can sometimes use as much as half the memory a modern web navigator typically uses. Imagine!</p> -<h2>Making each instance terminate earlier</h2> -<p>Even with an optimal choice of the degree of parallelism automatic reduction can be time-consuming. A sub-optimal interestingness test for a bug that takes several minutes to appear in Frama-C can make the entire reduction take days or exhaust the operator's patience altogether. This is only machine time we are talking about but sometimes a human is waiting on the result of the reduction. In this section we point out two useful tricks to bear in mind especially when the program under test can take a long time for some inputs. The fact that the program under test takes a long time can be the problem being investigated but does not have to.</p> -<h3>First trick: using grep option <code>-l</code></h3> -<p>Often as soon as a particular diagnostic message has been emitted it is possible to conclude that the testcase is interesting. In the example above as soon as the message “failure: invalid implicit conversion…†has been seen in Frama-C's output for a C program that GCC otherwise accepts the input C program is known to be interesting.</p> -<p>By default a shell script such as <code>frama-c … test.c | grep "interesting message"</code> allows Frama-C to finish its analysis before returning a boolean value. A simple improvement is to use grep's <code>-l</code> option that causes <code>grep</code> to exit just after the matching line has been seen.</p> -<p>Contrast these two Unix sessions:</p> -<pre>$ cat | grep interesting ; echo $? -nothing to see here -still nothing -this is interesting -this is interesting ↠this matching line is repeated by grep -one more line -two more lines -three more lines -cat is taking a long time -... -^D -0 ↠error code of grep printed by echo indicating an interesting line was seen -</pre> -<p>In the above session the <code>grep</code> command was still scanning its input after an interesting line had been seen until I indicated that the “analysis†was finished with control-D. Below I repeat the experiment this time using <code>grep -l</code> to detect the keyword “interestingâ€.</p> -<pre>$ cat | grep -l interesting ; echo $? -nothing to see here -still nothing -this is interesting -(standard input) ↠grep indicates a matching line has been seen on stdin -one more line -0 ↠error code of grep printed by echo indicating an interesting line was seen -</pre> -<p>Thanks to the <code>-l</code> option the <code>cat</code> command was terminated abruptly before it had finished when emitting the line immediately after the interesting line (<code>cat</code> was terminated for trying to write to a closed file descriptor). Actually this is a slight chink in the armor: the program whose output is piped into <code>grep</code> needs to write one more line after the interesting line in order to be terminated. If the interesting behavior is Frama-C taking a long time for some inputs and the interesting log line is one that says “warning: things are going to take an infinite time from now on†and nothing is ever printed after that line Frama-C will not be terminated. My Unix-fu is too weak for me to offer a solution where the program under test is terminated as soon as possible but the next subsection offers a palliative anyway.</p> -<h3>Second trick: using a timeout</h3> -<p>The initial input program may fail (i.e. “be interestingâ€) within say 5 minutes. This does not prevent slight variations of the program to take forever to fail or to take forever to succeed. In each case we do not want the reduction process to waste days of computations testing a single variation. We want the reduction process instead to try as many variations as possible quickly in order to converge to a short one as soon as possible. The strength of delta debugging is in iteration.</p> -<p>A simple idea here is to define the interestingness property as “the C program causes the interesting message to be emitted by Frama-C within 10 minutesâ€. Any program that has already been analyzed for 11 minutes is uninteresting by this definition. This property can be implemented simply with the Unix command <code>ulimit</code>.</p> -<p>Strictly speaking the interestingness property should be completely reproducible whereas this one is not. However C-Reduce still works very well in practice with such a limit in place in the interestingness test. -To limit the risk of breaking internal C-Reduce assertions the time the initial program takes to be interesting should be multiplied by a safety factor. Because C-Reduce launches several instances in parallel each instance runs a bit slower than if it was alone and execution times can vary a bit. I have never had any trouble using as the timeout twice the time the initial program takes to fail.</p> -<h2>Automating the manual</h2> -<p>Let us take a step back and look at what we have been doing above. We started with one obvious interesting property and we progressively refined it in order to delineate the really interesting programs. We initially thought we were interested in C programs that cause Frama-C to emit the message “include/linux/delay.h:39:[kernel] failure: invalid implicit conversion from void to int†but it eventually turned out that we really wanted Frama-C to emit “failure: invalid implicit conversion from void to int†within 10 minutes for a C program that GCC compiles without emitting warnings about <code>? :</code> syntax extensions or implicit return types.</p> -<p>We have been obtaining the additional sub-properties in a trial-and-error fashion: we did not know that we wanted any of them until C-Reduce produced a program that did not have it. Still I believe that:</p> -<ol> -<li>These additional sub-properties would always come from the same repertoire in actual C-Reduce practice. It is possible to build a large catalog of these desirable properties so that the end user does not need to re-discover each of them.</li> -<li>Before the reduction per se even starts the original program should be tested for all the above niceness properties. All the niceness properties the original program has should be preserved in the reduced program by making them part of the interestingness test. That is if the original program does not warn about implicit return types the reduced program should not warn about implicit return types. On the other hand if the original program does warn about implicit return types then the bug being investigated may be about implicit return types so it is not possible to require the reduced program to avoid the warning.</li> -<li>Still it would be a useful feature if the reducer could detect that a niceness property has appeared during reduction and strove to preserve it from there on. This was perhaps easy to implement in the early non-parallel version of C-Reduce: it looks like it could be done entirely by side-effects in the interestingness test. Since C-Reduce has been parallelized which greatly helps with reduction speed but means that implementing this feature becomes more complicated if it is at all desirable.</li> -</ol> -<h2>Conclusion</h2> <p>This post collects a number of useful tricks for using C-Reduce in particular when reducing bugs for Frama-C. C-Reduce is already immensely useful as it is but this post also indicates some future work directions to make its use more automatic and more convenient yet.</p> {% endraw %} diff --git a/_posts/2013-12-21-Improving-the-world-for-2014-one-programmer-at-a-time.html b/_posts/2013-12-21-Improving-the-world-for-2014-one-programmer-at-a-time.html index 78ba852ecf00db161eedeb997ab9d0a87767d000..a640127a1214d25e23573a39322d15bb636bd5aa 100644 --- a/_posts/2013-12-21-Improving-the-world-for-2014-one-programmer-at-a-time.html +++ b/_posts/2013-12-21-Improving-the-world-for-2014-one-programmer-at-a-time.html @@ -15,13 +15,5 @@ summary: <li>Print numbers in hexadecimal format as often as you can (<code>%a</code> in C99). Input them that way when it makes sense.</li> <li>Don't worry floating-point numbers are just bits. Stop listening to anyone who tries to confuse you with generic reasoning about an arbitrary base β.</li> </ol> -<p>YMMV</p> - <p>I move that all computing devices be equipped with a small explosive charge, set to explode when someone refers someone else to Goldberg's <a href="http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html">What Every Computer Scientist Should Know About Floating-Point Arithmetic</a> without the referrer <a href="http://en.wikipedia.org/wiki/Spivak_pronoun">emself</a> having read it.</p> -<p>It would not have to be lethal. I could be content if the apparatus maimed the user into harmlessness.</p> -<p>For what it is worth the advice I wish I had received instead of being suggested Goldberg's essay the first time is:</p> -<ol> -<li>Print numbers in hexadecimal format as often as you can (<code>%a</code> in C99). Input them that way when it makes sense.</li> -<li>Don't worry floating-point numbers are just bits. Stop listening to anyone who tries to confuse you with generic reasoning about an arbitrary base β.</li> -</ol> <p>YMMV</p> {% endraw %} diff --git a/_posts/2014-01-17-Post-conditions-and-names-of-arguments.html b/_posts/2014-01-17-Post-conditions-and-names-of-arguments.html index 1541d43e7e9194290374f9535b8c8f3ef5f1fdf1..a282cf9df928c1918174c3e0903b2eda7502b93c 100644 --- a/_posts/2014-01-17-Post-conditions-and-names-of-arguments.html +++ b/_posts/2014-01-17-Post-conditions-and-names-of-arguments.html @@ -16,13 +16,5 @@ void f(int arg) } </pre> <p>For instance, in function <code>f</code> above, Frama-C's value analysis plug-in will typically say that the status of the post-condition is unknown, because <code>arg</code> is taken to mean <code>\old(arg)</code>, the value passed to <code>f</code> and thus untouched by the assignment. The rationale is that <code>arg</code> has already ceased to live when the post-condition is evaluated: the program could not observe or otherwise depend on the value of <code>arg</code> after the call to <code>f()</code> anyway. On the other hand, it is convenient to be able to relate results and arguments of the function, and this can be done with the simple syntax “<code>arg</code>â€. For a global variable <code>G</code>, one would have to write “<code>\old(G)</code>†to refer in <code>f</code>'s post-condition to the value of <code>G</code> just before the call to <code>f</code>. The syntax “<code>G</code>†in a post-condition would refer to the value of <code>G</code> at the end of the function.</p> -<p>But do not worry, if you forget the above subtlety, you can always spend twenty minutes adding debug messages to the value analysis plug-in until you finally remember that said subtlety is what is actually implemented.</p> <p>In an ACSL post-condition, any reference to the name of one of the function's arguments is assumed to refer to the initial value of the argument.</p> -<pre>/* ensures arg == 1; */ -void f(int arg) -{ - arg = 1; -} -</pre> -<p>For instance, in function <code>f</code> above, Frama-C's value analysis plug-in will typically say that the status of the post-condition is unknown, because <code>arg</code> is taken to mean <code>\old(arg)</code>, the value passed to <code>f</code> and thus untouched by the assignment. The rationale is that <code>arg</code> has already ceased to live when the post-condition is evaluated: the program could not observe or otherwise depend on the value of <code>arg</code> after the call to <code>f()</code> anyway. On the other hand, it is convenient to be able to relate results and arguments of the function, and this can be done with the simple syntax “<code>arg</code>â€. For a global variable <code>G</code>, one would have to write “<code>\old(G)</code>†to refer in <code>f</code>'s post-condition to the value of <code>G</code> just before the call to <code>f</code>. The syntax “<code>G</code>†in a post-condition would refer to the value of <code>G</code> at the end of the function.</p> -<p>But do not worry, if you forget the above subtlety, you can always spend twenty minutes adding debug messages to the value analysis plug-in until you finally remember that said subtlety is what is actually implemented.</p> +<p>But do not worry, if you forget the above subtlety, you can always spend twenty minutes adding debug messages to the value analysis plug-in until you finally remember that said subtlety is what is actually implemented.</p> {% endraw %} diff --git a/_posts/2014-01-24-Bear-joke-security-is-dead.html b/_posts/2014-01-24-Bear-joke-security-is-dead.html index da6e3ab76f2fbdb78a7553baa6d7eec6707533ff..3b2b522be90bb85fbca93b5e59db4ca6a656e1b6 100644 --- a/_posts/2014-01-24-Bear-joke-security-is-dead.html +++ b/_posts/2014-01-24-Bear-joke-security-is-dead.html @@ -20,18 +20,5 @@ To which Alex replies: “I don't have to outrun the bear. I only have to outrun </blockquote> <p>Yes we do but we don't have to use them.</p> <p>Here is to 2014 being the year of reliable cryptography implementations that cannot be circumvented through defects.</p> -<p>(*) “literally†within the confines of this metaphor</p> - <p>Likely, you have heard this one before:</p> -<blockquote><p>Two campers are surprised by an angry bear. One of them starts putting on <a href="http://en.wikipedia.org/wiki/Spivak_pronoun">eir</a> running shoes. Surprised the other exclaims “What are you doing Alex? You can't outrun a bear!â€</p> -<p> -To which Alex replies: “I don't have to outrun the bear. I only have to outrun you.â€</p> -</blockquote> -<p>This joke used to be popular with security experts who employed it as a metaphor. I only ever heard it in that context the first time as a student in the late nineties. The bear joke was still used for this purpose <a href="http://spiresecurity.com/?p=123">in 2008</a>.</p> -<p>You may also have heard that there is a new bear in town and the new bear can take both Alex and eir friend with or without running shoes. Also the new bear could literally(*) eat a horse. And the bear is part of an organized network of hungry bears with walkie-talkies and sniper guns.</p> -<p>If your approach to security was based on bear jokes with dubious morals now must really suck. Andy Green's <a href="http://blog.varonis.com/cryptography-may-dead-life-support/">blog post</a> “Cryptography may not be dead but it is on life support†is representative of the change. One of the quote he takes from Schneier's talk is:</p> -<blockquote><p>Most of how the NSA deals with cryptography is by getting around it … They exploit bad implementations—we have lots of those.</p> -</blockquote> -<p>Yes we do but we don't have to use them.</p> -<p>Here is to 2014 being the year of reliable cryptography implementations that cannot be circumvented through defects.</p> <p>(*) “literally†within the confines of this metaphor</p> {% endraw %} diff --git a/_posts/2014-02-04-Assertions.html b/_posts/2014-02-04-Assertions.html index 635e5ecab2389b39206cfcd11c0bc58add117368..40c196531090164c58ac338168fb22316333a334 100644 --- a/_posts/2014-02-04-Assertions.html +++ b/_posts/2014-02-04-Assertions.html @@ -61,59 +61,5 @@ t.c:1:[value] Function sqrt: precondition got status valid. [value] Values at end of function dist: s ∈ [-0. .. 9.22337203685e+18] </pre> -<p>On the same example the builtin version of assert detects that it may be passed a null expression and warns about that. These is no improvement there (annotating the example to convince the analyzer that <code>s</code> is always positive is left as an exercise to the reader). Subsequently and this is an improvement with respect to the previous analysis the builtin does its best to incorporate the information provided in the assertion so that it can tell that <code>s</code> is henceforth positive and that the pre-condition of <code>sqrt()</code> is satisfied.</p> - <h2>Jesse Ruderman on assertions and fuzzing</h2> -<p>Jesse Ruderman has published a <a href="http://www.squarefree.com/2014/02/03/fuzzers-love-assertions/" hreflang="en">blog post on assertions</a> and how they complement fuzzing. -Key quote: <strong>“Fuzzers make things go wrong. Assertions make sure we find out.â€</strong></p> -<p>Readers of this blog are accustomed to me talking about <a href="/index.php?pages/Csmith-testing">differential testing</a> where a reference result (say obtained by compiling a random C program with a quality compiler) is used to detect bugs in the target program (say a static analysis framework for C programs). Differential testing imposes constraints: the random input must have a definite meaning and a reference implementation needs to be available to compute this meaning. Often one finds bugs in the reference implementation together with bugs in the target program.</p> -<p>Besides there are deeply burrowed bugs that are difficult to reveal with such a black-box approach. Assertions simplify the problem: if the code being tested contains enough well-chosen assertions <strong>bugs can be caught without a reference implementation</strong>.</p> -<p>Sometimes an assertion is a reference implementation: some of the assertions in Frama-C are alternative computations of the same intermediate result followed by a comparison of the normally computed result with the alternately computed result. These assertions initially caught bugs in either computation. Since then they have caught many more bugs in hash-consing where the two results are structurally identical but are not shared.</p> -<p>Even when an assertion happens to contain a reference implementation for an intermediate result it saves a lot of time to write the assertion as opposed to producing a complete reference implementation for the whole problem (say interpreting C programs). The alternative implementation in the assertion does not have to be efficient: in Frama-C's value analysis it is considered acceptable to spend 20% of the analysis time executing inefficient reference implementations in assertions.</p> -<h2>John Regehr on writing and using assertions</h2> -<p>John Regehr just published a <a href="http://blog.regehr.org/archives/1091">blog post too on the subject of assertions</a>. What a coincidence! Key quote: <strong>“we have tools that are specifically designed to help us reason about assertions; my favorite one for C code is Frama-Câ€</strong>.</p> -<p>In most of his post John describes executable assertions written in the same language as the program being debugged. In the section quoted above he moves to specific annotation languages to write assertions in. The advantages of using the same language as the programming language for assertions require no elaboration: it's the same language! The programmer already knows it and the reviewer of the code already knows it.</p> -<p>But there is a spectrum of annotation languages for assertions. Eiffel stands its ground somewhere on this spectrum very close to the underlying programming language but with enough good intentions to be noted. I think that the JML annotation language for Java was initially mostly intended for run-time checking but ended up being very popular too as the annotation language used by static analyzers (I would be happy to be corrected if I am getting this wrong). Nearby JML lies E-ACSL an executable subset of ACSL and also a <a href="http://frama-c.com/eacsl.html">Frama-C plug-in</a> to convert a C program annotated with <code>/*@ ... */</code> assertions into an instrumented C program that detects at run-time violated assertions. SPARK 2014 aims at making both camps happy.</p> -<p>I should point out for the sake of scientific integrity that I am being slightly cheeky in the choice of the key quote to represent John's post. I recommend you read the whole thing of which the Frama-C endorsement is only a tiny fraction.</p> -<h2>Taking advantage of C assertions with Frama-C</h2> -<p>One can also use Frama-C in conjunction with existing executable assertions typically implemented with the standard function <code>assert()</code> in header <code>assert.h</code>. The function <code>assert()</code> takes a C expression representing a property that should hold.</p> -<p><strong>One way to take advantage of assertions is to fail to establish that they always hold</strong> and warn the user that perhaps they don't. It is easy for anyone who wants this behavior to obtain it. One simply needs to specify <code>assert()</code> thus:</p> -<pre>/*@ requires x != 0 ; */ -void assert(int x); -</pre> -<p>With this specification any existing call to the C function <code>assert()</code> intended for the programmer to be executed at run-time is required to have an argument that demonstrably corresponds to a non-null expression. This specification creates a link of sorts between static verification and run-time checking (or expressions intended to be checked at run-time anyway).</p> -<p>Here is an example:</p> -<pre>... -/*@ requires x >= 0 ;*/ -double sqrt(double x); -int get_int(void); -double dist(double x double y) -{ - double s = x * x + y * y; - assert(s >= 0.0); - return sqrt(s); -} -int main(int c char **v){ - dist(get_int() get_int()); -} -</pre> -<p>When this program is analyzed the value analysis detects that the assertion <code>s >= 0.0</code> helpfully inserted by the programmer as an argument to <code>assert()</code> may not hold. In this particular example the warning is a false positive but never mind that for the moment.</p> -<pre>$ frama-c -val t.c -... -t.c:4:[value] Function assert: precondition got status unknown. -... -t.c:1:[value] Function sqrt: precondition got status unknown. -</pre> -<p>Even more irritating in the example above is that after producing a false positive for <code>assert()</code> the analyzer produces a false positive for the pre-condition of <code>sqrt()</code>. This brings us to another way a static checker could use C assertions to its advantage: it could take them as hints <strong>properties that can be assumed to hold in order to avoid warning</strong> for problems that would seem to arise later if they did not.</p> -<p>With the user-specified function <code>assert()</code> above the analyzer computes the truth value of the argument <code>s >= 0.0</code>. Because the set of values computed for <code>s</code> is approximated the set of values for the expression <code>s >= 0.0</code> is <code>{0; 1}</code>. The analyzer can tell that the pre-condition for <code>assert()</code> may not hold but the relationship with the possible values of <code>s</code> is too indirect for it to decide that the forbidden situation corresponds to <code>s</code> negative and that only <code>s</code> positive is allowed.</p> -<p>There exists a better modelization of <code>assert()</code>. It was implemented as a value analysis built-in in order to offer the very functionality we are describing here:</p> -<pre>$ frama-c -val -val-builtin assert:Frama_C_assert t.c -... -t.c:11:[value] warning: Frama_C_assert: unknown -... -t.c:1:[value] Function sqrt: precondition got status valid. -... -[value] Values at end of function dist: - s ∈ [-0. .. 9.22337203685e+18] -</pre> <p>On the same example the builtin version of assert detects that it may be passed a null expression and warns about that. These is no improvement there (annotating the example to convince the analyzer that <code>s</code> is always positive is left as an exercise to the reader). Subsequently and this is an improvement with respect to the previous analysis the builtin does its best to incorporate the information provided in the assertion so that it can tell that <code>s</code> is henceforth positive and that the pre-condition of <code>sqrt()</code> is satisfied.</p> {% endraw %} diff --git a/_posts/2014-02-23-An-interesting-SSL-implementation-bug-CVE-2013-5914.html b/_posts/2014-02-23-An-interesting-SSL-implementation-bug-CVE-2013-5914.html index ba65d7730d386d0e1f489c1e5c643c7f793ce9bf..9d787497042cc6ba7e44a808f451da8674e82fc2 100644 --- a/_posts/2014-02-23-An-interesting-SSL-implementation-bug-CVE-2013-5914.html +++ b/_posts/2014-02-23-An-interesting-SSL-implementation-bug-CVE-2013-5914.html @@ -91,89 +91,5 @@ In contrast the value of <code>nb_want</code> can only be <code>5</code> when < <h2>Acknowledgments</h2> <p>Philippe Herrmann was first to use Frama-C to find a security bug in PolarSSL (Philippe's bug was a <a href="https://github.com/polarssl/polarssl/commit/e2f8ff67972a85bfc748b16b7128fee08c4dd4c0">denial of service</a> in versions up to 1.1.1 fixed in 1.1.2). Anne Pacalet and Paul Bakker have helped me with various aspects of PolarSSL's verification including but not limited to the bug described in this post. -Twitter users aloria thegrugq and johnregehr provided comments on drafts of this post. And finally the Internet made this post possible by being itself.</p> - <h2>SSL in the news</h2> -<p>SSL is a protocol for point-to-point confidential and authenticated communication over an insecure medium. It is the protocol behind HTTPS, among many other uses. In an Internet-connected system, the SSL implementation stands at the frontier between the system and the hostile outside world. For this reason, SSL implementation flaws are a prime target for attacks.</p> -<h3>An ordinary bug</h3> -<p>A rather banal SSL implementation bug was revealed over the weekend. A duplicated line in a crucial, if ordinary-looking, sequence of validation operations means that some of the validation steps are not <a href="http://opensource.apple.com/source/Security/Security-55471/libsecurity_ssl/lib/sslKeyExchange.c?txt">taken</a>:</p> -<pre> ... - if ((err = ReadyHash(&SSLHashSHA1 &hashCtx)) != 0) - goto fail; - if ((err = SSLHashSHA1.update(&hashCtx &clientRandom)) != 0) - goto fail; - if ((err = SSLHashSHA1.update(&hashCtx &serverRandom)) != 0) - goto fail; - if ((err = SSLHashSHA1.update(&hashCtx &signedParams)) != 0) - goto fail; - goto fail; // <------------------------------------------------- - if ((err = SSLHashSHA1.final(&hashCtx &hashOut)) != 0) - goto fail; - ... -fail: - SSLFreeBuffer(&signedHashes); - SSLFreeBuffer(&hashCtx); - return err; -} -</pre> -<p>Note that the second consecutive <code>goto fail</code> is executed with variable <code>err</code> containing the result of the last validation operation <code>0</code> indicating success. This value is returned as-is by the function; the caller is therefore mislead into believing that the validation succeeded despite some of the validation steps not having been executed.</p> -<p>Because C lacks an exception mechanism the above is an often-seen programming pattern. The programming style here can hardly be blamed: this is how the best C programs are written. Except of course for the extraneous <code>goto</code>.</p> -<p>The SSL implementation and thus the bug in question are found in tens of millions of iOS devices with a few additional Mac OS X computers on top of that. The scope of the security problem caused by this bug and the obviousness of the issue when pointed out have together lead to much commentary on Twitter and other popular discussion forums.</p> -<h3>So reaction. Very noise</h3> -<p>“I would never have had this problem because I know that <code>goto</code> is bad†some commenters claim. I wish I was caricaturing but I am unfortunately only paraphrasing and combining several public reactions into one.</p> -<p>“I would never have had this problem because I use braces†essentially state others. Certainly the root cause of the problem must have been that the developer who introduced the bug was confused about the meaning of <code>if (c) stmt1; stmt2;</code>. Just look how <a href="http://en.wikipedia.org/wiki/Spivak_pronoun">ey</a> indented it!</p> -<p>These two often-heard remarks strongly suggest to use brace-less control flow or the presence of <code>goto</code> as predictors of defects in C code. I am sure this will be a fruitful research direction. Someone from the software engineering academic community should look into it.</p> -<p>“Just adding a single line of code can bring a system to its knees†<a href="http://avandeursen.com/2014/02/22/gotofail-security/">reminds</a> Arie van Deursen. True true an important lesson there. We should all insert the following line somewhere in our respective codebases from time to time and take a good look at the effect it has in remembrance.</p> -<p>It is <a href="/rant/2011/09/27/About-the-rounding-error-in-these-Patriot-missiles">Ariane 5</a> all over again! Worse instead of just the makers of formal verification systems everyone seems to have a scheme to prevent the problem they already know is there.</p> -<h2>An interesting bug in a different SSL implementation</h2> -<p>The problem in most of the armchair analysis that has been going on on the Internet lies in the two following questions: how many more bugs in security-critical C code does the proposed remedy (be it more braces fewer gotos …) find? How many time-costly tedious soul-crushingly boring false positives does it uncover?</p> -<p>Since commenters have been generalizing on the basis of a population of one sample I feel no shame in presenting my own single example raising the total number of scrutinized bugs to two. Note that for us to make statistically sound arguments we will eventually need to extend the discussion to examples of correct code that we do not wish to change.</p> -<p>Until then here is a funny SSL implementation bug. It is characterized as follows in a version of PolarSSL 1.1.8 that colleagues and I have been modifying.</p> -<h3>Screenshot 1: an alarm in <strong>our</strong> <code>tis_recv()</code> function?</h3> -<p><a href="/assets/img/blog/imported-posts/CVE-2013-5914/CVE-2013-5914-1.png" title="CVE-2013-5914-1.png"><img src="/assets/img/blog/imported-posts/CVE-2013-5914/CVE-2013-5914-1s.png" alt="CVE-2013-5914-1.png" style="display:block; margin:0 auto;" title="CVE-2013-5914-1.png fév. 2014" /></a></p> -<p>PolarSSL expects the program in which it is incorporated to provide it with a function that receives data from the outside world and writes it to a memory buffer. We have made such a function baptized it <code>tis_recv</code> and we have set up PolarSSL to use it.</p> -<p>The function <code>tis_recv</code> takes three arguments. The first one is a context argument in case someone needs one (our function ignores this argument). Second is a pointer to the buffer where the data is to be written then third is the maximum size the function is allowed to write there.</p> -<p>We have specified our function <code>tis_recv</code> thus:</p> -<pre>/*@ - requires recv_r1: \valid(output+(0..output_len-1)) ; - requires recv_r2: output_len > 0 ; -*/ -int tis_recv(void* p unsigned char * output size_t output_len); -</pre> -<p>The screenshot indicates on the bottom right that the pre-condition <code>recv_r1</code> which states that the argument <code>output</code> points to a buffer large enough for <code>output_len</code> characters is not verified. How could this be? Surely a false positive… Or someone is calling the function with the wrong arguments. It does not look like the problem is in our function.</p> -<p>The GUI informs us that the function <code>tis_recv</code> is called in one place only and that place is inside <code>ssl_fetch_input()</code>. It is called through a function pointer stored inside a member of a struct accessed through a pointer. The GUI tells us that we can mentally substitute <code>ssl->f_recv(..)</code> with <code>tis_recv(...)</code>.</p> -<h3>Screenshot 2: a wrong third argument</h3> -<p>The GUI tells us that the buffer that PolarSSL passes to <code>tis_recv()</code> has size 16KiB-ish (not pictured) and that the variable <code>len</code> passed as third argument appears to take any of the values of its <code>size_t</code> type (pictured in the bottom panel below).</p> -<p><a href="/assets/img/blog/imported-posts/CVE-2013-5914/CVE-2013-5914-2.png" title="CVE-2013-5914-2.png"><img src="/assets/img/blog/imported-posts/CVE-2013-5914/CVE-2013-5914-2s.png" alt="CVE-2013-5914-2.png" style="display:block; margin:0 auto;" title="CVE-2013-5914-2.png fév. 2014" /></a></p> -<h3>Screenshot 3: jumping back to the origin of the value</h3> -<p>We inquire where the value of variable <code>len</code> was last set and the GUI tells us it is at the yellow line just above the function call (pictured in the middle panel). Well hum yes we could have noticed that but it was faster to click.</p> -<p><a href="/assets/img/blog/imported-posts/CVE-2013-5914/CVE-2013-5914-3.png" title="CVE-2013-5914-3.png"><img src="/assets/img/blog/imported-posts/CVE-2013-5914/CVE-2013-5914-3s.png" alt="CVE-2013-5914-3.png" style="display:block; margin:0 auto;" title="CVE-2013-5914-3.png fév. 2014" /></a></p> -<h3>Screenshot 4: argument <code>nb_want</code> is too large</h3> -<p>The value of <code>len</code> is computed from <code>ssl_fetch_input()</code>'s argument <code>nb_want</code> and the value of <code>nb_want</code> appears to be too large <code>65540</code> for the size of the buffer that the GUI tells us we have (in the screenshot below the values computed as possible for <code>nb_want</code> are displayed in the bottom panel).</p> -<p><a href="/assets/img/blog/imported-posts/CVE-2013-5914/CVE-2013-5914-4.png" title="CVE-2013-5914-4.png"><img src="/assets/img/blog/imported-posts/CVE-2013-5914/CVE-2013-5914-4s.png" alt="CVE-2013-5914-4.png" style="display:block; margin:0 auto;" title="CVE-2013-5914-4.png fév. 2014" /></a></p> -<h3>Screenshot 5: dangerous values come from caller <code>ssl_read_record()</code></h3> -<p>A new possibility offered by the Frama-C version I am using that may not even(*) be available in the latest release Fluorine is to observe in the bottom panel which call-sites and originating call-stacks cause which values to occur in a variable. Here the GUI shows that <code>nb_want</code> appears to be <code>65540</code> when called from function <code>ssl_read_record()</code> at line 1178 in file ssl_tls.c of PolarSSL. This means we can continue the investigation there. -In contrast the value of <code>nb_want</code> can only be <code>5</code> when <code>ssl_fetch_input()</code> is called from <code>ssl_parse_client_key_exchange()</code> so there is no need to look at that function: it is definitely not part of this problem.</p> -<p>(*) I don't remember. It has been a long time has it not?</p> -<p><a href="/assets/img/blog/imported-posts/CVE-2013-5914/CVE-2013-5914-5.png" title="CVE-2013-5914-5.png"><img src="/assets/img/blog/imported-posts/CVE-2013-5914/CVE-2013-5914-5s.png" alt="CVE-2013-5914-5.png" style="display:block; margin:0 auto;" title="CVE-2013-5914-5.png fév. 2014" /></a></p> -<h3>Screenshot 6: the seemingly too large argument is <code>ssl->in_msglen</code></h3> -<p><a href="/assets/img/blog/imported-posts/CVE-2013-5914/CVE-2013-5914-6.png" title="CVE-2013-5914-6.png"><img src="/assets/img/blog/imported-posts/CVE-2013-5914/CVE-2013-5914-6s.png" alt="CVE-2013-5914-6.png" style="display:block; margin:0 auto;" title="CVE-2013-5914-6.png fév. 2014" /></a></p> -<p>The problem is that <code>ssl->in_msglen</code> is too large here. But where does it come from?</p> -<h3>Screenshot 7:</h3> -<p><code>ssl->in_msglen</code> has been computed from two bytes sent by the network (bad bad network). But the value of <code>ssl->in_msglen</code> is supposed to have been validated before being used. This is what the lines between the obtention of the value and its use are supposed to do.</p> -<p><a href="/assets/img/blog/imported-posts/CVE-2013-5914/CVE-2013-5914-7.png" title="CVE-2013-5914-7.png"><img src="/assets/img/blog/imported-posts/CVE-2013-5914/CVE-2013-5914-7s.png" alt="CVE-2013-5914-7.png" style="display:block; margin:0 auto;" title="CVE-2013-5914-7.png fév. 2014" /></a></p> -<h3>Screenshot 8:</h3> -<p><a href="/assets/img/blog/imported-posts/CVE-2013-5914/CVE-2013-5914-8.png" title="CVE-2013-5914-8.png"><img src="/assets/img/blog/imported-posts/CVE-2013-5914/CVE-2013-5914-8s.png" alt="CVE-2013-5914-8.png" style="display:block; margin:0 auto;" title="CVE-2013-5914-8.png fév. 2014" /></a></p> -<p>The value of <code>ssl->in_msglen</code> is validated when <code>ssl->minor_ver</code> is 0 and it is validated when <code>ssl->minor_ver</code> is 1. But according to the GUI <code>ssl->minor_ver</code> can be any of <code>0</code> <code>1</code> or <code>2</code>.</p> -<h3>Explanation</h3> -<p>At this point it is only a matter of confirming that the call to <code>ssl_read_record()</code> can indeed be reached with <code>ssl->minor_ver</code> set to 2. This is where one switches to existential mode possibly crafting a malicious message or simply building a convincing argument that values can converge here to cause bad things and send it to the official maintainer .</p> -<p>When I said that this was a modified PolarSSL 1.1.8 we were analyzing I cheated a little. This is a 1.1.8 version in which I have re-introduced a bug that was there from 1.0.0 to 1.1.7. The principal maintainer of PolarSSL <a href="https://polarssl.org/tech-updates/security-advisories/polarssl-security-advisory-2013-04">suggests</a> to fix the bug by replacing <code>== SSL_MINOR_VERSION_1</code> by <code>>= SSL_MINOR_VERSION_1</code>.</p> -<h2>Conclusion</h2> -<p>We have seen a <strong>second</strong> example of a real bug that can occur in an SSL implementation. Understandably in the current context there has been much speculation over the last 48 hours on the innocence of the bug in Apple's implementation. Might it be a voluntarily inserted backdoor? Is the <a href="http://daringfireball.net/2014/02/apple_prism">NSA</a> behind this bug? (I link here to John Gruber's post because he writes clearly but the same question is raised all over the Internet).</p> -<p>Allow me to put it this way: if the Apple SSL bug is a trick from the NSA then you US citizens are lucky. Our spy agency in Europe is so much better that it does not even have a name you have heard before and it is able to plant bugs where the buffer overflow leading to arbitrary code execution is three function calls away from the actual bug. The bug from our spy agency is so deniable that the code actually used to be fine when there were only two minor revisions of the SSL protocol. The backdoors from your spy agency are so lame that the Internet has opinions about them.</p> -<p>Real bugs come in all sizes and shapes. That one mistake with security implication also causes easily detectable unreachable code or wrongly-indented lines does not mean that all security flaws will be detected so easily and that plenty of quirky but functionally correct code will not be wrongly flagged.</p> -<p>Speaking of varied bugs “what about PolarSSL version 1.1.8 without the manually re-inserted bug from CVE-2013-5914?†I hear you ask. This will be the subject of another blog post.</p> -<h2>Acknowledgments</h2> -<p>Philippe Herrmann was first to use Frama-C to find a security bug in PolarSSL (Philippe's bug was a <a href="https://github.com/polarssl/polarssl/commit/e2f8ff67972a85bfc748b16b7128fee08c4dd4c0">denial of service</a> in versions up to 1.1.1 fixed in 1.1.2). -Anne Pacalet and Paul Bakker have helped me with various aspects of PolarSSL's verification including but not limited to the bug described in this post. Twitter users aloria thegrugq and johnregehr provided comments on drafts of this post. And finally the Internet made this post possible by being itself.</p> {% endraw %} diff --git a/_posts/2014-03-18-Nginx-buffer-overflow.html b/_posts/2014-03-18-Nginx-buffer-overflow.html index b5cb9ea4380faec5e371fb3251d8092096590e67..57800ebc4ee2de43a07aa1111ce69fd6357272bc 100644 --- a/_posts/2014-03-18-Nginx-buffer-overflow.html +++ b/_posts/2014-03-18-Nginx-buffer-overflow.html @@ -11,9 +11,5 @@ summary: <p>A <a href="http://nginx.org/download/patch.2014.spdy2.txt">buffer overflow</a> has been discovered in recent versions of the HTTP server Nginx.</p> <p>Hacker News user jmnicolas pondered out loud: “I wonder if this discovery is a result of OpenBSD switching its focus from Apache to Nginx?â€</p> <p>It took me one minute to understand what ey meant. I was actually wondering why OpenBSD would be putting buffer overflows in Nginx now that they are done putting buffer overflows in Apache. I mean surely there is room for one more buffer overflow in Apache?</p> -<p>The analysis of what this means about this industry and/or me is left as an exercise to the reader.</p> - <p>A <a href="http://nginx.org/download/patch.2014.spdy2.txt">buffer overflow</a> has been discovered in recent versions of the HTTP server Nginx.</p> -<p>Hacker News user jmnicolas pondered out loud: “I wonder if this discovery is a result of OpenBSD switching its focus from Apache to Nginx?â€</p> -<p>It took me one minute to understand what ey meant. I was actually wondering why OpenBSD would be putting buffer overflows in Nginx now that they are done putting buffer overflows in Apache. I mean surely there is room for one more buffer overflow in Apache?</p> <p>The analysis of what this means about this industry and/or me is left as an exercise to the reader.</p> {% endraw %} diff --git a/_posts/2014-05-19-Frama-C-blog-becomes-self-aware-author-unnecessary.html b/_posts/2014-05-19-Frama-C-blog-becomes-self-aware-author-unnecessary.html index 89983c3b53838eeea16b6c520c3e9ef67348a5fa..48e9227125a45364989897b302d02ec9a9db8c9e 100644 --- a/_posts/2014-05-19-Frama-C-blog-becomes-self-aware-author-unnecessary.html +++ b/_posts/2014-05-19-Frama-C-blog-becomes-self-aware-author-unnecessary.html @@ -20,18 +20,5 @@ The many warnings Value Analysis produced spurred me to substantially rewrite th </blockquote> <h2>A farewell</h2> <p>It is a great pleasure for me to discover that this blog has reached its independence. It has had more comments than posts for a little while and now with readers sending in their own posts I might as well move to a <a href="http://trust-in-soft.com">start-up</a> that in collaboration with my previous employer CEA LIST provides products and services based on Frama-C. I may even publish a blurb <a href="http://trust-in-soft.com/news/">there</a> from time to time when something newsworthy comes up.</p> -<p>My facetious colleague Virgile Prevosto will hopefully continue to provide insights on the more subtle aspects of ACSL's semantics here. I know I will read them.</p> - <h2>A reader's challenge</h2> -<p>A couple of days ago, faithful reader David Gil sent in a challenge:</p> -<blockquote><p>The <a href="https://github.com/gvanas/KeccakCodePackage/tree/1b2fcd2d6a02ac25136e3ef16c547ec40e10245a">reference code for Keccak/SHA-3</a> has a correctness bug in the Optimized64 implementation. Can the value analysis plugin find it?</p> -<p> -My <a href="https://github.com/gvanas/KeccakCodePackage/tree/f8195963a1ff7f6395dd86944a478e982f79a644">patch fixing that bug</a> was accepted; I believe that <a href="https://github.com/gvanas/KeccakCodePackage">the trunk</a> is correct as well. (The correctness problem was in the Optimized64 implementation.)</p> -<p> -Of course Value Analysis produces (many) warnings on the Keccak code but I was unable to find settings that provided sufficient precision to recognize this bug as especially serious. (If you would like a hint correctness depends on the color of your bird.)</p> -<p> -The many warnings Value Analysis produced spurred me to substantially rewrite the Keccak Team's implementation. My <a href="https://github.com/coruus/keccakc">version with some ASCL annotations</a> is in a very preliminary state. I am sure there are many bugs... There are some attempts at verification in the directory verification/frama-c</p> -</blockquote> -<h2>A farewell</h2> -<p>It is a great pleasure for me to discover that this blog has reached its independence. It has had more comments than posts for a little while and now with readers sending in their own posts I might as well move to a <a href="http://trust-in-soft.com">start-up</a> that in collaboration with my previous employer CEA LIST provides products and services based on Frama-C. I may even publish a blurb <a href="http://trust-in-soft.com/news/">there</a> from time to time when something newsworthy comes up.</p> <p>My facetious colleague Virgile Prevosto will hopefully continue to provide insights on the more subtle aspects of ACSL's semantics here. I know I will read them.</p> {% endraw %} diff --git a/assets/css/main.css b/assets/css/main.css index 67f0a9fed3622bedb4dd2ee28ba7e11ad9dfb56d..15f7236437de3d791ea12fc0172036b1838c3116 100644 --- a/assets/css/main.css +++ b/assets/css/main.css @@ -460,7 +460,7 @@ div#wpadminbar:hover div#wp-toolbar { left: 0; top: 0; height: 64px; - z-index: 51; + z-index: 52; } @media (min-width: 768px) { .siteHeader { @@ -551,17 +551,6 @@ div#wpadminbar:hover div#wp-toolbar { height: 4px; visibility: hidden; } -@media (max-width: 767px) { - .siteHeader.menuOpen { - height: 100%; - background: transparent; - position: fixed; - z-index: 53; - } -} -.siteHeader.menuOpen nav { - display: block; -} @media (min-width: 768px) { .siteHeader nav { display: block; @@ -598,6 +587,10 @@ div#wpadminbar:hover div#wp-toolbar { border-bottom: #f26521 1px solid; } + .menu-item.download { + display: none; + } + .siteHeader nav li a:hover { border-bottom: #f26521 1px solid; } @@ -733,68 +726,92 @@ div#wpadminbar:hover div#wp-toolbar { height: 65px; } } -.menuToggle { + +.burger { + display: inline-block; + border: 0; + background: none; + outline: 0; + padding: 0; + cursor: pointer; + border-bottom: 4px solid #f7931c; + border-radius: 2px; + width: 28px; + transition: border-bottom 1s ease-in-out; + -webkit-transition: border-bottom 1s ease-in-out; position: absolute; right: 15px; top: 15px; z-index: 62; backface-visibility: hidden; -} -.menuToggle span { - display: block; margin: 8px 0 8px 8px; - position: relative; - width: 26px; - height: 22px; -} -.menuToggle span i { - background: #f7931c; - border-radius: 8px; - display: block; - height: 4px; - width: 26px; - transition: all 0.4s; - transform: scaleY(0.8); - position: absolute; - right: 0; } -.menuToggle span i:first-child { - top: 0; -} -.menuToggle span i:first-child + i { - top: 8px; +.burger::-moz-focus-inner { + border: 0; + padding: 0; } -.menuToggle span i:first-child + i + i { - top: 16px; +.burger:before { + content: ""; + display: block; + border-bottom: 4px solid #f7931c; + border-radius: 8px; + width: 100%; + margin-bottom: 5px; + transition: -webkit-transform 0.5s ease-in-out; + transition: transform 0.5s ease-in-out; + transition: transform 0.5s ease-in-out, -webkit-transform 0.5s ease-in-out; + -webkit-transition: -webkit-transform 0.5s ease-in-out; } -.menuToggle span.close i { - background: #fff; - width: 26px; - height: 3px; +.burger:after { + content: ""; + display: block; + border-bottom: 4px solid #f7931c; + width: 100%; + margin-bottom: 5px; + border-radius: 8px; + transition: -webkit-transform 0.5s ease-in-out; + transition: transform 0.5s ease-in-out; + transition: transform 0.5s ease-in-out, -webkit-transform 0.5s ease-in-out; + -webkit-transition: -webkit-transform 0.5s ease-in-out; } -.menuToggle .close { + +.burger-check { display: none; } -.menuOpen .menuToggle .open { - display: none; + +.burger-check:checked ~ .burger { + border-bottom: 4px solid transparent; + border-radius: 0px; + transition: border-bottom 0.8s ease-in-out; + -webkit-transition: border-bottom 0.8s ease-in-out; +} +.burger-check:checked ~ .burger:before { + border-radius: 0px; + border-bottom: 4px solid white; + transform: rotate(-405deg) translateY(1px) translateX(-3px); + -webkit-transform: rotate(-405deg) translateY(1px) translateX(-3px); + transition: -webkit-transform 0.5s ease-in-out; + transition: transform 0.5s ease-in-out; + transition: transform 0.5s ease-in-out, -webkit-transform 0.5s ease-in-out; + -webkit-transition: -webkit-transform 0.5s ease-in-out; +} +.burger-check:checked ~ .burger:after { + border-radius: 0px; + border-bottom: 4px solid white; + transform: rotate(405deg) translateY(-4px) translateX(-5px); + -webkit-transform: rotate(405deg) translateY(-4px) translateX(-5px); + transition: -webkit-transform 0.5s ease-in-out; + transition: transform 0.5s ease-in-out; + transition: transform 0.5s ease-in-out, -webkit-transform 0.5s ease-in-out; + -webkit-transition: -webkit-transform 0.5s ease-in-out; } -.menuOpen .menuToggle .close { + +.burger-check:checked ~ #menu { display: block; } -.menuOpen .menuToggle span i { - transform: rotate(45deg); -} -.menuOpen .menuToggle span i:first-child { - top: 8px; - width: 26px; -} -.menuOpen .menuToggle span i:first-child + i { - transform: rotate(-45deg); - top: 8px; - width: 26px; -} + @media (min-width: 768px) { - .menuToggle { + .burger { display: none; } } diff --git a/html/get-frama-c.html b/html/get-frama-c.html index 2faa3835147f5ca412e1395661b26480de366bfe..b87508aecdd0031cd8363972710f4a058eec72f2 100644 --- a/html/get-frama-c.html +++ b/html/get-frama-c.html @@ -6,7 +6,7 @@ title: Get Frama-C <div id="wrapper" class="hfeed"> - {% include headers.html %} + {% include headers.html header="download" %} <div id="container" class="mainContainer"> <div class="getFramaC">