CTF: Dynamic Memory
8 challenges — Week 7
Dynamic Memory Challenges
| 8 challenges | Week 7 | Week 7 (Dynamic Memory Management) |
Dynamic memory challenges covering malloc/free lifecycle, memory leak detection, double-free and use-after-free bugs, realloc for dynamic arrays, Valgrind interpretation, cleanup functions for nested allocations, stack vs heap decision-making, and nested struct allocation. These exercises build on the pointer foundations from Week 6 and prepare students for struct-based data structures in Week 8.
Difficulty Breakdown
| Level | Count |
|---|---|
| Beginner | 2 |
| Intermediate | 4 |
| Advanced | 2 |
Challenges
1. Malloc Basics
| Difficulty: Beginner | Time: ~10 min | Type: function |
Complete the skeleton program below by replacing each TODO with the correct code. The program should allocate an int array with malloc, check for NULL, fill each element with the formula arr[i] = i * 10, print each element, free the memory, and set the pointer to NULL.
#include
Concepts: malloc with sizeof for correct allocation size, NULL check after malloc, array indexing on heap-allocated memory, free to release heap memory, setting pointer to NULL after free
2. Memory Leak Detection
| Difficulty: Intermediate | Time: ~12 min | Type: bare code |
Each of the following code snippets contains one or more memory leaks. For each, identify which allocation leaks, explain why, and provide corrected code.
Concepts: memory leak via overwritten pointer, memory leak via early return without cleanup, memory leak in loops, memory leak from uncaptured heap return value, ownership semantics: who is responsible for freeing
3. Double Free Use After Free
| Difficulty: Intermediate | Time: ~12 min | Type: bare code |
Each snippet below contains a double-free or use-after-free bug. Identify the bug type, explain the potential consequences (including the relevant CWE identifier), and provide corrected code.
Relevant CWE identifiers:
- CWE-415: Double Free
- CWE-416: Use After Free
Concepts: use-after-free detection (CWE-416), double-free detection (CWE-415), setting pointer to NULL after free as defensive pattern, free(NULL) is safe (C standard guarantee), conditional control flow with heap memory
4. Dynamic Array Realloc
| Difficulty: Advanced | Time: ~15 min | Type: function |
Write a program that reads integers from stdin until the sentinel value -1 is entered. Store the integers in a dynamically growing array. Start with an initial capacity of 4 and double the capacity with realloc whenever the array is full.
Requirements:
- Use the safe realloc pattern: store reall…
Concepts: realloc for dynamic array growth, safe realloc pattern with temporary pointer, size vs capacity tracking, doubling strategy for amortized O(1) append, sentinel-controlled input loop
5. Valgrind Interpretation
| Difficulty: Intermediate | Time: ~12 min | Type: expression evaluation |
Given three Valgrind output excerpts, interpret each to identify the error type, source line, byte count, root cause, and fix.
Valgrind command reference: valgrind –leak-check=full –show-leak-kinds=all –track-origins=yes ./program
Concepts: interpreting Valgrind HEAP SUMMARY (allocs vs frees), understanding ‘definitely lost’ vs ‘possibly lost’, reading stack traces to find source lines, identifying use-after-free from ‘block was free’d’ message, identifying buffer overflow from ‘N bytes after a block of size M’
6. Cleanup Function
| Difficulty: Intermediate | Time: ~12 min | Type: function |
Given the following allocation code, write a cleanup function that frees all memory in the correct order.
Allocation code: char **names = malloc(3 * sizeof(char *)); names[0] = malloc(10); strcpy(names[0], “Alice”); names[1] = malloc(10); strcpy(names[1], “Bob”); names[2] = malloc(10); s…
Concepts: inside-out free order for nested allocations, freeing array of pointers (char **), NULL checks at multiple levels, defensive cleanup function design, ownership semantics: cleanup takes responsibility for freeing
7. Stack Vs Heap
| Difficulty: Beginner | Time: ~8 min | Type: expression evaluation |
For each scenario below, determine whether stack allocation or heap allocation is more appropriate, and explain why.
Decision criteria:
- Lifetime: Does the data need to outlive the current function?
- Size: Is the size known at compile time? Is it very large?
- Ownership: Does the data need …
Concepts: stack vs heap allocation trade-offs, object lifetime and scope, stack size limitations (typically 1-8 MB), returning pointers to local variables (dangling pointer), VLA limitations vs malloc
8. Nested Struct Allocation
| Difficulty: Advanced | Time: ~18 min | Type: function |
Given the Student struct below, write three functions: createStudent, printStudent, and freeStudent.
typedef struct { char *firstName; char *lastName; int *grades; int numGrades; } Student;
Function signatures: Student *createStudent(const char *first, const char *last, const …
Concepts: struct with dynamically allocated fields, malloc for struct itself (sizeof(Student)), malloc+strcpy for string fields (strlen+1), malloc+memcpy for array fields, inside-out free order (fields before struct)