2010-07-20 21 views
20

तो यहाँ मेरा मानना ​​है कि मैं एक छोटे से बफर अतिप्रवाह समस्या मैंने पाया जब किसी और के कोड की समीक्षा की है। यह तुरंत मुझे गलत, और संभावित रूप से खतरनाक के रूप में मारा, लेकिन स्वीकार्य रूप से मैं इस "गलती" के वास्तविक परिणामों की व्याख्या नहीं कर सका, यदि कोई हो।इस बफर ओवरफ़्लो के परिणाम?

मैं त्रुटि प्रदर्शित करने के लिए एक परीक्षण एप्लिकेशन को लिखा है, लेकिन (मेरे निराशा) पाया इसे सही ढंग से अतिप्रवाह की परवाह किए बिना चलाने के लिए लगता है कि था। मैं विश्वास करना चाहता हूं कि यह सिर्फ मौका है, लेकिन यह निर्धारित करने के लिए कुछ फीडबैक चाहते थे कि मेरी सोच गलत थी या अगर वास्तव में कोई समस्या है तो यह मेरे टेस्ट ऐप में अपना सिर नहीं दिखा रहा है।

समस्या कोड (मुझे लगता है कि यह है, वैसे भी):

char* buffer = new char[strlen("This string is 27 char long" + 1)]; 
sprintf(buffer, "This string is 27 char long"); 

अब, कारण यह बाहर मेरे लिए खड़ा था और मैं इसे झंडा करना चाहते हैं के रूप में एक संभव बफर अतिप्रवाह पहले strlen की वजह से है। सूचक अंकगणित के कारण, 'गलत' + 1 की नियुक्ति strlen26 बजाय 27 वापस जाने के लिए कारण होगा (की लंबाई लेने "अपने स्ट्रिंग 27 वर्ण लंबा है")। sprintf, मुझे विश्वास है, फिर 27 char को बफर में प्रिंट करता है और एक बफर ओवरफ़्लो का कारण बनता है।

है कि एक सही आकलन है?

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

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




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

+4

आप पैडिंग/संरेखण के कारण उपरोक्त कोड के साथ काट नहीं सकते हैं। क्या आप अपने प्रयोगों को एक स्ट्रिंग के साथ दोहरा सकते हैं, 64 अक्षरों का कहना है, इसलिए आवंटन 65 वर्ण होने की आवश्यकता होगी? और 'sprintf' से पहले दो ऐसे तार आवंटित करें, उन्हें विभिन्न आदेशों में भरें। –

+4

कच्चे स्ट्रिंग लेने और इसे +1 जोड़ने के लिए यह बहुत बुरा कोड है! मैं केवल उस तथ्य पर कोड समीक्षा को झुका दूंगा। –

+1

और यही कारण है कि हम डेवलपर कई अच्छी तरह से परीक्षण पुस्तकालयों का उपयोग करते हैं जैसे हम कर सकते हैं ... क्योंकि हम इस तरह मूर्खतापूर्ण गलतियां करते हैं! :-) @ जॉन्सन मुझे पूरा यकीन है कि डेवलपर का मतलब लंबाई में 1 जोड़ना था, न कि स्ट्रिंग स्वयं, इसलिए बग। – corsiKa

उत्तर

14

आपका मूल्यांकन सही है। [संपादित करें] जेम्स Curran द्वारा उल्लिखित सुधार के अतिरिक्त [संपादित करें]

संभावना है कि, आपके टेस्ट ऐप ने समस्या नहीं दिखायी क्योंकि आवंटन 4, 8 या 16 के अगले एकाधिक तक है (जो आम आवंटन ग्रैन्युलरिटी हैं)।

इसका मतलब है कि आप 31 वर्ण लंबी स्ट्रिंग के साथ प्रदर्शित करने में सक्षम होना चाहिए।

वैकल्पिक रूप से, "उपकरण" मूल स्मृति प्रोफाइलर का उपयोग करें जो इस तरह के आवंटन के आसपास गार्ड बाइट्स को बारीकी से रख सकता है।

6

आप आकलन सही है, सिवाय इसके कि springf बफर में 28 अक्षर रखा जाएगा अंत में अंत के स्ट्रिंग NUL गिनती (यही कारण है कि आप गलत "+1" की जरूरत है पहली जगह में)

ध्यान दें कि मेरे अनुभवों में, अगर कुछ डीबगर के बाहर विफल रहता है, लेकिन डीबगर में चरणबद्ध होने के साथ काम करता है, तो 100% समय में, आपने स्थानीय बफर को ओवरराउन कर दिया है। डिबगर्स स्टैक पर बहुत अधिक धक्का देते हैं, इसलिए कम महत्वपूर्ण बात यह है कि कुछ महत्वपूर्ण ओवरराइट किया गया था।

+0

'\ 0' पर सुधार के लिए धन्यवाद, मुझे यकीन नहीं है कि यह मेरे दिमाग को क्यों फिसल गया :) – KevenK

1

हां, आप सही हैं। स्ट्रिंग को पकड़ने के लिए आवंटित बफर 2 बाइट बहुत छोटा होगा।

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

3

समस्या यह है कि आप स्मृति में कहीं लिख रहे हैं, लेकिन ढेर पर नहीं। इसलिए, वास्तव में यह देखना मुश्किल है कि क्या गलत है। आप नुकसान को देखने के लिए चाहते हैं, ढेर

char buffer[strlen("This string is 27 char long" + 1)]; 

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

इस तरह एक बफर ओवरफ़्लो का फायदा उठाने के लिए, आपको इच्छित डेटा लिखने की आवश्यकता है, फिर निष्पादित करने के लिए इस डेटा पर "कूदें" का एक तरीका खोजें।

+0

यह अभी भी एक गारंटी के लिए * गारंटीकृत * नहीं है क्योंकि स्टैक आवंटन आमतौर पर 4 या 8 बाइट सीमाओं के साथ गठबंधन होते हैं । – Roddy

1

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

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

भले ही आप अगली आवंटन शीर्षलेख (जिसे आवंटित मेमोरी ब्लॉक प्रबंधित करने के लिए उपयोग किया जाता है) को ओवरराइट करें, फिर भी यह उस समस्या के रूप में प्रकट नहीं होगा जब तक कि अगले ब्लॉक के मालिक ने इसे ढेर में वापस करने का प्रयास नहीं किया।

1

कई ऐतिहासिक malloc कार्यान्वयन ने पहले और/या आवंटित ब्लॉक के तुरंत बाद बहीखाता डेटा रखा। यह संभव है कि आप इस तरह के डेटा को ओवरराइट कर रहे हों, इस स्थिति में जब तक आप स्मृति को मुक्त करने का प्रयास नहीं करते हैं, तब तक आपको कोई त्रुटि/क्रैश नहीं दिखाई देगा (या शायद अगला ब्लॉक जो भी हो)। इसी प्रकार, यह संभव है कि बाद के आवंटन के लिए बहीखाता जानकारी बाद में आपकी स्ट्रिंग को ओवरराइट कर देगी।

मैं आधुनिक malloc कार्यान्वयन अखंडता की जांच डेटा के साथ गद्दी आवंटन से ढेर भ्रष्टाचार के खिलाफ की रक्षा के लिए कुछ प्रयास करना संदेह है, इसलिए यदि आप भाग्यशाली हैं, बुरा कुछ नहीं होगा या आप एक बाद में आवंटन/मुक्त दौरान एक चेतावनी संदेश मिल सकता ऑपरेशन।

0

जैसा कि दूसरों ने कहा है, आप यह मानने में पूरी तरह से सही हैं कि यह कोई अच्छा नहीं है, और कारण यह है कि आप इसे नहीं देखते हैं। इस पर valgrind आज़माएं, यह निश्चित रूप से उस त्रुटि को ढूंढ लेगा।

0

आपका असली समस्या यह है कि आप मतलब है कि पहले एक पर आप strlen दे रहे हैं() एक पते जो नहीं है

char* buffer = new char[strlen("This string is 27 char long") + 1]; 

के बजाय

char* buffer = new char[strlen("This string is 27 char long" + 1)]; 

लिख रहे है आपकी स्ट्रिंग की शुरुआत

इस कोड का प्रयास करें:

const char szText[] = "This string is 27 char long"; 
char* buffer = new char[strlen(szText) + 1]; 
sprintf(buffer, szText); 
+0

वह पहले से ही जानता है।उत्तर पोस्ट करने से पहले प्रश्न पढ़ें। – manneorama

+1

मुझे समस्या पता है, यही वह है जो मुझे खड़ा था और मुझे यहां लाया। यह किसी और के कोड में था, मुझे बस दूसरी राय की आवश्यकता थी और उम्मीद है कि अतिरिक्त ज्ञान और अंतर्दृष्टि यहां शानदार रही है। आपके सहयोग के लिए धन्यवाद! – KevenK

+0

आप इस सवाल का जवाब नहीं दे रहे हैं। वह जानता है कि '1' जगह से बाहर है। उन्होंने स्पष्ट रूप से इस सवाल में कहा। वह जानना चाहता था कि त्रुटि का उसका मूल्यांकन सही था क्योंकि वह परीक्षण के साथ गलत व्यवहार नहीं कर सका। –

1

मैं ढेर आवंटन के साथ यह कोशिश की, चर इस मामले में स्मृति में निरंतर नहीं हैं। यही कारण है कि इस मामले में बफर ओवरफ्लो बनाना मुश्किल है।

खरीदें ढेर अतिप्रवाह के साथ प्रयास करें

#include "stdio.h" 
#include "string.h" 

int main() 
{ 
    unsigned int y  = (0xFFFFFFFF); 
    char buffer[strlen("This string is 27 char long" + 1)]; 
     unsigned int x  = (0xFFFFFFFF); 
     sprintf(buffer, "This string is 27 char long"); 

     printf("X (%#x) is %#x, Y (%#x) is %#x, buffer '%s' (%#x) \n", &x, x,&y, y, buffer, buffer); 
     return 0; 
    } 

आपको लगता है कि वाई दूषित है देखेंगे।

0

डीबगर में स्ट्रिंग ठीक प्रिंटिंग का कारण यह है कि स्पिंटफ के हिस्से के रूप में, पीछे वाले नल चरित्र को स्मृति में लिखा जा रहा है (इस मामले में आपके द्वारा आवंटित बफर से परे) और जब स्ट्रिंग को पढ़ने की बात आती है अपेक्षित स्ट्रिंग को समाप्त करने के लिए पूर्ण वर्ण मौजूद है।

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

0

सही कथन। चूंकि आप स्ट्रिंग के दूसरे अक्षर के स्ट्रिंग() को संबोधित कर रहे हैं, इसलिए परिणामस्वरूप आपको लंबाई एक वर्ण कम हो रहा है। इसके अलावा, मुख्य समस्या sprintf() के साथ है, यह एक कारण है कि यह सुरक्षित नहीं है।

यहां तक ​​कि यह संकलित और निष्पादित (भी क्रैश हो सकता है)।

char* x = new char; 
    sprintf(x, "This is way longer than one character"); 
    printf("%s", x); 

आदेश में इस खतरनाक समस्या से बचने के लिए, आपको जीसीसी या sprintf_s() MSVC के तहत के तहत snprintf की तरह इस समारोह() या asprintf() की सुरक्षित संस्करण का उपयोग करना चाहिए।

संदर्भ के रूप में, कृपया इस संबंध में The GNU C Library documentation पर और एमएसडीएन के sprintf() आलेख की सुरक्षा नोट देखें।

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