Example of use of debugging tools: I was given the enclosed version of the program for Problem I of Homework 2. I was told that the program fails with a bus error in the form given below, but works correctly if the strings are read in from the keyboard (scanf() or cin) instead of from the command line. The person who wrote the program asked me what the problem was. As you know, my answer to questions about program bugs is "Use a debugger; use a debugger; use a debugger;..." Here is how to use a debugger in this case. (I used gdb in order to have a record in this text file, but would otherwise have used DDD for greater convenience.) Recall that a bus error occurs if we attempt a word access with an address not divisible by 4. So, I had to find out why that was happening. First, I ran the program under gdb without any breakpoints, in order to determine WHERE the bus error was occurring: (gdb) r abcd abce 4 Starting program: /home/matloff/c1 abcd abce 4 warning: Unable to find __d_pid symbol in object file. warning: Suggest linking with /usr/lib/end.o. warning: GDB will be unable to track shl_load/shl_unload calls General comparison result is -1 String S1 'abcd' less than string S2 'abce' strcmp comparison result is -1 Big Endian comparison Program received signal SIGBUS, Bus error. 0x3430 in bestrcmp (S1=0x7b03a011 "abcd", S2=0x7b03a016 "abce", N=4) at compare.c:49 49 if (*ptr1 - *ptr2 < 0) Aha! Since we got a bus error, one of these two pointers was not divisible by 4. Not only that, but we can see it was probably ptr1, because we see above that S1 = 0x7b03a011. Let's check: (gdb) p ptr1 $1 = (int *) 0x7b03a011 Yep, sure enough! Now, why did that occur? Well, S1 came from argv[1], as seen in the source code: S1=argv[1]; So, the problem arose was caused by argv[1] not starting on a word boundary. SO, WE'VE FOUND THE SOURCE OF OUR BUG IN JUST 2 MINUTES, USING THE DEBUGGER. Now, why did argv[1] not start at a word boundary? Well, why should it? It's just a string, not an integer, and the operating system put it in the first spot the OS found to be free. This happened to be at 0x7b03a011. To fix the problem, the person who wrote the program would have to copy the string to a place which is guaranteed to start at a word boundary. The most convenient way to ensure this is to copy the string to an int array. NM Script started on Wed Jan 30 12:55:01 2002 hp16% cat compare.c #include #include int genstrcmp(char *S1, char *S2, int N) { int count=1; /* when count = N then the comparison stops */ char *ptr1,*ptr2; /* make ptr1 and ptr2 point to the first character in S1 and S2 respectively */ ptr1=(char *)S1; ptr2=(char *)S2; /* do <= N comparisons */ while (count<=N) { if (*ptr1 - *ptr2 < 0) { /* S1 less than S2 */ return -1; } else if (*ptr1 - *ptr2 > 0) { /* S1 greater than S2 */ return 1; } else { /* count character of both S1 and S2 are equal */ count++; ptr1++; ptr2++; } } /* the strings are equal */ return 0; } int bestrcmp(char *S1, char *S2, int N) { int *ptr1=(int *)S1; int *ptr2=(int *)S2; int wcount,i=1; wcount = N/4; /* count the number of words in N . Strings are supposed to start and end on word boundaries */ while (i<=wcount) { if (*ptr1 - *ptr2 < 0) { /* S1 less than S2 */ return -1; } else if (*ptr1 - *ptr2 > 0) { /* S1 greater than S2 */ return 1; } else { /* count character of both S1 and S2 are equal */ i++; ptr1++; ptr2++; } } /* the strings are equal */ return 0; } int main(int argc, char *argv[]) { char *S1, *S2; int N,result; /* get N, S1 and S2 from the user */ S1=argv[1]; S2=argv[2]; N=atoi(argv[3]); /* call GenStrCmp */ printf("\nGeneral comparison \n"); result=genstrcmp(S1,S2,N); printf("result is %d \n",result); if (result == -1) { printf("String S1 '%s' less than string S2 '%s' \n",S1,S2); } else if (result == 1) { printf("String S2 '%s' greater than string S1 '%s' \n",S2,S1); } else printf("String S1 '%s' and string S2 '%s' are the same \n",S1,S2); /* strcmp */ result=strcmp(S1,S2); printf("\nstrcmp comparison result is %d\n",result); /* call BEStrCmp */ printf("\nBig Endian comparison \n"); result=bestrcmp(S1,S2,N); printf("result is %d \n",result); if (result == -1) { printf("String S1 '%s' less than string S2 '%s' \n",S1,S2); } else if (result == 1) { printf("String S2 '%s' greater than string S1 '%s' \n",S2,S1); } else printf("String S1 '%s' and string S2 '%s' are the same \n",S1,S2); printf("\n"); return 0; } hp16% gcc -g -o c1 compare.c hp16% c1 abcd abce 4 General comparison result is -1 String S1 'abcd' less than string S2 'abce' strcmp comparison result is -1 Big Endian comparison Bus error hp16% gdb c1 GDB is free software and you are welcome to distribute copies of it under certain conditions; type "show copying" to see the conditions. There is absolutely no warranty for GDB; type "show warranty" for details. GDB 4.16 (hppa1.1-hp-hpux10.10), Copyright 1996 Free Software Foundation, Inc... (gdb) r abcd abce 4 Starting program: /home/matloff/c1 abcd abce 4 warning: Unable to find __d_pid symbol in object file. warning: Suggest linking with /usr/lib/end.o. warning: GDB will be unable to track shl_load/shl_unload calls General comparison result is -1 String S1 'abcd' less than string S2 'abce' strcmp comparison result is -1 Big Endian comparison Program received signal SIGBUS, Bus error. 0x3430 in bestrcmp (S1=0x7b03a011 "abcd", S2=0x7b03a016 "abce", N=4) at compare.c:49 49 if (*ptr1 - *ptr2 < 0) (gdb) p ptr1 $1 = (int *) 0x7b03a011 (gdb) q The program is running. Quit anyway (and kill it)? (y or n) y hp16% e exit script done on Wed Jan 30 13:00:10 2002