कुछ ऐसा जो मुझे शिक्षा-प्रयोजनों के लिए कुछ समय पहले लिखा ...
int q[200];
main(void) {
int i;
for(i=0;i<2000;i++) {
q[i]=i;
}
}
यह संकलन और यह क्रियान्वित करने के बाद, एक कोर डंप का उत्पादन किया है::
निम्नलिखित सी कार्यक्रम पर विचार करें
$ gcc -ggdb3 segfault.c
$ ulimit -c unlimited
$ ./a.out
Segmentation fault (core dumped)
अब gdb का उपयोग कर पोस्टमार्टम विश्लेषण करने के लिए:
$ gdb -q ./a.out core
Program terminated with signal 11, Segmentation fault.
[New process 7221]
#0 0x080483b4 in main() at s.c:8
8 q[i]=i;
(gdb) p i
$1 = 1008
(gdb)
हू, कार्यक्रम को आवंटित 200 आइटमों के बाहर लिखा गया था, तो प्रोग्राम segfault नहीं था यह क्रैश हो गया जब मैं = 1008, क्यों?
पृष्ठों को दर्ज करें।
#include <stdio.h>
#include <unistd.h> // sysconf(3)
int main(void) {
printf("The page size for this system is %ld bytes.\n",
sysconf(_SC_PAGESIZE));
return 0;
}
जो उत्पादन देता है:
एक यूनिक्स/लिनक्स पर कई मायनों में पृष्ठ आकार निर्धारित कर सकते हैं, एक तरह से प्रणाली समारोह को sysconf() इस तरह उपयोग करने के लिए है
इस प्रणाली के लिए पृष्ठ का आकार 4096 बाइट है।
या एक इस तरह कमांडलाइन उपयोगिता getconf उपयोग कर सकते हैं:
$ getconf PAGESIZE
4096
पोस्टमार्टम
ऐसा लगता है कि segfault पर मैं = 200 नहीं होता है, लेकिन मैं = 1008 पर, आइए क्यों पता करें। शुरू gdb कुछ पोस्टमार्टम ananlysis करना है:
$gdb -q ./a.out core
Core was generated by `./a.out'.
Program terminated with signal 11, Segmentation fault.
[New process 4605]
#0 0x080483b4 in main() at seg.c:6
6 q[i]=i;
(gdb) p i
$1 = 1008
(gdb) p &q
$2 = (int (*)[200]) 0x804a040
(gdb) p &q[199]
$3 = (int *) 0x804a35c
क्ष पता 0x804a35c पर पर समाप्त हो गया, या बल्कि, क्ष के अंतिम बाइट [199] उस स्थान पर था। पेज का आकार जैसा कि हमने पहले 4096 बाइट्स देखा था और मशीन के 32-बिट शब्द का आकार देता है कि वर्चुअल एड्रेस 20-बिट पेज नंबर और 12-बिट ऑफ़सेट में टूट जाता है।
क्ष [] में आभासी पृष्ठ संख्या समाप्त हो गया:
0x804a = 32,842 ऑफसेट:
0x35c = 860 तो वहाँ अभी भी थे:
4096 - 864 = 3232 बाइट्स कि पर छोड़ दिया स्मृति का पृष्ठ जिस पर q [] आवंटित किया गया था। यही कारण है कि अंतरिक्ष पकड़ कर सकते हैं:
3232/4 = 808 पूर्णांकों, और कोड यह इलाज किया जैसे कि वह 1008
को स्थिति 200 पर क्ष के तत्वों का समावेश है हम सभी जानते हैं कि उन तत्वों मौजूद नहीं करते हैं और संकलक ने शिकायत नहीं की, न ही एचडब्ल्यू किया क्योंकि हमारे पास उस पृष्ठ पर लिखने की अनुमति है। केवल जब मैं = 1008 q था [] एक अलग पृष्ठ पर एक पते का संदर्भ लें जिसके लिए हमारे पास लेखन अनुमति नहीं थी, वर्चुअल मेमोरी एचडब्ल्यू ने इसका पता लगाया और एक सेगफॉल्ट ट्रिगर किया।
एक पूर्णांक 4 बाइट्स में संग्रहीत किया जाता है, जिसका अर्थ है कि इस पृष्ठ में 808 (3236/4) अतिरिक्त नकली तत्व हैं जिसका अर्थ है कि यह अभी भी q [200], q [201] से इन तत्वों तक पहुंचने के लिए पूरी तरह से कानूनी है एक एसईजी गलती ट्रिगर किए बिना तत्व 199 + 808 = 1007 (क्यू [1007]) तक। Q [1008] तक पहुंचने पर आप एक नया पृष्ठ दर्ज करते हैं जिसके लिए अनुमति अलग होती है।
स्टैक ओवरफ़्लो तब होता है जब ढेर से बहुत अधिक मेमोरी आवंटित की जाती है। इस मामले में, 'sizeof (int) == 4' मानते हुए, आपने स्टैक से कम से कम 12 बाइट आवंटित किए हैं। आपका कोड एक सरणी के अंत से परे लिख रहा है। यह ढेर अतिप्रवाह नहीं है। यह _undefined व्यवहार_ है। –
उसी स्थान से आता है जैसे आपको अपनी बाकी रैम मिलती है, शायद जो भी आपको कंप्यूटर बेचती है। 'arr [3]' का अर्थ है "मेरे उपयोग के लिए उपलब्ध अंतरिक्ष के 3 'int' को निर्दिष्ट करें", इसका अर्थ यह नहीं है कि "ईथर के बाहर अंतरिक्ष का 3 'int' बनाएं", हालांकि यह कानूनी कार्यान्वयन होगा यदि यह था शारीरिक रूप से संभव है। आप जो कुछ भी स्मृति/पता 'arr' के निकट होने के लिए होता है) (अच्छी तरह से, अगले दरवाजे-लेकिन-वास्तव में), जो डेविड कहते हैं, यूबी है। हां, यह आपके ढेर का हिस्सा है (सी और सी ++ मानक स्टैक के बारे में बात नहीं करते हैं, लेकिन व्यावहारिक रूप से जहां स्वचालित चर चलते हैं)। –
@vprajan - मैंने प्रश्न को प्रतिबिंबित करने के लिए अपना शीर्षक अपडेट किया है, क्योंकि ध्यान आकर्षित करने के लिए यहां एक अच्छा जवाब है। –