title: c : gdb : Overwriting and freeing too much memory
body: <p>Using a very simple sample that uses 2 pointers. 
  Pointer 1 (s1_buffer) is malloc then memset. 
  Pointer 2 (s2_buffer) is malloc then memset right afterward so the location would hopefully be close to Pointer 1 (which it is).</p>
  
  <p>Granted it isn't the preferred method of using pointers and structs but it is being done to mimic other code. The objective is to understand what is happening behind the scenes and what gdb is showing. </p>
  
  <p>Here is the code :</p>
  
  <pre><code>#include &lt;stdio.h&gt;
  #include &lt;stdlib.h&gt;
  
  typedef struct
      {
      struct
          {
          int a;
          int b;
          int c;
          int d;
          } n_s;
      int    e;
      } struct1;
  
  
  typedef struct
      {
      char  aa[5];
      int   bb;
      } struct2;
  
  int main () {
  
     struct1      s1;
     struct2      s2;
     int *        s1_buffer = (int*) 0;
     int *        s2_buffer = (int*) 0;
  
     printf("Size...\n");
     printf("     s1 : %d\n", sizeof (struct1));
     printf("     s2 : %d\n", sizeof (struct2));
  
     int numOfElements  = 1;
  
     s1_buffer = ( int*) malloc((numOfElements * sizeof (struct1)));
     memset((int *)s1_buffer, 0, (numOfElements * sizeof (struct1)));
  
     s2_buffer = ( int*) malloc((numOfElements * sizeof (struct2)));
     memset((int *)s2_buffer, 0, (numOfElements * sizeof (struct2)));
  
  
     //The following shows that the memory locations are close to each other. 
     printf("\nMemory Location... \n");
     printf("     s1_buffer    : %p\n", s1_buffer);
     printf("     s2_buffer    : %p\n", s2_buffer);
  
     numOfElements  = 2;
  
     //Here a memset is done WITHOUT doing a malloc and since the size is 
     //now twice as large Pointer 1's area should overwrite Pointer 2's memory. 
     memset((int *)s1_buffer, 0, (numOfElements * sizeof (struct1)));
  
     printf("\nFreeing Memory... \n");
     printf("   s1_buffer\n");
     free(s1_buffer);
     printf("   s2_buffer\n");
     free(s2_buffer);
  
     return(0);
  }
  </code></pre>
  
  <p>Running the program produces the following output.</p>
  
  <pre><code>&gt; ./memFreeTest
  Size...
       s1 : 20
       s2 : 12
  
  Memory Location...
       s1_buffer    : 0x16a6010
       s2_buffer    : 0x16a6030
  
  Freeing Memory...
     s1_buffer
  *** Error in `./memFreeTest': free(): invalid next size (fast): 0x00000000016a6010 ***
  ======= Backtrace: =========
  /usr/lib64/libc.so.6(+0x7c503)[0x2af569904503]
  ./memFreeTest[0x4007b1]
  /usr/lib64/libc.so.6(__libc_start_main+0xf5)[0x2af5698a9b35]
  ./memFreeTest[0x400589]
  ======= Memory map: ========
  </code></pre>
  
  <p>Based on the addresses of s1_buffer and s2_buffer, they are within 32 bytes of each other. When the 2nd memset of s1_buffer is done, it should step on s2_buffer area. </p>
  
  <p>Analyzing the core file via gdb, the following is seen after the "disassemble main" call and viewing the registers. </p>
  
  <pre><code>   0x0000000000400779 &lt;+300&gt;:   shl    $0x2,%rax
     0x000000000040077d &lt;+304&gt;:   mov    %rax,%rdx
     0x0000000000400780 &lt;+307&gt;:   mov    -0x8(%rbp),%rax
     0x0000000000400784 &lt;+311&gt;:   mov    $0x0,%esi
     0x0000000000400789 &lt;+316&gt;:   mov    %rax,%rdi
  </code></pre>
  
  <p>The following is the 2nd memset.</p>
  
  <pre><code>   0x000000000040078c &lt;+319&gt;:   callq  0x400520 &lt;memset@plt&gt;
  </code></pre>
  
  <p>Why is it moving the value $0x4008c9 to edi?</p>
  
  <pre><code>   0x0000000000400791 &lt;+324&gt;:   mov    $0x4008c9,%edi
     0x0000000000400796 &lt;+329&gt;:   callq  0x400500 &lt;puts@plt&gt;
     0x000000000040079b &lt;+334&gt;:   mov    $0x4008dd,%edi
     0x00000000004007a0 &lt;+339&gt;:   callq  0x400500 &lt;puts@plt&gt;
     0x00000000004007a5 &lt;+344&gt;:   mov    -0x8(%rbp),%rax
     0x00000000004007a9 &lt;+348&gt;:   mov    %rax,%rdi
     0x00000000004007ac &lt;+351&gt;:   callq  0x4004f0 &lt;free@plt&gt;
  </code></pre>
  
  <p>The next line is where it fails. 
  Why is it moving the value $0x4008ea to edi?</p>
  
  <p>I am referring to edi as it seems to be where the failure occurred. </p>
  
  <pre><code>=&gt; 0x00000000004007b1 &lt;+356&gt;:   mov    $0x4008ea,%edi
  </code></pre>
  
  <p>Checking edi and it appears to be valid :</p>
  
  <pre><code> (gdb) info reg edi
   edi            0x19569  103785
  </code></pre>
  
  <p>The dgb ouput continues here :</p>
  
  <pre><code>   0x00000000004007b6 &lt;+361&gt;:   callq  0x400500 &lt;puts@plt&gt;
     0x00000000004007bb &lt;+366&gt;:   mov    -0x10(%rbp),%rax
     0x00000000004007bf &lt;+370&gt;:   mov    %rax,%rdi
     0x00000000004007c2 &lt;+373&gt;:   callq  0x4004f0 &lt;free@plt&gt;
     0x00000000004007c7 &lt;+378&gt;:   mov    $0x0,%eax
     0x00000000004007cc &lt;+383&gt;:   leaveq
     0x00000000004007cd &lt;+384&gt;:   retq
  End of assembler dump.
  (gdb) info reg
  rax            0x0      0
  rbx            0x0      0
  rcx            0xffffffffffffffff       -1
  rdx            0x6      6
  rsi            0x19569  103785
  rdi            0x19569  103785
  rbp            0x7ffdc0b23440   0x7ffdc0b23440
  rsp            0x7ffdc0b23400   0x7ffdc0b23400
  r8             0x2af5699fe840   47233527441472
  r9             0x2af569886000   47233525899264
  r10            0x8      8
  r11            0x246    582
  r12            0x400560 4195680
  r13            0x7ffdc0b23520   140727836357920
  r14            0x0      0
  r15            0x0      0
  rip            0x4007b1 0x4007b1 &lt;main+356&gt;
  eflags         0x246    [ PF ZF IF ]
  cs             0x33     51
  ss             0x2b     43
  ds             0x0      0
  es             0x0      0
  fs             0x0      0
  gs             0x0      0
  (gdb) info reg edi
  edi            0x19569  103785
  </code></pre>
  
  <p>The core file occurs on the 1st free. How does it know this memory is not "owned" by s1_buffer? </p>
  
  <p>If it knows it doesn't "own" it to free it, why didn't it know it didn't own the area being memset? Seems like an error or warning should have appeared at that time. </p>