# Valgrind memcheck **memcheck** tracks every byte of memory and detects four main classes of error: invalid memory access (reading/writing past buffer bounds), use-after-free, uninitialized value usage, and memory leaks. It maintains shadow state for every allocation—whether each byte is initialized and whether it's still allocated. ```bash valgrind ./program valgrind --leak-check=full ./program valgrind --leak-check=full --track-origins=yes ./program ``` Without flags, memcheck only reports invalid accesses and leaks. `--leak-check=full` provides detailed leak information including allocation stack traces. `--track-origins=yes` tracks where uninitialized values came from (adds overhead but invaluable when debugging uninitialized value errors). **Invalid memory access** occurs when reading or writing outside an allocation's bounds: ```c int arr[10]; arr[15] = 5; // write past end of buffer int x = arr[100]; // read past end ``` memcheck catches this instantly and reports: "Invalid write/read of size N at address X, 0 bytes after a block of size M allocated at...". The report includes the allocation stack trace, making it easy to find where the buggy buffer came from. **Use-after-free** occurs when accessing memory that's been freed: ```c int *p = malloc(sizeof(int)); free(p); *p = 10; // use after free ``` memcheck reports: "Invalid write of size 4 at address X, which is 0 bytes inside a block of size 4 free'd at... previously allocated at...". Both the free and allocation stack traces are shown. **Uninitialized values** occur when reading memory before writing to it: ```c int x; printf("%d\n", x); // x is uninitialized ``` memcheck reports: "Use of uninitialised value of size 4". With `--track-origins=yes`, it shows where the uninitialized value came from (usually from a malloc or stack allocation). **Memory leaks** occur when allocated memory is never freed. Leak checking modes: ```bash --leak-check=no # don't check for leaks --leak-check=summary # report only summary (total leaked bytes) --leak-check=full # report each leaked block --leak-check=reachable # also show still-reachable blocks ``` Leak kinds: - **Definitely lost**: pointer to the block is gone (unambiguous leak) - **Indirectly lost**: leaked block is only reachable through another leaked block - **Possibly lost**: pointer may still exist in registers or on the stack (conservative) - **Still reachable**: block is allocated but never freed (usually not a leak, just poor cleanup) Report only definitely and indirectly lost by default. Use `--show-leak-kinds=all` to see everything. **Leak summary example:** ``` ==12345== LEAK SUMMARY: ==12345== definitely lost: 42 bytes in 3 blocks ==12345== indirectly lost: 0 bytes in 0 blocks ==12345== possibly lost: 10 bytes in 1 block ==12345== still reachable: 100 bytes in 5 blocks ``` Focus on "definitely lost"—those are real leaks. "Still reachable" is usually acceptable; it's memory allocated at startup and kept alive for the program's lifetime.