2008-09-23 5 views
7

तो मुझे कुछ सी कोड मिला है:वैश्विक चर के साथ स्ट्रैपी एक सेगमेंटेशन गलती क्यों ट्रिगर करता है?

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

/* putting one of the "char*"s here causes a segfault */ 
void main() { 
    char* path = "/temp"; 
    char* temp; 
    strcpy(temp, path); 
} 

यह दिखता है, चलाता है और व्यवहार करता है जैसा दिखता है। हालांकि, यदि एक या दोनों चरित्र पॉइंटर्स को ग्लोबल वैरिएबल के रूप में घोषित किया गया है, तो खंडन गलती में स्ट्रैपी परिणाम। क्यों होता है ऐसा? स्पष्ट रूप से गुंजाइश की मेरी समझ में एक त्रुटि है।

+0

चूंकि मुझे नहीं लगता कि यह वास्तव में समस्या को हल करने जा रहा है, मैं बस टिप्पणी करूंगा कि strnpy पर अत्यधिक strncpy की अनुशंसा की जाती है। –

+0

जोश गगनन: दरअसल, इनपुट स्ट्रिंग की लंबाई> = बफर होने पर strncpy शून्य टर्मिनेटर नहीं रखता है। अगर आप जानते हैं कि बफर काफी बड़ा है तो स्ट्रैपी पूरी तरह से सुरक्षित है। अन्यथा, 'snprintf (buffer, buffer_len, "% s", src) का उपयोग करें, क्योंकि, snprintf हमेशा एक शून्य टर्मिनेटर रखता है (बस सुनिश्चित करें कि buffer_len> 0)। –

+0

@ जोश: मैं 'strlcpy' पसंद करते हैं। दुर्भाग्य से ग्लिबैक इसका समर्थन नहीं करता है इसलिए मुझे इसका उपयोग करने का अधिक मौका नहीं मिलता है। मुझे लगता है कि मैं हमेशा अपना खुद का कार्यान्वयन कर सकता हूं और इसे अपनी व्यक्तिगत हेडर लाइब्रेरी में नल-चेकिंग मॉलोक और फ़ाइल से संबंधित कार्यों में जोड़ सकता हूं, लेकिन यह अभी भी मुझे परेशान करता है कि यूनिक्स के कई संस्करणों में यह है कि लिनक्स आमतौर पर नहीं करता है। – JAB

उत्तर

16

जैसा कि अन्य पोस्टर का उल्लेख है, समस्या की जड़ यह है कि अस्थायी प्रारंभ नहीं है। जब स्टैक पर एक स्वचालित चर के रूप में घोषित किया जाता है तो इसमें उस स्मृति स्थान में जो भी कचरा होता है, उसमें शामिल होगा। स्पष्ट रूप से संकलक + सीपीयू + ओएस के लिए आप चल रहे हैं, उस स्थान पर कचरा एक वैध सूचक है। Strcpy "सफल" है कि यह segfault नहीं है, लेकिन वास्तव में यह स्मृति में कहीं और मनमानी स्थान के लिए एक स्ट्रिंग की प्रतिलिपि बनाई। इस प्रकार की स्मृति भ्रष्टाचार की समस्या सी प्रोग्रामर के दिल में हर जगह डरती है क्योंकि यह असाधारण रूप से डीबग करना मुश्किल है।

जब आप अस्थायी घोषणा को वैश्विक दायरे में ले जाते हैं, तो यह बीएसएस अनुभाग में रखा जाता है और स्वचालित रूप से शून्य हो जाता है। Dereference * temp के प्रयासों के परिणामस्वरूप एक segfault में परिणाम।

जब आप वैश्विक दायरे के रास्ते * स्थानांतरित करते हैं, तो * अस्थायी स्थान पर एक स्थान ऊपर स्थानांतरित होता है। उस स्थान पर कचरा स्पष्ट रूप से मान्य सूचक नहीं है, और इसलिए एक segfault में dereferencing * temp परिणाम।

+0

जैसा कि अपेक्षित है, वैरिएबल घोषणाओं के क्रम को स्वैप करना प्रोग्राम segfault बनाता है। धन्यवाद! – codemonkey

8

आप आवंटित और अस्थायी प्रारंभ करने में भूल गया था। तुम भी रन-टाइम में इस गणना कर सकते हैं, तो यकीन है कि आकार के लिए पर्याप्त है (कम से कम strlen किया जाना चाहिए (पथ)) बनाने

+0

अस्थायी रूप से मेमोरी को शुरू करने की कोई आवश्यकता नहीं है - strcpy इसका ख्याल रखेगा, भले ही यह प्रारंभिक शून्य शब्द सेट कर रहा हो। –

+0

इसके अलावा, इसे कम अवधि या खराब चीजें टी (एम) के परिणामस्वरूप कम से कम स्ट्रेलन (पथ) +1 होना चाहिए। –

+0

उसका मतलब है कि आपको "temp [0] = 0" लाइन की आवश्यकता नहीं है, क्योंकि strcpy() आपके लिए नल टर्मिनेटर जोड़ देगा। –

1

महत्वपूर्ण हिस्सा गौर करने योग्य
गंतव्य स्ट्रिंग गंतव्य इतना बड़ा प्राप्त करने के लिए किया जाना चाहिए प्रति।
आपकी स्थिति में अस्थायी में प्रतिलिपि बनाने के लिए आवंटित कोई स्मृति नहीं है।

strcpy मैन ऑफ द पेज से कॉपी किया गया:

DESCRIPTION 
    The strcpy() function copies the string pointed to by src (including 
    the terminating '\0' character) to the array pointed to by dest. The 
    strings may not overlap, and the destination string dest must be large 
    enough to receive the copy. 
9

अस्थायी चर किसी भी भंडारण (स्मृति) को इंगित नहीं करता और यह अप्रारंभीकृत है।

यदि temp को char temp[32]; के रूप में घोषित किया गया है तो कोड काम करेगा चाहे वह कहां घोषित किया गया हो। हालांकि, इस तरह के एक निश्चित आकार के साथ temp घोषित करने के साथ अन्य समस्याएं हैं, लेकिन यह एक और दिन के लिए एक सवाल है।

अब वैश्विक स्तर पर घोषित होने पर यह क्यों दुर्घटनाग्रस्त हो जाता है। भाग्य ...

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

वैश्विक रूप से घोषित किए जाने पर, अधिकांश प्रोसेसर पर इन चरों को डेटा सेगमेंट में संग्रहीत किया जाएगा जो मांग शून्य पृष्ठों का उपयोग करेंगे। इस प्रकार char *temp प्रतीत होता है जैसे इसे char *temp=0 घोषित किया गया था।

1

आप अपरिभाषित व्यवहार का आह्वान कर रहे हैं, क्योंकि आप temp चर प्रारंभ नहीं कर रहे हैं। यह स्मृति में एक यादृच्छिक स्थान को इंगित करता है, इसलिए आपका प्रोग्राम काम कर सकता है, लेकिन अधिकतर संभावना है कि यह segfault होगा। ,

// Make temp a static array of 256 chars 
char temp[256]; 
strncpy(temp, 256, path); 

// Or, use dynamic memory 
char *temp = (char *)malloc(256); 
strncpy(temp, 256, path); 

इसके अलावा strncpy() बजाय strcpy() का उपयोग बफर लगने से बचने के लिए: आप अपने गंतव्य स्ट्रिंग एक सरणी होना है, या यह गतिशील स्मृति को इंगित करने की जरूरत है।

+0

एडम, क्या यह उन सभी जादू संख्याओं को चारों ओर तैरने का अच्छा विचार है? ;-) –

+0

कि अभी भी बग है क्योंकि स्रोत स्ट्रिंग 256 लंबाई है, तो तारों में शून्य समाप्ति नहीं होती है। – Torlack

+0

मॉलोक द्वारा लौटाए गए पॉइंटर को डालने की कोई ज़रूरत नहीं है - मॉलोक एक शून्य पॉइंटर देता है और इस प्रकार कोई कलाकार की आवश्यकता नहीं होती है। इसके अलावा, इसे कास्टिंग करने से यह आपको चोट पहुंचा सकता है क्योंकि यह कोड की इस पंक्ति पर मॉलोक के साथ समस्याओं को छिपा सकता है (जैसा कि मॉलोक की अंतर्निहित परिभाषा यह एक int वापस कर रही है)। –

3

जैसा ऊपर बताया गया है, आप अस्थायी स्थान के लिए स्थान आवंटित करना भूल गए हैं। मैं strdup से malloc+strcpy पसंद करता हूं। यह वही करता है जो आप करना चाहते हैं।

+0

मुझे strdup के बारे में पता नहीं था। धन्यवाद। – codemonkey

2

नहीं - यह चर के बावजूद काम नहीं करता है - ऐसा लगता है कि ऐसा इसलिए हुआ क्योंकि आपको भाग्यशाली नहीं था। परिवर्तनीय अनियंत्रित छोड़ने के बजाय, आपको स्ट्रिंग की सामग्री को संग्रहीत करने के लिए स्थान आवंटित करने की आवश्यकता है।

स्टैक पर अनियंत्रित चर मेमोरी के बहुत अधिक यादृच्छिक स्थानों पर इंगित करने जा रहे हैं।यदि ये पते वैध होने के लिए होते हैं, तो आपका कोड जो कुछ भी था, उसे मिटा देगा, लेकिन आपको कोई त्रुटि नहीं मिलेगी (लेकिन आपके कोड में कहीं और गंदा स्मृति भ्रष्टाचार संबंधी बग मिल सकती है)।

ग्लोबल्स लगातार विफल हो जाते हैं क्योंकि वे आमतौर पर विशिष्ट पैटर्न पर सेट होते हैं जो अप्रयुक्त स्मृति को इंगित करते हैं। Dereference करने का प्रयास करने से यह आपको तुरंत एक segfault देता है (जो बेहतर है - बाद में इसे छोड़कर बग को ट्रैक करने में बहुत मुश्किल होती है)।

2

मैं इस तरह आप के रूप में

// Make temp a static array of 256 chars 
char temp[256]; 
strncpy(temp, sizeof(temp), path); 
temp[sizeof(temp)-1] = '\0'; 

पहले एडम टुकड़ा पुनर्लेखन करना चाहते हैं:

1. don't have magic numbers laced through the code, and 
2. you guarantee that your string is null terminated. 

दूसरी बात अपने स्रोत स्ट्रिंग के अंतिम चार के नुकसान पर है अगर यह होता है > = 256 वर्ण लंबा।

+0

wchar_t का उपयोग करते समय, यह काम नहीं करता है। आकार का उपयोग केवल वर्णों के साथ काम करता है। मुझे पता है, यह वर्णों के बारे में एक सवाल है, लेकिन मैं बहुत सारी चीजें चलाता हूं जहां लोग wchar_t के साथ आकार का उपयोग करते हैं। – Torlack

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