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




दुनिया के सबसे खतरनाक जगह (9)

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

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

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

मैंने इसे प्राप्त किया

चेतावनी :

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

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

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

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


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

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


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

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

एक रेखा को पढ़ना जो सर के परिणामों को इंगित करता है, जो अनिश्चित व्यवहार में परिणामों के द्वारा इंगित होता है। Fgets () का उपयोग अनुशंसित है।


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

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

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

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


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

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

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

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

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


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

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

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

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

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

इसके अंत में, लगभग हर सी कोडर अपने करियर में किसी बिंदु पर भी 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;
}

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

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


सी 11 (आईएसओ / आईईसी 98 99: 201x) में, gets() को हटा दिया गया है। (यह आईएसओ / आईईसी 98 99: 1 999 / कोर 3: 2007 (ई) में बहिष्कृत है)

gets_s() अलावा, सी 11 एक नया सुरक्षित विकल्प 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 कॉलर्स परिणाम सरणी में एक नए रेखा चरित्र की उपस्थिति या अनुपस्थिति पर ध्यान दें। gets_s बजाय fgets (नए-पंक्ति वर्णों के आधार पर किसी भी आवश्यक प्रसंस्करण के साथ) का उपयोग करने पर gets_s


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

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

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


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

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

gets(array1);

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

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







gets