2011-01-28 29 views
5

पृष्ठभूमि: मेरे पास एक छोटी दिनचर्या है जो fgets(character, 2, fp) की नकल करती है सिवाय इसके कि यह एक धारा के बजाय स्ट्रिंग से एक वर्ण लेती है। newBuff गतिशील रूप से आवंटित स्ट्रिंग को पैरामीटर के रूप में पारित किया गया है और चरित्र char character[2] के रूप में घोषित किया गया है।वालग्रिंड चेतावनी: क्या मुझे इसे गंभीरता से लेना चाहिए

नियमित:

character[0] = newBuff[0]; 

character[1] = '\0'; 

strcpy(newBuff, newBuff+1); 

strcpy प्रत्येक चरित्र के रूप में सूचना के नुकसान replicates से पढ़ा जाता है।

समस्या: वेलग्रिंड मुझे के बारे में इस गतिविधि ने चेतावनी दी है, "स्रोत और गंतव्य strcpy में ओवरलैप (0x419b818, 0x419b819)"।

क्या मुझे इस चेतावनी के बारे में चिंता करनी चाहिए?

उत्तर

9

शायद मानक निर्दिष्ट नहीं करता है कि इन बफर ओवरलैप होने पर क्या होता है। तो हाँ, valgrind इस बारे में शिकायत करने का अधिकार है।

व्यावहारिक दृष्टि से आप सबसे अधिक संभावना पाएंगे कि अपनेstrcpy से क्रम में प्रतियां बाएँ-से-सही (जैसे। while (*dst++ = *src++);) है और यह कोई मुद्दा नहीं है कि। लेकिन यह अभी भी गलत है और अन्य सी पुस्तकालयों के साथ चलते समय समस्या हो सकती है।

एक मानकों पर सही तरीका लिखने के लिए इस होगा:

memmove(newBuff, newBuff+1, strlen(newBuff)); 

क्योंकि memmove ओवरलैप को संभालने के लिए परिभाषित किया गया है। (यहाँ यद्यपि आप ऊपर स्ट्रिंग traversing दो बार लंबाई की जांच करने के लिए खत्म हो जाएगा, एक बार और एक बार कॉपी करने के लिए। मैं भी एक शॉर्टकट ले लिया क्योंकि strlen(newBuff)strlen(newBuff+1)+1 है, जो है जो मैं मूल रूप से लिखा बराबर होना चाहिए।)

+0

भले ही ऑर्डरिंग बाएं से दाएं हो, फिर भी अनलॉकिंग/रीडरिंग और प्रतिलिपि की बड़ी-बाइट इकाइयों के कारण समस्याएं हो सकती हैं। मैं 'स्ट्रैपी' के इस उपयोग को अत्यधिक असुरक्षित और उसी पुस्तकालय के विभिन्न संस्करणों के बीच भी तोड़ने की संभावना, या विभिन्न कंपाइलरों के साथ अलग-अलग निर्माणों पर भी विचार करता हूं। –

+0

@ आर .. मैं सहमत हूं, विशेष रूप से बड़े-से-बाइट इकाइयों के बारे में बिंदु के साथ। बस स्पष्ट होने के लिए, मैं सहमत हूं कि कोड गलत है और बदला जाना चाहिए। – asveikau

2

strcpy() का व्यवहार आधिकारिक रूप से अपरिभाषित है यदि स्रोत और गंतव्य ओवरलैप हो। स्मृति क्षेत्र एस 1 को s2

memcpy() फ़ंक्शन प्रतियां n बाइट्स स्मृति क्षेत्र से:

memcpy के लिए मैनपेज से एक सुझाव आता है। यदि एस 1 और एस 2 ओवरलैप, व्यवहार अपरिभाषित है। जिन अनुप्रयोगों में एस 1 और एस 2 ओवरलैप हो सकते हैं, उन्हें इसके बजाय memmove (3) का उपयोग करना चाहिए।

+1

चाहे यह कैसे कार्यान्वित किया गया हो, व्यवहार अपरिभाषित है। यह मानक में स्पष्ट रूप से कहा गया है। –

+0

'strcpy' बफर ओवरलैप होने पर अपरिभाषित व्यवहार देता है। 'memcpy' वही करता है, लेकिन अन्यथा अप्रासंगिक है। –

+0

ठीक है, मेरे स्थानीय मैन पेज स्ट्रैपी के लिए उस चेतावनी में शामिल नहीं है, लेकिन memcpy एक करता है। – mkb

4

हां - strcpy का व्यवहार केवल तभी परिभाषित किया जाता है जब स्रोत और भाग ओवरलैप न हो। आप इसके बजाय strlen और memmove के संयोजन पर विचार कर सकते हैं।

3

हां, आपको चिंता करनी चाहिए। सी मानक बताता है कि strcpy का व्यवहार undefined है जब स्रोत और गंतव्य ऑब्जेक्ट ओवरलैप होते हैं। अनिर्धारित व्यवहार का अर्थ है कि यह कभी-कभी काम कर सकता है, या यह असफल हो सकता है, या यह सफल होने के लिए प्रकट हो सकता है लेकिन प्रोग्राम में कहीं और विफलता विफलता दिखाई दे सकती है।

+0

+1! –

5

हाँ, और आप यह भी चिंता करनी चाहिए कि आपके कार्य में पथदर्शी रूप से खराब प्रदर्शन है (O(n^2) एक कार्य के लिए जो O(n) होना चाहिए)। प्रत्येक बार जब आप एक चरित्र पढ़ते हैं तो स्ट्रिंग की पूरी सामग्री को किसी चरित्र द्वारा वापस ले जाना समय की एक बड़ी बर्बादी है। इसके बजाय आपको केवल वर्तमान स्थिति में पॉइंटर रखना चाहिए और उस सूचक को बढ़ा देना चाहिए।

हालात जहां आप अपने आप को memmove या समकक्ष (बफ़र्स जो आपस में मिलते बीच नकल) की आवश्यकता होगी, लगता है लगभग हमेशा एक डिजाइन दोष संकेत मिलता है। अक्सर यह कार्यान्वयन में केवल एक दोष नहीं है बल्कि इंटरफ़ेस में है।

2

उत्तर हाँ है: कुछ संकलक/लाइब्रेरी कार्यान्वयन के साथ, मुझे लगता है कि नवीनतम, आप एक फर्जी परिणाम के साथ खत्म हो जाएगा। उदाहरण के लिए How is strcpy implemented? देखें।