কেন 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
থেকে অক্ষরগুলি পড়ার মধ্যে উপস্থিত হবে
stdin
। 25)
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
gets()
বাফার_ওভারফ্লো_ট্যাক