Segmentation fault

Last Edited By Krjb Donovan
Last Updated: Mar 11, 2014 07:52 PM GMT

Question

QUESTION: Hi! I wrote this code and when i run i get a "Segmentation fault" and it doesn't tell me what line. Can you tell me where this problem is coming, from this code? I entered the value 9070002043 or 9995500000 for the input i get a segmentation fault but when i enter 0003194876 or 0003194875 i get the answer i want.

  1. include <iostream>
  2. include <iomanip>
  3. include <cstring>
  4. include <stdio.h>
  5. include <stdlib.h>
  6. include <sstream>

using namespace std;

int valid(const char* str); int decode(FILE* fp, const char* str, char* area, char* publisher, char* title);

FILE * open(const char filename[]); int registered(FILE* fp, int area); int minNoDigits(FILE* fp, int area); int registered(FILE* fp, int area, int publisher); int close(FILE* fp);

  1. define PREFIX_LIST "prefixRanges.txt"

int main() { int keepgoing; char isbn[11]; FILE* prefixFile = NULL; char area[6], publisher[8], title[7];

cout << "ISBN Decoder\n" "==============\n";

prefixFile = open(PREFIX_LIST); if (prefixFile == NULL) cout << "Could not open file " << PREFIX_LIST << endl; else { keepgoing = 1; do { cout << "\nISBN (0 to quit) : "; cin.getline(isbn, 11); if (!cin) { cin.clear(); cin.ignore(2000, '\n'); cout << "Error. Try Again " << endl; } else if (strcmp(isbn, "0") == 0) { keepgoing = 0; } else if (strlen(isbn) != 10) { cout << " Incorrect number of digits. Try again." << endl; } else if (valid(isbn) == 0) { cout << " Invalid check digit. Try again." << endl; } else if (decode(prefixFile, isbn, area, publisher, title) == 0) { cout << " This ISBN does not have a registered prefix." << endl; } else { cout << " Area  : " << area << endl; cout << " Publisher  : " << publisher << endl; cout << " Title  : " << title << endl; } cout << endl; } while (keepgoing == 1);

close(prefixFile);

cout << "Signing off ... " << endl; }

return 0; }


int valid(const char* str) { int number10 = 10; int total = 0; int temp; int i;

for (i = 0; i < 10; i++) { if(!isdigit(str[i])) { return false; } } for (i = 0; i < 9; i++, number10--) { temp = str[i] * number10; total += temp; } total += str[i]; if (total % 11) { return false; }

return true; }

int decode(FILE * fp, const char * str, char * area, char * publisher, char * title) { int keepGoing = 0, sendArea, areaLength, kgAreaLength; int x = 0, z = 0; int checkVar = 0;

char temp[6]; int checkArea, a, i; int minDigits = 1, arrayDigits[5], counter = 0, checkPublisher; char tempPublisher[10];

for (i = 0; i < 5; i++) { for (a = 0; a <= i; a++) { temp[a] = str[a]; } temp[a] = '\0'; checkArea = atoi(temp); keepGoing = registered(fp, checkArea); if (keepGoing) { break; } } if (keepGoing) { rewind(fp); while (minDigits) { minDigits = minNoDigits(fp, checkArea); if (minDigits) { arrayDigits[counter++] = minDigits; } }

string areaString; stringstream areaOut; areaOut << checkArea; areaString = areaOut.str(); while (!checkVar) { a = 0; for (i = areaString.size(); i < (areaString.size() + arrayDigits[x]); i++) { tempPublisher[a++] = str[i]; } tempPublisher[a] = '\0'; checkPublisher = atoi(temp); checkVar = registered(fp, checkArea, checkPublisher); if (checkVar) { for (i = 0; i < areaString.size(); i++) { area[i] = areaString[i]; } area[i] = '\0';

for (i = 0; i < strlen(tempPublisher); i++) { publisher[i] = tempPublisher[i]; } publisher[i] = '\0';

a = 0; for (i = (areaString.size() + strlen(tempPublisher)); i < 9 ; i++) { title[a++] = str[i]; } title[a] = '\0';

return 1; } x++; if (counter == x) { return 0; } } } else { return 0; } }


FILE* open(const char filename[]) { FILE * fp; fp = fopen(filename, "r"); if (fp == NULL) { return NULL; } else { return fp; } }

int registered(FILE* fp, int area) { int checkArea; char buffer[20];

rewind(fp); while ( (fscanf(fp, "%d%[^\n]\n", &checkArea, &buffer)) != EOF ) { if (area == checkArea && buffer[0] == ' ') { return 1; } } }


int minNoDigits(FILE* fp, int area) { int checkArea, minDigits; int buffer;

while ( (fscanf(fp, "%d%d%d\n", &checkArea, &buffer, &minDigits)) != EOF ) { if (area == checkArea) { string minDigitsString; stringstream minDigitsOut; minDigitsOut << minDigits; minDigitsString = minDigitsOut.str(); return minDigitsString.size(); } } return 0;

}


int registered(FILE * fp, int area, int publisher) { int checkArea, range1, range2; char buffer[20];

rewind(fp); while ( (fscanf(fp, "%d%d%d\n", &checkArea, &range1, &range2)) != EOF ) { if (area == checkArea && publisher >= range1 && publisher <= range2) { return 1; } } return 0; }

int close(FILE * fp) { fclose(fp); }

ANSWER: There is an obvious error in the function int registered(FILE* fp, int area) ;

while ( (fscanf(fp, "%d%[^\n]\n", &checkArea, /*** error ***/ &buffer /**/ )) != EOF ) { /* ... */ }

should be

while ( (fscanf(fp, "%d%[^\n]\n", &checkArea, buffer)) != EOF ) { /* ... */ }



---------- FOLLOW-UP ----------

QUESTION: Hi! i did what you told me and i run the code. I'm still getting the Segmentation fault. Again, When I entered the value 9070002043 or 9995500000 for the input i get a segmentation fault but when i enter 0003194876 or 0003194875 i get the answer i want. Can you help me?

Answer

I can't see anything else obviously causing the problem.

My guess would be that the data in the file "prefixRanges.txt" does not match the fscanf format specifiers.

The scanf() family of functions have no bounds checking capability - if the string in the file is longer than the buffer size, the characters will overflow into the adjoining memory space leading to undefined behaviour including segfaults. With the %s and %[ conversions, the number of characters read is limited only by where the next whitespace character appears. Invalid input could make your program crash, because input too long would overflow whatever buffer you have provided for it.

Ideally, new programmers should avoid the scanf family of functions. In C++, use the safe facilities provided by the iostream library instead. In C, if you have to use the scanf functions, always specify a field width to avoid buffer overflows. The field width you specify should not exceed the number of bytes allocated to your input buffer. For example:

char input_buffer[ 32 ] ; cout << "Please enter a string of 20 characters or fewer.\n" ; scanf( "%20s", input_buffer ) ;

Advertisement

©2017 eLuminary LLC. All rights reserved.