Skip to content
Snippets Groups Projects
2011-01-27-On-memcpy-part-1-the-source-code-approach.html 27.4 KiB
Newer Older
---
layout: post
author: Pascal Cuoq
date: 2011-01-27 13:58 +0200
categories: memcpy value
format: xhtml
title: "On memcpy (part 1: the source code approach)"
summary: 
---
{% raw %}
<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&lt;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 = &amp;a; 
  s.q = Frama_C_nondet_ptr(&amp;a  &amp;b); 
  s.i = Frama_C_interval(17  42); 
  s.j = 456; 
  s.d = Frama_C_double_interval(3.0  7.0); 
  memcpy(&amp;d  &amp;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 ∈ {{ &amp;a ;}} 
           .q ∈ {{ &amp;a ; &amp;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 &amp;{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>&amp;a</code> and <code>&amp;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 ∈ {{ &amp;a ;}} 
           .q ∈ {{ &amp;a ; &amp;b ;}} 
           .i ∈ [17..42] 
           .d ∈ [3. .. 7.] 
           .j ∈ {456; } 
          d.p ∈ {{ &amp;a ;}} 
           .q[bits 0 to 7]# ∈ {{ &amp;a ; &amp;b ;}} misaligned 0%32  
           .q[bits 8 to 15]# ∈ {{ &amp;a ; &amp;b ;}} misaligned 0%32  
           .q[bits 16 to 23]# ∈ {{ &amp;a ; &amp;b ;}} misaligned 0%32  
           .q[bits 24 to 31]# ∈ {{ &amp;a ; &amp;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>{{ &amp;a ; &amp;b ;}} misaligned 0%32</code> and bit 8 to 31 of <code>{{ &amp;a ; &amp;b ;}} misaligned 0%32</code> into <code>{{ &amp;a ; &amp;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(&amp;a  &amp;b); 
  int *q = Frama_C_nondet_ptr(&amp;a  &amp;b); 
  *(char*)&amp;p = *(char*)&amp;q; 
</pre> 
<p>After analyzing this piece of code  the value analysis predicts for <code>p</code>:</p> 
<pre>          p[bits 0 to 7]# ∈ {{ &amp;a ; &amp;b ;}} misaligned 0%32  
           [bits 8 to 31]# ∈ {{ &amp;a ; &amp;b ;}} misaligned 0%32  
</pre> 
<p>It would be incorrect to predict that <code>p</code> contains {{ &amp;a ; &amp;b ;}} here  because the first call to <code>Frama_C_nondet_ptr</code> may return <code>&amp;a</code> while the second one returns <code>&amp;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 {{ &amp;a ; }} (or { 456; })  which implies that properly ordered slices when put side by side can only rebuild &amp;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 ∈ {{ &amp;d ;}} 
        sp ∈ {{ &amp;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 ∈ {{ &amp;d ;}} 
        sp ∈ {{ &amp;s ;}} 
        d.p[bits 0 to 7]# ∈ {{ &amp;a ;}} misaligned 0%32  
         {.p[bits 8 to 31]; .q; .i; .d; .j; } ∈ UNINITIALIZED 
        i ∈ {0; 1; } 
        dp ∈ {{ &amp;d + {0; 1; } ;}} 
        sp ∈ {{ &amp;s + {0; 1; } ;}} 
        d.p[bits 0 to 15] ∈ 
         {{ garbled mix of &amp;{a; } (origin: Merge {m.c:12; }) }} or UNINITIALIZED 
         {.p[bits 16 to 31]; .q; .i; .d; .j; } ∈ UNINITIALIZED 
        i ∈ {0; 1; 2; } 
        dp ∈ {{ &amp;d + {0; 1; 2; } ;}} 
        sp ∈ {{ &amp;s + {0; 1; 2; } ;}} 
        d.p[bits 0 to 23] ∈ 
         {{ garbled mix of &amp;{a; } (origin: Merge {m.c:12; }) }} or UNINITIALIZED 
         {.p[bits 24 to 31]; .q; .i; .d; .j; } ∈ UNINITIALIZED 
        i ∈ {0; 1; 2; 3; } 
        dp ∈ {{ &amp;d + {0; 1; 2; 3; } ;}} 
        sp ∈ {{ &amp;s + {0; 1; 2; 3; } ;}} 
        d.p ∈ 
         {{ garbled mix of &amp;{a; } (origin: Merge {m.c:12; }) }} or UNINITIALIZED 
         {.q; .i; .d; .j; } ∈ UNINITIALIZED 
        i ∈ {0; 1; 2; 3; 4; } 
        dp ∈ {{ &amp;d + {0; 1; 2; 3; 4; } ;}} 
        sp ∈ {{ &amp;s + {0; 1; 2; 3; 4; } ;}} 
        d{.p; .q[bits 0 to 7]; } ∈ 
         {{ garbled mix of &amp;{a; b; } (origin: Merge {m.c:12; }) }} or UNINITIALIZED 
         {.q[bits 8 to 31]; .i; .d; .j; } ∈ UNINITIALIZED 
        i ∈ [0..15] 
        dp ∈ {{ &amp;d + {0; 1; 2; 3; 4; 5; } ;}} 
        sp ∈ {{ &amp;s + {0; 1; 2; 3; 4; 5; } ;}} 
        d{.p; .q[bits 0 to 15]; } ∈ 
         {{ garbled mix of &amp;{a; b; } (origin: Merge {m.c:12; }) }} or UNINITIALIZED 
         {.q[bits 16 to 31]; .i; .d; .j; } ∈ UNINITIALIZED 
        i ∈ [0..16] 
        dp ∈ {{ &amp;d + {0; 1; 2; 3; 4; 5; 6; } ;}} 
        sp ∈ {{ &amp;s + {0; 1; 2; 3; 4; 5; 6; } ;}} 
        d{.p; .q[bits 0 to 23]; } ∈ 
         {{ garbled mix of &amp;{a; b; } (origin: Merge {m.c:12; }) }} or UNINITIALIZED 
         {.q[bits 24 to 31]; .i; .d; .j; } ∈ UNINITIALIZED 
        i ∈ [0..23] 
        dp ∈ {{ &amp;d + [0..7] ;}} 
        sp ∈ {{ &amp;s + [0..7] ;}} 
        d{.p; .q; } ∈ 
         {{ garbled mix of &amp;{a; b; } (origin: Merge {m.c:12; }) }} or UNINITIALIZED 
         {.i; .d; .j; } ∈ UNINITIALIZED 
        i ∈ [0..23] 
        dp ∈ {{ &amp;d + [0..8] ;}} 
        sp ∈ {{ &amp;s + [0..8] ;}} 
        d{.p; .q; .i[bits 0 to 7]; } ∈ 
         {{ garbled mix of &amp;{a; b; } (origin: Merge {m.c:12; }) }} or UNINITIALIZED 
         {.i[bits 8 to 31]; .d; .j; } ∈ UNINITIALIZED 
        i ∈ [0..23] 
        dp ∈ {{ &amp;d + [0..15] ;}} 
        sp ∈ {{ &amp;s + [0..15] ;}} 
        d{.p; .q; .i; .d[bits 0 to 31]; } ∈ 
         {{ garbled mix of &amp;{a; b; } (origin: Merge {m.c:12; }) }} or UNINITIALIZED 
         {.d[bits 32 to 63]; .j; } ∈ UNINITIALIZED 
        i ∈ [0..23] 
        dp ∈ {{ &amp;d + [0..16] ;}} 
        sp ∈ {{ &amp;s + [0..16] ;}} 
        d{.p; .q; .i; .d[bits 0 to 39]; } ∈ 
         {{ garbled mix of &amp;{a; b; } (origin: Merge {m.c:12; }) }} or UNINITIALIZED 
         {.d[bits 40 to 63]; .j; } ∈ UNINITIALIZED 
        i ∈ [0..23] 
        dp ∈ {{ &amp;d + [0..23] ;}} 
        sp ∈ {{ &amp;s + [0..23] ;}} 
        d ∈ 
         {{ garbled mix of &amp;{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 ∈ {{ &amp;d ;}} 
        sp ∈ {{ &amp;s ;}} 
        d ∈ 
         {{ garbled mix of &amp;{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&lt;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 = &amp;a; 
  s.q = Frama_C_nondet_ptr(&amp;a  &amp;b); 
  s.i = Frama_C_interval(17  42); 
  s.j = 456; 
  s.d = Frama_C_double_interval(3.0  7.0); 
  memcpy(&amp;d  &amp;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 ∈ {{ &amp;a ;}} 
           .q ∈ {{ &amp;a ; &amp;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 &amp;{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>&amp;a</code> and <code>&amp;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 ∈ {{ &amp;a ;}} 
           .q ∈ {{ &amp;a ; &amp;b ;}} 
           .i ∈ [17..42] 
           .d ∈ [3. .. 7.] 
           .j ∈ {456; } 
          d.p ∈ {{ &amp;a ;}} 
           .q[bits 0 to 7]# ∈ {{ &amp;a ; &amp;b ;}} misaligned 0%32  
           .q[bits 8 to 15]# ∈ {{ &amp;a ; &amp;b ;}} misaligned 0%32  
           .q[bits 16 to 23]# ∈ {{ &amp;a ; &amp;b ;}} misaligned 0%32  
           .q[bits 24 to 31]# ∈ {{ &amp;a ; &amp;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>{{ &amp;a ; &amp;b ;}} misaligned 0%32</code> and bit 8 to 31 of <code>{{ &amp;a ; &amp;b ;}} misaligned 0%32</code> into <code>{{ &amp;a ; &amp;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(&amp;a  &amp;b); 
  int *q = Frama_C_nondet_ptr(&amp;a  &amp;b); 
  *(char*)&amp;p = *(char*)&amp;q; 
</pre> 
<p>After analyzing this piece of code  the value analysis predicts for <code>p</code>:</p> 
<pre>          p[bits 0 to 7]# ∈ {{ &amp;a ; &amp;b ;}} misaligned 0%32  
           [bits 8 to 31]# ∈ {{ &amp;a ; &amp;b ;}} misaligned 0%32  
</pre> 
<p>It would be incorrect to predict that <code>p</code> contains {{ &amp;a ; &amp;b ;}} here  because the first call to <code>Frama_C_nondet_ptr</code> may return <code>&amp;a</code> while the second one returns <code>&amp;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 {{ &amp;a ; }} (or { 456; })  which implies that properly ordered slices when put side by side can only rebuild &amp;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 ∈ {{ &amp;d ;}} 
        sp ∈ {{ &amp;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 ∈ {{ &amp;d ;}} 
        sp ∈ {{ &amp;s ;}} 
        d.p[bits 0 to 7]# ∈ {{ &amp;a ;}} misaligned 0%32  
         {.p[bits 8 to 31]; .q; .i; .d; .j; } ∈ UNINITIALIZED 
        i ∈ {0; 1; } 
        dp ∈ {{ &amp;d + {0; 1; } ;}} 
        sp ∈ {{ &amp;s + {0; 1; } ;}} 
        d.p[bits 0 to 15] ∈ 
         {{ garbled mix of &amp;{a; } (origin: Merge {m.c:12; }) }} or UNINITIALIZED 
         {.p[bits 16 to 31]; .q; .i; .d; .j; } ∈ UNINITIALIZED 
        i ∈ {0; 1; 2; } 
        dp ∈ {{ &amp;d + {0; 1; 2; } ;}} 
        sp ∈ {{ &amp;s + {0; 1; 2; } ;}} 
        d.p[bits 0 to 23] ∈ 
         {{ garbled mix of &amp;{a; } (origin: Merge {m.c:12; }) }} or UNINITIALIZED 
         {.p[bits 24 to 31]; .q; .i; .d; .j; } ∈ UNINITIALIZED 
        i ∈ {0; 1; 2; 3; } 
        dp ∈ {{ &amp;d + {0; 1; 2; 3; } ;}} 
        sp ∈ {{ &amp;s + {0; 1; 2; 3; } ;}} 
        d.p ∈ 
         {{ garbled mix of &amp;{a; } (origin: Merge {m.c:12; }) }} or UNINITIALIZED 
         {.q; .i; .d; .j; } ∈ UNINITIALIZED 
        i ∈ {0; 1; 2; 3; 4; } 
        dp ∈ {{ &amp;d + {0; 1; 2; 3; 4; } ;}} 
        sp ∈ {{ &amp;s + {0; 1; 2; 3; 4; } ;}} 
        d{.p; .q[bits 0 to 7]; } ∈ 
         {{ garbled mix of &amp;{a; b; } (origin: Merge {m.c:12; }) }} or UNINITIALIZED 
         {.q[bits 8 to 31]; .i; .d; .j; } ∈ UNINITIALIZED 
        i ∈ [0..15] 
        dp ∈ {{ &amp;d + {0; 1; 2; 3; 4; 5; } ;}} 
        sp ∈ {{ &amp;s + {0; 1; 2; 3; 4; 5; } ;}} 
        d{.p; .q[bits 0 to 15]; } ∈ 
         {{ garbled mix of &amp;{a; b; } (origin: Merge {m.c:12; }) }} or UNINITIALIZED 
         {.q[bits 16 to 31]; .i; .d; .j; } ∈ UNINITIALIZED 
        i ∈ [0..16] 
        dp ∈ {{ &amp;d + {0; 1; 2; 3; 4; 5; 6; } ;}} 
        sp ∈ {{ &amp;s + {0; 1; 2; 3; 4; 5; 6; } ;}} 
        d{.p; .q[bits 0 to 23]; } ∈ 
         {{ garbled mix of &amp;{a; b; } (origin: Merge {m.c:12; }) }} or UNINITIALIZED 
         {.q[bits 24 to 31]; .i; .d; .j; } ∈ UNINITIALIZED 
        i ∈ [0..23] 
        dp ∈ {{ &amp;d + [0..7] ;}} 
        sp ∈ {{ &amp;s + [0..7] ;}} 
        d{.p; .q; } ∈ 
         {{ garbled mix of &amp;{a; b; } (origin: Merge {m.c:12; }) }} or UNINITIALIZED 
         {.i; .d; .j; } ∈ UNINITIALIZED 
        i ∈ [0..23] 
        dp ∈ {{ &amp;d + [0..8] ;}} 
        sp ∈ {{ &amp;s + [0..8] ;}} 
        d{.p; .q; .i[bits 0 to 7]; } ∈ 
         {{ garbled mix of &amp;{a; b; } (origin: Merge {m.c:12; }) }} or UNINITIALIZED 
         {.i[bits 8 to 31]; .d; .j; } ∈ UNINITIALIZED 
        i ∈ [0..23] 
        dp ∈ {{ &amp;d + [0..15] ;}} 
        sp ∈ {{ &amp;s + [0..15] ;}} 
        d{.p; .q; .i; .d[bits 0 to 31]; } ∈ 
         {{ garbled mix of &amp;{a; b; } (origin: Merge {m.c:12; }) }} or UNINITIALIZED 
         {.d[bits 32 to 63]; .j; } ∈ UNINITIALIZED 
        i ∈ [0..23] 
        dp ∈ {{ &amp;d + [0..16] ;}} 
        sp ∈ {{ &amp;s + [0..16] ;}} 
        d{.p; .q; .i; .d[bits 0 to 39]; } ∈ 
         {{ garbled mix of &amp;{a; b; } (origin: Merge {m.c:12; }) }} or UNINITIALIZED 
         {.d[bits 40 to 63]; .j; } ∈ UNINITIALIZED 
        i ∈ [0..23] 
        dp ∈ {{ &amp;d + [0..23] ;}} 
        sp ∈ {{ &amp;s + [0..23] ;}} 
        d ∈ 
         {{ garbled mix of &amp;{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 ∈ {{ &amp;d ;}} 
        sp ∈ {{ &amp;s ;}} 
        d ∈ 
         {{ garbled mix of &amp;{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 %}