Skip to main content

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