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 thanmalloc (sizeof (struct thingy)).
- E.g.,
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
gdbto 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
memcpyand 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
mallocseems to pay attention to this issue.
How do you find those issues?
- Use
gdband 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
bafter the end ofathat we are overwriting. (E.g., the size ofb.)
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