Skip to content

Commit

Permalink
Add checker for lab 4
Browse files Browse the repository at this point in the history
Add the checker which will test for memory leaks.

Signed-off-by: Mihnea Firoiu <[email protected]>
  • Loading branch information
Mihnea0Firoiu authored and teodutu committed Oct 27, 2024
1 parent 08dcf1d commit 6018837
Show file tree
Hide file tree
Showing 9 changed files with 283 additions and 30 deletions.
Original file line number Diff line number Diff line change
@@ -1,3 +1 @@
/memory_leak
/memory_leak_malloc
/mem.trace
support/
10 changes: 10 additions & 0 deletions chapters/data/investigate-memory/guides/memory-leak/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
PYTHON = python3
SCRIPT = generate_skels.py

skels:
mkdir -p support/src/
$(PYTHON) $(SCRIPT) --input ./solution/src/ --output ./support/src/
cp -r solution/tests/ support/tests

clean:
rm -rf support/
70 changes: 47 additions & 23 deletions chapters/data/investigate-memory/guides/memory-leak/README.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
# Memory Leaks

A memory leak occurs when we lose reference to a memory area.
That is, a pointer used to point to a memory area.
And then it's pointing to a new memory area and the old memory area is lost.
A memory leak happens when a memory region is allocated but no longer accessible.
This typically occurs when a pointer that referenced a memory area is redirected to a new memory location, leaving the original memory area unreachable and unable to be freed.

Enter the `chapters/data/investigate-memory/guides/memory-leak/support` directory.
Enter the `chapters/data/investigate-memory/guides/memory-leak` folder, run `make skels`.
Enter the `chapters/data/investigate-memory/guides/memory-leak/support/src` directory.
It stores two files showing memory leaks:

- one in C++: `memory_leak.cpp`
- one in C: `memory_leak_malloc`
- one in C: `memory_leak_malloc.c`

Let's build and run the two executables:

```console
student@os:~/.../memory-leak/support$ make
student@os:~/.../memory-leak/support/src$ make
g++ -c -o memory_leak.o memory_leak.cpp
cc memory_leak.o -lstdc++ -o memory_leak
cc -c -o memory_leak_malloc.o memory_leak_malloc.c
Expand All @@ -23,25 +23,25 @@ cc memory_leak_malloc.o -lstdc++ -o memory_leak_malloc
Running them yields similar output:

```console
student@os:~/.../memory-leak/support$ ./memory_leak
Andrei Popescu is 22 years old and likes Linux
Ioana David is 23 years old and likes macOS
student@os:~/.../lab/support/memory-leak$ ./memory_leak_malloc
Andrei Popescu is 22 years old and likes Linux
Ioana David is 23 years old and likes macOS
student@os:~/.../memory-leak/support/src$ ./memory_leak
Linus Torvalds is 22 years old and likes Linux
Steve Jobs is 23 years old and likes macOS
student@os:~/.../memory-leak/support/src$ ./memory_leak_malloc
Linus Torvalds is 22 years old and likes Linux
Steve Jobs is 23 years old and likes macOS
```

We investigate the memory leaks of the two programs by using [Valgrind](https://valgrind.org/):

```console
student@os:~/.../memory-leak/support$ valgrind ./memory_leak
student@os:~/.../memory-leak/support/src$ valgrind ./memory_leak
==22362== Memcheck, a memory error detector
==22362== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==22362== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==22362== Command: ./memory_leak
==22362==
Andrei Popescu is 22 years old and likes Linux
Ioana David is 23 years old and likes macOS
Linus Torvalds is 22 years old and likes Linux
Steve Jobs is 23 years old and likes macOS
==22362==
==22362== HEAP SUMMARY:
==22362== in use at exit: 72 bytes in 1 blocks
Expand All @@ -58,14 +58,14 @@ Ioana David is 23 years old and likes macOS
==22362== For counts of detected and suppressed errors, rerun with: -v
==22362== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

student@os:~/.../memory-leak/support$ valgrind ./memory_leak_malloc
student@os:~/.../memory-leak/support/src$ valgrind ./memory_leak_malloc
==22369== Memcheck, a memory error detector
==22369== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==22369== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==22369== Command: ./memory_leak_malloc
==22369==
Andrei Popescu is 22 years old and likes Linux
Ioana David is 23 years old and likes macOS
Linus Torvalds is 22 years old and likes Linux
Steve Jobs is 23 years old and likes macOS
==22369==
==22369== HEAP SUMMARY:
==22369== in use at exit: 148 bytes in 1 blocks
Expand Down Expand Up @@ -93,15 +93,15 @@ We probably also require to preload the libc `malloc` debugging library, so we u
Note that the file path used for `LD_PRELOAD` may need to be updated, depending on your distribution:

```console
student@os:~/.../memory-leak/support$ LD_PRELOAD=/lib/x86_64-linux-gnu/libc_malloc_debug.so.0 MALLOC_TRACE=mem.trace ./memory_leak_malloc
Andrei Popescu is 22 years old and likes Linux
Ioana David is 23 years old and likes macOS
student@os:~/.../memory-leak/support/src$ LD_PRELOAD=/lib/x86_64-linux-gnu/libc_malloc_debug.so.0 MALLOC_TRACE=mem.trace ./memory_leak_malloc
Linus Torvalds is 22 years old and likes Linux
Steve Jobs is 23 years old and likes macOS
```

Subsequently, we use the `mtrace` tool to show information about the leaked data:

```console
student@os:~/.../memory-leak/support$ mtrace ./memory_leak_malloc mem.trace
student@os:~/.../memory-leak/support/src$ mtrace ./memory_leak_malloc mem.trace

Memory not freed:
-----------------
Expand All @@ -119,4 +119,28 @@ Valgrind is however more powerful: it works on different types of memory (not on
1. Print the size of the `Student` class and the `struct student` structure to see if it equates to the leak shown by Valgrind.

1. Solve the memory leaks in both programs.
Validate with Valgrind.
Run the checker (`./checker.sh` in the `memory-leak/support/tests/` folder) to check your results.

Sample run:

```console
student@so:~/.../support/tests/$ ./checker.sh
make: Entering directory '/home/student/operating-systems/chapters/data/investigate-memory/guides/memory-leak/support/src'
g++ -c -o memory_leak.o memory_leak.cpp
cc memory_leak.o -lstdc++ -o memory_leak
cc -c -o memory_leak_malloc.o memory_leak_malloc.c
cc memory_leak_malloc.o -lstdc++ -o memory_leak_malloc
make: Leaving directory '/home/student/operating-systems/chapters/data/investigate-memory/guides/memory-leak/support/src'
-------------------------------------------------
Checking memory leaks for C executable: ../src/memory_leak
C executable is leak-free!

Points for ../src/memory_leak: 50/50
-------------------------------------------------
Checking memory leaks for C++ executable: ../src/memory_leak_malloc
C++ executable is leak-free!

Points for ../src/memory_leak_malloc: 50/50
-------------------------------------------------
Total Points: 100/100
```
151 changes: 151 additions & 0 deletions chapters/data/investigate-memory/guides/memory-leak/generate_skels.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
#!/usr/bin/python3 -u
# SPDX-License-Identifier: BSD-3-Clause

import sys
import argparse
import os.path
import re


def process_file(src, dst, pattern, replace, remove, replace_pairs, end_string=None):
if not pattern or not replace or not remove:
print(
f"ERROR: The script behaviour is not properly specified for {src}",
file=sys.stderr,
)
sys.exit(1)

fin = open(src, "r")
fout = open(dst, "w")
remove_lines = 0
skip_lines = 0
uncomment_lines = 0
end_found = True

for l in fin.readlines():
# Skip generation of file.
if "SKIP_GENERATE" in l:
fout.close()
os.remove(dst)
return

if end_string and end_found == False:
fout.write(l)
if end_string in l:
end_found = True
continue

if remove_lines > 0:
remove_lines -= 1
continue

if skip_lines > 0:
skip_lines -= 1
m = re.search(pattern, l)
if m:
l = "%s%s\n" % (m.group(1), m.group(3))
fout.write(l)
continue

if uncomment_lines > 0:
uncomment_lines -= 1
for fro, to in replace_pairs:
l = re.sub(fro, to, l)
fout.write(l)
continue

m = re.search(pattern, l)
if m:
if m.group(2):
skip_lines = int(m.group(2))
else:
skip_lines = 1

if end_string and end_string not in l:
end_found = False

l = "%s%s\n" % (m.group(1), m.group(3))

m = re.search(replace, l)
if m:
if m.group(2):
uncomment_lines = int(m.group(2))
else:
uncomment_lines = 1
continue

m = re.search(remove, l)
if m:
if m.group(2):
remove_lines = int(m.group(2))
else:
remove_lines = 1
continue

fout.write(l)

fout.close()


def main():
parser = argparse.ArgumentParser(
description="Generate skeletons sources from reference solution sources"
)
parser.add_argument(
"--input", help="input directory to process files", required=True
)
parser.add_argument(
"--output", help="output directory to copy processed files", required=True
)
args = parser.parse_args()

for root, dirs, files in os.walk(args.input):
new_root = os.path.join(args.output, os.path.relpath(root, args.input))
for d in dirs:
os.makedirs(os.path.join(new_root, d), exist_ok=True)

for src in files:
if (
re.match("Makefile.*$", src)
or re.match(r".*\.sh$", src)
or re.match(r".*\.[sS]$", src)
or re.match(r".*\.py$", src)
):
pattern = r"(^\s*#\s*TODO)( [0-9]*)(:.*)"
replace = r"(^\s*#\s*REPLACE)( [0-9]*)"
remove = r"(^\s*#\s*REMOVE)( [0-9]*)"
replace_pairs = [("# ", "")]
end_string = None
elif re.match(r".*\.asm$", src):
pattern = r"(^\s*;\s*TODO)( [0-9]*)(:.*)"
replace = r"(^\s*;\s*REPLACE)( [0-9]*)"
remove = r"(^\s*;\s*REMOVE)( [0-9]*)"
replace_pairs = [("; ", "")]
end_string = None
elif (
re.match(r".*\.[ch]$", src)
or re.match(r".*\.cpp$", src)
or re.match(r".*\.hpp$", src)
):
pattern = r"(.*/\*\s*TODO)([ 0-9]*)(:.*)"
replace = r"(.*/\*\s*REPLACE)( [0-9]*)"
remove = r"(.*/\*\s*REMOVE)( [0-9]*)"
replace_pairs = [(r"/\* ", ""), (r" \*/", "")]
end_string = "*/"
elif re.match(r".*\.d$", src):
pattern = r"(.*//\s*TODO)([ 0-9]*)(:.*)"
replace = r"(.*//\s*REPLACE)( [0-9]*)"
remove = r"(.*//\s*REMOVE)( [0-9]*)"
replace_pairs = [(r"// ", "")]
end_string = None
else:
continue

dst = os.path.join(new_root, src)
src = os.path.join(root, src)
print(dst)
process_file(src, dst, pattern, replace, remove, replace_pairs, end_string)


if __name__ == "__main__":
sys.exit(main())
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,20 @@ int main(void)
{
Student *s;

s = new Student("Andrei Popescu", 22, "Linux");
s = new Student("Linus Torvalds", 22, "Linux");
s->Print();

s = new Student("Ioana David", 23, "macOS");
/* TODO 1: Solve memory leaks. */
delete s;

s = new Student("Steve Jobs", 23, "macOS");
s->Print();

/* REMOVE 2 */
delete s;

/* TODO 1: Print size of student. */
std::cout << "Size of class Student: " << sizeof(Student) << "\n";

return 0;
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,21 @@ int main(void)
mtrace();

s = malloc(sizeof(*s));
init_student(s, "Andrei Popescu", 22, "Linux");
init_student(s, "Linus Torvalds", 22, "Linux");
print_student(s);

/* TODO 1: Solve memory leaks. */
free(s);

s = malloc(sizeof(*s));
init_student(s, "Ioana David", 23, "macOS");
init_student(s, "Steve Jobs", 23, "macOS");
print_student(s);

/* REMOVE 2 */
free(s);

/* TODO 1: Print size of student. */
printf("Size of struct student: %ld\n", sizeof(struct student));

return 0;
}
Loading

0 comments on commit 6018837

Please sign in to comment.