Skip to main content

Memory Layout and Errors Clinic

Retrieval Prompts

  1. Name the main segments of a process's virtual address space and what each holds.
  2. State what a stack frame contains at minimum.
  3. Explain the difference between malloc, calloc, and realloc.
  4. State the canonical idioms after free(p) and after realloc(p, n).
  5. Name three tools that catch memory errors, and one thing each tool excels at.

Compare and Distinguish

Separate these pairs clearly:

  • stack versus heap (lifetime, addressing, who frees)
  • .data versus .bss versus .rodata
  • buffer overflow versus use-after-free versus memory leak
  • AddressSanitizer versus Valgrind Memcheck versus Clang static analyzer

Common Mistake Check

For each program, predict the sanitizer / tool report before you run it:

  1. char b[8]; strcpy(b, "123456789");
  2. int *p = malloc(4 * sizeof *p); free(p); p[0] = 1;
  3. int *p = malloc(4 * sizeof *p); free(p); free(p);
  4. int *p = malloc(4 * sizeof *p); /* never freed */ return 0;
  5. int x; printf("%d\n", x); /* uninitialized read */

Mini Application

  1. Read /proc/self/maps from a small C program and print each line. Identify the segments for .text, .data, .bss, heap, and stack, then run with ./a.out several times and note which base addresses change (ASLR).

  2. Write a function that recursively calls itself, printing the address of a local on each call. Observe whether addresses go up or down, and whether the program eventually stack-overflows (it will, eventually).

  3. Replace strcpy with snprintf in one of the earlier buggy examples. Confirm that ASan is silent afterwards, even for long inputs.

  4. Insert a deliberate off-by-one in a loop writing into a 32-byte buffer. Build with and without -fstack-protector-strong. Observe the difference in crash messages.

  5. Add a malloc-heavy program that allocates and never frees, then run valgrind --leak-check=full ./a.out. Read the LEAK SUMMARY lines and match them to your code.

Lab Tasks

  • Build a stack-frame tracer: write a trace() macro that prints the current function and the address of a local variable. Call it from several layers of functions; use the printed addresses to infer frame sizes.
  • Write a toy leak detector using __malloc_hook (old-style) or LD_PRELOAD with your own malloc wrapper that increments a counter. Intentionally leak, then verify the counter.
  • Add -fsanitize=address,undefined to the CMake / Makefile build flags for a small project. Run the test suite. Fix anything the sanitizer complains about.

Evidence Check

This page is complete only if you can:

  • classify any variable in a short C program by segment (stack / heap / .data / .bss / .rodata) without running it
  • predict which of ASan, UBSan, Valgrind Memcheck, and a static analyzer will report a given bug
  • fix a reported memory bug and re-run the tool to confirm the fix