একটি বিভাগ যখন এর জন্য বরাদ্দ করা হয়েছে তার বাইরে মেমোরি অ্যাক্সেস করার চেষ্টা করে তখন একটি সেগমেন্টেশন ত্রুটি ঘটে।
এই ক্ষেত্রে, অভিজ্ঞ সি প্রোগ্রামার দেখতে পাবে যে লাইনে ফোন করা হয়েছে সেখানে সমস্যা হচ্ছে sprintf
। তবে যদি আপনি বলতে না পারেন যে আপনার বিভাগের ত্রুটিটি কোথায় ঘটছে বা যদি আপনি কোডটি পড়ে এটি অনুধাবন করার চেষ্টা করতে চান না তবে আপনি ডিবাগ চিহ্ন সহ আপনার প্রোগ্রামটি তৈরি করতে পারেন (সহ gcc
, -g
পতাকাটি এটি করে ) এবং তারপরে এটি একটি ডিবাগারের মাধ্যমে চালিত করুন।
আমি আপনার উত্স কোডটি অনুলিপি করে এটিকে আমার নামের একটি ফাইলে আটকালাম slope.c
। তারপরে আমি এটি এটির মতো তৈরি করেছি:
gcc -Wall -g -o slope slope.c
(এটি -Wall
isচ্ছিক। এটি আরও পরিস্থিতিতে সতর্কবার্তা উত্পন্ন করার জন্য to এটি কী ভুল হতে পারে তা নির্ধারণেও সহায়তা করতে পারে))
তারপরে আমি প্রোগ্রামটি শুরু করার জন্য gdb
প্রথমে ছুটে গিয়ে ডিবাগারে প্রোগ্রামটি চালিত করি এবং তারপরে একবার ডিবাগারে, ডিবাগারকে কমান্ড দিয়ে:gdb ./slope
gdb
run
ek@Kip:~/source$ gdb ./slope
GNU gdb (GDB) 7.5-ubuntu
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/ek/source/slope...done.
(gdb) run
Starting program: /home/ek/source/slope
warning: Cannot call inferior functions, you have broken Linux kernel i386 NX (non-executable pages) support!
Program received signal SIGSEGV, Segmentation fault.
0x001a64cc in _IO_default_xsputn () from /lib/i386-linux-gnu/libc.so.6
(আমার you have broken Linux kernel i386 NX
... support
বার্তা সম্পর্কে উদ্বিগ্ন হবেন না ; এটি gdb
এই প্রোগ্রামটি ডিবাগ করার জন্য কার্যকরভাবে ব্যবহার হতে বাধা দেয় না ))
এই তথ্যটি অত্যন্ত ক্রিপ্টিক ... এবং যদি আপনার কাছে ডিবিগ প্রতীকগুলি libc এর জন্য ইনস্টল করা না থাকে তবে আপনি আরও একটি ক্রিপ্টিক বার্তা পাবেন যা প্রতীকী ফাংশন নামের পরিবর্তে একটি হেক্সাডেসিমাল ঠিকানা রয়েছে _IO_default_xsputn
। ভাগ্যক্রমে, এতে কিছু যায় আসে না, কারণ আমরা যা জানতে চাই তা হ'ল আপনার প্রোগ্রামে সমস্যাটি কোথায় ঘটছে।
সুতরাং, সমাধানটি পিছনের দিকে তাকাতে হবে, কোনও সিস্টেম লাইব্রেরিতে যে নির্দিষ্ট ফাংশন কলটি SIGSEGV
সংকেত অবশেষে ট্রিগার হয়েছিল সেখানে কী ফাংশন কলগুলি ঘটেছিল তা দেখার জন্য ।
gdb
(এবং যে কোনও ডিবাগার) এর মধ্যে এই বৈশিষ্ট্যটি অন্তর্নির্মিত রয়েছে: একে স্ট্যাক ট্রেস বা ব্যাকট্র্যাস বলা হয় । আমি bt
একটি ব্যাকট্রেস উত্পন্ন করতে ডিবাগার কমান্ডটি ব্যবহার করি gdb
:
(gdb) bt
#0 0x001a64cc in _IO_default_xsputn () from /lib/i386-linux-gnu/libc.so.6
#1 0x00178e04 in vfprintf () from /lib/i386-linux-gnu/libc.so.6
#2 0x0019b234 in vsprintf () from /lib/i386-linux-gnu/libc.so.6
#3 0x0017ff7b in sprintf () from /lib/i386-linux-gnu/libc.so.6
#4 0x080484cc in calc_slope (input1=1, input2=150) at slope.c:26
#5 0x08048578 in main () at slope.c:52
(gdb)
আপনি দেখতে পাচ্ছেন যে আপনার main
ফাংশনটি ফাংশনটিকে কল করে calc_slope
(যা আপনি ইচ্ছা করেছেন) এবং তারপরে calc_slope
কলগুলি sprintf
(যা এই সিস্টেমে) অন্যান্য কয়েকটি সম্পর্কিত লাইব্রেরির ফাংশনগুলিতে কল সহ প্রয়োগ করা হয়েছে।
আপনি যা সম্পর্কে সাধারণত আগ্রহী তা হ'ল আপনার প্রোগ্রামের ফাংশন কল যা আপনার প্রোগ্রামের বাইরে কোনও ফাংশনকে কল করে । আপনি যে লাইব্রেরি / লাইব্রেরিগুলিতে নিজেরাই ব্যবহার করছেন সেগুলির মধ্যে কোনও বাগ না থাকলে (এই ক্ষেত্রে, libc
লাইব্রেরি ফাইল দ্বারা সরবরাহিত স্ট্যান্ডার্ড সি লাইব্রেরি libc.so.6
), ক্র্যাশ হওয়ার কারণটি আপনার প্রোগ্রামে রয়েছে এবং প্রায়শই এটির কাছাকাছি বা কাছাকাছি থাকবে আপনার প্রোগ্রামে শেষ কল ।
এই ক্ষেত্রে, এটি:
#4 0x080484cc in calc_slope (input1=1, input2=150) at slope.c:26
আপনার প্রোগ্রাম কল যেখানে সেখানে sprintf
। আমরা এটি জানি কারণ sprintf
পরবর্তী পদক্ষেপ। তবে এটি উল্লেখ না করেও আপনি এটি জানেন কারণ ২ line লাইনে এটিই ঘটে এবং এটি বলে:
... at slope.c:26
আপনার প্রোগ্রামে 26 লাইনে রয়েছে:
sprintf(s,"%d",curr);
(আপনার সর্বদা এমন একটি পাঠ্য সম্পাদক ব্যবহার করা উচিত যা কমপক্ষে আপনি বর্তমানে যে লাইনে রয়েছেন তার জন্য স্বয়ংক্রিয়ভাবে লাইন নম্বরগুলি প্রদর্শন করে।
ডেনিস কার্সেমেকারের উত্তরে যেমন আলোচনা হয়েছে , তেমনিs
এক বাইট অ্যারে। (শূন্য নয়, কারণ যে মানটি আপনি এটি নির্ধারণ করেছেন, ""
এটি একটি বাইট দীর্ঘ, অর্থাৎ এটি সমান { '\0' }
, একইভাবে "Hello, world!\n"
সমান { 'h', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!', '\n', '\0' }
))
সুতরাং, কেন এটি এখনও কিছু প্ল্যাটফর্মে কাজ করতে পারে (এবং উইন্ডোজের জন্য ভিসি 9 দিয়ে সংকলন করার সময় দৃশ্যত তা করতে পারে)?
লোকেরা প্রায়শই বলে থাকে যে আপনি যখন মেমরি বরাদ্দ করেন এবং তার বাইরে স্মৃতি অ্যাক্সেস করার চেষ্টা করেন, এটি একটি ত্রুটি তৈরি করে। তবে এটি সত্য নয়। সি এবং সি ++ প্রযুক্তিগত মান অনুসারে, এটি সত্যিই যা উত্পন্ন করে তা হ'ল সংজ্ঞায়িত আচরণ।
অন্য কথায়, কিছু ঘটতে পারে!
তবুও কিছু জিনিস অন্যদের চেয়ে বেশি হয়। কেন এটি হ'ল স্ট্যাকের একটি ছোট অ্যারে, কিছু প্রয়োগে, স্ট্যাকের উপরে আরও বড় অ্যারের মতো কাজ করতে প্রদর্শিত হবে?
এটি স্ট্যাক বরাদ্দ কীভাবে প্রয়োগ করা হয় তার নীচে আসে, যা প্ল্যাটফর্ম থেকে প্ল্যাটফর্মের পরিবর্তে পৃথক হওয়ার অনুমতি দেওয়া হয়। আপনার এক্সিকিউটেবল তার স্ট্যাকটিতে আরও একবারে মেমরি বরাদ্দ করতে পারে যা আসলে কোনও এক সময় ব্যবহারের উদ্দেশ্যে করা হয়। কখনও কখনও এটি আপনাকে মেমোরি অবস্থানগুলিতে লেখার অনুমতি দিতে পারে যা আপনি আপনার কোডটিতে স্পষ্টভাবে দাবি করেননি । ভিসি 9-এ আপনি যখন আপনার প্রোগ্রামটি তৈরি করেন তখন খুব সম্ভবত এটি ঘটছে।
তবে, ভিসি 9 তেও আপনার এই আচরণের উপর নির্ভর করা উচিত নয়। এটি বিভিন্ন উইন্ডোজ সিস্টেমে থাকা লাইব্রেরির বিভিন্ন সংস্করণের উপর নির্ভর করে। তবে আরও সম্ভবত সমস্যাটি হ'ল অতিরিক্ত স্ট্যাক স্পেসটি বরাদ্দ করা হয় এই উদ্দেশ্য নিয়ে যে এটি আসলে ব্যবহৃত হবে, এবং তাই এটি বাস্তবে ব্যবহৃত হতে পারে।তারপরে আপনি "অপরিজ্ঞাত আচরণের" পুরো দুঃস্বপ্নটি অনুভব করেন যেখানে এই ক্ষেত্রে একাধিক ভেরিয়েবল একই স্থানে সঞ্চিত হতে পারে, যেখানে একজনকে লেখা অন্যটিকে ওভাররাইট করে ... তবে সর্বদা নয়, কারণ কখনও কখনও ভেরিয়েবলগুলিকে লেখেন নিবন্ধগুলিতে ক্যাশে হয় এবং তাত্ক্ষণিকভাবে সম্পাদন করা হয় না (বা ভেরিয়েবলগুলি পড়তে ক্যাশে করা যেতে পারে, বা কোনও ভেরিয়েবলটি আগের মতো একইরূপে ধরে নেওয়া যেতে পারে কারণ এটি বরাদ্দ করা মেমরিটি কম্পাইলার দ্বারা জানা যায় যে এটি লিখিত হয়নি) পরিবর্তনশীল নিজেই)।
এবং এটি ভিসি 9 দিয়ে নির্মিত যখন প্রোগ্রামটি কেন কাজ করেছিল তার অন্যান্য সম্ভাবনার সম্ভাবনা আমার কাছে নিয়ে আসে। এটি সম্ভব এবং কিছুটা সম্ভবত, ওয়ান-বাইট অ্যারের পরে স্থানটি ব্যবহার করার জন্য কিছু অ্যারে বা অন্যান্য ভেরিয়েবল আসলে আপনার প্রোগ্রাম দ্বারা বরাদ্দ করা হয়েছিল (যার মধ্যে আপনার প্রোগ্রামটি ব্যবহার করা একটি লাইব্রেরি দ্বারা বরাদ্দ থাকা অন্তর্ভুক্ত থাকতে পারে) s
। সুতরাং, s
আর একটি বাইটের চেয়ে বেশি অ্যারে হিসাবে চিকিত্সা করার ফলে সেই / সেইগুলি পরিবর্তনশীল / অ্যারেগুলির সামগ্রী অ্যাক্সেস করার প্রভাব পড়বে, যা খারাপও হতে পারে।
উপসংহারে, যখন আপনার মতো ভুল হয় তখন "বিভাগীয় ত্রুটি" বা "সাধারণ সুরক্ষা ত্রুটি" এর মতো ত্রুটি পাওয়া ভাগ্যবান । তুমি কখন না যে আছে, তবে আপনি নট আউট খুঁজে পেতে পারেন না হওয়া পর্যন্ত এটা খুব দেরি হয়ে যে আপনার প্রোগ্রাম আছে অনির্ধারিত আচরণ।