Low-level programming provides a lot of power… a lot of responsibility… and a lot of bugs (often hard to find)
Example sources of problems:
Fortunately we can instruct C compiler to embed debugging symbols in the executable:
cc -g -o main main.c
valgrind
) is MemcheckCode:
#include <stdio.h>
int main() {
int n;
("%d", &n);
scanf
int y;
if (n % 2 == 0) {
= 2;
y }
++;
yfor (int i = 0; i < 10; i++) {
("%d\n", y + i);
printf}
return 0;
}
Execution:
$ cc -g -o main main.c
$ echo 2 | ./main
3
4
5
6
7
8
9
10
11
12
$ echo 1 | ./main
-1976115535
-1976115534
-1976115533
-1976115532
-1976115531
-1976115530
-1976115529
-1976115528
-1976115527
-1976115526
Task:
valgrind ./main
valgrind --track-origins=yes ./main
Code:
#include <stdio.h>
#include <stdlib.h>
int main() {
int n;
("%d", &n);
scanf
// alloc a NxN matrix
int **t = malloc(n * sizeof(*t));
for (int i = 0; i < n; i++)
[i] = malloc(n * sizeof(*t[i]));
t
// do some matrix operations
// ...
// ...
// ...
// free the matrix
(t);
freereturn 0;
}
Execution:
$ cc -g -o main main.c
$ echo 10 | ./main
Task:
Execute the program using Valgrind
Try different numbers typed on input
Observe section LEAK SUMMARY
in Valigrind’s
output
Rerun Valgrind with open --leak-check=full
A correct code should contain this message from Valgrind:
All heap blocks were freed -- no leaks are possible
What should be changed in the code to achieve that?
Code:
#include <stdio.h>
int main() {
int t[4] = { 1, 2, 3, 4 };
for (unsigned int i = 3; i >= 0; i--) {
[i] -= 1;
t("%d\n", t[i]);
printf}
return 0;
}
Execution:
$ cc -g -o main main.c
$ ./main
3
2
1
0
Bus error (core dumped)
Task:
gdb ./main
run
backtrace full
Code:
#include <stdio.h>
int f(int p, int r) {
if (p == r)
return p;
return f(p + 1, r - 1);
}
int main() {
int p, r;
("%d %d", &p, &r);
scanf("%d\n", f(p, r));
printfreturn 0;
}
Execution:
$ cc -g -o main main.c
$ echo 0 6 | ./main
3
$ echo 0 5 | ./main
Segmentation fault (core dumped)
Task:
run
(remember that the program waits
for two integers for scanf
so write 0 5
and
press enter after executing run
in GDB)backtrace full
if
statement to make it work?Code:
#include <stdio.h>
#include <stdlib.h>
void f(char *p, int n) {
for (int i = 0; i < n; i++) {
[i] += 1;
p}
}
int main() {
char buffer[8] = "abcdefgh";
int length = sizeof(buffer);
(buffer, length + 1);
freturn 0;
}
Execution:
$ cc -g -o main main.c
$ ./main
*** stack smashing detected ***: terminated
Interrupted (core dumped)
Task:
Try executing it under Valgrind
Try compiling it with:
$ cc -g -fsanitize=address -o main main.c
Does it help to find the source of problem?
If not, execute the program under GDB
You can use break
to set a breakpoint in desired
code location
You can use step
instead of next
to go
into a function call
The code was supposed to modify abcdefgh
into
bcdefghi
. Can you fix the error to achieve that?
xyz
, the result was
abc
”)