0% found this document useful (0 votes)
13 views

EE485 DebuggingTechniques

Uploaded by

johnkim7972
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
13 views

EE485 DebuggingTechniques

Uploaded by

johnkim7972
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 24

EE485B: Introduction to Environments & Tools

for Modern Software Development


EE485: Introduction to Environment and Tools for Modern Software Development

Lecture 6: Debugging Techniques

Acknowledgement: content borrowed from Chapter 5 of


“The Practice of Programming” by Brian Kernighan & Rob Pike
Complementary to the “Debugging” Lecture in EE209
Debugging
• Good programmers know debugging takes as much time as writing the
original code
• Some people enjoy debugging – solving a puzzle!
• Others don’t – can’t submit my homework code

3
Language Features May Help (or Not)
• Language features that prevent bugs
• Range checking of array subscripts
• Restricted pointers (or no pointers)
• Garbage collection
• String data types
• Strong type checking

• Language features that are prone to generate bugs


• Global variables
• goto statements
• Unrestricted pointers
• Automatic type conversions

4
Bugs
• What if my program crashes, prints nonsense, or hangs forever?
• Novice programmers? blame compilers, libraries, anything other than my code
• Experienced programmers? most problems are likely to be their fault

• Most bugs are simple


• Infer the bug with the stack trace, debugging output, etc.
• Requires backward reasoning: how did it happen?
• Fixing bugs is like solving a mystery (who’s done it?)

5
Easy Bugs – Common Bugs
(1) Look for common patterns
int main()
{ printf(“%d %f”, n, d);
int n;
double d = 3.14;
printf("%d %f\n", d, n);
scanf("%d", n); scanf(“%d”, &n);
return 0;
}

• Easy to detect these errors by monitoring compiler warnings-Wall)


(

$ gcc test.c -Wall


test.c:8:11: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘double’ [-Wformat=]
printf("%d %f\n", d, n);
~^
%f
test.c:8:14: warning: format ‘%f’ expects argument of type ‘double’, but argument 3 has type ‘int’ [-Wformat=]
printf("%d %f\n", d, n);
~^
%d
test.c:9:10: warning: format ‘%d’ expects argument of type ‘int *’, but argument 2 has type ‘int’ [-Wformat=]
scanf("%d", n);
~^
test.c:8:2: warning: ‘n’ is used uninitialized in this function [-Wuninitialized]
printf("%d %f\n", d, n);
^ ~~~~~~~~~~~~~~~~~~~~~~

6
Easy Bugs - Program Hangs Forever or Crashes
(2) Program hangs or crashes? Get the stack trace & where!

$ gdb yourprog
(gdb) run
^C You need to type Ctrl+C to stop the program
Program received signal SIGINT, Interrupt.
(gdb) where
#0 __GI___libc_read (fd=0, buf=0x8402470, nbytes=512) at ../sysdeps/unix/sysv/linux/read.c:27
#1 _IO_new_file_underflow (fp=0x7fffff3eba00 <_IO_2_1_stdin_>) at fileops.c:531
#2 __GI__IO_default_uflow (fp=0x7fffff3eba00 <_IO_2_1_stdin_>) at genops.c:380
#3 _IO_vfscanf_internal (s=<>, format=<>, argptr=argptr@entry=0x7ffffffee220, errp=errp@entry=0x0)
at vfscanf.c:630
#4 __isoc99_scanf (format=<optimized out>) at isoc99_scanf.c:37 Program hangs waiting for input
#5 main () at test.c:9

Similarly, you can easily find out where the program crashes

$ gdb yourprog
(gdb) run
Program received signal SIGSEGV, Segmentation fault.
0x00007fffff06f8c2 in _IO_vfscanf_internal (s=<…>, format=<…>, argptr=…, errp=…) at vfscanf.c:1898
(gdb) where
#0 _IO_vfscanf_internal (s=<…>, format=<…>, argptr=…, errp=…) at vfscanf.c:1898
#1 __isoc99_scanf (format=<optimized out>) at isoc99_scanf.c:37
#2 main () at test.c:9

7
Debugging with Core Dump
• Sometimes, your program doesnot crash only when it runs with gdb
• Why? running with gdb incurs some overhead, which might make the program
avoid the crashing course
• Run the program without gdb and make it crash with a core dump
• Core dump: a binary file that contains the program state at the time of crash

$ ./myprog

Segmentation fault (core dumped)

• Why called “core”? “core” used to mean “memory” in the past


• Novice programmers: well, I don’t see any file that looks like a “core dump” file!
• Need to set a shell variable before running the application
• To enable storing core dump – default option is to disable core dump

$ ulimit -a

core file size (blocks, -c) 0 Core dump file size is set to 0; disabled!

8
Debugging with Core Dump
• Enable core dump file: set its file size large enough
• How large? Depends on your program size, but 10MB is enough for most cases

$ ulimit –c 10000000
$ ulimit –a

core file size (blocks, -c) 10000000

• How to run gdb with core dump file?


$ ./myprog

Segmentation fault (core dumped)
$ ls core*
core
$ gdb myprog core
Core was generated by `./myrpog'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0 _IO_vfscanf_internal (s=<>, format=<>, argptr=…, errp=…) at vfscanf.c:1899
(gdb) where
#0 _IO_vfscanf_internal (s=<>, format=<>, argptr=…, errp=…) at vfscanf.c:1899
#1 __isoc99_scanf (format=<optimized out>) at isoc99_scanf.c:37
#2 main () at test.c:9

9
Gdb with core in eelab machines

• Note the location of the core file in eelab machines.

• Note a.out is compiled with –g flag. (ulimit–c unlimited)

10
Other Ways to Deal with Bugs
(3) Read before typing– resist the urge to start typing
• Hastily changing the code to see if it fixes the code would waste time
• That could introduce new bugs without fixing the original ones
• Take a break, and return - what you currently see may be what you meant, not
what you wrote!

(4) Don’t make the same mistake twice


• Copy and paste the boilerplate code from somewhere else
• And you forgot the code has a problem

(5) Debug it now, not later


• Mars Pathfinder malfunctioned once every day – could have been fixed before
launch as the engineers knew the problem (but forgot to fix!)

(6) Explain your code to someone else


• While explaining the problem, you might realize what the problem is!

11
Dealing with Difficult Bugs
• Sometimes you have no clue on what’s going on!
(1) Make the bug reproducible
• Bugs that do not manifest often are hard to debug
• See if you can construct input/parameters to reproduce the bug “reliably”

(2) Divide and conquer


• Binary search to find the problem with minimal input
• Remove the half of the input and see if the problem persists – otherwise test with
the remaining half. Repeat this until you come up with the minimal input.

(3) Study the numerology of failures


• See if the bug has some numerical pattern
• Say copy & paste loses a character at a random location. See if the location has
some pattern (e.g., the distance of missing characters is 1023 characters long)
• Then, find the source code that’s related to 1023 (like 1024). Overwrite to 1024-
th place in a string array that is erased by “null”?

12
Dealing with Hard Bugs
(4) Display output to localize your search
• Display more information (e.g., print “can’t get here”, if it should be impossible
to reach here – you can set up a breakpoint to inspect further)
• Display message in a compact fixed format – easy to find a pattern by eye or
grep (e.g., format the value in the same way – %x or %p in C/C++)
(5) Add self-checking code
• Write a check function to see whether some code leads into a weird state
• Leave the check code even after debugging (e.g., #ifdef DEBUGX … #endif)

check(“before suspect”);
/* … suspect code … */
check(“after suspect”);

/* check: test condition, print, and die */


void check(char *s) {
if (var1 > var2) {
printf(“%s: var1 %d var2 %d\n”, s, var1, var2);
fflush(stdout); /* make sure all output is out */
abort(); /* signal abnormal termination */
}
}

13
What If Nothing Works?
• What if your logic is plain wrong, but you don’t realize it’s wrong?
• Debugger (gdb) might help to elucidate the errors in your mental model

• Misconception
• Operator precedence, wrong operator, wrong indentation

if (x & 1 == 0) // why always false? while ((c == getchar()) != EOF)


… if (c = ‘\n’) break;

for (i=0; i < n; i++); // extra code


a[i++] = 0; // i++?

• Local variable that hides a global name (or global variable in local scope)

14
Non -reproducible Bugs
• Non-deterministic manifestation of bugs
• Not likely to be a bug in your algorithm
• Your code might be using information that changes each time the program runs

• Check whether all variables have been initialized


• Some variable picks up random value, which ends up producing wrong behavior

• Bugs disappear if debugging code is added?


• Likely to be a problem with dynamic memory allocation
• Writing outside the allocated memory – the behavior could change if you add
debugging code (like printf())

15
Non -reproducible Bugs
• Crashes in the middle of nowhere?
• Far away from anything that could be wrong
• Most likely problem is overwriting memory that isn’t used until much later
• Or return an address of a local variable as a pointer – recipe for delayed disaster!

char * msg(int n, char *s) {


char buf[100];
sprintf(buf, “error %d: %s\n”, n, s);
return buf;
}

• Anything wrong with the following code?

struct X *p, *nextp;


for (p = listp; p != NULL; p = nextp) {
free(p);
nextp = p->next;
}

16
Debugging Memory Management

• Some debugging techniques are specific todynamic memory management


• That is, to memory managed by malloc(), calloc(), realloc(), and free()

17
Debugging Memory Management (cont.)

• Look for familiar dynamic memory management bugs


• Some popular ones:

int *p; /* value of p undefined */


… Dangling pointer
*p = somevalue;

int *p;
… Dangling pointer
p = (int*)malloc(sizeof(int));

free(p);

*p = 5;

18
Debugging Memory Management (cont.)

• Look for familiar dynamic memory management bugs (cont.)


• Some popular ones:

int *p; Memory leak


… alias
p = (int*)malloc(sizeof(int));
… Garbage creation
p = (int*)malloc(sizeof(int));

Detection: Valgrind, etc.

int *p;

p = (int*)malloc(sizeof(int));
Multiple free

free(p); Detection: man malloc,

free(p); MALLOC_CHECK_

19
Debugging Memory Management (cont.)

• Look for familiar dynamic memory management bugs (cont.)


• Some popular ones:

char *s1 = "Hello";


char *s2; Allocating too few bytes
s2 = (char*)malloc(strlen(s1));
strcpy(s2, s1);

Allocating too few bytes


char *s1 = "Hello";
char *s2;
on 32-bit OS.
s2 = (char*)malloc(sizeof(s1)); On 64-bit OS, malloc()
strcpy(s2, s1); allocates 8 bytes (no problem)

double *p;
Allocating too few bytes
p = (double*)malloc(sizeof(double*)); on 32-bit OS.
On 64-bit OS, malloc()
allocates 8 bytes (no problem)

20
Debugging Memory Management (cont.)

• Segmentation fault? Make it happen within gdb, and then issue the gdb
“where” command. The output will lead you to the line that caused the fault.
(But that line may not be where the error resides.)

• Manually inspect each call of malloc(), calloc(), and realloc() in your code,
making sure that it allocates enough memory

• Temporarily hardcode each call of malloc(), calloc(), and realloc() such that it
requests a large number of bytes. If the error disappears, you'll know that at
least one of your calls is requesting too few bytes

21
Debugging Memory Management (cont.)

• Temporarily comment- out each call of free() in your code.If the error
disappears, then you'll know that you're freeing memory too soon, freeing
memory that already has been freed, or freeing memory that should not be
freed, etc.

22
Assignment for Lecture 6
• Due Next Friday 10:25AM
• This homework is open-ended, and there’s no “right” answer
• As long as you submit the homework with relevant comments, you’ll get full credit!
• Homework description:
• If you take EE209, share with us your debugging experience for assignment 2 of
EE209. Did you use gdb? If so, briefly explain why you used it and if it was useful to
debug it with gdb. Point out any techniques in Lectures 5 or 6 that were useful in
doing assignment 2 of EE209. If you did not use gdb, explain why not. Explain any
non-gdb techniques that were useful to debug your assignment code.
• If you do not take EE209, please point out what techniques in Lectures 5/6 would
be most useful to you, and explain why. If you have any recent C
programming/debugging experience, explain what was the most difficult in terms of
debugging. Any relevant story is fine.
• Write your comments into a PDF file (named YourStudentID.pdf)

23
24

You might also like