COMP 348: Principles of
Programming Languages
Section 6: Profiling and
Debugging
Section 6 Topics
• Program safety in C
• Debugging
– Stack traces
– Breakpoints
– Examining variables
• Profiling
– Tools
– Examining output
6-2
Program safety
• C programming can be more error prone
than is the case with more “modern”
languages.
– No bounds checking on arrays
– Complex string handling
– Manual memory management
– Obscure pointer-related errors
• While experienced C programmers will
make fewer errors, it is still quite easy to
create programs that will fail at run-time
6-3
Finding problems
• Good C programming should build upon (at
least) the following practices
1. Always compile with warnings enabled and fix
these warnings as early as possible.
2. Compile in “debug mode” and use the
debugger to track down problems.
3. Once the code is compiling, profile your
running code to discover additional problems
4. Use a proper testing environment (e.g., unit
testing)
6-4
Debugging
• Most contemporary languages include a debugger
– In the case of gcc, this is gdb
• gdb is a command line tool, but most IDEs provide
a graphical “wrapper” plugin that allows you to use
the debugger much more intuitively.
• IMPORTANT: In order to use gdb effectively, you
must include the “-g” switch on the command line.
– The –g switch will instruct the compiler to include symbol
table information in the executable.
– The debugger needs the additional information in order to
display useful information about variables and line
numbers
gcc –Wall –g myFile.c
6-5
Graphical debugging
• As noted, it is possible to use the command line version
of the debugger.
• However, Eclipse (and other IDEs) provides a GUI
debugger “perspective” with the C/C++ plugin.
– Access it by opening the Debug perspective under the
Window menu
• In order to run a debug session, you may need to set up
a “debug configuration”
– This can be accessed under the “bug” icon
– Various options, including command line arguments can be
set here.
• Note that eclipse will, by default, compile your code
with the –g switch when you use the “hammer” icon.
• So the typical debug sequence is:
– Compile within Eclipse with the hammer icon
– Then switch to the Debug perspective.
6-6
Basic debugging
• In the top left corner of the Debug window,
you will see the main controls
Step ahead one
Step ahead line, and over
Run/continue terminate one line, and functions, if
into functions, necessary
if necessary
6-7
Stack trace
• When a program fails, you often see a “segmentation
fault”
• In the top left window, a stack trace is printed
• Work upwards to find the point in your code at which
the error was produced
– In this case, at line 31 in the copy() function
6-8
Breakpoints
• We can set breakpoints at one or more lines
– Typically, this is by right-clicking at the line number
• When “run/continue” is chosen, the debugger will
stop here
6-9
Variable values
• In the top right window, we can see the values of
all variables in the current scope
• Below, we can see that new_string has a NULL
value
– This looks “suspicious”
6-10
Last word on debugging
• Debugging, especially for C programs, takes
some practice and experience
• There are a lot of other debugger options
– For example, we can define “watch points” that will
stop the debugger when a variable changes value.
• Bottom line: Learn to debug your programs
properly WITH a debugger
– Print statements are for toy programs
– They are completely inappropriate for large complex
applications.
Source file: profiling.c
6-11
Profiling
• In contrast to debugging, profiling works by
analyzing code for you.
• It is particularly useful for finding memory
leaks and bounds errors.
• While good commercial tools exists for
profiling C code, there are also very good (and
free) open source tools.
• We will use valgrind in this section
• valgrind is often available already on Linux/
Unix systems but can be downloaded and
installed quite easily.
6-12
Running valgrind
• valgrind has a lot of options, many of them
very obscure, but a basic invocation would
be:
valgrind –-leak-check=yes myApp
• This will send a report to the screen that
includes a listing of
– invalid reads/writes
– Memory allocation problems
• Like the debugger, valgrind includes stack
traces to help identify the location of problems
6-13
NULL pointers
• Processing invalid pointers typically leads to program
crashes.
• Typically we can find these errors either with a
debugger or a profiler.
• In the latter case, valgrind may give an error like:
==94470== Invalid read of size 1
==94470== at 0x4C2DD94: strcat (in /usr/lib/
valgrind/vgpreload_memcheck-amd64-linux.so)
==94470== by 0x4005E7: copy (profiling.c:31)
==94470== by 0x4005A7: main (profiling.c:22)
==94470== Address 0x0 is not stack'd, malloc'd
or (recently) free'd
6-14
Out of bounds errors
• As discussed, accessing arrays outside their memory
limits produce undefined results
– The code or may not seem to work
– But this is very dangerous
• Below, we see detects and “off-by-one” error when
processing an array
==94813== Invalid read of size 4
==94813== at 0x400676: print_array (profiling.c:50)
==94813== by 0x4005DA: main (profiling.c:27)
==94813== Address 0x51fc050 is 0 bytes after a block
of size 16 alloc'd
==94813== at 0x4C2AB80: malloc (in /usr/lib/
valgrind/vgpreload_memcheck-amd64-linux.so)
==94813== by 0x400626: print_array (profiling.c:41)
==94813== by 0x4005DA: main (profiling.c:27)
6-15
Memory allocation errors
• Memory leaks are very hard to find with the
“eyeball” test.
• valgrind can make this almost trivial
– Below, we can see how we have malloc’d an array on
line 41 but we have not freed’d it
==94813== HEAP SUMMARY:
==94813== in use at exit: 16 bytes in 1 blocks
==94813== total heap usage: 1 allocs, 0 frees, 16
bytes allocated
==94813==
==94813== 16 bytes in 1 blocks are definitely lost in
loss record 1 of 1
==94813== at 0x4C2AB80: malloc (in /usr/lib/
valgrind/vgpreload_memcheck-amd64-linux.so)
==94813== by 0x400626: print_array (profiling.c:41)
==94813== by 0x4005DA: main (profiling.c:27) 6-16
Final thoughts on C
• At first glance, C is not a large language.
– Note that we have only touched on a portion of its
syntax.
• However, its low level functionality brings both
great power and great risks.
• Still, it remains a very important language due
to its enormous installed base.
– There is a good chance you will code in C at some
point in your careers.
• In addition, a deeper understanding of C will
help you better appreciate the features of
languages that have been developed more
recently.
– …and will be discussed in this course.
6-17