গেমস ফাংশনটি কেন এত বিপজ্জনক যে এটি ব্যবহার করা উচিত নয়?


229

আমি যখন gets()জি সি সি এর সাথে ফাংশনটি ব্যবহার করে সি কোড সংকলন করার চেষ্টা করি তখন আমি এই সতর্কতাটি পাই:

(.text + 0x34): সতর্কতা: `পায় 'ফাংশনটি বিপজ্জনক এবং ব্যবহার করা উচিত নয়।

আমার মনে আছে স্ট্যাক সুরক্ষা এবং সুরক্ষার সাথে এর কিছু করার আছে তবে আমি কেন ঠিক তা নিশ্চিত নই।

আমি কীভাবে এই সতর্কতাটি সরিয়ে ফেলব এবং কেন ব্যবহার সম্পর্কে এই ধরনের সতর্কতা রয়েছে gets()?

যদি gets()এত বিপজ্জনক হয় তবে আমরা কেন এটি অপসারণ করতে পারি না?



উত্তর:


179

getsনিরাপদে ব্যবহার করার জন্য , আপনাকে ঠিক কতটা অক্ষর পড়বেন তা জানতে হবে, যাতে আপনি আপনার বাফারকে যথেষ্ট বড় করতে পারেন। আপনি কেবল এটি জানবেন যে আপনি যদি সঠিকভাবে জানতে চান তবে আপনি কী ডেটা পড়বেন।

ব্যবহারের পরিবর্তে gets, আপনি ব্যবহার করতে চান fgets, যার স্বাক্ষর রয়েছে

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

( fgets, যদি এটি একটি সম্পূর্ণ লাইন পড়ে, তবে '\n'স্ট্রিংটিতে ছেড়ে যাবে ; আপনাকে এটি মোকাবেলা করতে হবে))

এটি 1999 এর আইএসও সি স্ট্যান্ডার্ড পর্যন্ত ভাষার একটি সরকারী অংশ হিসাবে রয়ে গেছে তবে এটি ২০১১ এর স্ট্যান্ডার্ড দ্বারা সরকারীভাবে সরানো হয়েছে। বেশিরভাগ সি বাস্তবায়ন এখনও এটি সমর্থন করে তবে কমপক্ষে জিসিসি এটি ব্যবহার করে এমন কোনও কোডের জন্য একটি সতর্কতা জারি করে।


79
এটি প্রকৃতপক্ষে জিসিসি নয় যা সতর্ক করে, এটি গ্লিবসি যার মধ্যে একটি প্রগমা বা বৈশিষ্ট্য রয়েছে যা ব্যবহারের সময় সংকলকটি gets()একটি সতর্কতা নির্গত করে।
ফুজ

@ ফুজ আসলে, এটি কেবল সংকলকই সতর্ক করে না: ওপিতে উদ্ধৃত সতর্কতাটি লিঙ্কার দ্বারা মুদ্রিত হয়েছিল!
রুসলান

163

কেন gets() বিপজ্জনক

প্রথম ইন্টারনেট কীট ( মরিস ইন্টারনেট কীট ) প্রায় 30 বছর আগে (1988-11-02) পালিয়েছিল এবং এটি ব্যবহার করেছিলgets() সিস্টেম থেকে সিস্টেমে প্রচারের একটি পদ্ধতি হিসাবে এবং একটি বাফার ওভারফ্লো করে। মূল সমস্যাটি হ'ল ফাংশনটি জানে না যে বাফারটি কত বড়, সুতরাং এটি একটি নতুন লাইন না পাওয়া বা ইওএফের মুখোমুখি না হওয়া অবধি পড়া চালিয়ে যায় এবং এটি প্রদত্ত বাফারের সীমানাকে উপচে ফেলে দিতে পারে।

আপনার ভুলে যাওয়া উচিত যে আপনি কখনও শুনেছেন যে gets()অস্তিত্ব ছিল।

সি 11 স্ট্যান্ডার্ড আইএসও / আইইসি 9899: 2011 gets()একটি স্ট্যান্ডার্ড ফাংশন হিসাবে বাদ দেওয়া হয়েছে , এটি একটি ভাল জিনিস ™ (এটি আনুষ্ঠানিকভাবে 'অপ্রচলিত' হিসাবে চিহ্নিত হয়েছিল এবং আইএসও / আইইসি 9899: 1999 / Cor.3: 2007 - প্রযুক্তিগত সংশোধনী) সি 99 এর জন্য 3, এবং তারপরে সি 11 এ সরানো হবে)। দুঃখের বিষয়, পিছনের সামঞ্জস্যের কারণে এটি বহু বছর ধরে (অর্থাত 'দশক') গ্রন্থাগারে থাকবে। যদি এটি আমার উপর নির্ভর করে 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;
}

এছাড়াও, যেমন CAF একটি মন্তব্য এবং পয়েন্ট আউট paxdiablo তার উত্তর শো সঙ্গে fgets()আপনি ডাটা একটি লাইনে অবশিষ্ট থাকতে পারে। আমার মোড়কের কোডটি সেই তথ্যটি পরের বার পড়তে ছাড়বে; আপনি যদি পছন্দ করেন তবে ডেটা লাইনের বাকী অংশটি গাব্বল করতে সহজেই তা সংশোধন করতে পারেন:

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

অবশিষ্ট সমস্যাটি কীভাবে তিনটি পৃথক ফলাফলের প্রতিবেদন করতে হয় - ইওএফ বা ত্রুটি, লাইন রিড এবং কাটা না, এবং আংশিক লাইন পড়ুন তবে ডেটা কাটা হয়েছিল।

এই সমস্যাটি উত্থাপিত হয় না gets()কারণ এটি জানেন না যে আপনার বাফারটি কোথায় শেষ হয় এবং শেষ পর্যন্ত আনন্দের সাথে পদদলিত হয়, আপনার সুন্দর প্রবণতাযুক্ত মেমরি লেআউটে বিধ্বস্ত হয়, প্রায়শই রিটার্ন স্ট্যাকের সাথে ঝামেলা জড়িত হয় (একটি স্ট্যাক ওভারফ্লো ) যদি বাফার বরাদ্দ করা হয় স্ট্যাক, বা বাফারকে ডায়নামিকভাবে বরাদ্দ করা হলে নিয়ন্ত্রণ তথ্যকে পদদলিত করা বা বাফারকে স্থিতিশীলভাবে বরাদ্দ করা হলে অন্যান্য মূল্যবান গ্লোবাল (বা মডিউল) ভেরিয়েবলের উপর ডেটা অনুলিপি করা। এগুলির কোনওটিই একটি ভাল ধারণা নয় - এগুলি 'অপরিজ্ঞাত আচরণ' শব্দটির প্রতিচ্ছবি দেয় `


এছাড়াও টিআর 24731-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আর শূন্যের সমান বা আরএসআইজেডএমএএমএক্সের চেয়ে বড় হবে না। একটি নতুন-লাইন অক্ষর, ফাইল-এর শেষে, বা পড়ার ত্রুটি 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_s। যে প্রোগ্রামগুলি ব্যবহার করে তারা getsএমন সম্পর্কের প্রত্যাশা করে।

মাইক্রোসফ্ট ভিজ্যুয়াল স্টুডিও সংকলকগুলি টিআর 24731-1 স্ট্যান্ডার্ডের একটি অনুমিতি প্রয়োগ করে, তবে মাইক্রোসফ্ট এবং টিআর-এ থাকা প্রয়োগকারীদের স্বাক্ষরের মধ্যে পার্থক্য রয়েছে are

সি 11 স্ট্যান্ডার্ড, আইএসও / আইইসি 9899-2011 লাইব্রেরির optionচ্ছিক অংশ হিসাবে এনেক্সেক্স কেতে টিআর 24731 অন্তর্ভুক্ত করেছে। দুর্ভাগ্যক্রমে, এটি ইউনিক্সের মতো সিস্টেমে খুব কমই প্রয়োগ করা হয়।


getline() - পসিক্স

POSIX 2008 আরো একটি নিরাপদ বিকল্প প্রদান gets()নামক getline()। এটি গতিশীলভাবে লাইনের জন্য স্থান বরাদ্দ করে, তাই আপনি এটি মুক্ত করার প্রয়োজন শেষ করেন। সুতরাং লাইন দৈর্ঘ্যের সীমাবদ্ধতা অপসারণ করে। এটি যে ডেটা পড়েছিল বা তার -1(এবং না EOF!) দৈর্ঘ্যও ফেরত দেয় যার অর্থ ইনপুটটিতে নাল বাইটগুলি নির্ভরযোগ্যভাবে পরিচালনা করা যায়। এখানে 'নিজের সিঙ্গল-ক্যারেক্টার ডিলিমিটার বেছে নিন' প্রকরণও বলা হয় getdelim(); উদাহরণস্বরূপ, যদি আপনি আউটপুটটির সাথে find -print0ফাইল নামগুলির প্রান্তটিকে ASCII NUL '\0'অক্ষর দ্বারা চিহ্নিত করা হয় তবে আউটপুট নিয়ে কাজ করছেন are


8
এটি উল্লেখ করাও মূল্যবান fgets()এবং আপনার fgets_wrapper()সংস্করণটি ইনপুট বাফারে একটি দীর্ঘ-দীর্ঘ লাইনের পিছনের অংশটি পরবর্তী ইনপুট ফাংশনটি দ্বারা পড়তে দেবে। অনেক ক্ষেত্রে, আপনি এই অক্ষরগুলি পড়তে এবং বাতিল করতে চাইবেন।
ক্যাফে

5
আমি অবাক হয়েছি কেন তারা কেন এমন কোনও কল্পিত () বিকল্প যুক্ত করেনি যা একটি মূর্খ স্ট্রেন কল না করেই এর কার্যকারিতাটি ব্যবহার করতে দেয়। উদাহরণস্বরূপ, একটি fgets বৈকল্পিক যা স্ট্রিংয়ে পড়া বাইট সংখ্যাটি ফিরিয়ে দিয়েছিল কোডের পক্ষে এটি দেখতে সহজ হবে যে শেষ বাইটটি কোনও নতুনলাইন ছিল কিনা if যদি বাফারের জন্য নাল পয়েন্টারটি পাশ করার আচরণটিকে "পরবর্তী নিউলাইন অবধি এন -1 বাইট পর্যন্ত পড়ুন এবং বাতিল করুন" হিসাবে সংজ্ঞায়িত করা হয়, তবে কোডটি ওভার-দৈর্ঘ্যের লাইনের লেজটি সহজেই বাতিল করতে দেয়।
সুপারক্যাট

2
@ সুপের্যাট: হ্যাঁ, আমি সম্মতি জানাই - এটি দুঃখের বিষয়। এর নিকটতম পন্থা সম্ভবত পসিক্স getline()এবং এর সম্পর্কিত getdelim(), যা পুরো লাইনটি সঞ্চয় করতে সক্ষম হওয়ার জন্য স্থান বরাদ্দ করে কমান্ডগুলি দ্বারা 'পংক্তির' দৈর্ঘ্য ফিরিয়ে দেয়। এমনকি যদি আপনি একক লাইন জেএসওএন ফাইল শেষ করেন যা আকারে একাধিক গিগাবাইট হয়; আপনি কি সব স্মৃতি বহন করতে পারেন? (এবং আমরা যখন এটিতে থাকবেন, আমরা থাকতে পারে strcpy()এবং strcat()রূপগুলো যে শেষে নাল বাইট একটি পয়েন্টার আসতে ইত্যাদি?)
জোনাথন Leffler

4
@ সুপের্যাট: অন্য সমস্যাটি fgets()হ'ল যদি ফাইলটিতে নাল বাইট থাকে তবে লাইন (বা ইওএফ) অবধি নাল বাইটের পরে কতটা ডেটা আছে তা আপনি বলতে পারবেন না। strlen()তথ্যগুলিতে কেবল নাল বাইট পর্যন্ত রিপোর্ট করতে পারে; তারপরে এটি অনুমানের কাজ এবং তাই প্রায় অবশ্যই ভুল।
জোনাথন লেফলার

7
"ভুলে gets()গেছেন যে আপনি কখনও শুনেছেন যে বিদ্যমান ছিল।" আমি যখন এটি করি তখন আমি আবার এটিতে ছুটে আসি এবং এখানে ফিরে আসি। আপনি কি upvotes পেতে স্ট্যাকওভারফ্লো হ্যাক করছেন?
candied_orange 15

21

কারণ gets স্টিডিনের কাছ থেকে বাইট পেয়ে এবং কোথাও রাখার সময় কোনও ধরণের চেক করে না । একটি সাধারণ উদাহরণ:

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

gets(array1);

এখন, প্রথমে আপনাকে কতগুলি অক্ষর চান তা ইনপুট করার অনুমতি দেওয়া হয়েছে, gets এটির যত্ন নেবে না। দ্বিতীয়ত আপনি যে অ্যারে রেখেছেন সেটির আকারের উপরের বাইটগুলি (এই ক্ষেত্রে array1) তারা মেমরিতে যা খুশি তা ওভাররাইট getsকরবে কারণ সেগুলি তাদের লিখবে। পূর্ববর্তী উদাহরণে এর অর্থ হ'ল আপনি যদি ইনপুট "abcdefghijklmnopqrts"সম্ভবত, অনির্দেশ্য, এটি array2ও যে কোনও কিছুতে ওভাররাইট হয়ে যাবে ।

ফাংশনটি অনিরাপদ কারণ এটি ধারাবাহিক ইনপুট অনুমান করে। এটি কখনও ব্যবহার করুন!


3
যা getsসম্পূর্ণরূপে অপ্রয়োজনীয় করে তোলে তা হ'ল এটির অ্যারে দৈর্ঘ্য / গণনা প্যারামিটার নেই যা এটি লাগে; যদি এটি থাকত তবে এটি কেবল অন্য সাধারণ সি স্ট্যান্ডার্ড ফাংশন হবে।
কিংবদন্তি 2 কে

@ কিংবদন্তি 2 কে: আমি আগ্রহী যেটির জন্য ব্যবহারিক উদ্দেশ্যটি কী getsছিল এবং কেন কোনও স্ট্যান্ডার্ড fgets বৈকল্পিক ব্যবহারের ক্ষেত্রে সুবিধাজনক হিসাবে তৈরি করা হয়নি যেখানে নিউলাইনটি ইনপুটটির অংশ হিসাবে পছন্দসই নয়?
সুপারক্যাট

1
@ সুপের্যাট gets, যেমন নাম থেকেই বোঝানো হয়েছে, তার থেকে স্ট্রিং পাওয়ার জন্য ডিজাইন করা হয়েছিল stdin, তবে আকার পরামিতি না রাখার যুক্তি সি : স্পিরিট প্রোগ্রামার দ্বারা প্রকাশিত হতে পারে । এই ফাংশনটি সি 11-এ সরানো হয়েছিল এবং প্রদত্ত প্রতিস্থাপনটি gets_sইনপুট বাফারের আকার নেয় in fgetsযদিও এই অংশ সম্পর্কে আমার কোনও ধারণা নেই ।
কিংবদন্তি

@ কিংবদন্তি 2 কে: আমি কেবলমাত্র প্রসঙ্গটি দেখতে পাচ্ছি যেটি getsযদি ক্ষমাযোগ্য হতে পারে তবে যদি কেউ হার্ডওয়ার-লাইন-বাফার করা I / O সিস্টেম ব্যবহার করে যা কোনও নির্দিষ্ট দৈর্ঘ্যের উপরে লাইন জমা দিতে শারীরিকভাবে অক্ষম থাকে এবং প্রোগ্রামটির উদ্দেশ্যকৃত আজীবন থাকে হার্ডওয়্যারটির আজীবন চেয়ে খাটো ছিল। সেক্ষেত্রে হার্ডওয়্যার যদি 127 বাইটের বেশি লাইন জমা দিতে অক্ষম হয় তবে এটি gets128-বাইট বাফারের ক্ষেত্রে যুক্তিসঙ্গত হতে পারে , যদিও আমি মনে করি ছোট ইনপুটটি প্রত্যাশা করার সময় একটি সংক্ষিপ্ত বাফার নির্দিষ্ট করতে সক্ষম হওয়ার সুবিধাগুলি ন্যায়সঙ্গত হওয়ার চেয়ে আরও বেশি হবে খরচ।
সুপারক্যাট

@ কিংবদন্তি 2 কে: আসলে, আদর্শ হতে পারে একটি "স্ট্রিং পয়েন্টার" একটি বাইট চিহ্নিত করা যে কয়েকটি পৃথক স্ট্রিং / বাফার / বাফার-ইনফর্ম্যাট ফর্ম্যাটগুলির মধ্যে নির্বাচন করে, উপসর্গের বাইটের একটি মান সহ একটি কাঠামো নির্দেশ করে উপসর্গ বাইট [প্লাস প্যাডিং], বাফার আকার, ব্যবহৃত আকার এবং প্রকৃত পাঠ্যের ঠিকানা। এই জাতীয় নিদর্শন কোডের পক্ষে কোনও অনুলিপি না করেই অন্য স্ট্রিংয়ের একটি স্বেচ্ছাসেবী স্ট্রিং (কেবল লেজ নয়) পাস করা সম্ভব করে দেয় getsএবং পদ্ধতিগুলি strcatযেমন পছন্দ করবে ততটুকু গ্রহণযোগ্য ও নিরাপদে মেনে নেবে ।
সুপারক্যাট

16

আপনার ব্যবহার করা উচিত নয় getsযেহেতু এটির কোনও বাফার ওভারফ্লো বন্ধ করার কোনও উপায় নেই। যদি ব্যবহারকারী আপনার বাফারে ফিট করতে পারে তার চেয়ে বেশি ডেটা টাইপ করে থাকেন তবে আপনার সম্ভবত দুর্নীতি বা আরও খারাপ পরিণতি ঘটবে।

আসলে, আইএসও আসলে সি স্ট্যান্ডার্ড থেকে সরিয়ে gets নেওয়ার পদক্ষেপ নিয়েছে (যদিও এটি সি 99 তে হ্রাস করা হয়েছিল) যা তারা পশ্চাৎপদ সামঞ্জস্যকে কতটা রেট দেয়, সেই ফাংশনটি কতটা খারাপ ছিল তার ইঙ্গিত হওয়া উচিত।

সঠিক হ'ল ফাইল হ্যান্ডেলটি 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যা এটি বাফার ওভারফ্লোগুলিকে প্রতিরোধ করে তবে এটি কী ঘটেছে তা কলকারীকেও জানিয়ে দেয় এবং অতিরিক্ত অক্ষরগুলি পরিষ্কার করে দেয় যাতে তারা আপনার পরবর্তী ইনপুট ক্রিয়াকলাপটিকে প্রভাবিত না করে।

আপনার ইচ্ছামত এটিকে নির্দ্বিধায় ব্যবহার করুন, আমি এখানে এটিকে "আপনি যা করতে চান তা করুন" লাইসেন্সের আওতায় মুক্তি :-)


প্রকৃতপক্ষে, মূল সি 99 স্ট্যান্ডার্ডটি স্পষ্টভাবে 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

আপনি API টি ভাঙ্গা ছাড়াই API ফাংশনগুলি সরাতে পারবেন না। আপনি যদি করেন, অনেক অ্যাপ্লিকেশন আর কম্পাইল বা মোটে চালিত হবে না।

এই কারণেই একটি রেফারেন্স দেয়:

একটি রেখা পড়া যা অ্যারিকে উপচে ফেলেছে এর দ্বারা নির্দেশিত অপরিবর্তিত আচরণের ফলে। Fgets () ব্যবহারের পরামর্শ দেওয়া হয়।


4

আমি সম্প্রতি পড়েছি, একটি ইউজনেট পোস্টেcomp.lang.c , gets()এটি স্ট্যান্ডার্ড থেকে সরানো হচ্ছে। সাব্বাস

আপনি জেনে খুশি হবেন যে কমিটি খসড়াটি থেকেও () সরিয়ে দেওয়ার জন্য সবেমাত্র (সর্বসম্মতিক্রমে, যেমন দেখা যাচ্ছে) ভোট দিয়েছে।


3
এটি দুর্দান্ত যে এটি স্ট্যান্ডার্ড থেকে সরানো হচ্ছে। তবে, বেশিরভাগ বাস্তবায়ন পিছনে সামঞ্জস্যতার কারণে কমপক্ষে পরবর্তী 20 বছরের জন্য এটি 'এখন অ-মানক এক্সটেনশন' হিসাবে সরবরাহ করবে।
জোনাথন লেফলার

1
হ্যাঁ, ঠিক আছে, তবে আপনি যখন gcc -std=c2012 -pedantic ...() দিয়ে সংকলন করবেন তখন তা পাবে না। (আমি সবেমাত্র -stdপ্যারামিটারটি তৈরি করেছি )
পিএমজি

4

সি 11 এ (আইএসও / আইসিসি 9899: 201x) gets()সরানো হয়েছে। (এটি আইএসও / আইসিসি 9899: 1999 / Cor.3: 2007 (ই) এ অবচয় করা হয়েছে)

এছাড়াও fgets(), সি 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ফলাফল অ্যারেতে একটি নতুন-লাইনের চরিত্রের উপস্থিতি বা অনুপস্থিতিতে মনোযোগ দিন। পরিবর্তে fgets(নতুন-লাইন অক্ষরের উপর ভিত্তি করে প্রয়োজনীয় প্রসেসিং সহ) ব্যবহার করার বিষয়টি বিবেচনা করুন gets_s


3

gets()বিপজ্জনক কারণ ব্যবহারকারীদের পক্ষে প্রম্পটে খুব বেশি টাইপ করে প্রোগ্রামটি ক্র্যাশ করা সম্ভব। এটি উপলভ্য মেমরির শেষ সনাক্ত করতে পারে না, সুতরাং আপনি যদি উদ্দেশ্যটির জন্য খুব সামান্য পরিমাণ মেমরি বরাদ্দ করেন তবে এটি সেগ দোষ এবং ক্রাশের কারণ হতে পারে। কখনও কখনও এটি খুব অসম্ভব বলে মনে হয় যে কোনও ব্যবহারকারী কোনও ব্যক্তির নামের জন্য প্রম্পটে 1000 বর্ণগুলি টাইপ করবেন তবে প্রোগ্রামার হিসাবে আমাদের আমাদের প্রোগ্রামগুলি বুলেটপ্রুফ করা দরকার। (যদি ব্যবহারকারী খুব বেশি ডেটা প্রেরণ করে কোনও সিস্টেম প্রোগ্রাম ক্র্যাশ করতে পারে তবে এটি সুরক্ষা ঝুঁকিও হতে পারে)।

fgets() আপনাকে স্ট্যান্ডার্ড ইনপুট বাফার থেকে কয়টি অক্ষর বের করা হয়েছে তা নির্দিষ্ট করতে দেয়, যাতে তারা ভেরিয়েবলটিকে ছাড়িয়ে না।


নোট করুন যে আসল বিপদটি আপনার প্রোগ্রামটি ক্রাশ করতে সক্ষম নয় , তবে এটিকে স্বেচ্ছাসেবক কোড চালাতে সক্ষম হবেন । (সাধারণভাবে,
অপরিজ্ঞাত

2

আমি সেখানে যে কোনও সি লাইব্রেরি রক্ষণাবেক্ষণকারীদের আন্তরিক আমন্ত্রণটি প্রসারিত করতে চাই, যারা এখনও getsতাদের লাইব্রেরিতে অন্তর্ভুক্ত রয়েছে "যদি কেউ এখনও তার উপর নির্ভর করে" তবে দয়া করে আপনার বাস্তবায়নটি এর সমতুল্য সাথে প্রতিস্থাপন করুন

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

এটি নিশ্চিত করতে সহায়তা করবে যে কেউ এখনও তার উপর নির্ভর করে না। ধন্যবাদ.


2

সি পেয়ে যায় কাজটি বিপজ্জনক এবং খুব ব্যয়বহুল ভুল ছিল। টনি হোয়ার তার আলোচনার "নাল রেফারেন্স: দ্য বিলিয়ন ডলার ভুল" - এ নির্দিষ্ট উল্লেখের জন্য এটি একা করেছেন:

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

পুরো ঘন্টাটি দেখার মতো, তবে তার মন্তব্যের জন্য 30 মিনিটের সময় থেকে নির্দিষ্ট 39 মিনিটের সমালোচনা হয়।

আশা করি এটি পুরো আলাপটির জন্য আপনার ক্ষুধা বাড়িয়ে তোলে, যা আমাদের কীভাবে ভাষাগুলিতে আরও আনুষ্ঠানিক নির্ভুলতার প্রমাণ প্রয়োজন এবং ভাষা ডিজাইনারদের কীভাবে প্রোগ্রামিং নয়, তাদের ভাষাগুলির ভুলগুলির জন্য দোষ দেওয়া উচিত সেদিকে দৃষ্টি আকর্ষণ করে। এটি 'প্রোগ্রামার স্বাধীনতার' ছদ্মবেশে প্রোগ্রামারদের জন্য দোষ চাপানোর জন্য খারাপ ভাষার ডিজাইনারদের পুরো সন্দেহজনক কারণ বলে মনে হয়।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.