मानक पुस्तकालय से कौन से कार्य करने चाहिए?


90

मैंने स्टैक ओवरफ्लो पर पढ़ा है कि कुछ सी फ़ंक्शंस "अप्रचलित" हैं या "से बचा जाना चाहिए"। क्या आप मुझे इस तरह के समारोह के कुछ उदाहरण और कारण बता सकते हैं?

उन कार्यों के क्या विकल्प मौजूद हैं?

क्या हम उन्हें सुरक्षित रूप से उपयोग कर सकते हैं - कोई भी अच्छी प्रथा?


3
मेरा मानना ​​है कि यह जानना बहुत अच्छी बात है। सी के कुछ कार्यों को वास्तव में टाला जाना चाहिए और केवल शैक्षिक उद्देश्यों के लिए उपयोग किया जाना चाहिए ।
आईएनएस

@ फेलिक्स, भविष्य में एक एकल (सही चिह्नित) उत्तर को संपादित करना आसान होगा। यह वास्तव में उन उत्तरों के बारे में हवा में है जो समय के साथ बदल जाएंगे। कौन जानता है, शायद जेफ उन लोगों को एक 'चौकीदार' बैज प्रदान करेगा जो अगले कुछ वर्षों में जवाब प्रस्तुत करते हैं।
टिम पोस्ट

1
@ समय पोस्ट: ठीक है मैं अपनी टिप्पणी हटा दूंगा
फेलिक्स क्लिंग

3
मैं strncpy()एक सामान्य प्रतिस्थापन के रूप में उपयोग नहीं करूंगा strcpy(), और मैं strncat()कभी भी इसका उपयोग नहीं करूंगा क्योंकि इसमें सबसे अधिक अनपेक्षित इंटरफ़ेस कल्पनाशील है - क्या आप जानते हैं कि लंबाई पैरामीटर क्या निर्दिष्ट करता है?
जोनाथन लेफ़लर

2
Strncpy और strncat का उपयोग करना लगभग हमेशा एक गलती है। वे निश्चित रूप से strcpy और strcat के स्थान पर उपयोग नहीं किया जाना चाहिए !! स्कैनफ और स्प्रिंटफ भी पूरी तरह से उपयोग करने योग्य हैं यदि आप जानते हैं कि उनका उपयोग कैसे किया जाए ...
R .. GitHub STOP HELPING ICE

जवाबों:


58

पदावनत किए गए कार्य
असुरक्षित
ऐसे कार्य का एक आदर्श उदाहरण मिलता है () , क्योंकि यह बताने का कोई तरीका नहीं है कि गंतव्य बफर कितना बड़ा है। नतीजतन, कोई भी प्रोग्राम जो इनपुट का उपयोग करके पढ़ता है () में बफर अतिप्रवाह भेद्यता है । इसी तरह के कारणों के लिए, एक का उपयोग करना चाहिए strncpy () के स्थान पर strcpy () और strncat () के स्थान पर strcat ()

फिर भी कुछ और उदाहरणों में ओवरफ्लो अस्थायी फ़ाइलों के साथ संभावित सुरक्षा मुद्दों के कारण tmpfile () और mktemp () फ़ंक्शन शामिल हैं और जिन्हें अधिक सुरक्षित mkstemp () फ़ंक्शन द्वारा सुपरकोड किया गया है ।

गैर-अप्रेंटेंट
अन्य उदाहरणों में gethostbyaddr () और gethostbyname () शामिल हैं जो गैर-रीएंन्ट्रेंट (और, इसलिए, थ्रेडसेफ़ होने की गारंटी नहीं हैं) और पुनः प्राप्त करने वाले getadrinrinfo () और freeaddrinfo () द्वारा लिया गया है

आप यहां एक पैटर्न देख रहे हैं ... या तो सुरक्षा की कमी (संभवतः इसे सुरक्षित रूप से लागू करने के लिए हस्ताक्षर में पर्याप्त जानकारी शामिल करने में विफल होने से) या गैर-पुनरावृत्ति पदावनति के सामान्य स्रोत हैं।

आउटडेटेड, गैर-पोर्टेबल
कुछ अन्य कार्य केवल इसलिए हो जाते हैं क्योंकि वे कार्यक्षमता की नकल करते हैं और अन्य वेरिएंट की तरह पोर्टेबल नहीं होते हैं। उदाहरण के लिए, bzero () के पक्ष में पदावनत किया गया है memset ()

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

  • यह पश्चाताप है (यानी यह किसी भी राज्य को कॉल के बीच साझा नहीं करता है), या:
  • यह गैर-पश्चाताप है, लेकिन यह साझा राज्य के लिए आवश्यकतानुसार सिंक्रनाइज़ेशन / लॉकिंग का उपयोग करता है।

सामान्य तौर पर, सिंगल यूनिक्स स्पेसिफिकेशन और IEEE 1003.1 (यानी "POSIX") में, किसी भी फंक्शन को रीवेंटेंट होने की गारंटी नहीं दी जाती है, जो थ्रेड सुरक्षित होने की गारंटी नहीं है। इसलिए, दूसरे शब्दों में, केवल उन कार्यों को, जो प्रतिरूप होने की गारंटी दी जाती है, का उपयोग बहुपक्षीय अनुप्रयोगों में (बाहरी लॉक के बिना) किया जा सकता है। हालांकि, इसका मतलब यह नहीं है कि इन मानकों के कार्यान्वयन गैर-रीवेंट्रेंट फ़ंक्शन थ्रेडसेफ़ बनाने के लिए नहीं चुन सकते हैं। उदाहरण के लिए, लिनक्स अक्सर थ्रेडसैफिटी की गारंटी (सिंगल यूनिक्स विशिष्टता से परे) को जोड़ने के लिए गैर-रीक्रेंट कार्यों में सिंक्रनाइज़ेशन जोड़ता है।

स्ट्रिंग्स (और मेमोरी बफ़र्स, जनरल में)
आपने यह भी पूछा कि क्या स्ट्रिंग्स / सरणियों के साथ कुछ मूलभूत दोष है। कुछ लोग यह तर्क दे सकते हैं कि यह मामला है, लेकिन मैं तर्क दूंगा कि भाषा में कोई मौलिक दोष नहीं है। C और C ++ के लिए आपको किसी सरणी की लंबाई / क्षमता को अलग से पास करने की आवश्यकता होती है (यह कुछ भाषाओं में ".length" संपत्ति नहीं है)। यह एक दोष नहीं है, प्रति-से। कोई भी C और C ++ डेवलपर लंबाई को एक पैरामीटर के रूप में जहां जरूरत हो बस सही कोड लिख सकते हैं। समस्या यह है कि इस जानकारी की आवश्यकता वाले कई एपीआई इसे एक पैरामीटर के रूप में निर्दिष्ट करने में विफल रहे। या यह मान लिया जाए कि कुछ MAX_BUFFER_SIZE स्थिरांक का उपयोग किया जाएगा। इस तरह के एपीआई को अब बदल दिया गया है और वैकल्पिक एपीआई द्वारा प्रतिस्थापित किया गया है जो सरणी / बफर / स्ट्रिंग आकार को निर्दिष्ट करने की अनुमति देता है।

Scanf (आपके अंतिम प्रश्न के उत्तर में)
व्यक्तिगत रूप से, मैं C ++ iostreams लाइब्रेरी (std :: cin, std :: cout, the << और >> ऑपरेटर्स, std :: getline, std :: istringstream, std / ostringstream) का उपयोग करता हूं , आदि), इसलिए मैं आम तौर पर उस के साथ सौदा नहीं करता। मैं शुद्ध सी का उपयोग करने के लिए मजबूर किया गया तो, हालांकि, मैं व्यक्तिगत रूप से सिर्फ प्रयोग करेंगे fgetc () या getchar () संयोजन में साथ strtol () , strtoul () , आदि और पार्स बातें मैन्युअल रूप से, के बाद से मैं का एक बड़ा प्रशंसक नहीं हूँ varargs या format strings। उस ने कहा, मेरे ज्ञान का सबसे अच्छा करने के लिए, [एफ] स्कैनफ () , [एफ] प्रिंटफ () के साथ कोई समस्या नहीं है, आदि जब तक आप प्रारूप को स्वयं तार करते हैं, तब तक आप कभी भी मनमाने प्रारूप के तार पास नहीं करते हैं या उपयोगकर्ता इनपुट को प्रारूप के तार के रूप में उपयोग करने की अनुमति नहीं देते हैं, और आप <inttypes.h> में परिभाषित स्वरूपण मैक्रोज़ का उपयोग करते हैं, जहाँ उपयुक्त हो। (ध्यान दें, snprintf () के स्थान पर इस्तेमाल किया जाना चाहिए sprintf () , लेकिन वह गंतव्य बफर के आकार और नहीं प्रारूप तार के उपयोग को निर्दिष्ट करने में नाकाम रहने के साथ क्या करना है)। मुझे यह भी इंगित करना चाहिए कि, C ++ में, बढ़ावा :: प्रारूप , varargs के बिना प्रिंटफ़-जैसे स्वरूपण प्रदान करता है।


4
"पदावनत" एक मजबूत शब्द है, जिसका C ++ मानक पर चर्चा करते समय एक विशिष्ट अर्थ है। उस अर्थ में, हो जाता है (), strcpy () आदि को पदावनत नहीं किया जाता है।

4
बस जब तक आप "सी मानक द्वारा पदावनत", "माइकल आरोन सफायन द्वारा पदावनत", और "ऐसे व्यक्ति या व्यक्तियों द्वारा पदावनत किए गए जो अज्ञात हैं, जो उम्मीद करते हैं कि वे जानते हैं कि वे [प्रशस्ति पत्र की जरूरत है]" के बीच अंतर करते हैं। सवाल है के बारे में शैली कोडिंग, नहीं सी मानक के बारे में पसंद किया, दूसरा दो उपयुक्त हैं तो। लेकिन नील की तरह मुझे यह महसूस करने से पहले एक डबल-टेक की आवश्यकता थी कि आपके बयानों का पहला अर्थ नहीं था।
स्टीव जेसप

11
strncpyआम तौर पर के रूप में अच्छी तरह से बचा जाना चाहिए। यह वह नहीं करता है जो अधिकांश प्रोग्रामर मानते हैं। यह समाप्ति की गारंटी नहीं देता है (बफर ओवररन की ओर जाता है), और यह छोटे तार (संभवतः कुछ मामलों में प्रदर्शन को कम कर देता है) को पैड करता है।
एड्रियन मैक्कार्थी

2
@ एड्रियन: मैं आपसे सहमत हूँ - न तो strncpy()और न ही इससे भी बदतर strncat()n- कम वेरिएंट के लिए एक समझदार प्रतिस्थापन है।
जोनाथन लेफ़लर

4
यह जवाब बकवास हठधर्मिता के बारे में फैलता है "strcpy को strncpy से बदलें - मुझे नहीं पता लेकिन Microsoft मुझे क्यों बताता है।" strncpy को कभी भी strcpy का सुरक्षित संस्करण होने का इरादा नहीं था! सामना में यह कहीं अधिक असुरक्षित है। देखें कि क्यों असुरक्षित और अकड़ असुरक्षित माने जाते हैं?
लुंडिन

24

एक बार फिर से लोग दोहरा रहे हैं, मंत्र की तरह, लुभावनी मुखरता कि "एन" संस्करण के फंक्शंस सुरक्षित संस्करण हैं।

अगर ऐसा था, तो उनका इरादा था कि वे हमेशा तार समाप्त कर देंगे।

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

यदि s2 द्वारा इंगित की गई सरणी एक स्ट्रिंग है जो n बाइट्स से छोटी है, तो null बाइट्स s1 द्वारा इंगित की गई सरणी में कॉपी में संलग्न हैं, जब तक कि सभी में n बाइट्स नहीं लिखे जाते हैं।

जैसा कि फ़ाइल नाम को संभालने के लिए आवंटित बफ़र्स आमतौर पर 4kbytes होते हैं, इससे प्रदर्शन में भारी गिरावट हो सकती है।

यदि आप "कथित रूप से" सुरक्षित संस्करण चाहते हैं, तो अपने स्वयं के - strl routines (strlcpy, strlcat आदि) को प्राप्त करें या लिखें, जो हमेशा स्ट्रिंग्स को समाप्त करते हैं और साइड इफेक्ट नहीं होते हैं। कृपया ध्यान दें कि ये वास्तव में सुरक्षित नहीं हैं क्योंकि वे स्ट्रिंग को चुपचाप मिटा सकते हैं - यह शायद ही कभी किसी वास्तविक दुनिया के कार्यक्रम में कार्रवाई का सबसे अच्छा कोर्स है। ऐसे अवसर हैं जहां यह ठीक है, लेकिन कई परिस्थितियां भी हैं जहां यह भयावह परिणाम हो सकता है (उदाहरण के लिए चिकित्सा पर्चे छापना)।


1
आप सही हैं strncpy(), लेकिन गलत हैं strncat()strncat()तय लंबाई वाले क्षेत्रों के साथ उपयोग के लिए डिज़ाइन नहीं किया गया था - यह वास्तव में डिज़ाइन किया गया था जो strcat()कि वर्णों की संख्या को सीमित करता है। यह एक "सुरक्षित के रूप में उपयोग करने के लिए काफी आसान है strcat()बफर में शेष जब कई concatenations कर रही है, और भी आसान एक" सुरक्षित के रूप में उपयोग करने के लिए अंतरिक्ष का ट्रैक रखने के द्वारा " strcpy()करने के लिए गंतव्य बफर का पहला वर्ण की स्थापना द्वारा" ( '\0'पहले इसे पुकारना)। strncat() हमेशा गंतव्य स्ट्रिंग को समाप्त करता है, और यह अतिरिक्त '\0'एस नहीं लिखता है ।
कैफ़े

2
@caf - हाँ, लेकिन strncat () पूरी तरह से बेकार है क्योंकि यह एक पैरामीटर के रूप में कॉपी की जाने वाली अधिकतम लंबाई है - गंतव्य बफर की लंबाई नहीं। बफर ओवरफ्लो को रोकने के लिए आपको वर्तमान गंतव्य स्ट्रिंग की लंबाई जानने की आवश्यकता है, और यदि आप जानते हैं कि आप स्ट्रेंकट () का उपयोग क्यों करेंगे - जिससे इसे फिर से लंबाई में काम करना पड़ता है - बजाय केवल स्ट्रालकैट () स्रोत स्ट्रिंग गंतव्य स्ट्रिंग का अंत।
डिपस्टिक

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

2
@chrisharris: strncat()स्रोत स्ट्रिंग की लंबाई की परवाह किए बिना ठीक से काम करेगा, जबकि strcat()ऐसा नहीं होगा। यहाँ समस्या strlcat()यह है कि यह एक मानक C फ़ंक्शन नहीं है।
डेविड थॉर्नले

@ caf - आप strncat () के बारे में सही हैं। मैंने वास्तव में इसका उपयोग कभी नहीं किया क्योंकि - जैसा कि मैंने ऊपर बताया है - यह पूरी तरह से बेकार है। इसलिए अभी भी इससे बचना चाहिए।
डिपस्टिक

19

यहां कई जवाबों का उपयोग करके सुझाव दिया strncat()गया है strcat(); मेरा सुझाव है कि strncat()(और strncpy()) भी बचा जाना चाहिए। इसमें ऐसी समस्याएं हैं जो सही तरीके से उपयोग करना और बग को जन्म देती हैं:

  • लंबाई पैरामीटर से strncat()संबंधित है (लेकिन बिल्कुल ठीक नहीं - तीसरा बिंदु देखें) अधिकतम वर्ण जो गंतव्य बफ़र के आकार के बजाय गंतव्य पर कॉपी किए जा सकते हैं। यह strncat()उपयोग करने की तुलना में इसे और अधिक कठिन बनाता है, खासकर अगर कई वस्तुओं को गंतव्य तक पहुंचाया जाएगा।
  • यह निर्धारित करना मुश्किल हो सकता है कि क्या परिणाम छोटा था (जो महत्वपूर्ण हो सकता है या नहीं भी हो सकता है)
  • ऑफ-द-वन त्रुटि होना आसान है। C99 मानक नोटों के रूप में, "इस प्रकार, वर्णों की अधिकतम संख्या जो इंगित की गई सरणी में समाप्त हो सकती s1है strlen(s1)+n+1" एक कॉल के लिए है जो इस तरह दिखता हैstrncat( s1, s2, n)

strncpy()एक समस्या यह भी है कि बग आप इसे सहज तरीके से उपयोग करने की कोशिश कर सकते हैं - यह गारंटी नहीं है कि गंतव्य शून्य समाप्त हो गया है। यह सुनिश्चित करने के लिए कि आपको विशेष रूप '\0'से बफ़र के अंतिम स्थान पर स्वयं (कुछ स्थितियों में कम से कम) ड्रॉप करके उस कोने के मामले को विशेष रूप से संभालना है ।

मैं OpenBSD की तरह कुछ का उपयोग कर सुझाव देंगे strlcat()और strlcpy()(हालांकि मुझे पता है कि कुछ लोगों को उन कार्यों नापसंद, मेरा मानना है कि वे अब तक की तुलना में सुरक्षित रूप से उपयोग करने के लिए आसान कर रहे हैं strncat()/ strncpy())।

यहां बताया गया है टोड मिलर और थियो द रादत के साथ समस्याओं के बारे में कहना था का एक छोटा है strncat()और strncpy():

वहाँ कई समस्याओं का सामना करना पड़ा जब कर रहे हैं strncpy()और strncat()के सुरक्षित संस्करण के रूप में उपयोग किया जाता है strcpy()और strcat()। दोनों फ़ंक्शन एनयूएल-समाप्ति और अलग-अलग और गैर-सहज तरीके से लंबाई पैरामीटर से निपटते हैं जो अनुभवी प्रोग्रामर को भ्रमित करते हैं। ट्रंकेशन होने पर वे पता लगाने का कोई आसान तरीका भी प्रदान करते हैं। ... इन सभी मुद्दों में, लंबाई मापदंडों और एनयूएल-समाप्ति के संबंधित मुद्दे के कारण भ्रम सबसे महत्वपूर्ण हैं। जब हम संभावित सुरक्षा छेद के लिए OpenBSD स्रोत पेड़ लेखा परीक्षित हम के बड़े पैमाने पर दुरुपयोग पाया strncpy()और strncat()। हालांकि इन सभी के कारण शोषक सुरक्षा छेद नहीं थे, उन्होंने यह स्पष्ट कर दिया कि उपयोग करने के लिए strncpy()और strncat()सुरक्षित स्ट्रिंग संचालन में नियमों का व्यापक रूप से गलत अर्थ है।

ओपनबीएसडी के सुरक्षा ऑडिट में पाया गया कि इन कार्यों के साथ बग "उग्र" थे। इसके विपरीत gets(), इन फ़ंक्शंस को सुरक्षित रूप से उपयोग किया जा सकता है, लेकिन व्यवहार में बहुत सारी समस्याएं हैं क्योंकि इंटरफ़ेस भ्रामक है, अचूक और सही ढंग से उपयोग करने में मुश्किल है। मुझे पता है कि Microsoft ने भी विश्लेषण किया है (हालांकि मुझे नहीं पता कि उनके डेटा का कितना हिस्सा वे प्रकाशित कर सकते हैं), और परिणामस्वरूप प्रतिबंध लगा दिया है (या कम से कम बहुत दृढ़ता से हतोत्साहित - 'प्रतिबंध' निरपेक्ष नहीं हो सकता है) का उपयोग करें strncat()और strncpy()(अन्य कार्यों के अलावा)।

अधिक जानकारी के साथ कुछ लिंक:


1
स्ट्रिंग के बाहर तारों की लंबाई का ट्रैक रखना कहीं बेहतर है। उस तरह, दो स्ट्रिंग्स (-विथ-लंबाई) को सुरक्षित रूप से सुरक्षित करना एक साधारण गणना (आवश्यक बफर आकार प्राप्त करने के लिए) एक संभावित वास्तविककरण, और ए memmove()। (ठीक है, आप memcpy()सामान्य स्थिति में उपयोग कर सकते हैं जब तार स्वतंत्र होते हैं।)
डोनल फैलो

1
आपका दूसरा बिंदु गलत है - strncat() हमेशा गंतव्य स्ट्रिंग को समाप्त करता है।
कैफे

1
आपके लिए दूसरा बिंदु गलत है strncat()। हालाँकि, यह सही है strncpy(), जिसमें कुछ अन्य समस्याएं हैं। strncat()के लिए एक उचित प्रतिस्थापन है strcat(), लेकिन के strncpy()लिए एक उचित प्रतिस्थापन नहीं है strcpy()
डेविड थॉर्नले

2
कैफे और डेविड मेरे दावे के बारे में 100% सही हैं जो strncat()हमेशा समाप्त नहीं करता है। मैं strncat()और व्यवहार को strncpy()थोड़ा भ्रमित कर रहा था (एक और कारण जो वे बचने के लिए कार्य कर रहे हैं - उनके पास ऐसे नाम हैं जो समान व्यवहार करते हैं, लेकिन वास्तव में महत्वपूर्ण तरीकों से अलग व्यवहार करते हैं ...)। मैंने इसे सुधारने के साथ-साथ अतिरिक्त जानकारी जोड़ने के लिए अपने उत्तर में संशोधन किया है।
माइकल बूर

1
ध्यान दें कि char str[N] = ""; strncat(str, "long string", sizeof(str));एक बफर अतिप्रवाह है यदि N पर्याप्त बड़ा नहीं है। strncat()समारोह दुरुपयोग करने के लिए बहुत आसान है; इसका उपयोग नहीं किया जाना चाहिए। यदि आप strncat()सुरक्षित रूप से उपयोग कर सकते हैं , तो आप उपयोग कर सकते हैं memmove()या memcpy()इसके बजाय (और वे अधिक कुशल होंगे)।
जोनाथन लेफ्लर

9

मानक पुस्तकालय कार्य जिनका उपयोग कभी नहीं किया जाना चाहिए :

setjmp.h

  • setjmp()। साथ में longjmp(), इन कार्यों को व्यापक रूप से उपयोग करने के लिए अविश्वसनीय रूप से खतरनाक के रूप में पहचाना जाता है: वे स्पेगेटी प्रोग्रामिंग का नेतृत्व करते हैं, वे अपरिभाषित व्यवहार के कई रूपों के साथ आते हैं, वे कार्यक्रम के वातावरण में अनपेक्षित दुष्प्रभावों का कारण बन सकते हैं, जैसे कि स्टैक पर संग्रहीत मूल्यों को प्रभावित करना। संदर्भ: MISRA-C: 2012 नियम 21.4, CERT C MSC22-C
  • longjmp()। देखते हैं setjmp()

stdio.h

  • gets()। फ़ंक्शन को C भाषा (C11 के अनुसार) से हटा दिया गया है, क्योंकि यह डिज़ाइन के अनुसार असुरक्षित था। फ़ंक्शन को पहले ही C99 में अप्रचलित के रूप में फ़्लैग किया गया था। fgets()इसके बजाय उपयोग करें । संदर्भ: आईएसओ 9899: 2011 K.3.5.4.1, नोट 404 भी देखें।

stdlib.h

  • atoi()कार्यों का परिवार। जब भी त्रुटियां होती हैं, तो इनमें कोई त्रुटि नहीं होती है, लेकिन अपरिभाषित व्यवहार को लागू करती है। पूरी तरह से शानदार कार्य जिन्हें कार्यों के strtol()परिवार के साथ बदला जा सकता है । संदर्भ: MISRA-C: 2012 नियम 21.7।

string.h

  • strncat()। एक अजीब इंटरफ़ेस है जिसका अक्सर दुरुपयोग किया जाता है। यह ज्यादातर एक शानदार फंक्शन है। इसके लिए टिप्पणी भी देखें strncpy()
  • strncpy()। इस समारोह का उद्देश्य कभी भी सुरक्षित संस्करण नहीं था strcpy()। इसका एकमात्र उद्देश्य हमेशा यूनिक्स सिस्टम पर एक प्राचीन स्ट्रिंग प्रारूप को संभालना था, और इसे मानक पुस्तकालय में शामिल किया जाना एक ज्ञात गलती है। यह फ़ंक्शन खतरनाक है क्योंकि यह बिना शून्य समाप्ति के स्ट्रिंग छोड़ सकता है और प्रोग्रामर को अक्सर इसका गलत तरीके से उपयोग करने के लिए जाना जाता है। सन्दर्भ: क्यों strlcpy और strlcat को असुरक्षित माना जाता है?

मानक पुस्तकालय कार्य जिनका उपयोग सावधानी के साथ किया जाना चाहिए:

assert.h

  • assert()। ओवरहेड के साथ आता है और आमतौर पर उत्पादन कोड में उपयोग नहीं किया जाना चाहिए। एप्लिकेशन-विशिष्ट त्रुटि हैंडलर का उपयोग करना बेहतर है जो त्रुटियों को प्रदर्शित करता है लेकिन जरूरी नहीं कि पूरे कार्यक्रम को बंद कर दें।

signal.h

  • signal()। संदर्भ: MISRA-C: 2012 नियम 21.5, CERT C SIG32-C

stdarg.h

  • va_arg()कार्यों का परिवार। एक सी कार्यक्रम में चर-लंबाई के कार्यों की उपस्थिति लगभग हमेशा खराब कार्यक्रम डिजाइन का संकेत है। जब तक आपके पास बहुत विशिष्ट आवश्यकताएं हैं, तब तक बचा जाना चाहिए।

stdio.h
आम तौर पर, यह पूरी लाइब्रेरी उत्पादन कोड के लिए अनुशंसित नहीं है , क्योंकि यह खराब-परिभाषित व्यवहार और खराब सुरक्षा के कई मामलों के साथ आता है।

  • fflush()। आउटपुट स्ट्रीम के लिए उपयोग करने के लिए बिल्कुल ठीक है। इनपुट धाराओं के लिए उपयोग किए जाने पर अपरिभाषित व्यवहार को आमंत्रित करता है।
  • gets_s()gets()C11 सीमा-जाँच इंटरफ़ेस में शामिल का सुरक्षित संस्करण । fgets()सी मानक अनुशंसा के अनुसार इसका उपयोग करना पसंद किया जाता है। संदर्भ: आईएसओ 9899: 2011 K.3.5.4.1।
  • printf()कार्यों का परिवार। संसाधन भारी कार्य जो बहुत सारे अपरिभाषित व्यवहार और खराब प्रकार की सुरक्षा के साथ आते हैं। sprintf()भेद्यता भी है। उत्पादन कोड में इन कार्यों से बचा जाना चाहिए। संदर्भ: MISRA-C: 2012 नियम 21.6।
  • scanf()कार्यों का परिवार। टिप्पणियों के बारे में देखें printf()। इसके अलावा, - scanf()अगर यह सही तरीके से उपयोग नहीं किया जाता है तो बफर ओवररन के लिए कमजोर है। fgets()जब संभव हो तो उपयोग करना पसंद किया जाता है। संदर्भ: CERT C INT05-C , MISRA-C: 2012 नियम 21.6।
  • tmpfile()कार्यों का परिवार। विभिन्न भेद्यता मुद्दों के साथ आता है। संदर्भ: CERT सी FIO21 सी

stdlib.h

  • malloc()कार्यों का परिवार। होस्ट किए गए सिस्टम में उपयोग करने के लिए पूरी तरह से ठीक है, हालांकि C90 में अच्छी तरह से ज्ञात मुद्दों के बारे में जानते हैं और इसलिए परिणाम नहीं देते हैंmalloc()कार्यों के परिवार अनुप्रयोगों फ्रीस्टैंडिंग में कभी नहीं किया जाना चाहिए। संदर्भ: MISRA-C: 2012 नियम 21.3।

    यह भी ध्यान दें कि realloc()यदि आप परिणाम के साथ पुराने सूचक को ओवरराइट करते हैं तो यह खतरनाक है realloc()। यदि फ़ंक्शन विफल हो जाता है, तो आप एक रिसाव बनाते हैं।

  • system()। बहुत सारे ओवरहेड और यद्यपि पोर्टेबल के साथ आता है, इसके बजाय सिस्टम-विशिष्ट एपीआई फ़ंक्शन का उपयोग करना अक्सर बेहतर होता है। विभिन्न खराब परिभाषित व्यवहार के साथ आता है। संदर्भ: CERT सी ENV33 सी

string.h

  • strcat()। के लिए टिप्पणी देखें strcpy()
  • strcpy()। उपयोग करने के लिए पूरी तरह से ठीक है, जब तक कि नकल किए जाने वाले डेटा का आकार गंतव्य बफर से अज्ञात या बड़ा न हो। यदि आने वाले डेटा आकार की कोई जांच नहीं की जाती है, तो बफर ओवररन हो सकते हैं। जो strcpy()स्वयं का कोई दोष नहीं है , लेकिन कॉलिंग एप्लिकेशन - जो strcpy()असुरक्षित है, ज्यादातर Microsoft द्वारा बनाया गया एक मिथक है
  • strtok()। कॉलर स्ट्रिंग को बदल देता है और आंतरिक राज्य चर का उपयोग करता है, जो इसे बहु-थ्रेडेड वातावरण में असुरक्षित बना सकता है।

मैं सुझाव देता हूं कि यदि संकलित समय पर स्थिति का समाधान किया जा सकता है, तो इसके static_assert()स्थान पर सिफारिश करना assert()। इसके अलावा, sprintf()लगभग हमेशा बदला जा सकता है snprintf()जो थोड़ा सा सुरक्षित है।
user694733

1
strtok()फ़ंक्शन में ए का उपयोग करने का मतलब है कि (ए) फ़ंक्शन किसी अन्य फ़ंक्शन को कॉल नहीं कर सकता है जो strtok()ए का उपयोग करते समय भी उपयोग करता है, और (बी) का अर्थ है कि ए को कॉल करने वाला कोई भी फ़ंक्शन ए का उपयोग नहीं किया जा सकता है strtok()strtok()कॉल चेन को जहर; इसे लाइब्रेरी कोड में सुरक्षित रूप से उपयोग नहीं किया जा सकता है क्योंकि यह दस्तावेज़ होना चाहिए जो strtok()अन्य उपयोगकर्ताओं strtok()को लाइब्रेरी कोड को कॉल करने से रोकने के लिए उपयोग करता है ।
जोनाथन लेफ़लर

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

7

कुछ लोग दावा करेंगे कि strcpyऔर strcat, के पक्ष में strncpyऔर बचा जाना चाहिए strncat। यह कुछ हद तक व्यक्तिपरक है, मेरी राय में।

उपयोगकर्ता इनपुट से निपटने के दौरान उन्हें निश्चित रूप से बचा जाना चाहिए - यहां कोई संदेह नहीं है।

उपयोगकर्ता से "दूर" कोड में, जब आप जानते हैं कि बफ़र्स लंबे समय तक पर्याप्त हैं, strcpyऔर strcatथोड़ा अधिक कुशल हो सकता है क्योंकि nउनके चचेरे भाइयों को पारित करने के लिए कंप्यूटिंग सुपरफ्लस हो सकती है।


4
और अगर उपलब्ध है, तो बेहतर है strlcatऔर strlcpy, चूंकि 'एन' संस्करण गंतव्य स्ट्रिंग की पूर्ण समाप्ति की गारंटी नहीं देता है।
दान एंड्रीटा

मेरे लिए समय से पहले अनुकूलन जैसा लगता है। लेकिन IIRC, यदि आवश्यक हो तो nul वर्णों का उपयोग करते हुए, strncpy()बिल्कुल nबाइट्स लिखेंगे । डैन के रूप में, एक सुरक्षित संस्करण का उपयोग करना सबसे अच्छा विकल्प आईएमओ है।
बैस्टियन लेओनार्ड

@, ये कार्य दुर्भाग्य से गैर-मानक हैं, और इसलिए इस चर्चा से संबंधित नहीं हैं
एली बेन्द्स्की

@ एली: लेकिन यह तथ्य कि strncat()सही और सुरक्षित रूप से उपयोग करना मुश्किल हो सकता है (और बचा जाना चाहिए) विषय पर है।
माइकल Burr

@ माइकल: मैं यह नहीं कहूंगा कि इसका सही और सुरक्षित रूप से उपयोग करना मुश्किल है। देखभाल के साथ, यह ठीक काम करता है
एली बेंडरस्की

6

बचें

  • strtok इसके थ्रेड-सुरक्षित के रूप में बहुस्तरीय कार्यक्रमों के लिए।
  • gets क्योंकि इससे बफर ओवरफ्लो हो सकता है

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

9
strtok()थ्रेड सेफ़्टी से थोड़ा आगे बढ़ने के साथ समस्या - एक थ्रेडेड प्रोग्राम में भी सुरक्षित नहीं है जब तक कि आप यह निश्चित रूप से नहीं जानते कि कोई भी फ़ंक्शंस आपके कोड का उपयोग strtok()करते समय कॉल नहीं कर सकता है (या वे इसे strtok()सही स्थिति में गड़बड़ करेंगे। तुम्हारे नीचे से)। वास्तव में, बहु-थ्रेडेड प्लेटफ़ॉर्म को लक्षित करने वाले अधिकांश कंपाइलर्स strtok()संभावित समस्याओं का ध्यान रखते हैं, जहाँ तक थ्रेड के strtok()स्थैतिक डेटा के लिए थ्रेड-लोकल स्टोरेज का उपयोग करके धागे चलते हैं । लेकिन यह अभी भी अन्य कार्यों की समस्या को ठीक नहीं करता है जब आप इसका उपयोग करते हैं (उसी धागे में)।
माइकल बूर

वास्तव में और मैं अब चुप हो जाऊंगा क्योंकि मैं किसी को भी स्ट्रेटोक का उपयोग करने के लिए प्रोत्साहित नहीं करना चाहता क्योंकि यह कई समस्याओं से ग्रस्त है। मैं तो बस का कहना है कि यह अलग होता है के रूप में यह हो जाता है से चाहता था है इसे सुरक्षित रूप से उपयोग करने के लिए, जबकि यह उपयोग करने के लिए असंभव है संभव सुरक्षित रूप से हो जाता है।
जेकोडर

@ जिमी: अक्सर गैर-मानक लाइब्रेरी एक्सटेंशन होते हैं, या आप अपना स्वयं का लिख ​​सकते हैं। इसके साथ बड़ी समस्या strtok()यह है कि यह ठीक से काम करने के लिए एक बफर रखता है, इसलिए सबसे अच्छी प्रतिस्थापन को बफर मान रखने और इसे पास करने की आवश्यकता होती है।
डेविड थोरले

strcspnक्या आप की जरूरत है - अगले टोकन विभाजक पाते हैं। आप strtokइसके साथ एक सामान्य संस्करण को फिर से लागू कर सकते हैं ।
bluss

5

यह शायद फिर से जोड़ने के लायक है कि strncpy()यह सामान्य उद्देश्य प्रतिस्थापन नहीं है strcpy()कि यह नाम सुझा सकता है। यह निश्चित-लंबाई वाले क्षेत्रों के लिए डिज़ाइन किया गया है, जिसमें एक न्युल-टर्मिनेटर की आवश्यकता नहीं है (यह मूल रूप से UNIX निर्देशिका प्रविष्टियों के साथ उपयोग के लिए डिज़ाइन किया गया था, लेकिन एन्क्रिप्शन कुंजी फ़ील्ड जैसी चीज़ों के लिए उपयोगी हो सकता है)।

हालांकि, इसके strncat()प्रतिस्थापन के रूप में उपयोग करना आसान है strcpy():

if (dest_size > 0)
{
    dest[0] = '\0';
    strncat(dest, source, dest_size - 1);
}

( ifपरीक्षण स्पष्ट रूप से सामान्य मामले में गिराया जा सकता है, जहां आप जानते हैं कि dest_sizeनिश्चित रूप से नॉनजेरो है)।


5

Microsoft की प्रतिबंधित APIs की सूची भी देखें । ये एपीआई (यहां पहले से सूचीबद्ध कई सहित) हैं जो Microsoft कोड से प्रतिबंधित हैं क्योंकि उनका अक्सर दुरुपयोग होता है और सुरक्षा समस्याओं का कारण बनता है।

आप उन सभी से सहमत नहीं हो सकते हैं, लेकिन वे सभी विचार करने योग्य हैं। वे सूची में एक एपीआई जोड़ते हैं जब इसके दुरुपयोग ने कई सुरक्षा बगों को जन्म दिया है।


2

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


2

स्प्रिंट के बारे में मत भूलना - यह कई समस्याओं का कारण है। यह सच है क्योंकि विकल्प, स्निप्रफ में कभी-कभी अलग-अलग कार्यान्वयन होते हैं जो आपको कोड को असंगत बना सकते हैं।

  1. linux: http://linux.die.net/man/3/snprintf

  2. विंडोज़: http://msdn.microsoft.com/en-us/library/2ts7cx93%28VS.71%29 .aspx

मामले 1 में (लिनक्स) रिटर्न वैल्यू पूरे बफर को स्टोर करने के लिए आवश्यक डेटा की मात्रा है (यदि यह दिए गए बफर के आकार से छोटा है तो आउटपुट छोटा हो गया था)

यदि आउटपुट छोटा है, तो केस 2 (विंडोज़) में रिटर्न वैल्यू एक ऋणात्मक संख्या है।

आम तौर पर आपको उन कार्यों से बचना चाहिए जो नहीं हैं:

  1. बफर अतिप्रवाह सुरक्षित (बहुत सारे कार्य पहले से ही यहां बताए गए हैं)

  2. धागा सुरक्षित / प्रतिवादी नहीं (उदाहरण के लिए स्ट्रॉक)

प्रत्येक फ़ंक्शन के मैनुअल में आपको कीवर्ड की खोज करनी चाहिए जैसे: सुरक्षित, सिंक, एसिंक्स, थ्रेड, बफर, बग


2
_sprintf()Microsoft द्वारा मानक snprintf()IIRC आने से पहले बनाया गया था । ´StringCbPrintf ()snprintf() । हालांकि काफी समान है ।
बास्टियन लेओनार्ड

आप उपयोग कर सकते हैं sprintfकुछ मामलों में सुरक्षित रूप से किसी भी तरह: sprintf(buffer,"%10s",input);सीमित करता है की नकल की nb 10 बाइट्स (यदि bufferहै char buffer[11]यह सुरक्षित है, भले ही डेटा हवा हो सकता है छोटा कर दिया।
जीन फ़्राँस्वा Fabre

2

इसे scanfसुरक्षित रूप से उपयोग करना बहुत कठिन है । scanfबफर ओवरफ्लो से बचने का अच्छा उपयोग किया जा सकता है, लेकिन आप अभी भी अपरिभाषित व्यवहार की चपेट में हैं जब पढ़ी गई संख्याएं जो अनुरोधित प्रकार में फिट नहीं होती हैं। ज्यादातर मामलों में, fgetsस्वयं को पार्स द्वारा पीछा (का उपयोग कर sscanf, strchrआदि) एक बेहतर विकल्प है।

लेकिन मैं यह नहीं कहूंगा कि " scanfहर समय बचें "। scanfइसके उपयोग हैं। एक उदाहरण के रूप में, मान लें कि आप उपयोगकर्ता इनपुट को char10 बाइट्स वाली सरणी में पढ़ना चाहते हैं । यदि आप अनुगामी न्यूलाइन को हटाना चाहते हैं, यदि कोई हो। यदि उपयोगकर्ता किसी नई पंक्ति से पहले 9 से अधिक वर्णों में प्रवेश करता है, तो आप पहले 9 वर्णों को बफर में संग्रहित करना चाहते हैं और अगली नई तिथि तक सब कुछ छोड़ देते हैं। तुम कर सकते हो:

char buf[10];
scanf("%9[^\n]%*[^\n]", buf));
getchar();

एक बार जब आप इस मुहावरे के लिए अभ्यस्त हो जाते हैं, तो यह छोटा और कुछ मायनों में क्लीनर से निम्न होता है:

char buf[10];
if (fgets(buf, sizeof buf, stdin) != NULL) {
    char *nl;
    if ((nl = strrchr(buf, '\n')) == NULL) {
        int c;
        while ((c = getchar()) != EOF && c != '\n') {
            ;
        }
    } else {
        *nl = 0;
    }
}

0

सभी स्ट्रिंग-कॉपी / चाल परिदृश्यों में - strcat (), strncat (), strcpy (), strncpy (), इत्यादि - चीजें कुछ बेहतर ( सुरक्षित ) हो जाती हैं यदि एक युगल सरल उत्तराधिकार लागू किया जाता है:

   1. हमेशा NUL-fill डेटा जोड़ने से पहले आपका बफ़र।
   2. चरित्र-बफ़र्स को [SIZE + 1] के रूप में, स्थूल-स्थिरांक के साथ घोषित करें।

उदाहरण के लिए, दिया गया:

#define   BUFSIZE   10
char      Buffer[BUFSIZE+1] = { 0x00 };  /* The compiler NUL-fills the rest */

हम जैसे कोड का उपयोग कर सकते हैं:

memset(Buffer,0x00,sizeof(Buffer));
strncpy(Buffer,BUFSIZE,"12345678901234567890");

अपेक्षाकृत सुरक्षित रूप से। स्ट्रेट्स्की () से पहले ही समस्वरता () दिखाई देनी चाहिए, हालांकि हमने कंपाइलर-टाइम पर बफ़र को इनिशियलाइज़ किया है, क्योंकि हम नहीं जानते कि हमारे फंक्शन को कॉल करने से पहले कौन सा कचरा इसमें रखा गया था। Strncpy () कॉपी किए गए डेटा को "1234567890" पर काट देगा, और इसे NUL-term नहीं देगा । हालांकि, चूंकि हम पहले से ही BULSIZE के बजाय पूरे बफर - साइज़ोफ़ (बफ़र) को भर चुके हैं, वैसे भी NUL को समाप्त करने के लिए एक अंतिम "आउट-ऑफ-स्कोप" होने की गारंटी है, जब तक हम BUFSIZE का उपयोग करके अपने कार्यों को बाधित नहीं करते हैं आकार के बजाय स्थिर (बफर)।

स्निपर () के लिए बफर और BUFSIZE इसी तरह ठीक काम करते हैं:

memset(Buffer,0x00,sizeof(Buffer));
if(snprintf(Buffer,BUFIZE,"Data: %s","Too much data") > BUFSIZE) {
    /* Do some error-handling */
}   /* If using MFC, you need if(... < 0), instead */

हालांकि स्निप्रफ () विशेष रूप से केवल BUFIZE-1 अक्षर लिखते हैं, इसके बाद NUL, यह सुरक्षित रूप से काम करता है। इसलिए हम बफ़र के अंत में एक बाहरी एनयूएल बाइट को "बर्बाद" करते हैं ... हम बफर-अतिप्रवाह और असंबद्ध स्ट्रिंग स्थितियों दोनों को रोकते हैं, एक बहुत छोटी स्मृति-लागत के लिए।

Strcat () और strncat () पर मेरी कॉल अधिक हार्ड-लाइन है: उनका उपयोग न करें। स्ट्रैकट () को सुरक्षित रूप से उपयोग करना मुश्किल है, और स्ट्रेंकैट के लिए एपीआई () इतना जवाबी-सहज है कि इसे ठीक से उपयोग करने के लिए आवश्यक प्रयास किसी भी लाभ को उपेक्षित करता है। मैं निम्नलिखित ड्रॉप-इन का प्रस्ताव करता हूं:

#define strncat(target,source,bufsize) snprintf(target,source,"%s%s",target,source)

यह एक स्ट्रैट () ड्रॉप-इन बनाने के लिए आकर्षक है, लेकिन एक अच्छा विचार नहीं है:

#define strcat(target,source) snprintf(target,sizeof(target),"%s%s",target,source)

क्योंकि टार्गेट एक पॉइंटर हो सकता है (इस प्रकार sizeof () हमारे पास आवश्यक जानकारी नहीं देता है)। मेरे पास आपके कोड में strcat () के उदाहरणों के लिए एक अच्छा "सार्वभौमिक" समाधान नहीं है।

एक समस्या जिसे मैं अक्सर "strFunc () - जागरूक" प्रोग्रामर से सामना करता हूं, वह स्ट्रैलेन () का उपयोग करके बफर-ओवरफ्लो से बचाने का प्रयास है। यह ठीक है अगर सामग्री एनयूएल-समाप्त होने की गारंटी है। अन्यथा, स्ट्रैलेन () स्वयं एक बफर-ओवररन त्रुटि (आमतौर पर एक विभाजन उल्लंघन या अन्य कोर-डंप स्थिति के लिए अग्रणी) का कारण बन सकता है, इससे पहले कि आप "समस्याग्रस्त" कोड तक पहुंचने से पहले आप की रक्षा करने की कोशिश कर रहे हैं।


-2

atoi धागा सुरक्षित नहीं है। मैं मैन पेज से सिफारिश के अनुसार स्ट्रैटोल का उपयोग करता हूं।


5
ऐसा लगता है कि यह एक विशेष कार्यान्वयन पर लागू होता है। कोई कारण नहीं है कि strtol()थ्रेड सुरक्षित atoi()होगा और नहीं होगा।
डेविड थॉर्नले

2
स्ट्रेटोल का उपयोग करने की सिफारिश का थ्रेड सुरक्षा से कोई लेना-देना नहीं है, लेकिन त्रुटि से निपटने के साथ। निश्चित नहीं है कि आपको वह आदमी किस पृष्ठ से मिला है - मुझे नीचे कोई सिफारिश नहीं मिल सकती है man atoi(हालांकि होना चाहिए, हालांकि)।
लंडिन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.