/Teaching/System Level Programming/Assignments/A5
Pull from upstream before solving this task.
Task: Dynamic Memory Implementation
In this exercise, you are expected to create your own implementation of dynamic memory to allocate/deallocate memory on the heap. You will write your own implementation of malloc(...), free(...) and calloc(...) as well as operator new/operator delete to create instances during runtime.
Learning Objectives
Gain a deeper understanding of low-level applications
Compared to the other exercises, you are free in how you want to solve this assignment, as long as you fulfill the mandatory requirements and do not change the function signatures provided.
After having practiced reading and understanding man pages in the previous exercises and learning about defined and undefined behaviour, you are now expected to write these existing functions yourself, while providing the same behaviour.
Writing Tests and Debugging
This assignment should not be too difficult to write if you have some experience with C/ C++. Instead, the difficult part lies within writing tests, debugging them, and ensuring that your program does what you say it does. The testsystem only provides some sanity checks for you. The remaining functionality you will have to test and debug yourself, which is a big part of this assignment.The testsystem only tests things explicitly mentioned in this assignment description.
If you plan on attending the "Operating Systems" course, it is highly recommend not to skip this task. You will (hopefully) learn a lot about writing, testing and debugging low-level applications, which is essential to OS.
Support
If you want support, please write a few tests first. We will give feedback on which of your tests you should expand, or which ones you should rework. For the most part, we will not give you detailed feedback on your malloc implementation.
Without your own tests you will not know which parts of your malloc work correctly and which ones do not.
Where and How to start
It is recommended to start off with a simple malloc (and free) implementation and iteratively add features to it. calloc, operator new and operator delete will only give you points once your malloc implementation has basic functionality. However, the task of the operator new is much, much simpler than the malloc task.
The maximum amount of points that can be reached in this assignment is 27 (25 + 2 bonus points). Even a simple implementation of malloc and free will lead to some points, provided all the mandatory requirements are fulfilled. Implementing all features in combination may lead to unlocking the 2 additional bonus points.
If you do not feel very comfortable with C/C++, how to debug efficiently or would just like some extra advice, there will be a presentation for A5 during the lecture. Besides the assignment itself, we will look at how to debug and verify a similar program, using techniques you can then apply to your A5 implementation.
You can also attend the A5 question hours (29.04., 06.05.), where we can again demonstrate debugging etc if there is demand.
Mandatory requirements
malloc and free functions
- The interface of your implementation is required to conform to the POSIX standard (see
man malloc). - Make sure you support an arbitrary number of
mallocandfreecalls, and arbitrary sizes passed tomalloc. - Reduce the heap size whenever it makes sense, for example when all the malloc’d data has been freed.
- Note: This is not necessarily standard
mallocbehaviour. - You can decide for yourself when exactly you can reduce the heap size, especially if there are still some blocks allocated.
- Note: This is not necessarily standard
- Do not trust user pointers! Make sure your functions never cause a segmentation fault if you can prevent it.
Utility functions
- Implement the two functions
slp::Memory::total_used_memoryandslp::Memory::free_block_infoslp::Memory::total_used_memory(...): return the total amount of currently allocated memory.slp::Memory::free_block_info(...): this function takes a parameterint type. Whentypeis1, return the size of the first free block. Whentypeis2, return the starting address of the first free block. Whentypeis3, return the number of free blocks. Otherwise return-1! If no free block exists, return 0.
Additional requirements
malloc, calloc and free functions
- Reduce the number of syscalls where possible (allocating
100 kBshould take more than one but no more than 30 syscalls, regardless of the number ofmalloc-calls).- Hint: Do
brkandsbrkneed to be called every time you callmalloc? - You are also not allowed to call
sbrk(0)more than once during program execution. You can assumesbrkis only called in yourmalloc/freefunctions. - Think back to A3! What happens internally when you call
sbrk? Does it make sense to callsbrk(1)? What could you do instead? - Use
straceto examine the syscalls a process makes. - You can assume bigger sizes for each of the
malloccalls for the 30 syscalls requirement. Sizes of much more than 8 bytes. - This requirement only applies to testcases where
mallocis called more than once.
- Hint: Do
- Detect memory corruption errors. Bring in your own ideas which errors to detect. At least:
- Buffer overruns/memory corruption
- Invalid
free/doublefree - Handle out of memory correctly.
- Exit the program with exit code
-1in case of memory corruption, invalidfreeor doublefree. - In case you run out of memory,
mallocreturnsNULL. - Your
mallocfunctions must not be too slow. For example: Try to avoid iterating over the same list multiple times. - Organize the heap with respect to performance and memory usage overhead (fragmentation).
- Also think about implementing free chunk merging.
new and delete operators
- Use
mallocandfree. - Your implementation should use exceptions in the case of an error.
- See
std::newfor exception usage. - Take care that you throw the same exception as
std::new
- See
Implementation Guidelines
malloc, calloc and free functions
- Implement the methods
slp::Memory::malloc(...),slp::Memory::calloc(...)andslp::Memory::free(...). - Use only the
slp::brk(...)/slp::sbrk(...)functions for acquiring new memory (seeman brk). - Do not use
mmap(...), you can ignoreMMAP_THRESHOLD. - You do not need to worry about aligning the memory your
mallocreturns. - You do not have to implement the
errnomechanics. - You do not need to implement overflow-detection for
calloc. - Your implementation must not contain a main function in any file, except for the testcases in the tests directory
new and delete operators
- Put your implementation of
new/deletein the provided stubs. - Only change the already existing function implementations that have a
TODO STUDENTabove them. You can add additional functions/variables if you want. - We will overload the global
new/deleteoperators, so you can use it just as you would use the standardoperator newinC++. - Your implementation must not contain a main function in any file, except for the testcases in the tests directory.
Tips
malloc, calloc and free functions
- Start with a simple
malloc-implementation, and iteratively add new features. - You are expected to write your own tests, but they do not need to be complex and will not be graded. However, without your own testcases, you will not know if your
mallocbehaves as expected, and will probably not get the full points for this assignment. - For your
callocfunction, you can just call yourmallocfunction. - You can use the
placement new operatorand add your own classes to organize your implementation. This can make debugging easier as well. Usage of theplacement new operatorwill be shown in the lecture and the A5 extended question hour. - If you want to use void pointer arithmetic in
C++, you can usechar*instead. - If you want to use
C-style libraries, you can use<cstring>and<cstdlib>for example. - Some libraries are already included in your
malloc/newfiles, which should cover everything you need, however you can use additional ones if you need to. However, be careful when using standard library functions that may internally callmalloc(...)oroperator new, as they will then use your implementation and may cause unintended side effects. - Do not use a data structure like
std::listorstd::vector, as they usemallocinternally. You can use any data structure that does not usemallocinternally. - Even though you will implement malloc in
C++, you can write in a very similar manner to theCcode found in the other assignments (you do not need to use classes or otherC++-specifics). - Some of the tests are written in
C(and you can also decide if you preferCorC++for your tests), so you cannot use exceptions.
new and delete operators
- You should write your own tests for
new/delete. - You will only get points for this task once you have implemented the basic
malloc-mechanics. - You will probably find this task much, much easier than
malloc.
General Advice
- Try to test for every requirement found here or on the manpage. If you cannot figure out how to test for a specific requirement, feel free to ask via Discord.
- Make sure you have a working debugger, this assignment will be rather difficult without one. I recommend gdb or VSCode (which also uses gdb internally but provides a nice GUI), if you need help setting it up ask in Discord.
- You are not restricted in how you want to solve this assignment, as long as you do not change the function signatures and everything compiles you should be fine.
- Attend the A5 lecture unit and the A5 question hours (29.04., 06.05.) if you do not feel comfortable with
C/C++or do not know where to start. In the lecture unit you will see some basics on how you can debug, write tests and maybe some small tips for starting out. - Any mention of "block size" or similar will not include your metadata. A block allocated with
malloc(64)has the size 64 for our purposes.
Debugging in VSCode
You can use whatever debugger you prefer. However, if you would like an easy start you can try the following (assumes gdb and VSCode is installed):
- Download the vscode.zip file. Extract the two files inside into
YOUR_REPO/A5/.vscode/(create the folder if it does not exist already). - Open your A5 folder with VSCode. You should now have three choices to run within the debug section (the bug symbol on the left).
- Now add a breakpoint within your
malloc.cpportinytest.c(click on the left side of the line number, you should see a red circle). - If you select "exampletest_1 dbg" and click the green arrow next to it or press F5, you should be all done and ready to debug!
- If you write your own tests, select "current file dbg" and open the test you want to debug (make sure it is the currently active file), then press F5.
- You can also adapt launch.json to create entries for your own testcases.
- If you do not want VSCode to pause when it hits the main function, open
launch.jsonand set"stopAtEntry"fromtruetofalsefor all three configs. - Make sure to read up on how to use VSCode’s debug UI and all the features it provides, or attend the extended question hour for some basics.
- If you use this config, you can use
CTRL + SHIFT + P, choose "Tasks: Run Task" and then "Run tests" to execute all of your testcases at once.
Notes
Please pull from the upstream git repository.
You will find the files
A5/malloc.cppA5/memory.hA5/util.cppA5/new.cppA5/Makefile
which contain stubs for your implementation.
The testsystem only uses yourA5/malloc.cpp,A5/memory.handA5/new.cppfiles.
You can modify the other files and add new ones as you like, but yourmalloc/new-implementation should be contained in those three files.
Submission
Modify the files in your git repository. You can find this assignment’s files in the A5 directory.
Tag the submission with A5 and push it to the server. You may remove and re-push the A5 tag any time you like before the deadline.
Assignment Tutors
If you have any questions regarding this assignment, go to Discord and read through the SLP channels. The probability that your question was already answered or some discussions will lead you in the right direction is quite high. If not so, just create a new thread with the A5 flair applied.
If you have a more direct question regarding your specific solution, you can also ask the tutors who organize this assignment:
Thomas Halbedl, halbedl@student.tugraz.at
Philip Prohaska, prohaska@student.tugraz.at