5.1.30 · D5 · HinglishC Programming

Question bankUndefined behavior — comprehensive list, why to avoid

2,099 words10 min read↑ Read in English

5.1.30 · D5 · Coding › C Programming › Undefined behavior — comprehensive list, why to avoid

Shuru karne se pehle, ek anchor jo tumhare dimag mein har jawab ke liye rehna chahiye:

Pure page ke liye ek hi picture dimag mein rakho: tumhara program well-defined states ki ek "valley" ke andar rehta hai. Har UB trap ek cliff edge hai — uspe kadam rakho aur neeche zameen nahi hai, koi rule nahi ki tum kahan gire.

Figure — Undefined behavior — comprehensive list, why to avoid

True or false — justify

True or false: unsigned integer overflow undefined behavior hai.
False. Unsigned overflow defined hai — yeh modulo wrap karta hai. Sirf signed overflow UB hai. Dekho Integer Types and Overflow.
True or false: signed overflow theek hai jab tak CPU two's complement use karta hai.
False. Hardware wrapping irrelevant hai; standard kehta hai signed overflow UB hai, isliye optimizer yeh assume kar sakta hai ki yeh kabhi nahi hoga, chahe CPU kuch bhi kare.
True or false: INT_MIN / -1 safe hai kyunki se divide karna sirf sign flip karta hai.
False. Yeh UB hai: , se ek zyada hai, isliye mathematically sahi result represent nahi ho sakta — ek signed overflow hai.
True or false: C mein zero se divide karna UB hai.
Integers ke liye True — x / 0 aur x % 0 UB hain. (Floating-point division by zero ek alag, IEEE-governed kahani hai, yahan cover nahi ki gayi.)
True or false: i = i++; guaranteed hai ki i ya 5 ya 6 chodega.
False. i ko do baar modify karna bina kisi sequence point ke unhe order kiye UB hai, isliye result kuch bhi ho sakta hai, do values mein se choice nahi. Dekho Sequence Points and Operator Precedence.
True or false: uninitialized int padhna sirf ek unpredictable-but-real number deta hai.
False. Yeh UB hai — compiler assume kar sakta hai variable kabhi read hi nahi hota, aur ek hi variable ke do reads bhi alag-alag values ya trap representation de sakte hain.
True or false: ek program jo -O0 par saare tests pass karta hai mein koi UB nahi hai.
False. UB tab tak chhupi reh sakti hai jab tak koi naya compiler, -O2, ya naya input "never happens" assumption ko activate na kar de. Tests pass karna UB ke baare mein kuch nahi prove karta.
True or false: array ke end se ek past pointer banana legal hai, lekin usse dereference karna nahi.
True. Standard specifically one-past pointer ko loop bounds ke liye exist karne ki permission deta hai; usse read ya write karna UB hai.
True or false: char *s = "hi"; s[0]='H'; jaisa string literal modify karna theek hai kyunki s ek valid pointer hai.
False. String literals read-only memory mein reh sakte hain aur standard unhe modify karna UB banata hai — pointer valid hona write ko valid nahi banata.
True or false: printf("%d", 3.5) truncation ke baad 3 print karta hai.
False. varargs mein format/argument-type mismatch UB hai; printf stack ke galat jagah se bits ko int samajhkar padhta hai, isliye output meaningless hai, rounded 3 nahi.

Spot the error

if (x + 100 < x) return -1; — signed x ke liye overflow check mein kya galat hai?
Kyunki signed overflow UB hai, compiler assume karta hai yeh kabhi nahi hota, isliye x + 100 < x hamesha false hai aur poora check delete ho jata hai. Defined domain mein x > INT_MAX - 100 se check karo.
int *bad(void){ int local=42; return &local; }
Return kiye gaye pointer use karne mein kya undefined hai?
local ek automatic variable hai jiska lifetime bad() return hote hi khatam ho jata hai; return kiya gaya pointer dangling hai. Baad mein *p padhna UB hai chahe 42 "accidentally" wahan ho. Dekho Pointers and Memory in C.
free(p); free(p);
Yeh UB kyun hai?
Doosra free ek double free hai — pehle free ke baad, p ab kisi live allocation ki taraf point nahi karta, isliye use phir se free karna allocator ki bookkeeping corrupt kar deta hai. Dekho malloc and free — Dynamic Memory.
free(p); printf("%d", *p);
Kaun sa rule toot raha hai?
Use-after-free: storage ki lifetime free par khatam ho gayi, isliye p ko dereference karna UB hai. Bug ko loudly crash karane ke liye freeing ke baad pointer ko NULL karo.
int a[3]={1,2,3}; printf("%d", a[3]);
a[3] ek bug kyun hai jab bhi usne ek number print kiya?
Valid indices 0..2 hain; a[3] out of bounds read karta hai — UB. "Ek number" print karna sirf ek possible symptom hai; yeh crash bhi ho sakta hai ya kisi adjacent variable ko silently corrupt kar sakta hai.
int v; unsigned n = ...; int r = v << n;
n ki kaun si values ise UB banati hain?
n >= width_in_bits of int (jaise >= 32), aur negative v ko left-shift karna bhi. Kyunki n unsigned hai yeh kabhi negative nahi ho sakta, isliye khatra purely too-large ya negative-v cases mein hai; sirf 0..width-1 ke andar shifts suitable value par defined hain. (Agar signed shift count hota, toh n < 0 ek aur UB case add karta.)
Ek int foo(int x) function kisi path par return ke bina } par khatam hota hai; caller result use karta hai. UB kahan hai?
Non-void function ke end se gir jaana aur phir returned value use karna UB hai — returned "value" exist hi nahi karti. (Return na karna sirf tab theek hai jab value kabhi use na ho.)

Why questions

Line 50 par UB kabhi kabhi line 10 kyun tod deta hai?
Kyunki optimizer "yeh path kabhi nahi chalta" se aage aur peeche dono direction mein reason karta hai, yeh pehle wale code (jaise ek check ya printf) ko delete ya reorder kar sakta hai jo UB path mein le jaata hai — poore program ka meaning undefined ho jaata hai, sirf ek line ka nahi.
C committee ne itni saari cheezein undefined kyun chodhi instead of specify karne ke?
Speed ke liye (koi forced runtime checks nahi), portability ke liye (C ko kisi ek CPU ki quirks par freeze nahi karna), aur optimization licence ke liye (compiler assume kar sakta hai UB kabhi nahi hoti). Yeh "portable assembly" performance kharidta hai.
Unsigned overflow defined kyun hai lekin signed overflow nahi?
Unsigned arithmetic ka ek obvious, hardware-independent jawab hai — wrap mod . Signed representations historically alag-alag the (sign-magnitude, ones'/two's complement), isliye standard ne signed overflow undefined chodha rather than koi ek choose karna. Dekho Integer Types and Overflow.
Main "yeh sahi chala" pe trust kyun nahi kar sakta ki mera code UB-free hai?
Sahi dikhne wala run un infinitely many outcomes mein se ek accidental outcome hai jo UB permit karta hai. Compiler, flags, ya input badlo aur compiler ke assumptions kat khaate hain. Trust karne ki jagah UBSan/ASan use karo.
-O2 enable karne par kabhi kabhi ek bug "introduce" kyun ho jaata hai jo -O0 par nahi tha?
Bug (UB) hamesha se present tha; -O2 optimizer ko "never happens" assumption par act karne ki zyada freedom deta hai — checks delete karna ya reorder karna — isliye latent UB finally manifest hoti hai. Dekho Compiler Optimizations and -O flags.
Kisi object ko incompatible pointer type ke through access karna UB kyun hai chahe bytes line up hon?
Strict aliasing rule compiler ko assume karne deta hai ki alag-alag type ke pointers ek hi object ko kabhi nahi chhute, caching/reordering enable karta hai. Ise violate karne se woh optimizations galat results deti hain. Dekho Strict Aliasing Rule.
f(g(), h()) ke evaluation order par rely karna risky kyun hai, aur f(i++, i++) worse kyun hai?
Argument evaluation order unspecified hai (koi allowed order hota hai, lekin tum nahi jaante kaun sa). f(i++, i++) aage jaata hai: yeh i ko do baar modify karta hai bina unke beech kisi sequence point ke, jo undefined hai — kuch bhi ho sakta hai.

Edge cases

Kya C11 mein bina side effects wala infinite loop while(1); safe hai?
Reliably nahi — C11 compiler ko allow karta hai ki side-effect-free loops terminate hoti hain, isliye yeh loop (aur uske aas paas ka code) surprising ways mein optimize ho sakta hai. Agar tumhe genuinely spin karna hai toh volatile side effect add karo.
Kya array ke end se do past pointer banana (dereference nahi) UB hai?
Haan. Sirf ek past the end banana ek valid pointer hai; aage jaana UB hai chahe dereference na karo. Loop bounds exactly one-past par rukni chahiye.
Kya p = NULL; p + 1; — null pointer par pointer arithmetic — UB hai?
Haan. Standard sirf kisi real array object ke andar (ya ek past) pointer arithmetic define karta hai; null pointer kisi bhi object ki taraf point nahi karta, isliye p + 1 compute karna bhi (dereference toh door ki baat) UB hai. Arithmetic karne se pehle NULL check karo. Dekho Pointers and Memory in C.
Kya apne type ke liye correctly aligned na ho aisi pointer dereference karna UB hai?
Haan. Agar tum odd address par kisi char* ko int* mein cast karo aur ussse read karo, tum type ki alignment requirement violate karte ho — UB hai, chahe x86 par yeh "usually works" kare. Stricter CPUs (kuch ARM) par yeh outright fault karta hai. Bytes ko properly aligned object mein move karne ke liye memcpy use karo.
Kya x % 0 UB hai usi tarah jaise x / 0 hai?
Haan — integer modulo by zero UB hai bilkul integer division by zero ki tarah; yeh zyaadatar hardware par saath milkar compute hote hain aur na to kisi ka defined result hai.
Agar unsigned int n = 0; n--; — kya yeh UB hai?
Nahi. Unsigned arithmetic mod wrap karta hai, isliye n UINT_MAX ban jata hai — yeh puri tarah defined behavior hai, aur yahi reason hai ki unsigned sahi tool hai jab tum genuinely wraparound chahte ho.
Kya ek valid void* ko uske original type mein cast karna aur usse dereference karna UB cause karta hai?
Nahi — void* ko directly dereference karna error hai; correct object type se round-trip karna theek hai. UB galat type use karne mein hai, void* ko storage ke liye use karne mein nahi.

Recall Fast self-quiz

Signed overflow defined hai? ::: Nahi — UB. Unsigned overflow defined hai? ::: Haan — wraps mod . Kya UB pehle wali lines ko affect kar sakti hai? ::: Haan — compiler "never happens" se backward reason karta hai. UB pakadne ke do runtime tools? ::: UBSan aur ASan (-fsanitize=undefined,address). Kya one-past-the-end pointer banana legal hai? ::: Banana ke liye haan, dereference karne ke liye nahi. Kya NULL + 1 UB hai? ::: Haan — aise pointer par arithmetic jo kisi object ki taraf point nahi karta.