2012-03-02 9 views
9

तो, मुझे क्या करना:अधिकतम ढेर आकार, ulimit -s, segfault 11 - यह कैसे काम करता है?

$ ulimit -s 
8192 

महान। जैसा कि मैं इसे समझता हूं, किसी भी प्रक्रिया का स्टैक सेगमेंट 8192 किलोबाइट से अधिक नहीं हो सकता है।

अब, चुनौती देने के लिए कि ..

#include <stdio.h> 

void over_8k(void) { 
    char buf[1024*1024*20]; 
} 

int main(int argc, char** argv) { 
    printf("Starting .. "); 
    over_8k(); 
    printf(" finishing.\nHow did this work?\n"); 
    return 0; 
} 

संकलित। भाग गया। कोई समस्या नहीं। वैसे यह सही नहीं है? over_8k अकेले 20 मेगाबाइट से अधिक, एक ढेर फ्रेम होना चाहिए। ठीक है, उन 20 लाख बाइट्स तक पहुँचने की कोशिश करते हैं:

#include <stdio.h> 
#include <string.h> 

void over_8k(void) { 
    char buf[1024*1024*20]; 
    memset(buf, 'A', sizeof(buf)); 
} 

int main(int argc, char** argv) { 
    printf("Starting .. "); 
    over_8k(); 
    printf(" finishing.\nHow did this work?\n"); 
    return 0; 
} 

.. ड्रम रोल ..

Segmentation fault: 11 

महान। लेकिन यह वह त्रुटि नहीं है जिसकी मैं अपेक्षा करता हूं? अवैध स्मृति पहुंच?

यह एक सेगफॉल्ट क्यों बढ़ाता है, और इससे पहले कोई त्रुटि नहीं होती है? over_8k पर कॉल पर शायद? यह कैसे काम करता है? मैं सब कुछ जानना चाहता हूं।

+6

मेरा अनुमान है: आवंटन ढेर अक्सर स्टैक पॉइंटर में वृद्धि/कमी होती है। वह खुद ही segfault नहीं होगा। यह केवल तब होता है जब आप डेटा तक पहुंचने का प्रयास करते हैं, यह अपरिपक्व स्मृति और क्रैश में जाता है। – Mysticial

+1

@ मिस्टिकियल: ठीक है। यह देखना आसान है कि संकलक असेंबली कोड प्रदान करता है। – maverik

+0

उपरोक्त कोड संकलित और परीक्षण करने के लिए आप किस कंपाइलर और झंडे का उपयोग कर रहे हैं? – Matt

उत्तर

9

मेरी टिप्पणी पर विस्तार ...

वहाँ दो संभावनाएं मैं के बारे में सोच सकते हैं:

संकलक पूरे buf सरणी बाहर के अनुकूलन है:

MSVC में, अनुकूलन को सक्षम करने पर, पूरी सरणी पूरी तरह अनुकूलित हो रही है और बिल्कुल आवंटित नहीं है। तो यह किसी भी ढेर का उपयोग नहीं कर रहा है।

sub rsp, 20971520 

SEGFAULT नहीं होगा:

ढेर आवंटन सिर्फ एक वेतन वृद्धि/कमी ढेर सूचक है। यह सिर्फ एक सूचक है। जब आप इसे अप्रयुक्त स्मृति में एक्सेस करने का प्रयास करेंगे तो यह केवल segfault होगा।

+1

+1 # 1: "कंपाइलर पूरे बफ सरणी को अनुकूलित कर रहा है" – ArjunShankar

+0

अनुमान # 1 कोड के दूसरे संस्करण में सेगमेंटेशन गलती की व्याख्या नहीं करता है, क्योंकि 'buf' का उपयोग किया जा रहा है, इसलिए' टी को ऑप्टिमाइज़ नहीं किया जा सकता है, या चूंकि 'buf' नहीं पढ़ा जाता है, इसलिए आवंटन और' मेमसेट 'कथन दोनों को ऑप्टिमाइज़ किया जाना चाहिए, इसलिए कोई गलती नहीं होनी चाहिए। बेशक असेंबली को देखते हुए तुरंत इसकी पुष्टि होगी। – Matt

+0

मैंने एमएसवीसी में परीक्षण किया और असेंबली से पता चलता है कि इसे अभी भी अनुकूलित किया जा रहा है। स्पष्ट रूप से यह पूरे 'memset() 'को मृत कोड के रूप में पहचानने में सक्षम है और इस प्रकार इसे सभी बाहर ले जाता है। शायद जीसीसी अलग है, या डिफ़ॉल्ट अनुकूलन स्तर बहुत अधिक है। – Mysticial

6

अपने buf सरणी को अस्वीकार करना स्टैक पॉइंटर को बढ़ाने से कहीं ज्यादा कुछ नहीं है।

स्टैक क्षेत्र की सीमा से परे स्टैक पॉइंटर को बढ़ाने से प्रोग्राम क्रैश नहीं हो रहा है - यह केवल एक रजिस्टर है जो एक बड़ा मूल्य होता है। हालांकि, उस क्षेत्र से परे स्मृति का जिक्र करते हुए, निश्चित रूप से कार्यक्रम को क्रैश कर देगा।

+0

मैं निम्नलिखित प्रतिस्थापन करने की अनुशंसा करता हूं: वृद्धि -> कमी, सीमा से परे -> बाहर, बड़ा -> छोटा, (अंतिम) -> नीचे/बाहर। –

+0

सच है, अधिकांश प्लेटफ़ॉर्म पर ढेर नीचे बढ़ता है लेकिन सिद्धांत समान है। अनुमान के लिए –

2

यदि आप जीसीसी का उपयोग कर रहे हैं, तो आप -fstack-check का उपयोग करके देखना चाहेंगे, आप this page पर इसके लिए कुछ विकल्प देख सकते हैं।

2

यह एक सेगफॉल्ट क्यों बढ़ाता है?

प्रोग्राम स्मृति स्थान तक पहुंच रहा है जो ओएस से आवंटित नहीं किया गया था। स्मृति स्थान ढेर से संबंधित नहीं है और न ही यह ढेर से संबंधित है। त्रुटि संदेश Segmentation fault: 11 से अधिक विस्तृत नहीं हो सकता है क्योंकि स्मृति स्थान किसी भी चीज़ से संबंधित नहीं है।

यह पहले क्यों त्रुटि नहीं करता है? ओवर_8k पर कॉल पर यह त्रुटि क्यों नहीं है?

सी प्रोग्राम प्रदर्शन पर जोर देने के साथ एक असुरक्षित भाषा है। प्रत्येक समारोह की शुरुआत में ढेर की जांच करना सभी सी कार्यक्रमों को धीमा कर देगा।

यह कैसे काम करता है?

सी में, सभी चर (जिन्हें स्पष्ट रूप से प्रारंभ नहीं किया जाता है) वे बनाए जाने पर अनियमित होते हैं। कोड की निम्न पंक्ति:

char buf[1024*1024*20]; 

buf स्टैक पर आबंटित करता है, लेकिन यह आबंटित स्मृति स्पर्श नहीं करता है।

3

अधिकांश ऑपरेटिंग सिस्टम पर ढेर मांग-आवंटित है।

इसका मतलब है कि स्टैक अपने पूर्ण आकार के सामने नहीं बनाया गया है - इसके बजाय, यह स्वचालित रूप से पहली बार विस्तारित होता है जब आप प्रत्येक पृष्ठ को स्टैक के वर्तमान छोर से बाहर स्पर्श करते हैं।

इसलिए इस मामले में, memset() के कारण पहुंच 20 मीटर स्टैक आवंटित करने का प्रयास करती है, और यह स्टैक आकार सीमा के कारण विफल हो जाती है। जब किसी पृष्ठ गलती को पूरा करने के लिए स्मृति आवंटित करने में विफलता होती है, तो त्रुटि रिपोर्टिंग के लिए बहुत सारे विकल्प नहीं हैं - जो वास्तव में यूनिक्स जैसी प्रणाली पर किया जा सकता है, वह प्रक्रिया को सिग्नल भेजना है। आपके मामले में, यह SIGSEGV है।

संबंधित मुद्दे