CSc 352 Debugging Tools
Uninitialized pointers
str was never initialized to point to anything
2
Uninitialized pointers
Suppose this was a program of realistic size.
How would we identify the location and reason for the problem?
3
Locating the problem: gdb
load the program into gdb
run the program within gdb
show where execution stopped
show values of variables
4
Memory error diagnosis: valgrind
invoking the tool:
valgrind progName arg1 arg2 …
indicates:
(1) there was a problem; (2) what happened
(3) where it happened
5
Dangling pointers
We looked at this code earlier:
runtime stack
string
main
my_read
read_string
a
c
buf
str
b
a
dangling pointer!
6
Dangling pointers
Minor variation on this code:
7
Dangling pointers
the code seems to work!!! (on hedgehog.cs.arizona.edu)
8
Dangling pointers
doesn’t work
(on lectura.cs.arizona.edu)
9
What’s going on?
the array padding[ ] “protects” buf[ ] from getting overwritten — so the code seems to work (on some machines)
main
my_read
strlen
runtime stack
padding[ ]
a
a
c
buf[ ]
b
a
read_string
10
More diagnosis
11
Summary
• Just because a program produces the expected output doesn’t mean that it’s correct
– the observed behavior may be accidental
– the observed behavior may be system-dependent
• Use valgrind to check whether the execution was free of memory errors
– provides information only about one execution • other executions may contain erroneous behaviors
– provides some help in identifying where the error occurred.
12
Another example
Bad! Not protecting against buffer overflow. Would lose points!
13
Example 2
out of bounds memory access
14
Example 2
where the invalid memory access occurred,
(incl. stack trace)
where this memory was allocated
(incl. stack trace)
15
Example 3
off-by-one problem fixed
Bad! Not protecting against buffer overflow. Would lose points!
16
Example 3
17
Compiling with -g
• In the examples listed above, valgrind gave the function where the error occurred, but not the line number.
• Togetthelinenumber,thecompiledprogrammust have additional “tracking” information.
• Using the “-g” flag when compiling will add that information.
• To be really useful when using valgrind or gdb, you should compile with the -g flag.
18
Compiling with -g
• Not that compiling with the -g flag is good for debugging, but creates slower code (nothing is free)
• Because of this, many programmers use the -g flag when developing, but compile without it when the code is finished and debugged.
19
gdb: basic functionality
• Interactive debugger
– allows the user to run a program and interactively examine its execution. Features include:
• breakpoints (“run until control reaches here, then prompt user”) • stack backtrace (chain of calls leading to some point in the code) • examination of program variables
• Usage:
– compile program using
gcc –g…
– invoke the program as
gdb prog (then supply arguments inside gdb)
20
Interactive debugging: gdb
expected behavior
buggy behavior
21
gdb: example usage
invocation
set a breakpoint
in this case: at entry to main()
start execution specify command-line arguments here
execution reaches breakpoint and returns control to user
examine the program
move to next statement
22
gdb: Looking at the program
“list the program source around the line number specified”
23
gdb
set a breakpoint here
24
gdb
execution reaches breakpoint and returns control to user
single-step through the execution
25
gdb
examine program state
continue to next breakpoint
26
gdb
27
gdb: moving around the runtime stack
where did the Seg Fault occur?
move up the stack (i.e., to the caller) to examine variable values
28
gdb: other features
• Gdbprovidesmanyotherdebuggingfeatures,e.g.: – conditional breakpoints
•
• “break execution at some point in the code and return control to the user if some condition holds”
– watchpoints
• “break execution and return control to user if a variable is read or
written’
– change the value of a variable in the program state
Look for tutorials on the web
29