2012-08-31 16 views
6

डेटा को स्टोर करने के लिए उपयोग किए जाने वाले प्रोग्राम में निश्चित आकार के साथ कुछ बाइनरी बफर हैं। और बफर को एक से दूसरे में कॉपी करने के लिए memcpy का उपयोग किया जाता है। चूंकि स्रोत बफर गंतव्य बफर से बड़ा हो सकता है। बफर ओवरफ्लो होने पर मैं कैसे पता लगा सकता हूं?memcpy बफर ओवरफ़्लो को कैसे रोकें?

+1

पता लगाना? आप गंतव्य बफर आकार जानते हैं? फिर इस memcpy (src, dst, sizeof (dst)) जैसे कोड लिखें – BSen

+0

स्रोत बफर और गंतव्य बफर के आकार की तुलना करें और देखें कि कौन सा बड़ा है? – SingerOfTheFall

+1

@BSen कि 'sizeof'' केवल एक सूचक का आकार देगा। – juanchopanza

उत्तर

8

आपको यह जानना होगा कि स्रोत बफर में कितना डेटा है और लक्ष्य बफर में कितनी जगह उपलब्ध है।

memcpy() पर कॉल न करें यदि आपके द्वारा स्रोत बफर से कॉपी करने के लिए इच्छित सभी डेटा के लिए लक्ष्य बफर में पर्याप्त स्थान नहीं है। (आपको यह तय करना है कि स्रोत लक्ष्य से बड़ा है या नहीं, तो डेटा को छोटा करना ठीक है या नहीं।)

यदि आपको नहीं पता है, तो कोड को फिर से लिखें ताकि आप जान सकें कि कितनी जगह है; अन्यथा, यह सुरक्षित नहीं है।

ध्यान दें कि यदि स्रोत और लक्ष्य बफर ओवरलैपिंग का कोई मौका है, तो आपको का उपयोग करना चाहिए, बल्कि memcpy()

सी ++ में, पहले स्थान पर memcpy() का उपयोग करने पर पूछें; यह सी ++ की बजाय सी-स्टाइल ऑपरेशन है।

+0

धन्यवाद। सी ++ में मेमोरी कॉपी करने का सही तरीका क्या है? –

+1

@ माइकल डी: अपने डेटा को 'std :: vector <>' में संग्रहीत करें, और बस 'vector2 = vector1' का उपयोग करें। – MSalters

+0

मैं वेक्टर में डेटा कैसे सम्मिलित कर सकता हूं? बाइट द्वारा दिनांक बाइट डालने के लिए push_back का उपयोग करें? –

3

आपको हमेशा स्रोत और dest buffers आकार को जानना और जांचना चाहिए!

void *memcpy(void *dest, const void *src, size_t n); 

n कभी नहीं की तुलना में src या dest आकार बड़ा होना चाहिए।

0

उदाहरण के लिए आपके पास: आप कॉपी करने के लिए सुनिश्चित कर सकते हैं, अधिक से अधिक, गंतव्य बफर करने के लिए 4 बाइट

गंतव्य 4 बाइट आकार

स्रोत 5 बाइट्स आकार

:

size_t getCopySize(size_t sourceSize, size_t destSize) 
{ 
    return (destSize <= sourceSize ? destSize : sourceSize); 
} 
memcpy(destination, source, getCopySize(sizeof(source),sizeof(destination))); 

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

4

मैं कैसे पता लगा सकता हूं कि बफर ओवरफ़्लो है या नहीं?

मुझे लगता है कि आपके पास तीन या चार विकल्प हैं (देना या लेना)।


पहली पसंद memcpy के लिए एक "सुरक्षित" समारोह प्रदान करना है। मेरे अधिकार के तहत कोड में मुझे यही आवश्यकता है, और मैं इसके लिए नियमित रूप से लेखा परीक्षा करता हूं। मुझे सभी पैरामीटर की भी आवश्यकता है, और सभी मानकों को ज़ोर दिया जाता है।

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

errno_t safe_memcpy(void* dest, size_t dsize, void* src, size_t ssize, size_t cnt) 
{ 
    ASSERT(dest != NULL); 
    ASSERT(src != NULL); 
    ASSERT(dsize != 0); 
    ASSERT(ssize != 0); 
    ASSERT(cnt != 0); 

    // What was the point of this call? 
    if(cnt == 0) 
     retrn 0; 

    if(dest == NULL || src == NULL) 
     return EINVALID; 

    if(dsize == 0 || ssize == 0) 
     return EINVALID; 

    ASSERT(dsize <= RSIZE_MAX); 
    ASSERT(ssize <= RSIZE_MAX); 
    ASSERT(cnt <= RSIZE_MAX); 

    if(dsize > RSIZE_MAX || ssize > RSIZE_MAX || cnt > RSIZE_MAX) 
     return EINVALID; 

    size_t cc = min(min(dsize, ssize), cnt); 
    memmove(dest, src, cc); 

    if(cc != cnt) 
     return ETRUNCATE; 

    return 0; 
} 

यदि आपका safe_memcpy रिटर्न गैर 0 है, तो वहाँ एक बुरा पैरामीटर या संभावित बफर अतिप्रवाह की तरह एक त्रुटि हुई।


दूसरा विकल्प सी मानक द्वारा प्रदान किए गए "सुरक्षित" कार्यों का उपयोग करना है। सी ISO/IEC TR 24731-1, Bounds Checking Interfaces के माध्यम से "सुरक्षित" कार्यों में है। अनुरूप प्लेटफॉर्म पर, आप बस gets_s और sprintf_s पर कॉल कर सकते हैं। वे लगातार व्यवहार की पेशकश करते हैं (जैसे हमेशा एक स्ट्रिंग सुनिश्चित करना NULL समाप्त होता है) और लगातार वापसी मान (जैसे सफलता पर 0 या errno_t)।

errno_t err = memcpy_s(dest, dsize, src, cnt); 
... 

दुर्भाग्य से, जीसीसी और ग्लिब सी मानक के अनुरूप नहीं है। Ulrich Drepper (ग्लिबैक रखरखाव में से एक) को सीमाओं की जांच इंटरफेस "horribly inefficient BSD crap" कहा जाता है, और उन्हें कभी नहीं जोड़ा गया था।


तीसरा विकल्प मंच के "सुरक्षित" इंटरफेस का उपयोग करना है, यदि मौजूद है। विंडोज़ पर, यह ISO/IEC TR 24731-1, Bounds Checking Interfaces में समान होता है। आपके पास स्ट्रिंग सेफ़ लाइब्रेरी भी है।

ऐप्पल और बीएसडी पर, आपके पास memcpy के लिए "सुरक्षित" फ़ंक्शन नहीं है। लेकिन आपके पास strlcpy, strlcat और दोस्तों जैसे सुरक्षित स्ट्रिंग फ़ंक्शन हैं।


लिनक्स पर, आपकी चौथी पसंद FORTIFY_SOURCE का उपयोग करना है। FORTIFY_SOURCE memcpy, strcpy और gets जैसे उच्च जोखिम कार्यों के "सुरक्षित" रूपों का उपयोग करता है। कंपाइलर सुरक्षित भिन्नता का उपयोग करता है जब यह गंतव्य बफर आकार को कम कर सकता है। यदि प्रतिलिपि गंतव्य बफर आकार से अधिक हो जाएगी, तो प्रोग्राम abort() पर कॉल करता है। यदि संकलक गंतव्य बफर आकार को कम नहीं कर सकता है, तो "सुरक्षित" रूपों का उपयोग नहीं किया जाता है।

परीक्षण के लिए FORTIFY_SOURCE को अक्षम करने के लिए, आपको प्रोग्राम को -U_FORTIFY_SOURCE या -D_FORTIFY_SOURCE=0 से संकलित करना चाहिए।

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