CSE 374 Programming Concepts and Tools
Lecture 10 - Memory Leaks
This week
Today
Monday: Dynamic Memory Allocation
Today: Memory Leaks
Friday: Debugging, GDB
Reviewing malloc and free
Memory Examples and Demos
Valgrind: Detecting memory leaks
Discussion
Turn and talk:
Should memory safety be the programmer’s responsibility or the language’s responsibility?
What are the tradeoffs between having the programmer manage memory directly versus relying on the language to enforce safety? In what kinds of situations might one approach be preferable over the other?
Review: malloc()
Usage:
Returns a void* to uninitialized heap memory
Cast void* pointer to known type
sizeof() makes code portable to different machines
4
type* var = (type*) malloc(n * sizeof(type))
Review: free()
Usage:
Pointer must point to the first byte of heap-allocated memory
Pointer is unaffected by call to free
Rule of thumb: for every call to malloc there should be one call to free
5
free(pointer);
Example: Heap and Stack
Initialized data
7
#include <stdlib.h>
int* copy(int a[], int size) {
int i, *a2;
a2 = (int*) malloc(size*sizeof(int));
if (a2 == NULL)
return NULL;
for (i = 0; i < size; i++)
a2[i] = a[i];
return a2;
}
int main(int argc, char** argv) {
int nums[4] = {1, 2, 3, 4};
int* ncopy = copy(nums, 4);
// .. do stuff with the array ..
free(ncopy);
return EXIT_SUCCESS;
}
OS kernel [protected]
Stack
Heap (malloc/free)
Globals
Code
main
ncopy
nums
Note: Arrow points to next line to run.
main local variables in stack
8
#include <stdlib.h>
int* copy(int a[], int size) {
int i, *a2;
a2 = (int*) malloc(size*sizeof(int));
if (a2 == NULL)
return NULL;
for (i = 0; i < size; i++)
a2[i] = a[i];
return a2;
}
int main(int argc, char** argv) {
int nums[4] = {1, 2, 3, 4};
int* ncopy = copy(nums, 4);
// .. do stuff with the array ..
free(ncopy);
return EXIT_SUCCESS;
}
OS kernel [protected]
Stack
Heap (malloc/free)
Globals
Code
main
ncopy
nums
1
2
3
4
copy local variables in stack
9
#include <stdlib.h>
int* copy(int a[], int size) {
int i, *a2;
a2 = (int*) malloc(size*sizeof(int));
if (a2 == NULL)
return NULL;
for (i = 0; i < size; i++)
a2[i] = a[i];
return a2;
}
int main(int argc, char** argv) {
int nums[4] = {1, 2, 3, 4};
int* ncopy = copy(nums, 4);
// .. do stuff with the array ..
free(ncopy);
return EXIT_SUCCESS;
}
OS kernel [protected]
Stack
Heap (malloc/free)
Globals
Code
main
ncopy
copy
a
size
4
nums
1
2
3
4
i
a2
malloc space for int array
10
#include <stdlib.h>
int* copy(int a[], int size) {
int i, *a2;
a2 = (int*) malloc(size*sizeof(int));
if (a2 == NULL)
return NULL;
for (i = 0; i < size; i++)
a2[i] = a[i];
return a2;
}
int main(int argc, char** argv) {
int nums[4] = {1, 2, 3, 4};
int* ncopy = copy(nums, 4);
// .. do stuff with the array ..
free(ncopy);
return EXIT_SUCCESS;
}
OS kernel [protected]
Stack
Heap (malloc/free)
Globals
Code
malloc
main
ncopy
copy
a
size
4
nums
1
2
3
4
i
a2
malloc space for int array
11
#include <stdlib.h>
int* copy(int a[], int size) {
int i, *a2;
a2 = (int*) malloc(size*sizeof(int));
if (a2 == NULL)
return NULL;
for (i = 0; i < size; i++)
a2[i] = a[i];
return a2;
}
int main(int argc, char** argv) {
int nums[4] = {1, 2, 3, 4};
int* ncopy = copy(nums, 4);
// .. do stuff with the array ..
free(ncopy);
return EXIT_SUCCESS;
}
OS kernel [protected]
Stack
Heap (malloc/free)
Globals
Code
main
ncopy
copy
a
size
4
nums
1
2
3
4
i
a2
Fill available space from local variables
12
#include <stdlib.h>
int* copy(int a[], int size) {
int i, *a2;
a2 = (int*) malloc(size*sizeof(int));
if (a2 == NULL)
return NULL;
for (i = 0; i < size; i++)
a2[i] = a[i];
return a2;
}
int main(int argc, char** argv) {
int nums[4] = {1, 2, 3, 4};
int* ncopy = copy(nums, 4);
// .. do stuff with the array ..
free(ncopy);
return EXIT_SUCCESS;
}
OS kernel [protected]
Stack
Heap (malloc/free)
Globals
Code
main
ncopy
copy
a
size
4
nums
1
2
3
4
i
0
a2
Fill available space from local variables
13
#include <stdlib.h>
int* copy(int a[], int size) {
int i, *a2;
a2 = (int*) malloc(size*sizeof(int));
if (a2 == NULL)
return NULL;
for (i = 0; i < size; i++)
a2[i] = a[i];
return a2;
}
int main(int argc, char** argv) {
int nums[4] = {1, 2, 3, 4};
int* ncopy = copy(nums, 4);
// .. do stuff with the array ..
free(ncopy);
return EXIT_SUCCESS;
}
OS kernel [protected]
Stack
Heap (malloc/free)
Globals
Code
1
2
3
4
main
ncopy
copy
a
size
4
nums
1
2
3
4
i
4
a2
Finish copy and free stack space
14
#include <stdlib.h>
int* copy(int a[], int size) {
int i, *a2;
a2 = (int*) malloc(size*sizeof(int));
if (a2 == NULL)
return NULL;
for (i = 0; i < size; i++)
a2[i] = a[i];
return a2;
}
int main(int argc, char** argv) {
int nums[4] = {1, 2, 3, 4};
int* ncopy = copy(nums, 4);
// .. do stuff with the array ..
free(ncopy);
return EXIT_SUCCESS;
}
OS kernel [protected]
Stack
Heap (malloc/free)
Globals
Code
1
2
3
4
main
ncopy
nums
1
2
3
4
Do stuff with the array…
15
#include <stdlib.h>
int* copy(int a[], int size) {
int i, *a2;
a2 = (int*) malloc(size*sizeof(int));
if (a2 == NULL)
return NULL;
for (i = 0; i < size; i++)
a2[i] = a[i];
return a2;
}
int main(int argc, char** argv) {
int nums[4] = {1, 2, 3, 4};
int* ncopy = copy(nums, 4);
// .. do stuff with the array ..
free(ncopy);
return EXIT_SUCCESS;
}
OS kernel [protected]
Stack
Heap (malloc/free)
Globals
Code
1
2
3
4
main
ncopy
nums
1
2
3
4
free ncopy from heap
16
#include <stdlib.h>
int* copy(int a[], int size) {
int i, *a2;
a2 = (int*) malloc(size*sizeof(int));
if (a2 == NULL)
return NULL;
for (i = 0; i < size; i++)
a2[i] = a[i];
return a2;
}
int main(int argc, char** argv) {
int nums[4] = {1, 2, 3, 4};
int* ncopy = copy(nums, 4);
// .. do stuff with the array ..
free(ncopy);
return EXIT_SUCCESS;
}
OS kernel [protected]
Stack
Heap (malloc/free)
Globals
Code
main
ncopy
nums
1
2
3
4
free
Exit
17
#include <stdlib.h>
int* copy(int a[], int size) {
int i, *a2;
a2 = (int*) malloc(size*sizeof(int));
if (a2 == NULL)
return NULL;
for (i = 0; i < size; i++)
a2[i] = a[i];
return a2;
}
int main(int argc, char** argv) {
int nums[4] = {1, 2, 3, 4};
int* ncopy = copy(nums, 4);
// .. do stuff with the array ..
free(ncopy);
return EXIT_SUCCESS;
}
OS kernel [protected]
Stack
Heap (malloc/free)
Globals
Code
main
ncopy
nums
1
2
3
4
Polling Time!
Please answer in the LP10 assignment on Gradescope!
Which line(s)�contain a memory error?
Select all that apply.
18
#include <stdlib.h>
int main(int argc, char** argv) {
int a[2];
int* b = (int*) malloc(2*sizeof(int));
a[2] = 5;
b[0] += 2;
free(&(a[0]));
free(b);
free(b);
b[0] = 5;
return EXIT_SUCCESS;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Demo: corrupt mem
19
Memory Errors
What is wrong here?
int x[] = {1, 2, 3};
free(x);
x is a local variable stored in stack, cannot be freed !
Common Memory Errors
22
Memory Leak
A memory leak occurs when code fails to deallocate dynamically-allocated memory that is no longer used
The Consequences: program’s memory will keep growing
23
Memory Leaks in Production
Memory leaks occur in reality all of the time.
Developers need to resolve the issue, otherwise the system crashes.
24
Find the Bug!
Find That Bug! 🐞1
26
#define LEN 8
int arr[LEN];
for (int i = 0; i <= LEN; i++) {
arr[i] = 0;
}
Error Type:
Fix:
Improper bounds checking
27
#define LEN 8
int arr[LEN];
for (int i = 0; i <= LEN; i++) {
arr[i] = 0;
}
Error Type:
E
Fix: i < LEN
Find That Bug! 🐞2
28
int* foo() {
int val = 0;
return &val;
}
Error Type:
Fix:
Dangling pointer
29
int* foo() {
int val = 0;
return &val;
}
Error Type:
G
Fix: Allocate val dynamically (via malloc)
Find That Bug! 🐞3
30
// Create a matrix of N by M
int** p;
p = (int**)malloc(N * sizeof(int));
for (int i = 0; i < N; i++) {
p[i] = (int*)malloc(M * sizeof(int));
}
Error Type:
Fix:
Wrong allocation size
31
// Create a matrix of N by M
int** p;
p = (int**)malloc(N * sizeof(int));
for (int i = 0; i < N; i++) {
p[i] = (int*)malloc(M * sizeof(int));
}
Error Type:
H
Fix: N * sizeof(int*)
Find That Bug! 🐞4
32
int sum_int(int* arr, int len) {
int sum;
for (int i = 0; i < len; i++) {
sum += arr[i];
}
return sum;
}
Error Type:
Fix:
Invalid read
33
int sum_int(int* arr, int len) {
int sum;
for (int i = 0; i < len; i++) {
sum += arr[i];
}
return sum;
}
Error Type:
F
Fix: int sum = 0;
Aside: scanf
printf prints variables to stdout using format specifiers
scanf reads in values from stdin using format specifiers
int age;
printf("What is your age? ");
scanf("%d", &age);
printf("You are %d years old\n", age);
34
Demo: scanf
35
Find That Bug! 🐞5
The classic scanf bug
int scanf(const char* format, ...)
36
long val;
scanf("%ld", val);
Error Type:
Fix:
Dereferencing a non-pointer
The classic scanf bug
int scanf(const char* format, ...)
37
long val;
scanf("%ld", val);
Error Type:
A
Fix: &val
Find That Bug! 🐞6
38
x = (int*)malloc(N * sizeof(int));
… // manipulate x
free(x);
…
y = (int*)malloc(M * sizeof(int));
… // manipulate y
free(x);
Error Type:
Fix:
Double free
39
x = (int*)malloc(N * sizeof(int));
… // manipulate x
free(x);
…
y = (int*)malloc(M * sizeof(int));
… // manipulate y
free(x);
Error Type:
C
Fix: free(y)
Find That Bug! 🐞7
40
x = (int*)malloc(M * sizeof(int));
// manipulate x
free(x);
// ...
y = (int*)malloc(M * sizeof(int));
for (int i = 0; i < M; i++) {
y[i] = x[i];
}
Error Type:
Fix:
Accessing already freed memory
41
x = (int*)malloc(M * sizeof(int));
// manipulate x
free(x);
// ...
y = (int*)malloc(M * sizeof(int));
for (int i = 0; i < M; i++) {
y[i] = x[i];
}
Error Type:
B
Fix: move free(x) after for loop
Find That Bug! 🐞8
42
int foo() {
int* arr = (int*)malloc(sizeof(int) * N);
read_n_ints(N, arr);
int sum = 0;
for(int i = 0; i < N; i++) {
sum += arr[i];
}
return sum;
}
Error Type:
Fix:
Memory leak - failing to free memory
43
int foo() {
int* arr = (int*)malloc(sizeof(int) * N);
read_n_ints(N, arr);
int sum = 0;
for(int i = 0; i < N; i++) {
sum += arr[i];
}
return sum;
}
Error Type:
D
Fix: add free(arr) before returning
Finding and Fixing Memory Errors
Valgrind is a tool that simulates your program to find memory errors
It can detect all of the errors we just talked about! 😲
It catches pointer errors during execution, prints summary of heap usage, including details of memory leaks
valgrind [options] ./myprogram args args...
44
Valgrind Isn’t Perfect
Valgrind isn’t guaranteed to find all your memory problems.
For example, a memory leak might only manifest for a specific user input!
45
Demo: Valgrind
46
Assignment Reminders
EX8 due Friday 7/18 @10:49am
HW3: Wordcount due this Friday 7/18 @11:59pm
Make sure to submit LP10 before the next class as well.
All of these assignments can be found on our course's Gradescope page.