क्यों फ़ंक्शन इतना खतरनाक है कि इसका उपयोग नहीं किया जाना चाहिए?


229

जब मैं gets()GCC के साथ फ़ंक्शन का उपयोग करने वाले C कोड को संकलित करने का प्रयास करता हूं, तो मुझे यह चेतावनी मिलती है:

(.text + 0x34): चेतावनी: `प्राप्त 'फ़ंक्शन खतरनाक है और इसका उपयोग नहीं किया जाना चाहिए।

मुझे याद है कि स्टैक सुरक्षा और सुरक्षा के साथ इसका कुछ करना है, लेकिन मुझे यकीन नहीं है कि ऐसा क्यों है।

मैं इस चेतावनी को कैसे हटा सकता हूं और उपयोग करने के बारे में ऐसी चेतावनी क्यों है gets()?

अगर gets()इतना खतरनाक है तो हम इसे क्यों नहीं हटा सकते?



जवाबों:


179

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

उपयोग करने के बजाय gets, आप उपयोग करना चाहते हैं fgets, जिस पर हस्ताक्षर हैं

char* fgets(char *string, int length, FILE * stream);

( fgets, यदि यह एक पूरी पंक्ति पढ़ता है, तो '\n'स्ट्रिंग को छोड़ देगा , आपको इससे निपटना होगा।)

यह 1999 आईएसओ सी मानक तक भाषा का एक आधिकारिक हिस्सा बना रहा, लेकिन इसे 2011 के मानक द्वारा आधिकारिक तौर पर हटा दिया गया। अधिकांश सी कार्यान्वयन अभी भी इसका समर्थन करते हैं, लेकिन कम से कम जीसीसी किसी भी कोड के लिए चेतावनी जारी करता है जो इसका उपयोग करता है।


79
यह वास्तव में gcc नहीं है जो चेतावनी देता है, यह glibc है जिसमें एक प्रज्ञा या विशेषता होती है gets()जिसके कारण कंपाइलर उपयोग किए जाने पर चेतावनी का उत्सर्जन करता है।
फुज

@ वास्तव में, यह केवल संकलक भी नहीं है जो चेतावनी देता है: ओपी में उद्धृत चेतावनी लिंकर द्वारा छपी थी!
रुसलान

163

क्यों gets()खतरनाक है

पहला इंटरनेट वर्म ( मॉरिस इंटरनेट वर्म ) लगभग 30 साल पहले (1988-11-02) बच गया था, और इसका इस्तेमाल gets()सिस्टम से सिस्टम के प्रचार के तरीकों में से एक के रूप में एक बफर ओवरफ्लो हुआ। मूल समस्या यह है कि फ़ंक्शन को यह पता नहीं है कि बफर कितना बड़ा है, इसलिए यह तब तक पढ़ना जारी रखता है जब तक कि यह एक नई लाइन या ईओएफ का सामना नहीं करता है, और यह दिए गए बफर की सीमा को ओवरफ्लो कर सकता है।

तुम भूल जाना चाहिए तुम कभी सुना है कि gets()अस्तित्व में है।

C11 मानक ISO / IEC 9899: 2011 gets()एक मानक फ़ंक्शन के रूप में समाप्त हो गया, जो कि ए थिंग थिंग ™ है (इसे औपचारिक रूप से ISO / IEC 9899 में 1999 और Cor.3 में 'अपवित्र' और 'पदावनत' के रूप में चिह्नित किया गया था) C99 के लिए 3, और फिर C11 में हटा दिया गया)। अफसोस की बात है कि यह पश्चगामी अनुकूलता के कारणों के लिए कई वर्षों तक (मतलब 'दशकों') पुस्तकालयों में बना रहेगा। यदि यह मेरे ऊपर होता, तो इसका कार्यान्वयन gets()हो जाता:

char *gets(char *buffer)
{
    assert(buffer != 0);
    abort();
    return 0;
}

यह देखते हुए कि आपका कोड किसी भी समय, जितनी जल्दी या बाद में दुर्घटनाग्रस्त हो जाएगा, यह बेहतर है कि मुसीबत को जल्द से जल्द दूर करें। मैं एक त्रुटि संदेश जोड़ने के लिए तैयार हूँ:

fputs("obsolete and dangerous function gets() called\n", stderr);

लिनक्स संकलन प्रणाली के आधुनिक संस्करण चेतावनी देते हैं यदि आप लिंक करते हैं gets()- और कुछ अन्य कार्यों के लिए भी जिनमें सुरक्षा समस्याएं हैं ( mktemp()...)।

के लिए विकल्प gets()

fgets ()

के रूप में हर किसी ने कहा, विहित विकल्प के लिए gets()किया जाता है fgets()निर्दिष्ट करने stdinफ़ाइल धारा के रूप में।

char buffer[BUFSIZ];

while (fgets(buffer, sizeof(buffer), stdin) != 0)
{
    ...process line of data...
}

अभी तक किसी और ने जो उल्लेख किया है, gets()उसमें न्यूलाइन शामिल नहीं है, लेकिन fgets()है। तो, आपको fgets()उस रैपर का उपयोग करने की आवश्यकता हो सकती है जो नई लाइन को हटाता है:

char *fgets_wrapper(char *buffer, size_t buflen, FILE *fp)
{
    if (fgets(buffer, buflen, fp) != 0)
    {
        size_t len = strlen(buffer);
        if (len > 0 && buffer[len-1] == '\n')
            buffer[len-1] = '\0';
        return buffer;
    }
    return 0;
}

या और अच्छा:

char *fgets_wrapper(char *buffer, size_t buflen, FILE *fp)
{
    if (fgets(buffer, buflen, fp) != 0)
    {
        buffer[strcspn(buffer, "\n")] = '\0';
        return buffer;
    }
    return 0;
}

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

        if (len > 0 && buffer[len-1] == '\n')
            buffer[len-1] = '\0';
        else
        {
             int ch;
             while ((ch = getc(fp)) != EOF && ch != '\n')
                 ;
        }

अवशिष्ट समस्या यह है कि तीन अलग-अलग परिणाम राज्यों को कैसे रिपोर्ट किया जाए - ईओएफ या त्रुटि, लाइन रीड एंड नॉट ट्रंकेटेड, और आंशिक लाइन रीड लेकिन डेटा को छोटा किया गया।

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


वहाँ भी है टी.आर. 24,731-1 (सी मानक समिति से तकनीकी रिपोर्ट), जो काम करता है, सहित की एक किस्म के लिए सुरक्षित विकल्प प्रदान करता है gets():

§6.5.4.1 gets_sफ़ंक्शन

सार

#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
char *gets_s(char *s, rsize_t n);

क्रम-बाधाओं

sअशक्त सूचक नहीं होगा। nन तो शून्य के बराबर होना चाहिए और न ही RSIZE_MAX से अधिक होना चाहिए। एक नया-पंक्ति वर्ण, फ़ाइल का अंत, या पढ़ने में त्रुटि, n-1पात्रों से पढ़ने के भीतर होगी stdin25)

3 यदि कोई रनटाइम-बाधा उल्लंघन है, s[0]तो अशक्त वर्ण पर सेट किया गया है, और वर्णों को stdinतब तक पढ़ा और खारिज किया जाता है जब तक कि एक नई-पंक्ति वर्ण पढ़ा नहीं जाता है, या अंत-फ़ाइल या एक पढ़ने में त्रुटि होती है।

विवरण

4 gets_sफ़ंक्शन द्वारा n इंगित की गई stdinसरणी में, द्वारा निर्दिष्ट धारा से निर्दिष्ट वर्णों की संख्या से कम से कम एक पर पढ़ता है s। कोई भी अतिरिक्त वर्ण नई-पंक्ति वर्ण (जो छूट गया है) के बाद या फ़ाइल के अंत के बाद पढ़ा जाता है। छोड़ी गई नई-पंक्ति वाला वर्ण पढ़े जाने वाले वर्णों की संख्या में नहीं गिना जाता है। अंतिम वर्ण को सरणी में पढ़ा जाने के तुरंत बाद एक अशक्त चरित्र लिखा जाता है।

5 यदि एंड- s[0]टू -फाइल का सामना करना पड़ा है और कोई वर्ण सरणी में नहीं पढ़ा गया है, या यदि ऑपरेशन के दौरान कोई रीड एरर होती है, तो अशक्त चरित्र में सेट की जाती है, और sअनिर्दिष्ट मान लेने के अन्य तत्व ।

अनुशंसित अभ्यास

6 fgetsफ़ंक्शन सही प्रकार से लिखे गए प्रोग्राम को परिणाम सरणी में संग्रहीत करने के लिए इनपुट लाइनों को सुरक्षित रूप से संसाधित करने की अनुमति देता है। सामान्य तौर पर इसके लिए यह आवश्यक होता है कि fgetsपरिणाम सरणी में नए-पंक्ति वर्ण की उपस्थिति या अनुपस्थिति पर ध्यान देने वाले कॉलर्स । fgetsइसके बजाय (नए-लाइन वर्णों पर आधारित किसी भी आवश्यक प्रसंस्करण के साथ) का उपयोग करने पर विचार करें gets_s

25)gets_s समारोह, के विपरीत gets, यह इनपुट की एक पंक्ति बफर यह स्टोर करने के लिए अतिप्रवाह के लिए एक क्रम-बाधा उल्लंघन करता है। इसके विपरीत fgets, gets_sइनपुट लाइनों और सफल कॉल के बीच एक-से-एक संबंध बनाए रखता है gets_sgetsऐसे कार्यक्रम जो इस तरह के रिश्ते की उम्मीद करते हैं।

Microsoft Visual Studio कंपाइलर TR 24731-1 मानक के लिए एक सन्निकटन लागू करता है, लेकिन Microsoft और TR में लागू किए गए हस्ताक्षरों के बीच अंतर हैं।

C11 मानक, ISO / IEC 9899-2011, लाइब्रेरी के वैकल्पिक भाग के रूप में अनुलग्नक K में TR24731 शामिल है। दुर्भाग्य से, यह शायद ही कभी यूनिक्स जैसी प्रणालियों पर लागू किया गया है।


getline() - पॉसिक्स

POSIX 2008 भी gets()कॉल करने के लिए एक सुरक्षित विकल्प प्रदान करता है getline()। यह गतिशील रूप से लाइन के लिए स्थान आवंटित करता है, इसलिए आपको इसे मुक्त करने की आवश्यकता है। यह लाइन की लंबाई पर सीमा को हटा देता है, इसलिए। यह उस डेटा की लंबाई भी देता है जो पढ़ा गया था, या -1(और नहीं EOF!), जिसका अर्थ है कि इनपुट में अशक्त बाइट्स को मज़बूती से संभाला जा सकता है। कहा जाता है एक 'अपने खुद के एकल चरित्र सीमांकक भिन्नता चुनें' getdelim(); यह उपयोगी हो सकता है यदि आप आउटपुट के साथ काम कर रहे हैं find -print0जहां फ़ाइल नामों के छोर ASCII NUL '\0'वर्ण के साथ चिह्नित हैं, उदाहरण के लिए।


8
यह भी इंगित करने के लायक है कि fgets()और आपका fgets_wrapper()संस्करण इनपुट बफर में ओवर-लॉन्ग लाइन के अनुगामी हिस्से को अगले इनपुट फ़ंक्शन द्वारा पढ़ा जाएगा। कई मामलों में, आप इन वर्णों को पढ़ना-छोड़ना चाहेंगे।
कैफे

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

2
@ सुपरकैट: हाँ, मैं सहमत हूँ - यह एक दया है। संभवतः getline()इसके लिए निकटतम दृष्टिकोण संभवतः POSIX और इसके रिश्तेदार हैं getdelim(), जो कमांड द्वारा पढ़ी गई 'लाइन' की लंबाई को वापस करते हैं, पूरी लाइन को स्टोर करने में सक्षम होने के लिए आवश्यक स्थान आवंटित करते हैं। यहां तक ​​कि अगर आप एकल-लाइन JSON फ़ाइल जो कि आकार में कई गीगाबाइट है, के साथ समाप्त होने पर समस्याएं पैदा कर सकती हैं; क्या आप वह सब याद कर सकते हैं? (और जब हम इस पर होते हैं, तो क्या हमारे पास strcpy()और strcat()वेरिएंट हो सकते हैं जो एक सूचक को अंत में अशक्त बाइट पर वापस भेजते हैं? आदि)
जोनाथन लेफ़लर

4
@supercat: इसके साथ दूसरी समस्या fgets()यह है कि यदि फ़ाइल में एक नल बाइट है, तो आप यह नहीं बता सकते हैं कि लाइन के अंत तक (या EOF) तक कितना डेटा है। strlen()केवल डेटा में अशक्त बाइट तक रिपोर्ट कर सकते हैं; उसके बाद, यह अनुमान है और इसलिए लगभग निश्चित रूप से गलत है।
जोनाथन लेफ़लर

7
"तुम भूल जाओ कभी सुना है कि gets()अस्तित्व में है।" जब मैं ऐसा करता हूं तो मैं इसमें फिर से दौड़ता हूं और यहां वापस आता हूं। क्या आप स्टैकओवरफ्लो को हैक कर रहे हैं?
कैंडिड_ओरेंज

21

क्योंकि स्टडgets से बाइट्स प्राप्त करने और उन्हें कहीं भी डालते समय किसी भी प्रकार की जांच नहीं होती है। एक सरल उदाहरण:

char array1[] = "12345";
char array2[] = "67890";

gets(array1);

अब, सबसे पहले आपको इनपुट करने की अनुमति है कि आप कितने वर्ण चाहते हैं, getsइसके बारे में परवाह नहीं करेंगे। दूसरे जिस सरणी में आप उन्हें डालते हैं, उसके आकार पर बाइट्स (इस मामले में array1) वे जो कुछ भी स्मृति में पाते हैं, उन्हें अधिलेखित कर getsदेंगे क्योंकि उन्हें लिखेंगे। पिछले उदाहरण में इसका मतलब यह है कि यदि आप इनपुट करते हैं "abcdefghijklmnopqrts", तो अप्रत्याशित रूप से, यह भी array2या जो कुछ भी ओवरराइट करेगा ।

फ़ंक्शन असुरक्षित है क्योंकि यह लगातार इनपुट मानता है। कभी भी इसका उपयोग न करें!


3
क्या है getsएकमुश्त व्यर्थ है कि यह एक सरणी की लंबाई नहीं है / गिनती पैरामीटर है कि यह लेता है; यह वहाँ गया था, यह सिर्फ एक और साधारण सी मानक समारोह होगा।
लीजेंड 2k

@ legends2k: मैं उत्सुक हूं कि किस उद्देश्य के लिए उपयोग किया getsगया था, और क्यों कोई मानक फिट संस्करण उपयोग के मामलों के लिए सुविधाजनक नहीं बनाया गया था, जहां इनपुट के हिस्से के रूप में नई लाइन वांछित नहीं है?
18

1
@supercat getsथा, जैसा कि नाम से पता चलता है, से एक स्ट्रिंग प्राप्त करने के लिए डिज़ाइन किया गया है stdin, हालांकि आकार पैरामीटर नहीं होने का तर्क सी की भावना से हो सकता है : प्रोग्रामर पर भरोसा करें। यह फ़ंक्शन C11 में हटा दिया गया था और दिया गया प्रतिस्थापन gets_sइनपुट बफर के आकार में है। मैं fgetsहालांकि भाग के बारे में कोई सुराग नहीं है ।
लीजेंड्स 2

@ legends2k: केवल एक संदर्भ जिसे मैं देख सकता हूं getsकि यह बहाना हो सकता है यदि कोई एक हार्डवेयर-लाइन-बफ़र किया गया I / O सिस्टम का उपयोग कर रहा था, जो कि एक निश्चित लंबाई पर एक लाइन प्रस्तुत करने में शारीरिक रूप से अक्षम था, और कार्यक्रम का इरादा जीवनकाल था। हार्डवेयर के जीवनकाल से कम था। उस स्थिति में, यदि हार्डवेयर 127 बाइट्स से अधिक लंबी लाइनें प्रस्तुत करने में असमर्थ है, तो यह gets128-बाइट बफर में उचित हो सकता है , हालांकि मुझे लगता है कि छोटे इनपुट को निर्दिष्ट करने में सक्षम होने पर छोटे बफर को निर्दिष्ट करने के फायदे बताए जाएंगे। लागत।
सुपरकैट

@ किंवदंतियों 2k: वास्तव में, जो आदर्श हो सकता है वह "स्ट्रिंग पॉइंटर" होता है जो एक बाइट की पहचान करता है जो कुछ अलग स्ट्रिंग / बफर / बफर-जानकारी स्वरूपों में से एक का चयन करेगा, जिसमें उपसर्ग बाइट का एक मान एक संरचना को दर्शाता है। उपसर्ग बाइट [प्लस पैडिंग], प्लस बफर आकार, प्रयुक्त आकार, और वास्तविक पाठ का पता। इस तरह के एक पैटर्न से कोड के लिए किसी भी स्ट्रिंग की एक मनमाना सबरिंग (न केवल पूंछ) पास करना संभव होगा, बल्कि कुछ भी कॉपी किए बिना getsऔर strcatसुरक्षित तरीके से जितना संभव हो उतना सुरक्षित तरीके से स्वीकार करने की अनुमति देगा ।
सुपरकैट

16

आपको इसका उपयोग नहीं करना चाहिए getsक्योंकि इसके पास बफर ओवरफ्लो को रोकने का कोई तरीका नहीं है। यदि उपयोगकर्ता आपके बफ़र में फिट होने से अधिक डेटा टाइप करता है, तो आप सबसे अधिक संभावना भ्रष्टाचार या इससे भी बदतर होंगे।

वास्तव में, आईएसओ ने वास्तव में सी मानक (C11 के रूप में, हालांकि इसे C99 में पदावनत किया गया था) से हटाने का कदम उठाया है gets, जो यह देखते हुए कि वे पिछड़ी संगतता को कितना दर देते हैं, यह इस बात का संकेत होना चाहिए कि वह कार्य कितना खराब था।

सही बात यह है fgetsकि stdinफ़ाइल हैंडल के साथ फ़ंक्शन का उपयोग करें क्योंकि आप उपयोगकर्ता से पढ़े गए पात्रों को सीमित कर सकते हैं।

लेकिन इसकी समस्याएं भी हैं जैसे:

  • उपयोगकर्ता द्वारा दर्ज अतिरिक्त वर्णों को अगली बार के आसपास उठाया जाएगा।
  • कोई त्वरित सूचना नहीं है कि उपयोगकर्ता ने बहुत अधिक डेटा दर्ज किया है।

यह अंत करने के लिए, लगभग हर सी कोडर अपने करियर में किसी भी बिंदु पर एक अधिक उपयोगी आवरण लिखेंगे fgets। ये मेरा:

#include <stdio.h>
#include <string.h>

#define OK       0
#define NO_INPUT 1
#define TOO_LONG 2
static int getLine (char *prmpt, char *buff, size_t sz) {
    int ch, extra;

    // Get line with buffer overrun protection.
    if (prmpt != NULL) {
        printf ("%s", prmpt);
        fflush (stdout);
    }
    if (fgets (buff, sz, stdin) == NULL)
        return NO_INPUT;

    // If it was too long, there'll be no newline. In that case, we flush
    // to end of line so that excess doesn't affect the next call.
    if (buff[strlen(buff)-1] != '\n') {
        extra = 0;
        while (((ch = getchar()) != '\n') && (ch != EOF))
            extra = 1;
        return (extra == 1) ? TOO_LONG : OK;
    }

    // Otherwise remove newline and give string back to caller.
    buff[strlen(buff)-1] = '\0';
    return OK;
}

कुछ परीक्षण कोड के साथ:

// Test program for getLine().

int main (void) {
    int rc;
    char buff[10];

    rc = getLine ("Enter string> ", buff, sizeof(buff));
    if (rc == NO_INPUT) {
        printf ("No input\n");
        return 1;
    }

    if (rc == TOO_LONG) {
        printf ("Input too long\n");
        return 1;
    }

    printf ("OK [%s]\n", buff);

    return 0;
}

यह उसी तरह की सुरक्षा प्रदान करता है जैसे fgetsकि यह बफर ओवरफ्लो को रोकता है लेकिन यह कॉलर को यह भी सूचित करता है कि क्या हुआ और अतिरिक्त पात्रों को हटा दिया गया ताकि वे आपके अगले इनपुट ऑपरेशन को प्रभावित न करें।

अपनी इच्छानुसार इसका उपयोग करने के लिए स्वतंत्र महसूस करें, मैं इसके द्वारा इसे "लाइसेंस प्राप्त करना चाहता हूं" के तहत जारी करता हूं "लाइसेंस :-)


वास्तव में, मूल C99 मानक स्पष्ट रूप से gets()या तो खंड 7.19.7.7 में नहीं दर्शाया गया है जहां इसे परिभाषित किया गया है या खंड 7.26.9 भविष्य की पुस्तकालय दिशाओं और इसके लिए उप-खंड में है <stdio.h>। खतरनाक होने पर भी कोई फुटनोट नहीं है। (करने के बाद ही कहा, मैं देख रहा हूँ "यह आईएसओ / आईईसी 9899 में पदावनत किया गया: 1999 / Cor.3: 2007 (ई))" में जवाब द्वारा यू हाओ ) लेकिन C11 मानक से हटाने था - और नहीं समय से पहले।!
जोनाथन लेफ्लर

int getLine (char *prmpt, char *buff, size_t sz) { ... if (fgets (buff, sz, stdin) == NULL)के रूपांतरण के size_tलिए छुपाता intहै szsz > INT_MAX || sz < 2के अजीब मूल्यों को पकड़ना होगा sz
chux -

if (buff[strlen(buff)-1] != '\n') {हैकर का शोषण एक दुष्ट व्यक्ति के रूप में किया गया पहला चरित्र है जो एक अंतर्निहित अशक्त चरित्र buff[strlen(buff)-1]यूबी प्रदान कर सकता है । while (((ch = getchar())...उपयोगकर्ता को एक अशक्त चरित्र में प्रवेश करने में परेशानी होनी चाहिए।
chux -


6

आप एपीआई को तोड़ने के बिना एपीआई कार्यों को दूर नहीं कर सकते। यदि आप चाहते हैं, तो कई एप्लिकेशन अब संकलन या बिल्कुल नहीं चलेंगे।

यही कारण है कि एक संदर्भ देता है:

एक पंक्ति को पढ़ना, जो अपरिभाषित व्यवहार के परिणामों द्वारा इंगित की गई सरणी को ओवरफ्लो करती है। फ़िज़ेट्स () का उपयोग करने की सिफारिश की जाती है।


4

मैंने हाल ही में पढ़ा, एक USENET पोस्ट मेंcomp.lang.c , जो gets()मानक से हटाया जा रहा है। वू हू

आपको यह जानकर खुशी होगी कि समिति ने मसौदे से () को हटाने के लिए सिर्फ (सर्वसम्मति से, जैसा कि यह निकला) को वोट दिया।


3
यह उत्कृष्ट है कि इसे मानक से हटाया जा रहा है। हालांकि, अधिकांश कार्यान्वयन इसे कम से कम अगले 20 वर्षों के लिए 'अब गैर-मानक विस्तार' के रूप में प्रदान करेंगे, क्योंकि पीछे की संगतता।
जोनाथन लेफ़लर

1
हां, ठीक है, लेकिन जब आप gcc -std=c2012 -pedantic ...प्राप्त करते हैं () के साथ संकलित किया जाएगा। (मैंने अभी-अभी -stdपैरामीटर बनाया है )
pmg

4

C11 (ISO / IEC 9899: 201x) में, gets()हटा दिया गया है। (यह ISO / IEC 9899: 1999 / Cor.3: 2007 (E) में चित्रित है)

इसके अलावा fgets(), C11 एक नया सुरक्षित विकल्प प्रस्तुत करता है gets_s():

C11 K.3.5.4.1 gets_sफ़ंक्शन

#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
char *gets_s(char *s, rsize_t n);

हालांकि, अनुशंसित अभ्यास अनुभाग में, fgets()अभी भी पसंद किया जाता है।

fgetsसमारोह को सुरक्षित रूप से प्रक्रिया इनपुट लाइनों के लिए बहुत लंबा दुकान में परिणाम सरणी में ठीक से लिखा कार्यक्रमों की अनुमति देता है। सामान्य तौर पर इसके लिए यह आवश्यक होता है कि fgetsपरिणाम सरणी में नए-पंक्ति वर्ण की उपस्थिति या अनुपस्थिति पर ध्यान देने वाले कॉलर्स । fgetsइसके बजाय (नए-लाइन वर्णों पर आधारित किसी भी आवश्यक प्रसंस्करण के साथ) का उपयोग करने पर विचार करें gets_s


3

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

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


ध्यान दें कि वास्तविक खतरा आपके प्रोग्राम को क्रैश करने में सक्षम नहीं है , लेकिन यह मनमाने कोड चलाने में सक्षम है । (सामान्य तौर पर, अपरिभाषित व्यवहार का शोषण ।)
तंज87

2

मैं किसी भी सी लाइब्रेरी के रख-रखाव करने वालों के लिए एक निष्ठापूर्ण निमंत्रण देना चाहता हूं, जो अभी भी getsअपने पुस्तकालयों में शामिल हैं "बस किसी के मामले में अभी भी इस पर निर्भर है": कृपया अपने कार्यान्वयन को इसके समकक्ष से बदलें

char *gets(char *str)
{
    strcpy(str, "Never use gets!");
    return str;
}

यह सुनिश्चित करने में मदद करेगा कि कोई भी इस पर निर्भर नहीं है। धन्यवाद।


2

C हो जाता है फ़ंक्शन खतरनाक है और यह बहुत महंगी गलती है। टोनी होरे ने अपनी बात "नल संदर्भ: द बिलियन डॉलर गलती" में विशिष्ट उल्लेख के लिए इसे एकल किया:

http://www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare

पूरा घंटा देखने लायक है, लेकिन उनकी टिप्पणियों के लिए 30 मिनट के दृश्य पर विशिष्ट को लगभग 39 मिनट तक आलोचना मिलती है।

उम्मीद है कि यह पूरी बात के लिए आपकी भूख को बढ़ाता है, जो इस बात पर ध्यान आकर्षित करता है कि कैसे हमें भाषाओं में अधिक औपचारिक शुद्धता प्रमाण की आवश्यकता है और कैसे भाषा डिजाइनरों को उनकी भाषाओं में गलतियों के लिए दोषी ठहराया जाना चाहिए, न कि प्रोग्रामर को। ऐसा लगता है कि 'प्रोग्रामर आजादी' की आड़ में दोषियों को दोष देने के लिए बुरी भाषाओं के डिजाइनरों को पूरी तरह से संदेह का कारण बनाया गया है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.