---
title: Eboard 12  Understanding your code, continued
number: 12
section: eboards
held: 2017-04-27
---
CSC 282.01, Class 12:  Understanding your code, continued
=========================================================

_Overview_

* Preliminaries
    * Good things to do
* Other memory problems
* Two examPles
* Tracing errors with `gdb`
* Checking memory usage with `valgrind`
* Designing `malloc`

### Good things to do

* CS Extras, Today: Project Gadfly
* CS Extras, Next Week: Inclusion in CS (PLEASE ATTEND)

The joy of segfaults
--------------------

Why might your program segfault?

* When you reference something that doesn't exist.
     * `perpetual_motion_machine = 3`
     * Referencing a non-existent field is a compiler error
       `mac.field = 2`.
* Go too far in an array.
     * Files may behave differently
* You attempt to write your own linked lists, and you are not yet 
  competent.
* malloc and free
     * Assign to pointer that has not been allocated

What problems do (novice) programmers have with malloc and free?

* Assigning using pointers that do not have correspoinding allocated
  space.
* Forgetting to free: Memory leaks.
* Double freeing.
* Referencing things after you free them.
* Allocating the wrong size 
    * E.g., `malloc (sizeof (struct thingy *))` rather than
      `malloc (sizeof (struct thingy))`.

What do you do when your program segfaults?

* Find someone who knows C better than I do and ask for help.
* Rely on my knowledge of likely causes of errors and think carefully
  about any places in the code.
* Use some strange tool that Sam doesn't know to backtrace it.
* Use `gdb` to backtrace it.
* Add lots of print statements!  (Sam would prefer that you not make this
  regular practice.)
* Binary search on code.  (Comment out half ...)
* Use another language that provides you with less pure joy.
* `valgrind`

Other memory problems
---------------------

What memory issues might crop up that don't cause (immediate) segfaults?

* Go too far in an array.
* Use lower level memory stuff poorly.
* Use `memcpy` and don't pay attention to amount of memory you're
  copying.
* The joy of phantom errors caused by freeing.
* Using memory on the stack (after stack has been popped).
* Stack overflow.

What happens if you free twice?

* Our implementation of `malloc` seems to pay attention to this issue.

How do you find those issues?

* Use `gdb` and walk through the program until things go wrong.
* Use `valgrind`

A Silly Example
---------------

```
/**
 * square.c
 *   A simple program that looks at a simple form of something like map
 *   in C.
 */

// +---------+---------------------------------------------------------
// | Headers |
// +---------+

#include <stdio.h>

// +-----------+-------------------------------------------------------
// | Constants |
// +-----------+

/**
 * The number of items in our array.
 */
#define N 4

// +---------+---------------------------------------------------------
// | Helpers |
// +---------+

/**
 * Some functions.
 */
static int 
fun (int i)
{
  return i*i;
} // fun


// +------+------------------------------------------------------------
// | Main |
// +------+

int
main (int argc, char *argv[])
{
  int size = N;
  int values[N];
  int i;

  // Do the mapping
  for (i = 0; i <= size; i++)
    {
      values[i] = fun (i);
    } // for

  // Sum the results
  int sum = 0;
  for (i = 0; i <= size; i++)
    sum += values[i];

  // Print the results
  printf ("The sum of the first %d squares is %d.\n", N, sum);

  // And we're done
  return 0;
} // main
```

Another strange program
-----------------------

```
/**
 * some weird memory errors, or so I hope.
 */

// +---------+-------------------------------------------------------
// | Headers |
// +---------+

#include <stdlib.h>

// +---------+-------------------------------------------------------
// | Helpers |
// +---------+

void
silly (int *a)
{
  int i;
  for (i = 0; i < 16; i++)
    {
      a[i] = i;
    }
} // silly

// +------+----------------------------------------------------------
// | Main |
// +------+

int
main (int argc, char *argv[])
{
  int *a;
  int *b;
  a = (int *) malloc (16);
  b = (int *) malloc (11);
  silly (a);
  free (b);
  return 0;
} // main
```

What went wrong?

* Perhaps there is metadata about `b` after the end of `a` that
  we are overwriting.  (E.g., the size of `b`.)

Designing `malloc`
------------------

How does `free` likely work?

For `malloc`, we keep a giant linked list of memory.

* How do you keep track of how big a chunk is.

Tracing errors with `gdb`
-------------------------

When you get a segfault, it's easy to get a "big picture view"

```
$ gdb program
$ run
<segfault>
$ bt
```

Stepping through a program with `gdb`

```
$ gdb program
$ break line ; or proc
$ run command-line-params
$ print variable
$ step
$ next
$ continue ; until next breakpoint
```

Checking memory usage with `valgrind`
-------------------------------------

```
$ valgrind program
```

