Trouble debugging seg fault when using fscanf - c

I get a segmentation fault on the fscanf line below. I added the character width for each variable to try and fix it so I don't understand why it would seg fault.
I read from a CSV file into an array of structs.
The struct is:
typedef struct Person
{
int ID;
int salary;
int deleted;
char salutation[4];
char firstName[21];
char surName[31];
char job[16];
} Person;
I declare the array of structs:
Person* persons;
persons = (Person*)malloc(SIZE * sizeof(Person));
And then use this while loop to read the CSV file into the values:
(i is initialised at 0)
while(fscanf(f, "%d,%3[^,],%20[^,],%30[^,],%15[^,],%d,%d", &inPersons[i].ID, inPersons[i].salutation, inPersons[i].firstName, inPersons[i].surName, inPersons[i].job, &inPersons[i].salary, &inPersons[i].deleted)!=EOF)
{
newID = inPersons[i].ID;
i++;
}
The segfault happens during the fscanf statement. I'm not experienced with valgrind but it gives me this error for that line:
==16810== Invalid write of size 4
==16810== at 0x578215: _IO_vfscanf (in /lib/libc-2.12.so)
==16810== by 0x585368: __isoc99_fscanf (in /lib/libc-2.12.so)
==16810== by 0x8048951: loadDb (Database.c:23)
==16810== by 0x8048711: menu (Menu.c:37)
==16810== by 0x804861E: main (main.c:6)
==16810== Address 0x27230128 is not stack'd, malloc'd or (recently) free'd
I also get these Valgrind faults for the same line:
==18457== Use of uninitialised value of size 4
==18457== at 0x405A215: _IO_vfscanf (in /lib/libc-2.12.so)
==18457== by 0x4067368: __isoc99_fscanf (in /lib/libc-2.12.so)
==18457== by 0x8048943: loadDb (Database.c:23)
==18457== by 0x8048711: menu (Menu.c:37)
==18457== by 0x804861E: main (main.c:6)
==18457== Process terminating with default action of signal 11 (SIGSEGV)
==18457== Access not within mapped region at address 0x5C5E4128
==18457== at 0x405A215: _IO_vfscanf (in /lib/libc-2.12.so)
==18457== by 0x4067368: __isoc99_fscanf (in /lib/libc-2.12.so)
==18457== by 0x8048943: loadDb (Database.c:23)
==18457== by 0x8048711: menu (Menu.c:37)
==18457== by 0x804861E: main (main.c:6)

If you have an alphabetic or punctuation character where you should have a digit, you have an infinite loop and you overflow the bounds of the array of people that you allocated. You should be checking:
while (i < SIZE && (num = fscanf(f, "...", ...)) == 7)
{
...process valid input...
}
...consider what to do here, using `num` to distinguish between EOF and failed conversions...
The fact that valgrind can't identify the memory is puzzling. You've taken most of the relevant steps to ensure that you don't get buffer overflows (all except checking on the status of fscanf() properly).
Oh…you allocate persons; you're reading into inPersons…which is correct?
I think I would be writing a function to call fscanf() and detect and report errors, and then calling that from the while loop:
while (i < SIZE && get_person(&persons[i]) != EOF)
...
or:
while (i < SIZE && get_person(&inPersons[i]) != EOF)
...
This also allows you to switch from fscanf() to either fgets() and sscanf(), or getline() and sscanf().

Related

I get segmentation fault (core dumped) when I tried to run program with struct

I need to read a file and store the data from the file into a structure. The first line of the file contains the size of the array of structs that i have to dynamically allocate.
4
12/04/2010
Interview went well I think, though was told to wear shoes.
18/04/2010
Doc advised me to concentrate on something... I forget.
03/05/2010
Was asked today if I was an art exhibit.
19/05/2010
Apparently mudcakes not made of mud, or angry wasps.
I am to run my code perfectly in Windows but when I run in Unix environment it shows me segmentation fault (core dumped). I did use valgrind to check for the memory leak and that is the results
==4344== Invalid read of size 1
==4344== at 0x407F842: ____strtol_l_internal (strtol_l.c:298)
==4344== by 0x407F606: strtol (strtol.c:108)
==4344== by 0x407C87E: atoi (atoi.c:27)
==4344== by 0x8048837: main (in /home/admininistrator/ucp/p6/gg)
==4344== Address 0x0 is not stack'd, malloc'd or (recently) free'd
==4344==
==4344==
==4344== Process terminating with default action of signal 11 (SIGSEGV)
==4344== Access not within mapped region at address 0x0
==4344== at 0x407F842: ____strtol_l_internal (strtol_l.c:298)
==4344== by 0x407F606: strtol (strtol.c:108)
==4344== by 0x407C87E: atoi (atoi.c:27)
==4344== by 0x8048837: main (in /home/admininistrator/ucp/p6/gg)
==4344== If you believe this happened as a result of a stack
==4344== overflow in your program's main thread (unlikely but
==4344== possible), you can try to increase the size of the
==4344== main thread stack using the --main-stacksize= flag.
==4344== The main thread stack size used in this run was 8388608.
==4344==
==4344== HEAP SUMMARY:
==4344== in use at exit: 1,396 bytes in 3 blocks
==4344== total heap usage: 3 allocs, 0 frees, 1,396 bytes allocated
==4344==
==4344== LEAK SUMMARY:
==4344== definitely lost: 0 bytes in 0 blocks
==4344== indirectly lost: 0 bytes in 0 blocks
==4344== possibly lost: 0 bytes in 0 blocks
==4344== still reachable: 1,396 bytes in 3 blocks
==4344== suppressed: 0 bytes in 0 blocks
==4344== Rerun with --leak-check=full to see details of leaked memory
==4344==
==4344== For counts of detected and suppressed errors, rerun with: -v
==4344== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Segmentation fault (core dumped)
Here is my code attached
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include"struct.h"
int main(int argc, char* argv[])
{
if (argc < 2)
{
printf("You have enter less arguments.\n");
}
else if (argc > 2)
{
printf("You have enter too many arguments.");
}
else
{
FILE *file;
Diary *res;
Diary *res2;
char line[102];
int i, size, k, l, choice;
int day, month, year;
/* int d[10],m[10],y[10];*/
char as[102];
char* oken;
char* yoken;
char* coken;
oken = NULL;
yoken = NULL;
coken = NULL;
i = 0;
file = fopen("struct.txt", "r");
if (file == NULL)
{
perror("Error opening file\n.");
}
else
{
fscanf(file, "%d", &size);
res = (Diary*) malloc(size * sizeof(Diary));
res2 = (Diary*) calloc((5), sizeof(Diary));
while (fgets(line, sizeof(line), file) != NULL)
{
oken = strtok(line, "/");
if (oken != NULL)
{
res2[i].day= atoi(oken);
coken = strtok(NULL, "/");
if (oken != NULL)
{
res2[i].month = atoi(coken);
yoken = strtok(NULL, "\n ");
if (coken != NULL)
{
/*printf("%s",yoken);*/
res2[i].year = atoi(yoken);
fgets(as, 102, file);
strncpy(res2[i].entry, as, 102);
}
}
}
i++;
}
k = 1;
l = 0;
while (l < size)
{
res[l].day = res2[k].day;
res[l].month = res2[k].month;
res[l].year = res2[k].year;
strncpy(res[l].entry, res2[k].entry, 102);
k++;
l++;
}
choice = atoi(argv[1]);
printf("%d-%02d-%02d:%s",res[choice].year, res[choice].month,res[choice].day,res[choice].entry);
free(res2);
free(res);
}
fclose(file);
}
return 0;
}
I need to read all the data from the file to the struct and print it out whenever user want the entry. I tried to debug part by part, and I found out it is the part while( fgets( line, sizeof( line ), file) != NULL) that loop, gives the problem. But I have no idea how to fix it.
My struct.h is given as below:
typedef struct journal{
int day;
int month;
int year;
char entry[1024];
} Diary;
I don't quite understand all of what you are trying to achieve, but here are a few issues.
You probably don't need the day month year variables.
This line
day = atoi(oken);
should probably be
res2[i].day = atoi(oken);
There is a problem with the line that reads the size
fscanf(file, "%d", &size)
This reads an integer but it does not read the trailing newline
You need to change this to be something like
fscanf(file, "%d\n", &size)
or use fgets.
Because of the trailing newline, the next time you call gets you obtain a string containing just the newline.
Your strtok calls and NULL checks are out of phase. The first one, for oken is OK. But then you do a strtok returning coken but a NULL check on oken and lastly a strtok returning yoken and a NULL check on coken. In all 3 cases, the call to strtok should be followed by a NULL check on the returned value (as is the case for oken).
I don't understand the purpose of the while (l < size) loop (maybe because of the mishandling of the newline as described above?). You allocate 5 structs, read 4 from structs.txt into res2 (elements 0 to 3) then you copy elements 1 to 4 of res2 into elements 0 to 3 of res. This means that element 0 of res2 doesn't get copied and element 4 which is all zeroes does get copied.
The cause of the crash is a combination of points 3 and 4.
I would advise against using atoi as it does no error checking. It is unsafe to use unless you are certain that the string contains a well-formed integer. If you want your code to be robust, you need to add more error checking e.g., check the return values of malloc and calloc.

Segmentation fault traversing a text file

I have this code, it's supposed to read a text file character by character and then do something with it, but the code keeps on segfaulting at line 6.
#include <stdio.h>
int main(void)
{
printf("a\n");
FILE* fp = fopen("~/pset5/dictionaries/small", "r");
for (int a = fgetc(fp); a != EOF; a = fgetc(fp))
{
printf("b\n");
}
return 0;
}
Something weird is definitely happening, because it doesn't even print "a\n" to the terminal, even tough the call to printf is before the error. I've run the program with gdb, and this is where it fails.
6 for (int a = fgetc(fp); a != EOF; a = fgetc(fp))
(gdb) n
Program received signal SIGSEGV, Segmentation fault.
_IO_getc (fp=0x0) at getc.c:38
38 getc.c: No such file or directory.
I've also ran it with valgrind as in valgrind --leak-check=full ./test, with test being the name of the executable, and this is the relevant error message:
==7568== Invalid read of size 4
==7568== at 0x4EA8A21: getc (getc.c:38)
==7568== by 0x4005ED: main (test.c:6)
==7568== Address 0x0 is not stack'd, malloc'd or (recently) free'd
==7568==
==7568==
==7568== Process terminating with default action of signal 11 (SIGSEGV)
==7568== Access not within mapped region at address 0x0
I'm really at a loss here, can someone explain what's going on with this segmentation fault, and why the hell isn't the first call to printf printing anything?
As the debugger says (fp=0x0), you're calling fgetc with a null pointer. This is what causes the crash.
fp is null because the fopen call failed. You need to check for errors.
Opening the file fails because most likely you do not have a directory called ~. Recall that expanding ~ to your home directory is done by the shell when you type a command. fopen only takes real filenames.
You forgot to check the return value of fopen() against NULL, which indicates an error while attempting to open the file.
Your for loop busily uses a NULL pointer, hence you get segfault.
Check the global variable errno to find out more about what exactly went wrong in your case.

How to count newlines within a file, but not counting lines that are just newlines?

In order to properly parse input, I need to be able to count the number of lines in a file. However, I do not want to count lines that are just newlines. To help with this, I created the following function:
int countLinesInFile(char *filename) {
int newlines = 0;
if (access(filename,F_OK) != -1)
error("File not found",0);
FILE *input = fopen(filename,"r");
int size = 256 * 4;
char buffer[size];
while ((fgets(buffer,sizeof(buffer),input)) != EOF) {
printf("Read a string");
if (buffer == "\n")
continue;
newlines++;
}
fclose(input);
return newlines;
}
At the top of the file, I have the following:
#include <stdio.h>
#include <unistd.h>
When I run the program and attempt to count the lines, it segmentation faults. Using valgrind, I can see the following:
==6632== Invalid read of size 4
==6632== at 0x4EA8E6B: fgets (in /usr/lib64/libc-2.24.so)
==6632== by 0x402219: countLinesInFile (in [executable])
[other information about program, does not seem relevant]
==6632== Address 0x0 is not stack'd, malloc'd or (recently) free'd
==6632==
==6632==
==6632== Process terminating with default action of signal 11 (SIGSEGV)
==6632== Access not within mapped region at address 0x0
==6632== at 0x4EA8E6B: fgets (in /usr/lib64/libc-2.24.so)
==6632== by 0x402219: countLinesInFile (in [executable])
[other information about program, does not seem relevant]
==6632== If you believe this happened as a result of a stack
==6632== overflow in your program's main thread (unlikely but
==6632== possible), you can try to increase the size of the
==6632== main thread stack using the --main-stacksize= flag.
==6632== The main thread stack size used in this run was 8388608.
==6632==
==6632== HEAP SUMMARY:
==6632== in use at exit: 475 bytes in 16 blocks
==6632== total heap usage: 19 allocs, 3 frees, 3,075 bytes allocated
==6632==
==6632== LEAK SUMMARY:
==6632== definitely lost: 0 bytes in 0 blocks
==6632== indirectly lost: 0 bytes in 0 blocks
==6632== possibly lost: 0 bytes in 0 blocks
==6632== still reachable: 475 bytes in 16 blocks
==6632== suppressed: 0 bytes in 0 blocks
==6632== Rerun with --leak-check=full to see details of leaked memory
==6632==
==6632== For counts of detected and suppressed errors, rerun with: -v
==6632== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
I have attempted to put a line that says "printf("Reading file")" at the start of the while loop. This code does not execute, and I believe that the fgets is the problem. Unfortunately, I do not know what this problem is.
I have verified that the file I am trying to read does have the correct text in it, and is not empty.
Is the function that I have created the correct method of this task? If so, what problem could I be having? How could I avoid this problem in the future?
Update: This was really a stupid mistake on my part. I was running the program with Valgrind, which looks like it doesn't use the executable's directory, which meant it couldn't find the file. Thanks for helping.
Two things: first, fgets returns NULL as soon as no more line could be read, not EOF. Hence, the condition should be while(fgets(...) != NULL) or short while(fgets(...)).
Second, buffer == "\n" compares two pointers to characters, i.e. two memory addresses are compared. And it is very unlikely that anything has the same memory address as string literal "\n". Hence, compare characters, i.e. buffer[0]=='\n' or buffer[0]!='\n'.
And I think you could easily get rid of the continue-statement, such that the code looks like the following:
while (fgets(buffer,sizeof(buffer),input)) {
if (buffer[0] != '\n') {
newlines++;
}
}
I think you will need to keep track of the file offset of your last \n and if the position of this \n == last+1 then don't increment.
Function fgets returns a pointer value, or NULL on failure. EOF is (usually, unless you've changed it) defined as -1. They will never compare equal, which means you'll be calling fgets long after you should stop.
fgets() restricts you to a predefined line length. To get around that, you can use POSIX-standard getline().
When counting lines, to skip empty lines you can simply discount anything that matches "\n":
#include <stdio.h>
...
long countLines( const char *filename )
{
FILE *fp = fopen( filename, "r" );
if ( fp == NULL )
{
return( -1L );
}
char *line = NULL;
size_t bytes = 0UL;
long lineCount = 0L;
for ( ;; )
{
ssize_t result = getline( &line, &bytes, fp );
if ( -1 == result )
{
break;
}
if ( strcmp( line, "\n" ) )
{
lineCount++;
}
}
free( line );
fclose( fp );
return( lineCount );
}
FILE *input = fopen(filename,"r");
should be
FILE *input;
input = fopen(filename,"r");
I don't believe that fgets() returns a newline or an EOF. It stops reading at the character before the newline and the next read will be the character after the newline or successive newlines.
You probably need to use a binary file reading function that will read the entire file at once and then parse out the lines. This will also handle the case of a text file that does not have an EOF at the end. Many don't
Get the size of the file.
Allocate a buffer to hold the entire file.
Read the entire file into the buffer.
Parse the buffer.
C library function - fgets()
C File I/O and Binary File I/O

C token loop segfault issue

So sort of new to C and I am trying to make a listener so that User has to press enter twice to completed typing there input. Then split by the new line and run all the data through a loop and send them through my functions.
I am not sure what i am doing wrong but when the loop right under "//segfaulting at loop" in the code is commented out it runs fine but when I uncomment it and have my call to "// assemble(ftemp);" commented it out it is segfaulting so i know it here just dont know what. Valgrind says the below if that helps at all.
Thanks In Advanced Pete.
==14639== Invalid read of size 1
==14639== at 0x4E7754C: ____strtod_l_internal (strtod_l.c:608)
==14639== by 0x4011F8: main (in /home)
==14639== Address 0x0 is not stack'd, malloc'd or (recently) free'd
==14639== Process terminating with default action of signal 11 (SIGSEGV)
==14639== Access not within mapped region at address 0x0
==14639== at 0x4E7754C: ____strtod_l_internal (strtod_l.c:608)
==14639== by 0x4011F8: main (in /home)
==14639== If you believe this happened as a result of a stack
==14639== overflow in your program's main thread (unlikely but
==14639== possible), you can try to increase the size of the
==14639== main thread stack using the --main-stacksize= flag.
==14639== The main thread stack size used in this run was 8388608.
==14639== HEAP SUMMARY:
==14639== in use at exit: 0 bytes in 0 blocks
==14639== total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==14639== All heap blocks were freed -- no leaks are possible
==14639== For counts of detected and suppressed errors, rerun with: -v
==14639== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
My code:
int main(int argc, char * argv[]) {
printf("Please Enter In Float (Hit Enter Twice To Exicute)\n" );
#define MAXLENGTH 1000
char Input_string[MAXLENGTH];
int ilop = 0;
for(;;++ilop)
{
Input_string[ilop] = getchar();
if (ilop > 0 && Input_string[ilop] == '\n' &&
Input_string[ilop-1] == '\n') break;
}
Input_string[ilop] = 0;
char *pch;
// printf ("Splitting string \"%s\" into tokens:\n",Input_string);
pch = strtok (Input_string,"\n");
float ftemp = atof(pch);
//printf("price:, %f\n\n",ftemp);
assemble(ftemp);
//segfaulting at loop
while (pch != NULL)
{
pch = strtok (NULL, "\n");
ftemp = atof(pch);
printf("price:, %f\n\n",ftemp);
// assemble(ftemp);
}
return 0;
}
To expand on what Igal S. said, you’re first setting strtok inside the loop, then using it, and not checking it until the top of the loop. So, on the last iteration, it will set pch to NULL, then pass it to atof() without checking it.
You need something like (untested):
pch = strtok (Input_string, "\n");
while (pch != NULL)
{
/* ... */
pch = strtok (NULL, "\n");
}
There is a possibility of array out of bound access which might lead to undefined behavior.
In the for loop at the beginning add the check
if(ilop > 999)
{
break;
}

Invalid Write with strcpy

I have been programming for a while but I am new to C. I have this linked list implementation in ansi C that I need to test. I have narrowed the problem down to an issue with an invalid write. I ran the code through Valgrind and received the following output:
==18131== Invalid write of size 1
==18131== at 0x4C2C0CC: __GI_strcpy (in /usr/lib/valgrind/vgpreload_memcheck-amd64 linux.so)
==18131== by 0x40089B: main (in /home/btm7984/hw3/TestList)
==18131== Address 0x51f1388 is 0 bytes after a block of size 8 alloc'd
==18131== at 0x4C2B6CD: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==18131== by 0x400880: main (in /home/btm7984/hw3/TestList)
==18131==
==18131== Invalid write of size 1
==18131== at 0x4C2C0DF: __GI_strcpy (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==18131== by 0x40089B: main (in /home/btm7984/hw3/TestList)
==18131== Address 0x51f138e is 6 bytes after a block of size 8 alloc'd
==18131== at 0x4C2B6CD: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==18131== by 0x400880: main (in /home/btm7984/hw3/TestList)
==18131==
--18131-- VALGRIND INTERNAL ERROR: Valgrind received a signal 11 (SIGSEGV) - exiting
--18131-- si_code=1; Faulting address: 0x6D4FCAA; sp: 0x402bdae00
All that I can ascertain from this is that I am allocating something wrong. I think it has to be with my strcpy line. I really don't know how to approach this question. What follows is my use of the LinkedLists interface. InitLinkedLists, AddToBackOfList, and DestroyList are all defined in that interface.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "LinkedLists.h"
int main(int argc, char *argv[]) {
FILE *fp;
char tmpString[100];
LinkedLists *ListPtr = malloc(sizeof(LinkedLists));
ElementStructs *DataPtr;
LinkedListNodes* curr = malloc(sizeof(LinkedListNodes));
int counter = 0;
int Done = 0;
InitLinkedList(ListPtr);
fp = fopen(argv[1], "r");
if (!fp){
fprintf(stderr,"%s Cannot open file %s\n", argv[0], argv[1]);
exit(1);
}
do{
fscanf(fp,"%s",tmpString);
if (!feof(fp)) {
DataPtr = malloc(sizeof(DataPtr));
printf("%d %d : %d\n",counter,(int)strlen(DataPtr->str),(int)strlen(tmpString));
strcpy(DataPtr->str,tmpString);
DataPtr->index=counter;
AddToBackOfLinkedList(ListPtr, DataPtr);
counter++;
Done = 1;
} else {
Done = 0;
}
}while (Done);
In conclusion, I think strcpy is causing an invalid write and I don't know why.
Any help would be greatly appreciated. Thanks in advance.
EDIT: ElementStructs is defined as follows:
typedef struct ElementStructs
{
/* Application Specific Definitions */
int index;
char str[100];
} ElementStructs;
The problem resides in this statement:
DataPtr = malloc(sizeof(DataPtr));
You allocate only enough memory to hold a pointer and not a full struct.
You should allocate using:
DatapPtr = malloc(sizeof(ElementStructs));
or, as described in the comments (WhozCraig):
DatapPtr = malloc(sizeof(*DataPtr));

Resources