5.1.30 · Coding › C Programming
Intuition Is topic ki ek-line soul
C standard ek contract hai — tumhare aur compiler ke beech. Undefined behavior (UB) woh clause hai jo kehta hai: "Agar TUM YEH rules todte ho, toh main (compiler) tumhara KUCH bhi nahi deta — program crash ho sakta hai, kaam kar sakta hai, data corrupt kar sakta hai, ya nasal demons bula sakta hai, aur main phir bhi ek sahi compiler rahunga." Jaise hi UB trigger hoti hai, poore program ka meaning void ho jaata hai , sirf buggy line ka nahi.
Definition Category 1 — Memory & pointers
Null pointer ya dangling pointer ko dereference karna (freed/expired storage ki taraf point karta hai).
Array ke out of bounds read/write karna (buffer overflow/underflow).
free ke baad memory use karna (use-after-free) ya do baar free karna (double free ).
Uninitialized variable ko indeterminate value ke saath padhna.
Pointer arithmetic jo array ke end se ek se zyada past jaaye.
void* ko directly dereference karna, ya strict aliasing violate karna (ek object ko incompatible pointer type se access karna).
Definition Category 2 — Arithmetic
Signed integer overflow : INT_MAX + 1 UB hai. (Unsigned overflow defined hai — yeh mod 2 n wrap karta hai.)
Division / modulo by zero : x / 0, x % 0.
Shift errors : x << n ya x >> n jahan n < 0 ya n >= width-in-bits ho, ya negative/overflowing value ko left-shift karna.
INT_MIN / -1 (overflow hota hai kyunki − I N T _ M I N > I N T _ M A X ).
Definition Category 3 — Sequencing
Ek object ko sequence points ke beech do baar modify karna , ya usse modify karna aur kisi unrelated purpose ke liye padhna: i = i++;, a[i] = i++;.
Function arguments ke evaluation order pe rely karna unspecified hai, lekin f(i++, i++) undefined hai.
Definition Category 4 — Lifetime & objects
Local (automatic) variable ka pointer return karna aur function return hone ke baad use karna.
Object ko uski lifetime ke baahir access karna.
Type punning unions ke zariye aisa karna jo standard forbid karta hai, ya alignment requirements todna.
Definition Category 5 — Control flow & misc
Non-void function ke } tak pahunchna bina return ke aur phir value use karna.
Function ko incompatible type ke pointer se call karna.
No side effects wale infinite loops (compiler assume kar sakta hai ki yeh terminate hote hain, C11).
printf("%d", 3.5) — format-specifier / argument type mismatch (varargs UB).
String literal modify karna: char *s = "hi"; s[0] = 'H';.
Worked example Example 1 — Signed overflow check jo gayab ho jaata hai
int f ( int x ) {
if (x + 100 < x) return - 1 ; // overflow check?
return x + 100 ;
}
Yeh fail kyun hota hai? Signed overflow UB hai, isliye compiler assume karta hai yeh kabhi hota hi nahi . Phir mathematically x + 100 < x hamesha false hota hai → yeh return -1 delete kar deta hai. Tumhara "safety check" gone.
Fix — defined domain mein sochho:
if (x > INT_MAX - 100 ) return - 1 ; // yahan koi overflow nahi hota
Yeh step kyun? Hum add karne se pehle compare karte hain, isliye addition kabhi overflow nahi hoti; comparison meaningful hai aur compiler isse delete nahi kar sakta.
Worked example Example 2 —
i = i++ (sequencing)
int i = 5 ;
i = i ++ ; // UB
UB kyun? i ko assign karne (= se) aur increment karne (++ se) ke beech koi sequence point nahi hai jo dono ko order kare. Standard kehta hai i ko do baar modify karna bina ordering ke = UB. Result "implementation 5 ya 6 choose karta hai" nahi hai — yeh kuch bhi hai.
Fix:
i = i + 1 ; // single, well-ordered modification
Worked example Example 3 — Dangling pointer
int * bad ( void ) {
int local = 42 ;
return & local; // local mar jaata hai jab bad() return karta hai
}
// baad mein: int *p = bad(); printf("%d", *p); // UB
Yeh theek lagta hai lekin hai nahi kyun: Value 42 shayad abhi bhi stack slot mein ho jab tum padhte ho — isliye tumhari machine pe "kaam karta hai". Lekin local ki lifetime khatam ho gayi; slot reusable hai. "Ek baar kaam karna" UB ka sabse dangerous symptom hai.
Fix: value se return karo, ya malloc se allocate karo aur caller ko free karne do.
Worked example Example 4 — Out-of-bounds + "print theek hua" wala trap
int a [ 3 ] = { 1 , 2 , 3 };
printf ( " %d " , a [ 3 ]); // index 3 out of bounds hai (valid: 0..2)
Yeh step kyun? a[3] array ke ek element past read karta hai. Kabhi garbage print hota hai, kabhi crash, kabhi adjacent variable corrupt hoti hai — silently . Koi rule nahi hai ki "one past" reads safe hain (sirf one-past pointers form ho sakte hain, dereference nahi).
Common mistake "Unsigned aur signed overflow dono bas wrap karte hain, right?"
Theek kyun lagta hai: Two's-complement hardware dono ke liye wrap karta hai; tumne dekha hai isse debug build mein wrap karte hue.
Sach: Unsigned overflow defined hai (mod 2 n ). Signed overflow UB hai. Optimizer dono ko bilkul alag treat karta hai. unsigned/uint32_t use karo jab tumhein wraparound chahiye .
Common mistake "UB sirf buggy line ko mess karta hai."
Theek kyun lagta hai: Normal bugs local hote hain.
Sach: UB compiler ko backwards aur forwards reason karne deta hai. Line 50 ki UB line 10 ko impossibly behave kara sakti hai (ek printf skip, ek check delete). Poore program ka behavior undefined hai.
Common mistake "Yeh sahi run hua, toh theek hai."
Theek kyun lagta hai: Tests pass ho gaye.
Sach: UB appear kar sakta hai kaam karne ka, phir naye compiler version, optimization flag (-O2), ya input se break ho jaaye. Sanitizers use karo: -fsanitize=undefined,address, plus -Wall -Wextra.
Common mistake "Uninitialized
int padhna bas ek random number deta hai."
Theek kyun lagta hai: Random lagta hai.
Sach: Yeh UB hai — compiler assume kar sakta hai isse kabhi read hi nahi kiya, aur same variable ke alag reads alag values de sakte hain ya trap representations trigger kar sakte hain. Hamesha initialize karo.
Recall Defensive checklist
-Wall -Wextra -Wpedantic ke saath compile karo aur warnings ko errors treat karo.
Testing mein -fsanitize=address,undefined (UBSan/ASan) ke saath run karo.
Static analyzers use karo (clang --analyze, cppcheck).
Check karo compute karne se pehle (overflow), baad mein nahi.
Har variable initialize karo; har freed pointer ko NULL karo; kabhi &local return mat karo.
unsigned use karo jab wraparound chahiye; kabhi assume mat karo signed wraps.
Har array index aur pointer arithmetic validate karo.
Recall Khud test karo (answers chhupa ke)
UB, unspecified, aur implementation-defined mein difference?
Line 50 ki UB line 10 ka behavior kyun change kar sakti hai?
Kya INT_MAX + 1 UB hai? Kya UINT_MAX + 1 UB hai?
i = i++; undefined kyun hai aur sirf "5 ya 6" nahi?
Do flags jo runtime par UB pakadne mein help karte hain?
C mein Undefined Behavior (UB) kya hai? Aisi situation jis par standard KOI requirement impose nahi karta; poore program ka behavior void ho jaata hai — kuch bhi ho sakta hai.
UB vs unspecified vs implementation-defined? UB = bilkul koi requirement nahi; unspecified = kai allowed outcomes mein se ek, undocumented; implementation-defined = allowed outcome jo DOCUMENT hona CHAHIYE.
Kya signed integer overflow UB hai? Haan — INT_MAX + 1 undefined hai.
Kya unsigned integer overflow UB hai? Nahi — yeh 2^n modulo wrap karne ke liye defined hai.
Compiler UB ko exploit kyun karta hai? Yeh assume karta hai ki UB kabhi nahi hoti, jo aggressive optimizations ko license deta hai (e.g. "impossible" checks delete karna).
i = i++; UB kyun hai?i do baar modify hota hai bina kisi intervening sequence point ke jo dono modifications ko order kare.
Kya one-past-the-end pointer dereference allowed hai? Nahi — pointer form karna legal hai, isse dereference karna UB hai.
"Yeh sahi run hua" proof kyun nahi hai ki code UB-free hai? UB appear kar sakta hai kaam karne ka, phir naye compiler, flag, ya input se break ho jaaye; yeh spec se nondeterministic hai.
UB pakadne ke liye do compiler tools? -fsanitize=undefined (UBSan) aur -fsanitize=address (ASan), plus -Wall -Wextra.
100 add karne se pehle signed overflow check karne ka sahi tarika? if (x > INT_MAX - 100) ... — non-overflowing domain mein compare karo.
Kya string literal modify karna UB hai? Haan — char *s="hi"; s[0]='H'; undefined hai.
Dangling pointer kya hota hai? Aisi storage ki taraf pointer jiska lifetime khatam ho gayi hai (freed memory ya returned local).
Recall Feynman: 12-saal ke bachche ko samjhao
Ek board game socho jisme ek rulebook hai. Zyaadatar rules exactly batate hain kya karna hai. Lekin ek scary rule hai: "Agar tumne kabhi YAHI forbidden move ki, toh rulebook apply hona band ho jaata hai aur game literally kuch bhi kar sakta hai — tumhe million points de, board flip kare, ya game crash kare." C mein, woh forbidden moves undefined behavior hain. Tricky part yeh hai: computer ko assume karne ki permission hai ki tum kabhi forbidden move nahi karoge , isliye woh safety checks skip karta hai taaki faster chale. Jab tum obey karte ho tab yeh achha hai, lekin agar tum ghalti karo, toh pehle ki moves bhi galat ho sakti hain. Toh lesson simple hai: kabhi forbidden moves mat karo — list ke end se past mat padho, kisi cheez ko throw karne ke baad use mat karo, number ko itna bada mat banao ki fit na ho.
Mnemonic Bade UB families yaad rakho:
"OUS-DUP"
O verflow (signed), U ninitialized read, S equencing (i=i++), D angling/out-of-bounds pointer, U se-after-free, P rototype/format mismatch. → "OUS baaton mein DUP mat bano!"
Performance and Portability
Optimizer assumes UB never happens
Bugs upstream of the line
Memory and Pointer errors
null deref, use-after-free, out of bounds
signed overflow, div by zero, bad shift