क्या मेम्ची (0,0,0) प्रदर्शन करने के लिए सुरक्षित होने की गारंटी है?


80

मैं सी मानक का इतना अच्छा जानकार नहीं हूं, इसलिए कृपया मेरे साथ रहें।

मैं यह जानना चाहूंगा कि क्या यह गारंटी है कि मानक द्वारा, memcpy(0,0,0)यह सुरक्षित है।

केवल प्रतिबंध मुझे मिल सकता है कि यदि स्मृति क्षेत्र ओवरलैप करते हैं, तो व्यवहार अपरिभाषित है ...

लेकिन क्या हम इस बात पर विचार कर सकते हैं कि स्मृति क्षेत्र यहां ओवरलैप करते हैं?


7
गणितीय रूप से दो खाली सेटों का प्रतिच्छेदन खाली है।
बेनोइट

मैं तुम्हारे लिए जाँच करना चाहता था (x) libC तुम्हारे लिए करता है, लेकिन जैसा कि यह asm (elibc / glibc) है, यह थोड़ा बहुत सुबह के लिए जटिल है :)
केविन

16
+1 मुझे यह सवाल बहुत पसंद है क्योंकि यह इस तरह का एक अजीब मामला है और क्योंकि मुझे लगता memcpy(0,0,0)है कि मैंने सी कोड के सबसे अजीब टुकड़ों में से एक देखा है।
templatetypedef

2
@eq क्या आप वास्तव में जानना चाहते हैं, या आप यह आरोप लगा रहे हैं कि जब आप चाहें तो ऐसी कोई स्थिति नहीं है? क्या आपने माना है कि वास्तविक कॉल हो सकता है, कहते हैं memcpy(outp, inp, len),? और यह कोड में हो सकता है जहां outpऔर inpगतिशील रूप से आवंटित किए गए हैं और शुरू में हैं 0? यह काम करता है, उदाहरण के लिए, के साथ p = realloc(p, len+n)जब pऔर lenकर रहे हैं 0। मैंने स्वयं इस तरह के memcpyकॉल का उपयोग किया है - जबकि यह तकनीकी रूप से यूबी है, मैंने कभी भी एक कार्यान्वयन का सामना नहीं किया है जहां यह एक नो-ऑप नहीं है और इसकी उम्मीद नहीं है।
जिम बेल्टर

7
@templatetypedef memcpy(0, 0, 0)सबसे अधिक संभावना है कि एक गतिशील का प्रतिनिधित्व करें, न कि स्थैतिक आह्वान का ... अर्थात, उन पैरामीटर मानों को शाब्दिक नहीं होना चाहिए।
जिम बाल्टर

जवाबों:


71

मेरे पास सी मानक (आईएसओ / आईईसी 9899: 1999) का एक मसौदा संस्करण है, और इसमें उस कॉल के बारे में कहने के लिए कुछ मजेदार चीजें हैं। शुरुआत के लिए, यह उल्लेख है (§7.21.1 / 2) के संबंध में memcpyहै कि

जहाँ size_tn के रूप में घोषित तर्क फ़ंक्शन के लिए सरणी की लंबाई निर्दिष्ट करता है, n उस फ़ंक्शन के लिए कॉल पर मान शून्य हो सकता है। जब तक स्पष्ट रूप से अन्यथा इस उप-धारा में किसी विशेष कार्य के विवरण में कहा गया हो, ऐसे कॉल पर सूचक तर्क में अभी भी मान्य मान होंगे, जैसा कि 7.1.4 में वर्णित है । ऐसे कॉल पर, एक फ़ंक्शन जो किसी वर्ण का पता लगाता है, कोई घटना नहीं होती है, एक ऐसा फ़ंक्शन जो दो वर्ण अनुक्रमों की तुलना करता है शून्य, और एक फ़ंक्शन जो वर्णों की प्रतिलिपि बनाता है, शून्य वर्णों की प्रतिलिपि बनाता है।

यहाँ इंगित किया गया संदर्भ इस ओर इशारा करता है:

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

तो ऐसा लगता है कि सी कल्पना के अनुसार, कॉलिंग

अपरिभाषित व्यवहार के परिणाम, क्योंकि अशक्त बिंदुओं को "अमान्य मान" माना जाता है।

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


3
मैं पुष्टि कर सकता हूं कि मसौदा मानक से उद्धृत भाग अंतिम दस्तावेज में समान हैं। ऐसे कॉल से कोई परेशानी नहीं होनी चाहिए, लेकिन यह अभी भी अपरिभाषित व्यवहार होगा जिस पर आप भरोसा कर रहे हैं। तो "यह गारंटी है" का जवाब "नहीं" है।
DevSolar

8
कोई कार्यान्वयन जिसे आप कभी भी उत्पादन में उपयोग करेंगे, इस तरह के कॉल के लिए नो-ऑप के अलावा कुछ भी उत्पादन करेंगे, लेकिन कार्यान्वयन जो अन्यथा अनुमति देते हैं और उचित हैं ... उदाहरण के लिए, एक सी दुभाषिया या संवर्धित संकलक त्रुटि जाँच के साथ जो अस्वीकार करता है। कॉल करें क्योंकि यह गैर-अनुरूप है। यदि मानक ने कॉल की अनुमति नहीं दी, तो यह उचित नहीं होगा realloc(0, 0)। उपयोग के मामले समान हैं, और मैंने उन दोनों का उपयोग किया है (प्रश्न के तहत मेरी टिप्पणी देखें)। यह व्यर्थ और दुर्भाग्यपूर्ण है कि मानक इस यूबी को बनाता है।
जिम बाल्टर

5
"अगर आपने ऐसा किया तो मेम्की का कोई भी वास्तविक क्रियान्वयन टूटने पर मैं एकदम चकित रह जाऊंगा" - मैंने एक प्रयोग किया है जो होगा; वास्तव में यदि आपने वैध संकेत के साथ लंबाई 0 पारित की है, तो यह वास्तव में 65536 बाइट्स की नकल करता है। (इसके लूप ने लंबाई को घटाया और फिर परीक्षण किया गया)।
MM

14
@MattMcNabb यह कार्यान्वयन टूट गया है।
जिम बाल्टर

3
@MattMcNabb: "सही" को "वास्तविक" में जोड़ें, हो सकता है। मुझे लगता है कि हम सभी को पुरानी, ​​यहूदी बस्ती के पुस्तकालयों की इतनी याद नहीं है और मुझे यकीन नहीं है कि हम उन यादों को याद करते हैं। :)
tmyklebu

24

बस मज़े के लिए, gcc-4.9 के लिए रिलीज़-नोट्स यह दर्शाते हैं कि इसके आशावादी इन नियमों का उपयोग करते हैं, और उदाहरण के लिए, इन शर्तों को दूर कर सकते हैं

जो तब अनपेक्षित परिणाम देता है जब copy(0,0,0)कहा जाता है (देखें https://gcc.gnu.org/gcc-4.9/porting_to.html )।

मैं gcc-4.9 व्यवहार के बारे में कुछ अस्पष्ट हूं; व्यवहार मानकों के अनुरूप हो सकता है, लेकिन मेमोवेट (0,0,0) को कॉल करने में सक्षम होना कभी-कभी उन मानकों के लिए एक उपयोगी विस्तार होता है।


2
दिलचस्प है। मैं आपकी महत्वाकांक्षा को समझता हूं लेकिन सी: कंपाइलर में अनुकूलन का दिल है मानता है कि डेवलपर्स कुछ नियमों का पालन करते हैं और इस प्रकार यह मानते हैं कि कुछ अनुकूलन वैध हैं (यदि वे नियमों का पालन किया जाता है)।
मैथ्यू एम।

2
@tmyklebu: दिया गया char *p = 0; int i=something;, अभिव्यक्ति का मूल्यांकन(p+i)i शून्य होने पर भी अपरिभाषित व्यवहार होगा ।
सुपरकैट

1
@tmyklebu: सभी सूचक अंकगणित (तुलना के अलावा) एक अशक्त सूचक जाल पर होने से IMHO एक अच्छी बात होगी; memcpy()गैर-शून्य गणना सुनिश्चित करने से पहले इसके तर्कों पर किसी भी सूचक अंकगणित को करने की अनुमति दी जानी चाहिए या नहीं, यह एक और सवाल है [अगर मैं मानकों को डिजाइन कर रहा था, तो मैं शायद निर्दिष्ट करूंगा कि यदि pअशक्त है, p+0तो फंस सकता है, लेकिन memcpy(p,p,0)कुछ नहीं करेगा]। एक बहुत बड़ी समस्या, IMHO, सबसे अपरिभाषित व्यवहार का खुलापन है। जबकि कुछ चीजें हैं जो वास्तव में अपरिभाषित व्यवहार (जैसे कॉलिंग ...free(p)
सुपरकैट) का

1
... और बाद में प्रदर्शन करते हुए p[0]=1;) बहुत सी चीजें हैं जिन्हें अनिश्चित परिणाम के परिणाम के रूप में निर्दिष्ट किया जाना चाहिए (जैसे असंबंधित बिंदुओं के बीच एक संबंधपरक तुलना किसी अन्य तुलना के अनुरूप नहीं होना चाहिए, लेकिन इसे या तो 0 के रूप में निर्दिष्ट किया जाना चाहिए। या 1), या कार्यान्वयन-परिभाषित की तुलना में थोड़ा कम व्यवहार व्यवहार करने के रूप में निर्दिष्ट किया जाना चाहिए (जैसे कि पूर्णांक अतिप्रवाह के सभी संभावित परिणामों को दस्तावेज करने के लिए आवश्यक होना चाहिए, लेकिन यह निर्दिष्ट नहीं करना चाहिए कि किसी विशेष मामले में परिणाम क्या होगा)।
सुपरकैट

8
कृपया मुझे बताएं, मुझे
स्टैकओवरफ़्लो

0

आप इसके उपयोग पर भी विचार कर सकते हैं memmove Git 2.14.x (Q3 2017) में देखे गए

देखें प्रतिबद्ध 168e635 (16 जुला 2017), और 1,773,664 प्रतिबद्ध , f331ab9 प्रतिबद्ध , प्रतिबद्ध 5,783,980 से (15 जुला 2017) रेने Scharfe ( rscharfe)
(द्वारा विलय Junio सी Hamano - gitster- में प्रतिबद्ध 32f9025 , 11 अगस्त 2017)

यह एक सहायक मैक्रोMOVE_ARRAY का उपयोग करता है जो हमारे लिए तत्वों की निर्दिष्ट संख्या के आधार पर आकार की गणना करता है और NULL उस संख्या के शून्य होने पर पॉइंटर्स का समर्थन करता है।
रॉ memmove(3)कॉल के साथ NULLकंपाइलर (अति-उत्सुकता से) बाद में होने वाले NULLचेक को ऑप्टिमाइज़ कर सकता है ।

MOVE_ARRAYसरणी प्रविष्टियों की संभावित अतिव्यापी सीमाओं को स्थानांतरित करने के लिए एक सुरक्षित और सुविधाजनक सहायक जोड़ता है।
यह तत्व आकार को संक्रमित करता है, बाइट में आकार प्राप्त करने के लिए स्वचालित रूप से और सुरक्षित रूप से गुणा करता है, तत्व के आकार की तुलना करके एक बुनियादी प्रकार की सुरक्षा जांच memmove(3)करता है और इसके विपरीत अगर यह NULL0 तत्वों को स्थानांतरित करने के लिए पॉइंटर्स का समर्थन करता है ।

उदाहरण :

इसका उपयोग करता है मैक्रोBUILD_ASSERT_OR_ZERO जो एक बिल्ड-टाइम निर्भरता को अभिव्यक्त करता है, एक अभिव्यक्ति के रूप में ( @condसंकलन-समय की स्थिति के साथ जो सच होना चाहिए)।
यदि स्थिति सत्य नहीं है, या संकलनकर्ता द्वारा मूल्यांकन नहीं किया जा सकता है तो संकलन विफल हो जाएगा।

उदाहरण:


2
ऑप्टिमाइज़र का अस्तित्व जो "चतुर" और "गूंगा" सोचते हैं, विलोम शब्द n को आवश्यक बनाता है, लेकिन अधिक कुशल कोड आम तौर पर एक कार्यान्वयन पर संभव होगा जो गारंटी देता है कि मेमोव (कोई भी, 0) एक नो-ऑप होगा । जब तक कोई कंपाइलर एक कॉल को मेम्मोव () को मेमोवेट एलेस्टीऑनबाइट () को कॉल करने के लिए बदल सकता है, जब तक कि चालाक / बेवकूफ कंपाइलर के "" ऑप्टिमाइज़ेशन "के खिलाफ गार्ड करने के लिए वर्कअराउंड आम तौर पर एक अतिरिक्त परिणाम होगा, एक कंपाइलर को समाप्त करने में सक्षम नहीं होगा।
सुपरकैट

-3

नहीं, memcpy(0,0,0)सुरक्षित नहीं है। मानक पुस्तकालय संभवतः उस कॉल पर विफल नहीं होगा। हालाँकि टेस्टिंग एनवायरनमेंट में, बफर अतिवृद्धि और अन्य समस्याओं का पता लगाने के लिए कुछ अतिरिक्त कोड मेम्ची () में मौजूद हो सकते हैं। और उस विशेष संस्करण का मेम्कॉपी () NULL पॉइंटर्स पर कैसे प्रतिक्रिया करता है, ठीक है, अपरिभाषित है।


मैं कुछ भी नहीं देख सकता कि आपका उत्तर मौजूदा उत्तरों में जोड़ता है जो पहले ही इंगित कर चुके हैं कि यह मानक से अंश के साथ सुरक्षित नहीं था।
मैथ्यू एम।

मैंने एक कारण लिखा है, क्यों एक मेमॉपी के कुछ कार्यान्वयन ("एक परीक्षण वातावरण में") मेमसीपी (0, 0, 0) के साथ समस्याओं का कारण हो सकता है। मैं इथिंक, वह नया है।
काई पेट्ज़के
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.