C எனும் கணினிமொழியில் சரங்களைப் படிப்பது மிகவும் பாதுகாப்பற்ற செயலாக இருந்துவந்தது. பயனாளரிடமிருந்து பெறுகின்ற உள்ளீட்டைப் படிக்கும்போது, சி செந்த நூலகத்திலிருந்து gets எனும் செயலியைப் பயன்படுத்த நிரலாளர்களில் சிலர் ஆசைப்படலாம். gets எனும் செயலியின் பயன்பாடு மிகவும் எளிமையானது:
char *gets(char *string);
இதுவே Gets எனும் செயலியைப் பயன்படுத்தி செந்தரஉள்ளீட்டிலிருந்து படிக்கின்றது ஒரு சரத்தின் மாறியிலிருந்துமுடிவுகளை சேமிக்கின்றது
தொடர்ந்து Gets எனும் செயலியைப் பயன்படுத்திசரத்திற்கு ஒரு சுட்டியை வழங்குகிறது அல்லது எதுவும் படிக்கப்படவில்லை என்றால் NULL மதிப்பை வழங்குகிறது.
எளிமையான உதாரணமாக, பயனாளரிடம் பின்வருமாறான குறிமுறைவரிகளின் வாயிலாக ஒரு கேள்வியைக் கேட்டு, அதன் முடிவை ஒரு சரமாகப் படிக்கலாம்:
#include <stdio.h>
#include <string.h>
int
main()
{
char city[10]; // Such as “Chennai”
// இது மோசமானது .. தயவுசெய்து gets பயன்படுத்த வேண்டாம்
puts(“Where do you live?”);
gets(city);
printf(“<%s> is length %ld\n”, city, strlen(city));
return 0;
}
மேலே உள்ள நிரலுடன் ஒப்பீட்டளவில் குறுகிய மதிப்பை உள்ளிடுவது போதுமானது:
Where do you live?
Chennai
<Chennai> is length 7
இருப்பினும்,Gets’ எனும் செயலியானது மிகவும் எளிமையானது, மேலும் பயனாளர் தன்னுடைய உள்ளீடு முடிந்துவிட்டதாக நினைக்கும் வரை இது அப்பாவியாக தரவைப் படித்துகொண்டேயிருக்கும். ஆனால் பயனாளரின் உள்ளீட்டை வைத்திருக்கும் சரம் போதுமானதாக உள்ளதா என்பதை இந்த‘Gets’ எனும் செயலியானது’ சரிபார்க்காது. மிக நீண்ட மதிப்பை உள்ளிடுவது சரத்தின் மாறியானது வைத்திருக்கக்கூடியதை விட அதிகமான தரவைச் சேமிக்கும், இதன் விளைவாக நினைவகத்தின் மற்ற பகுதிகளில் மேலெழுத வைக்கும்.
Where do you live?
Llanfairpwllgwyngyllgogerychwyrndrobwllllantysiliogogogoch
<Llanfairpwllgwyngyllgogerychwyrndrobwllllantysiliogogogoch> is length 58
Segmentation fault (core dumped)
சிறப்பாக, நினைவகத்தின் பகுதிகளை மேலெழுதுவது நிரலை உடைக்கிறது. மோசமான நிலையில், இது ஒரு முக்கியமான பாதுகாப்பு பிழையை அறிமுகப்படுத்துகிறது, அங்கு ஒரு மோசமான பயனாளர் நம்முடைய நிரலின் மூலம் கணினியின் நினைவகத்தில் தன்னிச்சையான தரவைச் செருக முடியும்.
அதனால்தான் ஒரு நிரலில் ‘Gets’ எனும் செயலியைப் பயன்படுத்துவது ஆபத்தானது. உள்ளீடு செய்துபெறுவதைப் பயன்படுத்தி, நிரலானது பயனரிடமிருந்து எவ்வளவு தரவைப் படிக்க முயற்சிக்கிறது என்பதில் நமக்கு எந்தக் கட்டுப்பாடும் இல்லை. இது அடிக்கடி இடையக வழிதலின் நிலையை ஏற்படுத்திடுகிறது.
பாதுகாப்பான வழிமுறை
fgets செயலியானது வரலாற்று ரீதியாக சரங்களை பாதுகாப்பாக படிக்க பரிந்துரைக்கப்பட்ட வழிமுறையாகும். இந்த getsஎனும் செயலியின் பதிப்பானது ஒரு குறிப்பிட்ட எண்ணிக்கையிலான எழுத்துகள் வரை மட்டுமே வாசிப்பதன் மூலம் பாதுகாப்புச் சரிபார்ப்பை வழங்குகிறது, இது செயலியன் தருக்கமாக கடத்தப்படுகின்றது:
char *fgets(char *string, int size, FILE *stream);
‘fgets’ செயலியானது கோப்பு சுட்டிக்காட்டியில் இருந்து படிக்கிறது, மேலும் தரவை ஒரு சரத்தின் மாறியில் சேமிக்கிறது, ஆனால் அளவு குறிப்பிடப்பட்ட நீளம் வரை மட்டுமே. Gets க்குப் பதிலாக fget ஐப் பயன்படுத்த பின்வருமாறான மாதிரி நிரலைப் புதுப்பிப்பதன் மூலம் இதைச் பரிசோதிக்கலாம்:
#include <stdio.h>
#include <string.h>
int
main()
{
char city[10]; // Such as “Chicago”
//fgets சிறந்தது ஆனால் சரியானது அன்று
puts(“Where do you live?”);
fgets(city, 10, stdin);
printf(“<%s> is length %ld\n”, city, strlen(city));
return 0;
}
இந்த நிரலைத் தொகுத்து இயக்கினால், வரியில் தன்னிச்சையாக நீண்ட நகரப் பெயரை உள்ளிடலாம். இருப்பினும், நிரல் அளவு = 10 என்ற சரத்தின் மாறியில் பொருந்தக்கூடிய போதுமான தரவை மட்டுமே படிக்கின்றது, C ஆனது சரங்களின் முனைமங்களில் ஒன்றுமில்லை (‘\0’) எனும் எழுத்தைச் சேர்ப்பதால், fgets சரத்தில் 9 எழுத்துக்களை மட்டுமே படிக்குமாறு செய்யலாம்:
Where do you live?
Minneapolis
<Minneapol> is length 9
பயனாளர் உள்ளீட்டைப் படிக்க ‘fgets’ ஐப் பயன்படுத்துவதை விட இது நிச்சயமாக பாதுகாப்பானது என்றாலும், பயனாளரின் உள்ளீடு மிக நீளமாக இருந்தால் “cutting off” என்பதில் இதைச் செய்கிறது.
புதிய பாதுகாப்பான வழிமுறை
நீண்ட தரவைப் படிப்பதற்கு மிகவும் நெகிழ்வான தீர்வாக, string-reading செயலியை சரத்திறற்கு அதிக நினைவகத்தை ஒதுக்க அனுமதிப்பது, மாறியானது தான் வைத்திருக்கும் தரவுகளின் அளவை விட அதிகமான தரவை பயனாளர் உள்ளிட்டால். சரத்தின் மாறியை தேவையான அளவு மாற்றுவதன் மூலம், நிரலானது எப்போதும் பயனாளரின் உள்ளீட்டைச் சேமிக்க போதுமான இடத்தைக் கொண்டுள்ளது.
‘getline’ எனும் செயலியானது அதைச் சரியாகச் செய்கிறது. இந்தச் செயலியானது விசைப்பலகை அல்லது கோப்பு போன்ற உள்ளீட்டு பாய்வுகளிலிருந்து உள்ளீட்டைப் படிக்கிறது, மேலும் தரவை ஒரு சரத்தின் மாறியில் சேமிக்கிறது. ஆனால் ‘fgets’ , ‘gets’ போலல்லாமல், ‘getline’ ஆனது சரத்தை ‘realloc’ மூலம் மறுஅளவாக்கி முழுமையான உள்ளீட்டைச் சேமிக்க போதுமான நினைவகம் இருப்பதை உறுதி செய்கிறது.
ssize_t getline(char **pstring, size_t *size, FILE *stream);
getline என்பது உண்மையில் ஒரு சிறப்பு வரம்பிடும் எழுத்து வரை தரவைப் படிக்கின்ற Getdelim எனும் இதேபோன்ற செயலிக்கான மூடுபவராகும். இந்த வழக்கில், ‘getline’ ஒரு புதிய வரியை (‘\n’) பிரிப்பாளராகப் பயன்படுத்துகிறது, ஏனெனில் விசைப்பலகை அல்லது கோப்பில் இருந்து பயனர் உள்ளீட்டைப் படிக்கும் போது, தரவுகளின் கோடுகள் புதிய வரி எழுத்தால் பிரிக்கப்படுகின்றன.
இதன் விளைவாக, தன்னிச்சையான தரவுகளைப் படிக்க மிகவும் பாதுகாப்பான முறையாகும், ஒரு நேரத்தில் ஒரு வரி. ‘getline’ ஐப் பயன்படுத்த, ஒரு சரத்தின் புள்ளியை வரையறுத்து, இன்னும் நினைவகம் எதுவும் ஒதுக்கப்படவில்லை என்பதைக் குறிக்க அதை NULL என அமைத்திடுக.size_t எனும் வகையின் “string size” எனும் மாறியை வரையறுத்து அதற்கு பூஜ்ஜிய மதிப்பை வழங்கிடுக. ‘getline’ ஐ அழைக்கும்போது, சரம் அந்த சரத்தின் அளவின் மாறிகள் ஆகிய இரண்டிற்கும் சுட்டிகளைப் பயன்படுத்திடலாம், மேலும் தரவை எங்கு படிக்க வேண்டும் என்பதைக் குறிப்பிடலாம். ஒரு பின்வருமாறான மாதிரி நிரலுக்கு, நிலையான உள்ளீட்டிலிருந்து படிக்கமுடியும்:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int
main()
{
char *string = NULL;
size_t size = 0;
ssize_t chars_read;
// getlineஉடன்ஒரு நீண்ட சரத்தைப் படித்திடுக
puts(“Enter a really long string:”);
chars_read = getline(&string, &size, stdin);
printf(“getline returned %ld\n”, chars_read);
// பிழைகளை சரிபார்த்திடுக
if (chars_read < 0) {
puts(“couldn’t read the input”);
free(string);
return 1;
}
// சரததினை அச்சிடுக
printf(“<%s> is length %ld\n”, string, strlen(string));
// சரத்தினால் பயன்படுத்தப்பட்ட நினைகத்தை காலியாக வைத்திடுக
free(string);
return 0;
}
getline எனும் செயலியை போன்றுதரவைப் படிக்கும்போது, தேவைக்கேற்ப சரம் மாறிக்கு அதிக நினைவகத்தை தானாகவே மறுஒதுக்கீடு செய்யும். செயல்பாடு ஒரு வரியில் இருந்து எல்லா தரவையும் படிக்கும் போது, அது சுட்டி வழியாக சரத்தின் அளவை புதுப்பித்து, டிலிமிட்டர் உட்பட படித்த எழுத்துக்களின் எண்ணிக்கையை வழங்குகிறது.
Enter a really long string:
Supercalifragilisticexpialidocious
getline returned 35
<Supercalifragilisticexpialidocious
> is length 35
சரத்தில் வரம்புக்குறி எழுத்து உள்ளது என்பதை நினைவில் கொள்க. ‘getlineஇற்கு, வரம்புக்குறி (delimiter) என்பது புதியவரியாகும், அதனால்தான் வெளியீட்டில் ஒரு வரி ஊட்டம் உள்ளது. சரத்தின் மதிப்பில் வரம்புகக்குறியை விரும்பவில்லை எனில், சரத்தில் உள்ள வரம்புக்குறியை பூஜ்ய எழுத்தாக மாற்ற மற்றொரு செயலியைப் பயன்படுத்திகொள்ளலாம்.
‘getline’ மூலம், சி நிரலாக்கத்தின் பொதுவான ஆபத்துகளில் ஒன்றை நிலாளர்கள் பாதுகாப்பாகத் தவிர்க்கலாம்.பயனர் எந்தத் தரவை உள்ளிட முயற்சிக்கலாம் என்பதை கூற முடியாது, அதனால்தான் ‘gets’ பயன்படுத்துவது பாதுகாப்பற்றது எனஅறிவுறுத்தப்படுகின்றது, மேலும் ‘fgets’ என்பது மோசமானது. அதற்கு பதிலாக, கணினியின் செயலைநிறுத்தாமல் நிரலில் பயனர் தரவைப் படிக்க ‘getline’ ஆனது மிகவும் நெகிழ்வான வழியை வழங்குகிறது.