5.1.19 · Coding › C Programming
Intuition Ek-sentence idea
Valgrind tumhara program ek virtual CPU ke andar chalata hai jo har ek memory access ko watch karta hai, taaki woh bugs pakad sake jo C compiler aur hardware chupchap jaane dete hain — jaise freed memory padhna, bhool-ke free na kiye gaye blocks ko leak karna, ya array se ek byte aage jaana.
C tumhe raw pointers deta hai aur koi automatic memory management nahi hoti. CPU khushi se kisi bhi address par read/write karta hai; agar tumne malloc(10) kiya aur byte 11 likha, toh kuch turant crash nahi hoga — tum heap corrupt karte ho aur program "randomly" 5000 lines baad mar jata hai. Yeh bugs hote hain:
Non-deterministic (heap layout aur timing par depend karte hain).
Silent (koi compiler warning nahi, aksar koi crash nahi).
Definition Valgrind / Memcheck
Valgrind ek instrumentation framework hai. Iska default tool Memcheck memory ke har byte ko metadata ke saath shadow karta hai taaki memory errors detect kar sake (invalid reads/writes, leaks, uninitialised values ka use).
YEH kya track karta hai (core trick — shadow memory):
Real memory ke har byte ke liye, Memcheck do bits of info rakhta hai:
A-bits (Addressability): kya yeh byte abhi access karne ki ijazat hai?
V-bits (Validity/defined-ness): kya is byte mein koi defined value hai, ya malloc ki garbage?
Intuition Do tarah ke bits kyun?
"Kya main ise chhu sakta hoon?" aur "Kya jo wahan hai woh meaningful hai?" — yeh alag sawal hain. Freed memory padhna ek A-bit error hai (tumhara nahi hai chhuना). Uninitialised variable par branch karna ek V-bit error hai (tum ise chhu sakते ho, lekin value garbage hai).
Yahan koi formula nahi hai — hamare paas ek decision procedure hai. Isko build karte hain.
Maano address a aur access size n hai. a se shuru hokar n bytes ke read ya write ke liye:
Access OK ⟺ ∀ i ∈ [ 0 , n ) : A [ a + i ] = accessible
Agar koi bhi byte accessible nahi hai ⇒ Invalid read/write error.
Defined-ness ke liye, V-bits operations ke through propagate hote hain. Starting rules:
malloc ( n ) : A [ a .. a + n ) = 1 , V [ a .. a + n ) = undefined
free ( p ) : A [ block ] = 0 ( also queued, not reused immediately )
Intuition "Queued, not reused immediately" kyun?
Agar free block ko turant allocator ko lौटा deta, toh baad ka malloc ise wapas de sakta tha, aur ek use-after-free bug valid memory access karta — undetectable hota. Valgrind freed blocks ko ek freelist quarantine mein rakhta hai taaki A-bits kaafi der tak 0 rahen aur bug pakda ja sake.
Leak rule (exit par mark-and-sweep): program khatam hone par, Memcheck ek GC-style scan karta hai. Ek heap block ho sakta hai:
Still reachable: koi pointer uski taraf exist karta hai → "lost" leak nahi (lekin phir bhi unfreed).
Definitely lost: koi bhi pointer kahin bhi uski taraf point nahi karta → tumne use leak kiya.
Indirectly lost: sirf kisi doosre lost block ke through reachable.
Possibly lost: sirf koi interior pointer uski taraf point karta hai.
leaked bytes = blocks b : b unreachable at exit ∑ size ( b )
#include <stdlib.h>
int main ( void ) {
int * a = malloc ( 5 * sizeof ( int )); // 20 bytes, A-bits=1, V-bits=undef
a [ 5 ] = 42 ; // writes bytes 20..23 -> A-bits=0!
free (a);
return 0 ;
}
Run: gcc -g -O0 prog.c && valgrind --leak-check=full ./a.out
Valgrind kehta hai:
Invalid write of size 4
at main (prog.c:4)
Address 0x... is 0 bytes after a block of size 20 alloc'd
Worked example Har step kyun?
-g → "Kyun?" taaki Valgrind address ko line 4 par naam ke saath map kar sake, raw hex nahi.
-O0 → "Kyun?" optimisation accesses ko reorder/elide kar sakta hai; tum chahte ho ki error sahi line par aaye.
"0 bytes after a block of size 20" → "Kyun?" a[5] index 5 × 4 = byte 20 hai, exactly 20-byte block ke baad. Wahan A-bit 0 hai.
#include <stdio.h>
#include <stdlib.h>
int main ( void ) {
int * p = malloc ( sizeof ( int )); // V-bits = undefined
if ( * p == 0 ) // branching on undefined value!
printf ( "zero \n " );
free (p);
return 0 ;
}
Conditional jump or move depends on uninitialised value(s)
Worked example Yeh V-bit error kyun hai, A-bit nahi
*p addressable hai (tumne malloc kiya) toh koi invalid-read nahi. Lekin iske V-bits undefined hain — Memcheck tabhi flag karta hai jab tum result ko control flow decide karne mein use karte ho (woh if), kyunki wahan garbage actually behaviour badalta hai. Sirf ek undefined value copy karna allowed hai; V-bits uske saath travel karte hain.
#include <stdlib.h>
int main ( void ) {
char * buf = malloc ( 100 );
buf = malloc ( 200 ); // first 100-byte block now unreachable
free (buf); // frees the 200, leaks the 100
return 0 ;
}
LEAK SUMMARY:
definitely lost: 100 bytes in 1 blocks
Worked example "Definitely lost" kyun?
buf = malloc(200) ke baad, koi bhi pointer kahin bhi pehle block ka address nahi rakhta → exit-time scan use unreachable pata hai ⇒ definitely lost. 200 block free hua tha, toh woh theek hai.
Common mistake Common errors ko steel-man karna
"Yeh theek se chala, toh koi bug nahi hai." Kyun sahi lagta hai: program ne correct output diya aur exit 0 kiya. Kami: heap overflows/uninitialised reads undefined behaviour hain — "aaj kaam karta hai" heap luck aur compiler version par depend karta hai. Fix: Valgrind ki report par trust karo, exit code par nahi.
"Realistic test ke liye -O2 se compile karo." Kyun sahi lagta hai: woh tumhara release build hai. Kami: optimisation line numbers chhupata hai aur shayad woh access hi optimize kar de. Fix: -O0 -g se debug karo, phir release alag se check karo.
"Still reachable bytes woh leaks hain jo mujhe fix karne chahiye." Kyun sahi lagta hai: yeh unfreed memory hai. Kami: still reachable matlab ek pointer abhi bhi exist karta hai (jaise ek global pool jo exit par OS free karta hai) — aksar harmless hota hai. Fix: definitely lost ko priority do.
"Koi --leak-check nahi, toh koi leaks nahi." Kyun sahi lagta hai: summary clean lagi. Kami: default leak detail summary hai; inhe actually dekhne ke liye --leak-check=full --show-leak-kinds=all use karo.
Recall Ek 12-saal ke bachche ko explain karo (hidden)
Socho tumhe 5 lockers ki ek row mili hai apna saman rakhne ke liye. C tumhe locker number 6 mein cheez daalne deta hai — jo tumhara nahi hai — aur koi rokta nahi. Valgrind ek strict guard hai jo tumhare peeche khada hai. Jab bhi tum ek locker kholte ho, guard check karta hai: "Kya yeh tumhara hai?" (addressability) aur "Kya tumne actually yahan kuch rakha hai, ya yeh khali kachra hai?" (defined-ness). Din ke ant mein guard yeh bhi check karta hai: "Kya tumne apna koi bag bina kisi ko bataye kahin chhod diya?" — woh leaks hain. Program slower chalta hai kyunki guard sab kuch check karta hai, lekin aakhirkar tum apni saari chhipi galtiyan pakad lete ho.
A ddress, V alue, L eak"
Teen sawaal jo Valgrind poochta hai: A — Kya mujhe ijazat hai yahan? V — Kya value sahi hai? L — Kya tumne ise chhod diya peeche? Agar tumhara bug in teeno mein se ek nahi hai, toh woh Memcheck bug nahi hai.
Valgrind ko har memory access dikhane wali virtual machine technique kya hai? Yeh program ko ek synthetic/virtual CPU (JIT-instrumented) par chalata hai, har load/store ke around checks insert karta hai.
Memcheck mein A-bits aur V-bits kya hain? A-bits = addressability (kya is byte ko access kiya ja sakta hai?); V-bits = validity/defined-ness (kya ismein koi defined value hai?).
Freed memory ka read kaunse tarah ka error hai? Ek A-bit (addressability) error → "Invalid read", use-after-free.
Malloc'd-lekin-unwritten variable par branch karna kya trigger karta hai? Ek V-bit error: "Conditional jump or move depends on uninitialised value(s)".
Valgrind freed blocks ko quarantine freelist mein kyun rakhta hai? Taaki unke A-bits 0 rahen aur immediately reuse na hon, jisse use-after-free detect ho sake.
"Definitely lost" aur "still reachable" mein fark? Definitely lost = koi pointer block ki taraf point nahi karta (sachi leak); still reachable = exit par ek pointer abhi bhi exist karta hai (aksar harmless).
Valgrind chalane se pehle -g -O0 se compile kyun karo? -g report mein source line/variable names deta hai; -O0 optimiser ko buggy access reorder/elide karne se rokta hai.
--track-origins=yes kya add karta hai? Yeh batata hai ki ek uninitialised value kahan se aayi, slower execution ki qeemat par.
Ek program "theek se chal" sakta hai phir bhi Valgrind error ho sakta hai kyun? Bug undefined behaviour hai; correct output heap layout/luck par depend karta hai, code ke sahi hone par nahi.
Full leak details dikhane wala flag kaunsa hai? --leak-check=full (plus --show-leak-kinds=all har category ke liye).
malloc and free — woh allocations jo Valgrind shadow karta hai
Pointers in C — invalid/dangling pointers woh hain jo A-bits guard karte hain
Undefined Behaviour in C — kyun yeh bugs silent hote hain
Stack vs Heap — Memcheck mainly heap ko police karta hai
AddressSanitizer (ASan) — compiler-based alternative, faster, alag trade-offs
Debugging with GDB — root-cause analysis ke liye Valgrind ke saath pair karo
C raw pointers, no auto memory mgmt
Silent non-deterministic memory bugs
Valgrind instrumentation framework
Invalid read/write errors
Use of uninitialised values
Mark-and-sweep leak check
Definitely / indirectly / possibly lost