malloc on Windows - c

I'm new in this forum and i hope to do it right.
My problem is the following:
I'm writing a program that has this function:
void* s_malloc(int _size, int dim){
printf("%d %d\n", _size, dim);
char* pointer;
pointer = (char*)malloc(_size * dim);
printf("Malloc eseguita \n");
if(pointer == NULL){
ExitFailure(strerror(errno));
}else{
for(int i = 0; i < dim * _size; i++){
pointer[i] = '\0';
}
printf("Allocata\n");
return (void*)pointer;
}
return (void*) NULL;
}
I tested this function a lot ( In the truth i wrote this function a month ago and since that moment i have used it a lot ). I'm pretty sure that the function works fine.
However in this other function i use 's_malloc' and it crash
#define LDTOCAT "C:\\Users\\admin\\logdrstrace\\"
void startProcess(){
char* logfile, *logfilefullpath;
int run = TRUE, lenth = 0;
/*
for(int i = 0; i < 16; i ++){
s_malloc(60, 1);
}*/ commented
while(run){
logfile = checkLogFileDirectory();
Sleep(1000);
#ifdef DEBUG_MODE
printf("\nValue returned: %s\n", logfile);
fflush(stdout);
#endif // DEBUG_MODE
if(strcmp(logfile, NOFILEFOUND) != 0){
run = FALSE;
}
}
lenth = (strlen(LDTOCAT)+strlen(logfile)+1);
#ifdef DEBUG_MODE
printf("Let's go forward allocating memory: size %d\n", lenth);
printf("LDTOCAT size: %d, logfile size: %d + 1\n", strlen(LDTOCAT), strlen(logfile));
fflush(stdout);
#endif // DEBUG_MODE
logfilefullpath =(char*) s_malloc(lenth, sizeof(char));
#ifdef DEBUG_MODE
printf("Memory created!\n");
fflush(stdout);
#endif // DEBUG_MODE
memcpy(logfilefullpath, LDTOCAT, sizeof(LDTOCAT));
#ifdef DEBUG_MODE
printf("Created logfilefullpath with directory: %s\n", logfilefullpath);
fflush(stdout);
printf("File found: %s\n", strcat(logfilefullpath, logfile));
#endif // DEBUG_MODE
int fd = open(strcat(LDTOCAT, logfile), O_RDONLY);
if(fd <= OK){
ExitFailure(strerror(errno));
}
}
As you can see there is a for loop at the begginning commented. Now we have three possibility:
1) If i compile and run the program it fails in s_malloc function when it executes the command 'loginfulpath = (char*)s_malloc(lenth, sizeof(char))' it enters in s_malloc and crash when it calls the original malloc. Sometimes the errno varible is setted on "Not enough memory" but sometimes crashes and stop.
2) if i decomment the loop at the begginning and the stop condition is 'i<15' it crashes like in the point one
3)if i put the stop condition 'i<16', magically, it works fine.
there is a third function that opens a directory and looks for a file,
infact as you can see in the code it avoids the first 2 files found becouse
they are . and ..
#define NOFILEFOUND "Nothing"
char* checkLogFileDirectory(){
HANDLE hfile = INVALID_HANDLE_VALUE;
WIN32_FIND_DATA fdata, nullValue;
char* file = NULL;
int counter=0;
while(hfile == INVALID_HANDLE_VALUE){
hfile = FindFirstFileA(LOGDIR, &nullValue);
}
#ifdef DEBUG_MODE
printf("-FileFound: %s\n", nullValue.cFileName);
#endif // DEBUG_MODE
while(FindNextFile(hfile, &fdata) && counter != 2){
#ifdef DEBUG_MODE
printf("-File found: %s\n", fdata.cFileName);
#endif // DEBUG_MODE
if(counter == 1){
#ifdef DEBUG_MODE
printf("Third file it's my file\n");
#endif // DEBUG_MODE
file = s_malloc(strlen(fdata.cFileName), sizeof(char));
memcpy(file, fdata.cFileName, strlen(fdata.cFileName)+1);
if(file == NULL){
ExitFailure("Error reading file");
}
file[strlen(fdata.cFileName)] = '\0';
}
counter ++;
}
#ifdef DEBUG_MODE
printf("\n\=>File selected: %s", file==NULL | file == "" ? NOFILEFOUND:file);
#endif // DEBUG_MODE
return counter == 2? file : NOFILEFOUND;
}
NB: I printed the vaule of any varibles and they were correct,
I'm on Virtual machine with vmware workstation.
I'm sorry for my english i hope you will able to understand it
This is the output when it crashes in cases 1 or 2
-FileFound: .
-File found: ..
-File found: drstrace.calc.exe.00532.0000.log
Third file it's my file
32 1
Malloc eseguita
Allocata
=>File selected: drstrace.calc.exe.00532.0000.log
Value returned: drstrace.calc.exe.00532.0000.log
Let's go forward allocating memory: size 60
LDTOCAT size: 27, logfile size: 32 + 1
60 1
Malloc eseguita
Error: Not enough space!!
Thank you!!

Your allocation function is okay (it's a poor man's version of calloc with error checking, maybe using calloc would save some manual code and would be more efficient)
But in checkLogFileDirectory this code is wrong:
file = s_malloc(strlen(fdata.cFileName), sizeof(char));
memcpy(file, fdata.cFileName, strlen(fdata.cFileName)+1);
there's not enough space for file (nul-terminating char). You're missing 1 byte, which can corrupt the rest of your application by undefined behaviour (allocating 15 or 16 useless blocks sometimes makes it "work" because it changes the memory layout).
Why not just do:
file = strdup(fdata.cFileName);
Also, as noted in comments, if you reach a further point of your program you'll have a big issue here:
int fd = open(strcat(LDTOCAT, logfile), O_RDONLY);
LDTOCAT is a string literal, you cannot apply strcat on it. And even if you could, you wouldn't have enough room.

HANDLE hfile = INVALID_HANDLE_VALUE;
WIN32_FIND_DATA fdata, nullValue;
while(hfile == INVALID_HANDLE_VALUE)
{
hfile = FindFirstFileA(LOGDIR, &nullValue);
}
Note that this loop will run forever if something is wrong. Then you put the whole function in another while loop.
If the function call is valid then you have success the first time, otherwise you cannot fix a problem with brute force.
You are not closing hfile. You have many more errors in this section. There are plenty of examples and documentation for FindFirstFile you can consult.
You already have strcat, you should have strcpy too. strcpy will add null terminator at the end of the string. Just use the standard malloc and strcpy
You have to free the malloc allocation, so it's simpler if your function always returns a pointer and NULL on failure.
char* checkLogFileDirectory()
{
char* file = NULL;
WIN32_FIND_DATA fdata;
HANDLE hfile = FindFirstFile("C:\\Users\\admin\\logdrstrace\\*.log", &fdata);
if(hfile != INVALID_HANDLE_VALUE)
{
do
{
if(strcmp(fdata.cFileName, ".") == 0 || strcmp(fdata.cFileName, "..") == 0)
continue;
int len = strlen(fdata.cFileName);
file = malloc(len + 1);
strcpy(file, fdata.cFileName);
break;
} while(FindNextFile(hfile, &fdata));
FindClose(hfile);
}
return file;
}
int main()
{
char *file = checkLogFileDirectory();
if(file) {
printf("%s\n", file);
free(file);
}
return 0;
}

Related

Segmentation fault due to string copy

In the code below the code crashes after executing while loop for 4th time, and it crashes in strcpy
strcpy(userver_info[location].Tag_Name, field);
When debugging it gave following error
Can't find a source file at "strcpy-sse2-unaligned.S"
I am not able to figureout what is the issue which is causing crash here, after facing the above issue i did structure padding thinking that may be the issue and even that is not working out, can anyone please tell me why is the code crashing.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFFER_SIZE 1024
#define NUM_OF_UNDERLYING_SERVER 0
#define SHM_ADDR_LEN 15
#define SERVER_NAME_LEN 25
#define TAG_NAME_LEN 25
#define TAG_DESC_LEN 30
#define ACCESS_LEVEL_LEN 5
#define DATA_TYPE_NAME_LEN 10
typedef struct {
char SHM_Location[SHM_ADDR_LEN];
char Server_ID[SERVER_NAME_LEN];
char Tag_Name[TAG_NAME_LEN];
int Tag_ID;
char Tag_Description[TAG_DESC_LEN];
char Access_Level[ACCESS_LEVEL_LEN];
char Data_Type[DATA_TYPE_NAME_LEN];
}u_server_info;
typedef struct {
int num_of_tags;
u_server_info *underlying_server_data;
}opcua_u_server;
void parse_underlying_opcua_server(char * buffer, u_server_info *userver_info) {
static int location = 0;
char *field;
/* get SHM_Location */
field = strtok(buffer,",");
strcpy(userver_info[location].SHM_Location, field);
/* get Server_ID */
field=strtok(NULL,",");
strcpy(userver_info[location].Server_ID, field);
/* get Tag_Name */
field = strtok(NULL,",");
strcpy(userver_info[location].Tag_Name, field);
/* get Tag_ID */
field=strtok(NULL,",");
userver_info[location].Tag_ID = atoi(field);
/* get Tag_Description */
field = strtok(NULL,",");
strcpy(userver_info[location].Tag_Description, field);
/* get Access_Level */
field = strtok(NULL,",");
strcpy(userver_info[location].Access_Level, field);
/* get Data_Type */
field = strtok(NULL,",");
strcpy(userver_info[location].Data_Type, field);
/* display the result */
printf("%s\t %s\t %s\t %d\t %s\t %s\t %s\n",
userver_info[location].SHM_Location,
userver_info[location].Server_ID,
userver_info[location].Tag_Name,
userver_info[location].Tag_ID,
userver_info[location].Tag_Description,
userver_info[location].Access_Level,
userver_info[location].Data_Type);
location++;
}
int get_line_count(char *filename) {
FILE *fp;
int line_count = 0;
char c;
fp = fopen(filename, "r");
if (fp == NULL){
printf("Unable to open file '%s' to count lines\n",filename);
return -1;
}
for (c = getc(fp); c != EOF; c = getc(fp))
if (c == '\n') // Increment count if this character is newline
line_count = line_count + 1;
fclose(fp);
return line_count;
}
int main(int argc, char **argv)
{
char filename[] = "underlying_server.csv";
char buffer[BUFFER_SIZE];
FILE *fp;
int tags_count = 0;
opcua_u_server *ua_server = NULL;
/* open the CSV file */
fp = fopen(filename,"r");
if( fp == NULL) {
printf("Unable to open file '%s'\n",filename);
exit(EXIT_FAILURE);
}
tags_count = get_line_count(filename);
/* Allocate memmory for each Underlying server */
ua_server= malloc(sizeof(opcua_u_server));
if (ua_server == NULL) {
printf("Malloc failed");
exit(EXIT_FAILURE);
}
/* Allocate memory for each underlying server tag information */
ua_server[NUM_OF_UNDERLYING_SERVER].underlying_server_data =
malloc(tags_count * sizeof(ua_server->underlying_server_data));
if (ua_server[NUM_OF_UNDERLYING_SERVER].underlying_server_data == NULL) {
printf("Malloc failed");
exit(EXIT_FAILURE);
}
/* process the data */
while(fgets(buffer,BUFFER_SIZE,fp)) {
parse_underlying_opcua_server(buffer,
ua_server[NUM_OF_UNDERLYING_SERVER].underlying_server_data);
}
ua_server->num_of_tags = tags_count;
/*Reset the value for next server*/
tags_count = 0;
/* close file */
fclose(fp);
return(0);
}
My underlying_server.csv is like this
1000,Server_1,Tag_1,3000,Created_tag_3000,AR,BOOL
1001,Server_1,Tag_2,3001,Created_tag_3001,AR,BOOL
1002,Server_1,Tag_3,3002,Created_tag_3002,AR,BOOL
1003,Server_1,Tag_4,3003,Created_tag_3003,AR,BOOL
1004,Server_1,Tag_5,3004,Created_tag_3004,AR,REAL
1005,Server_1,Tag_6,3005,Created_tag_3005,AR,REAL
1006,Server_1,Tag_7,3006,Created_tag_3006,AW,REAL
1007,Server_1,Tag_8,3007,Created_tag_3007,AW,REAL
1008,Server_1,Tag_9,3008,Created_tag_3008,AW,REAL
1009,Server_1,Tag_10,3009,Created_tag_3009,AW,REAL
1010,Server_1,Tag_11,3010,Created_tag_3010,AW,REAL
1011,Server_1,Tag_12,3011,Created_tag_3011,AW,DWORD
1012,Server_1,Tag_13,3012,Created_tag_3012,AW,DWORD
1013,Server_1,Tag_14,3013,Created_tag_3013,AR,DWORD
1014,Server_1,Tag_15,3014,Created_tag_3014,AR,DWORD
1015,Server_1,Tag_16,3015,Created_tag_3015,AR,DWORD
1016,Server_1,Tag_17,3016,Created_tag_3016,AR,DWORD
1017,Server_1,Tag_18,3017,Created_tag_3017,AR,DWORD
1018,Server_1,Tag_19,3018,Created_tag_3018,AR,DWORD
1019,Server_1,Tag_20,3019,Created_tag_3019,AR,DWORD
1020,Server_1,Tag_21,3020,Created_tag_3020,AR,DWORD
1021,Server_1,Tag_22,3021,Created_tag_3021,AW,BOOL
1022,Server_1,Tag_23,3022,Created_tag_3022,AW,BOOL
1023,Server_1,Tag_24,3023,Created_tag_3023,AW,BOOL
1024,Server_1,Tag_25,3024,Created_tag_3024,AW,BOOL
1025,Server_1,Tag_26,3025,Created_tag_3025,AW,BOOL
1026,Server_1,Tag_27,3026,Created_tag_3026,AW,DWORD
1027,Server_1,Tag_28,3027,Created_tag_3027,AR,DWORD
1028,Server_1,Tag_29,3028,Created_tag_3028,AR,DWORD
1029,Server_1,Tag_30,3029,Created_tag_3029,AR,DWORD
1030,Server_1,Tag_31,3030,Created_tag_3030,AR,REAL
I'm sure there is a dup for this, you are allocating the second buffer based on the sizeof the pointer, not the object being pointed to:
/* Allocate memory for each underlying server tag information */
ua_server[NUM_OF_UNDERLYING_SERVER].underlying_server_data =
malloc(tags_count * sizeof(ua_server->underlying_server_data));
becomes:
/* Allocate memory for each underlying server tag information */
ua_server[NUM_OF_UNDERLYING_SERVER].underlying_server_data =
malloc(tags_count * sizeof(*(ua_server->underlying_server_data)));
Note the actual code *(ua_server->underlying_server_data is bad at this moment, but sizeof is compile-time and is just using the code as a template to get the object size.
I sometimes wish there was a compiler warning for "You asked for the sizeof a pointer"
Never use strcpy, it's insecure, because it doesn't perform any form of bounds constraining and will just soldier on copying until it hits a 0 byte in the source buffer. If the source buffer isn't (properly) 0-terminated, or the contents of the source buffer are too long to fit into the destination, it will create undefined behavior (crash or be vulnerable to attack).
Putting aside the problem with fixed size fields, it is absolutely necessary to check the size limits of buffer operations. The standard function you'd use (although it still isn't perfect) is strncpy (note the extra n). The caveat is, that strncpy will omit the terminating 0 byte if it doesn't fit into the destination.
Since your fields are fixed size you can use it like this
strncpy(userver_info[location].SHM_Location, field, SHM_ADDR_LEN-1);
userver_info[location].SHM_Location[SHM_ADDR_LEN-1] = 0;
i.e. it copies up to SHM_ADDR_LEN-1 bytes and will always put a terminating 0 at the very end of the buffer.

c program crashes when retrieving sizeof(buff)

I am creating a program in C that splits a large text file into 10 segments, and then creates 10 threads with each thread generating a word count for each segment. I took the function word_count from this code: https://github.com/prateek-khatri/seaOfC/blob/master/frequencyMultiThread.c. That program works fine for me, but when I tried to use word_count in my own program, it crashes when trying to get the size of the buffer.
It seems like everything is ok in the function getCurrentSegmentWordcount, but when that function calls word_count, it crashes (segmentation fault) at the line printf("sizeof Buff: %d", sizeof(buff));.
#define _GNU_SOURCE
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <unistd.h>
#define NUMBER_OF_THREADS 10
//struct taken from reference:
struct return_val{
char wordlist[100][100]; //[chars][lines]
int count[100];
} *arr; //array of words
void *print_hello_world(void * tid)
{
//This function prints the thread’s identifier and then exits.
printf("Hello World. Greetings from thread %d\n", tid);
pthread_exit(NULL);
}
void *word_count(void* num)
{
int *ln = num;
unsigned int line_number = *ln;
//line_number++;
printf("Thread %d\n",line_number);
char cmd_p1[9] = "sed -n '\0";
char cmd_p2[2];
sprintf(cmd_p2,"%d",line_number); //stores string in buffer
char cmd_p3[21] = "p' 'maintainers.txt'\0";
char command[100];
command[0] = '\0';
//char * strcat ( char * destination, const char * source );
//appends a copy of source to destination
strcat(command,cmd_p1);
strcat(command,cmd_p2);
strcat(command,cmd_p3);
usleep(line_number);
char cmd[100] = " | tr [:space:] '\\n' | grep -v '^\\s*$' | sort | uniq -c | sort\0";
strcat(command,cmd);
printf("Command: %s\n",command);
//fflush(stdout);
FILE *in;
in= popen(command, "r"); //read command and pipe into the shell
rewind(in); //set file position to beginning of 'in'
char buff[50];
int counter = 0;
//char * fgets ( char * str, int num, FILE * stream );
//reads chars from stream and stores them as string into buff until all of buffer has been read
printf("before\n");
bool testBool = fgets(buff,sizeof(buff),in);
printf("testBool: %d\n", testBool);
//CRASH HAPPENS HERE:
//buff
printf("sizeof Buff: %d", sizeof(buff));
while(fgets(buff,sizeof(buff),in))
{
printf("fire 0.5");
char c=' ';
int i = 0;
int cnt = atoi(buff); //converts string to int.. buff == # of chars in file?
arr[line_number-1].count[counter] = cnt; //at this point line_number == 1
printf("fire1\n");
while(c!='\0')
{
c=buff[i];
buff[i]=buff[i+6];
i++;
}
int cnnt = 0;
while(c!=' ')
{
c = buff[cnnt];
cnnt++;
}
i=0;
while(c!='\0')
{
c=buff[i];
buff[i]=buff[i+cnnt];
i++;
}
sprintf(arr[line_number-1].wordlist[counter],"%s",buff);
printf("%d %s",arr[line_number-1].count[counter],arr[line_number-1].wordlist[counter]);
counter++;
}
printf("final count: %d", counter);
arr[line_number-1].count[counter] = -1;
fclose(in);
//pthread_exit(NULL); //didn't help to move here from getCurrentSegment...()
return NULL;
}
void *getCurrentSegmentWordcount(void * tid) { //declaring file pointer (value?)
int segment = tid;
segment = segment + 1; //converts to int
printf("segment/thread: %d \n", segment);
char text[1000];
//char buffer[150];
FILE *fp = fopen("words.txt", "r");
if(fp == NULL) {
printf("null file");
}
int i = 0;
long lSize;
char *buffer;
if( !fp ) perror("words.txt"),exit(1);
fseek( fp , 0L , SEEK_END);
lSize = ftell( fp );
rewind( fp );
buffer = calloc( 1, lSize+1 );
if( !buffer ) fclose(fp),fputs("memory alloc fails",stderr),exit(1);
if( 1!=fread( buffer , lSize, 1 , fp) )
fclose(fp),free(buffer),fputs("entire read fails",stderr),exit(1);
//printf(buffer);
char *token = strtok(buffer, "~");
if(segment == 1) {
printf("segment 1: %s", token);
word_count(&segment);
}
if(segment == 2) {
token = strtok(NULL,"~");
printf("segment 2: %s", token);
}
if(segment == 3) {
token = strtok(NULL,"~");
token = strtok(NULL,"~");
printf("segment 3: %s", token);
}
if(segment == 4) {
token = strtok(NULL,"~");
token = strtok(NULL,"~");
token = strtok(NULL,"~");
printf("segment 4: %s", token);
}
fclose(fp);
free(buffer);
//pthread_exit(NULL);//moving to end of word_count()
}
int main(int argc, char *argv[])
{
//The main program creates x threads and then exits.
pthread_t threads[NUMBER_OF_THREADS];
int status, i;
for(i=0; i < NUMBER_OF_THREADS; i++) {
printf("Main here. Creating thread %d\n", i+1);
status = pthread_create(&threads[i], NULL, getCurrentSegmentWordcount, (void * )i);
if (status != 0) {
printf("Oops. pthread create returned error code %d\n", status);
exit(-1);
}
}
sleep(8);
exit(NULL);
}
Output:
Main here. Creating thread 1
Main here. Creating thread 2
segment/thread: 1
Main here. Creating thread 3
segment 1: test(segment 1, handled my thread 1)
Thread 1
Main here. Creating thread 4
Command: sed -n '1p' 'maintainers.txt' | tr [:space:] '\n' | grep -v '^\s*$' | sort | uniq -c | sort
Main here. Creating thread 5
segment/thread: 2
before
segment/thread: 4
Main here. Creating thread 6
segment 4:
test test test test (segment 4, handled by thread 4)
Main here. Creating thread 7
segment 2:
test test (segment 2, handled by thread 2)
Main here. Creating thread 8
Main here. Creating thread 9
Main here. Creating thread 10
segment/thread: 3
segment 3:
test test test (segment 3, handled by thread 3)
segment/thread: 10
segment/thread: 9
segment/thread: 8
segment/thread: 5
segment/thread: 6
segment/thread: 7
testBool: 1
Makefile:20: recipe for target 'all' failed
make: *** [all] Segmentation fault (core dumped)
There are many issues with this code, some have been already mentioned by
user3629249, so I'll try to summarize the errors here.
Passing (void * )i for the argument for the thread is rather ugly. Sure it
works but this is for me sloppy programming, I'd declare an int array and fill
it with the id values and pass a pointer to the locations.
int ids[NUMBER_OF_THREADS];
for(i=0; i < NUMBER_OF_THREADS; i++) {
ids[i] = i+1;
status = pthread_create(&threads[i], NULL, getCurrentSegmentWordcount, ids + i);
...
}
and then in the thread function:
void *getCurrentSegmentWordcount(void * tid) { //declaring file pointer (value?)
int segment = *((int*) tid);
// segment = segment + 1; not needed anymore
...
}
This code is more clean, easier to understand for you and for the code reviewer,
does not relay on ugly unnecessary casts and is more portable.
Same thing with
void *print_hello_world(void *tid)
{
//This function prints the thread’s identifier and then exits.
printf("Hello World. Greetings from thread %d\n", tid);
pthread_exit(NULL);
}
This is uggly, you are trying to pass a pointer as an int. The size of a
pointer may not be the same as the size of an int. Using the same way of
passing a pointer to int (like for getCurrentSegmentWordcount):
void *print_hello_world(void *tid)
{
//This function prints the thread’s identifier and then exits.
printf("Hello World. Greetings from thread %d\n", *((int*) tid));
pthread_exit(NULL);
}
Write error messages to stderr. This FILE buffer is opened for that reason,
that's what people expect from programs to do. When you execute a program, you
can do this:
$ program 2>/tmp/error.log
or this
$ program 2>/dev/null | some_other_tool
so that you can separate the normal output from the error outputs.
And when a system function fails, the errno variable is set to the error code.
You can use perror for a standard error message or if you want a custom one,
use strerror:
pid_t p = fork();
if(p < 0)
{
perror("fork failed");
// or
fprintf(stderr, "Error while executing fork: %s\n", strerror(errno));
return; // or exit or whatever
}
You can write code in one line if you want to enter the C obfuscated contest,
otherwise don't do that. It's hard to read for you, it's hard to read for the
code reviewer/co-worker/superior. You gain nothing from it.
Instead of
if( !buffer ) fclose(fp),fputs("memory alloc fails",stderr),exit(1);
do
if(buffer == NULL)
{
fclose(fp);
fputs("memory alloc fails", stderr);
exit(EXIT_FAILURE); // or exit(your_exit_status)
}
It's easier to read for everyone.
You should always check the return value of functions that return a pointer.
Check the return value of malloc, calloc, realloc, strtok, etc.
if(segment == 2) {
token = strtok(NULL,"~");
printf("segment 2: %s", token);
}
If strtok returns NULL, then the printf line yields undefined behaviour.
See 3.5.3.3 comment 2:
3.5.3.3:
Synopsis
#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
int printf_s(const char * restrict format, ...);
[...]
2 format shall not be a null pointer. The %n specifier (modified or not by flags, field width, or precision) shall not appear in the string pointed to by format. Any argument to printf_s corresponding to a %s specifier shall not be a null pointer.
[...]
4 The printf_s function is equivalent to the printf function except for the explicit runtime-constraints listed above.
Some libc implementation may forgive you to pass NULL to printf with %s
and print (null), but this is not portable and is undefined behaviour. So you
can only do the printf if token is not NULL.
The word_count function is a little bit horrible, specially how you construct
the commands.
char cmd_p1[9] = "sed -n '\0";
can be rewritten as
char cmd_p1[] = "sed -n '";
This will create a char array with the correct amount of bytes and initialize
it with a valid 0-terminated string, no need to add the '\0' yourself.
The commands that are the same, meaning that they don't need a value from a
variable can be store in a char[] or even in a const char*. Then construct
the whole thing with snprintf and sprintf, less lines, less mistakes:
void *word_count(void* num)
{
...
const char *pipe_cmd = "| tr [:space:] '\\n' | grep -v '^\\s*$' | sort | uniq -c | sort";
const char *format = "sed -n '%dp' 'maintainers.txt' %s";
int cmd_size = snprintf(NULL, 0, format, line_number, pipe_cmd);
char *command = malloc(cmd_size + 1);
if(command == NULL)
return NULL;
sprintf(command, format, line_number, pipe_cmd);
...
FILE *in;
in= popen(command, "r");
free(command);
...
}
Also note that
char cmd_p2[2];
sprintf(cmd_p2,"%d",line_number); //stores string in buffer
will overflow the buffer if the line number is greater than 9.
bool testBool = fgets(buff,sizeof(buff),in);
printf("testBool: %d\n", testBool);
fgets returns a pointer to char, not a bool. The printf will print the
value of a pointer as an integer. A pointer size is not necessarily the same as
an int size, in fact on my system a pointer is 8 bytes long, int is 4 bytes
long. You should do:
if(fgets(buff, sizeof(buff), in))
puts("fgets success");
//CRASH HAPPENS HERE:
//buff
printf("sizeof Buff: %d", sizeof(buff));
It won't crash because of the sizeof. sizeof is evaluated at compile time,
not at run-time.
The sizeof-operator returns a size_t.
%d is not the correct specifier for size_t, %lu is, it should be
printf("sizeof buff: %lu\n", sizeof buff);
It will most probably crash because of all the undefined behaviour before
this point.
arr[line_number-1].count[counter] = cnt;
In your whole code, arr is uninitialized, so you are accessing a value
through an uninitialized pointer. That's undefined behaviour and might lead to a
segfault.
I want to quote user3629249 here:
user3629249 wrote:
the main() function is starting several threads, then immediately exiting. The process of exiting also eliminates the threads Suggest: in main() calling pthread_join() for each thread. in the thread, at the end, call pthread_exit()
Please don't ignore compiler warnings, they are not there to annoy you, they are
there to help you. They are a hint that what you are doing may not be what you
really want. Undefined behaviour, segfaults etc. are often a consequence of
that. So heed warnings of the compiler and when you see one, look at your code,
try to understand it and fix it. If you don't understand the warning, you can
come here and ask a question about it. But having thousand of warning and
ignoring them will lead to headaches and quite franky a lot of wasted time on
your side and ours.
So, please fix all this warnings and details, look at the warning messages of
the compiler and the code might run without problems.

C multi-thread wordcount program segmentation fault issue

I've been racking my brain against this program for a couple months now. This was an assignment of a class I took last semester and while I passed, I could never make this one assignment work correctly (Seg Fault). I welcome any help or tips but I greatly appreciate explanations with answers to follow along.
This program is supposed to receive a filename that contains a list of filenames (240 for my example). Those files are located in a folder within the same directory as the list and the program. This program is supposed to take this list and parse it for 4 threads, splitting the filenames evenly for each thread (60 per thread for my example). Each thread then takes this list of 60 file names and opens each file one by one performing a WordCount function on each file. Once the threads complete their tasks, they are supposed to print the results for each file in order with each thread in its own block(i.e. Thread1 Results | Thread2 Results | Thread 3 Results, etc...).
I've debugged quite a bit and know that up until the threads are created everything works as it is supposed to. My problem seems to be during thread launch/execution. I've tried adding mutex to the mix but sadly it hasn't helped. I seem to be missing something or over thinking something as some of my class mates have shown me their much more compact code. Please assist. Thanks!
Here is the Main:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define MaxLine 200
#define NUMTHREADS 4
char Line[MaxLine];
pthread_mutex_t Lock = PTHREAD_MUTEX_INITIALIZER;
typedef struct thread {
int id;
char file;
}ThreadData;
/* ThreadFunction will give each thread its processes to execute */
void *threadFunc (void *td) {
ThreadData *data = (ThreadData*)td;
int thread_num=data->id;
char filename=data->file;
printf("thread debug tid: %d and file: %c",thread_num, filename);
pthread_mutex_trylock(&Lock);
FILE *fn = fopen(filename, "r");
if (fn == NULL) {
error("ERROR: Opening file");
return 1;
}
while (fgets(Line, sizeof(Line), fn) != NULL) {
CountWord(thread_num, Line);
}
fclose(fn);
free(data);
pthread_mutex_unlock(&Lock);
pthread_exit(NULL);
}
int main(int argc, char *argv[]){
char buf[20];
int c, i, t, tnum, QUEUETOTAL;
pthread_t thread[NUMTHREADS];
ThreadData td[NUMTHREADS];
if (argc != 2){
fprintf(stderr,"ERROR: Usage must be Countfile filename\n", argv[0]);
exit(0);
}
char const* const filename = argv[1];
FILE* file = fopen(filename, "r");
if ( file == 0 ){
printf( "Could not open file!\n" );
exit(0);
}
/* Count iterations of while loop to divide files among threads. */
while (fgets(Line, sizeof(Line), file)){
QUEUETOTAL++;
}
/* Divide work for threads. */
int thread2taskstart=(QUEUETOTAL/NUMTHREADS); //60
int thread3taskstart=(QUEUETOTAL/NUMTHREADS)*2; //120
int thread4taskstart=(QUEUETOTAL/NUMTHREADS)*3; //180
// QUEUETOTAL = 240
rewind(file);
FILE *tempfile1 = fopen("temp1.txt","w");
for (i=0; i<thread2taskstart; i++) {
// populate tempfile1 with entries 1-60
if(fgets(Line,sizeof(Line),file)!=NULL) {
fputs(Line,tempfile1);
//printf("Debug temp1: %s",Line);
}
}
fclose(tempfile1);
FILE *tempfile2 = fopen("temp2.txt","w");
for (i=thread2taskstart; i<thread3taskstart; i++) {
// populate tempfile2 with entries 60-120
if(fgets(Line,sizeof(Line),file)!=NULL) {
fputs(Line,tempfile2);
//printf("Debug temp2: %s",Line);
}
}
fclose(tempfile2);
FILE *tempfile3 = fopen("temp3.txt","w");
for (i=thread3taskstart; i<thread4taskstart; i++) {
// populate tempfile3 with entries 120-180
if(fgets(Line,sizeof(Line),file)!=NULL) {
fputs(Line,tempfile3);
//printf("Debug temp3: %s",Line);
}
}
fclose(tempfile3);
FILE *tempfile4 = fopen("temp4.txt","w");
for (i=thread4taskstart; i<=QUEUETOTAL; i++) {
// populate tempfile3 with entries 180-240
if(fgets(Line,sizeof(Line),file)!=NULL) {
fputs(Line,tempfile4);
//printf("Debug temp4: %s",Line);
}
}
fclose(tempfile4);
fclose(file);
/* Prepare parameters & launch (4) threads. Wait for threads
to finish & print out results as specified in assignment. */
printf("Counting files …\n");
for(t=0;t<NUMTHREADS;t++){
tnum=t+1;
snprintf(buf, "temp%d.txt", tnum);
printf("debug tnum and array: %d and %s\n",tnum, buf);
td[t].id = tnum;
td[t].file = buf;
// Creates a new thread for each temp file.
pthread_create(&thread[t], NULL, threadFunc, td);
}
// Joins threads.
printf("debug: printing threads \n");
for(t=0;t<NUMTHREADS;t++){
pthread_join(thread[t], NULL);
printf("------------------------- Processes finished for Thread %d ----------------------- \n",t+1);
}
return 0;
}
Here is the Count Function:
#include <stdio.h>
int CountWord(int tinfo, char cfile){
int i;
int ccount = 0;
int wcount = 0;
int lcount = 0;
FILE *fname;
char fn[strlen(cfile) + 18];
sprintf(fn, "./CountingFolder/%s", cfile);
printf("Debug: %s\n", fn);
fname = fopen(fn, "r");
if (fname == NULL) {
error("ERROR: Opening file");
}
while ((i = fgetc(fname)) != EOF){
if (i == '\n') {
lcount++;
}
if (i == '\t' || i == ' '){
wcount++;
}
ccount++;
}
printf("Threadid %d processes %s which has %d characters, %d words and %d lines\n", tinfo, cfile, ccount, wcount, lcount);
fclose(fname);
return 0;
}
1) Probably a typo. But
int CountWord(int tinfo, char cfile){ .. }
should be
int CountWord(int tinfo, char *cfile){ .. }
2) You are passing the same buf to all threads from main(). Data race and undefined behaviour.
3) None of the snprintf() calls take the size argument. Undefined behaviour.
4) Since all threads work on different data, you don't need a lock at all.
5) You didn't allocate td array. So you can't call free(data); in the thread function. Undefined behaviour.
There may be more issues with the code but the segfault is likely because of (3) or (5).
In your code here
snprintf(buf, "temp%d.txt", tnum);
printf("debug tnum and array: %d and %s\n",tnum, buf);
td[t].id = tnum;
td[t].file = buf;
the last line assigns a pointer into the file field of this struct
typedef struct thread {
int id;
char file;
}ThreadData;
Shouldn't it be char *file; ? I don't have thread.h in MSVC so I can't compile it. Surely you have all warnings enabled??

Issues accessing a struct array when it is sent into a function

I am a new C programmer and so you will have to excuse my lack of knowledge. Slowly but surely I am improving. I am wondering why I am unable to access the members of my structure after I have sent them to a function that intends to modify them. This issue occurs in the code shown below. Basically my program analyzes an XML document and looks for certain patterns to extract text. In my main function I make the struct: artinfo artIn[128] = {}; which is defined in my header file as being:
#ifndef FILE_TABLE_H
#define FILE_TABLE_H
#ifdef __cplusplus
extern "C" {
#endif
typedef struct article_info {
char author1[512];
char author2[512];
char author3[512];
char author4[512];
char author5[512];
char author6[512];
char title[2048];
char version[4];
char year[4];
char page[64];
char abstract[4096];
char notes[4096];
} artinfo;
#ifdef __cplusplus
}
#endif
#endif
After instantiating this and clearing it with memset I proceed to send it to another function which will extract text and intends to put it back in the structure. The function is shown below.
bool readerParser(FILE *input, FILE *output, textlbuf *lbuf, artinfo *artIn[]){
int isNewline; /* Boolean indicating we've read a CR or LF */
long lFileLen; /* Length of file */
long lIndex; /* Index into cThisLine array */
long lLineCount; /* Current line number */
long lLineLen; /* Current line length */
long lStartPos; /* Offset of start of current line */
long lTotalChars; /* Total characters read */
char cThisLine[BUFSIZE]; /* Contents of current line */
char *cFile; /* Dynamically allocated buffer (entire file) */
char *cThisPtr; /* Pointer to current position in cFile */
char cNextLine[BUFSIZE];
char buffer[BUFSIZE];
char title[] = "<text top=\"245\"";
char ending[] = "$";
char author[] = "$</text>";
bool tfound, afound;
char *match, *cNextLinePtr;
long lNextLineCount;
int i, j;
//initialize some values
tfound = false;
afound = false;
fseek(input, 0L, SEEK_END); /* Position to end of file */
lFileLen = ftell(input); /* Get file length */
rewind(input); /* Back to start of file */
memset(&cThisLine,0,sizeof(cThisLine));
memset(&cNextLine,0,sizeof(cNextLine));
memset(&buffer,0,sizeof(buffer));
printf("TEST: Entered read parser\n");
cFile = calloc(lFileLen + 1, sizeof(char));
printf("TEST:\n");
if(cFile == NULL )
{
printf("\nInsufficient memory to read file.\n");
return 0;
}
fread(cFile, lFileLen, 1, input); /* Read the entire file into cFile */
printf("TEST: read the file in\n");
lLineCount = 0L;
lTotalChars = 0L;
cThisPtr = cFile; /* Point to beginning of array */
printf("TEST: Got to here.\n");
while (*cThisPtr) /* Read until reaching null char */
{
//printf("TEST: Got to here.\n");
lIndex = 0L; /* Reset counters and flags */
isNewline = 0;
lStartPos = lTotalChars;
while (*cThisPtr) /* Read until reaching null char */
{
if (!isNewline) /* Haven't read a CR or LF yet */
{
if (*cThisPtr == CR || *cThisPtr == LF) /* This char IS a CR or LF */
isNewline = 1; /* Set flag */
//printf("Flag was set");
//exit(0);
}
else if (*cThisPtr != CR && *cThisPtr != LF) /* Already found CR or LF */
break; /* Done with line */
cThisLine[lIndex++] = *cThisPtr++; /* Add char to output and increment */
++lTotalChars;
} /* end while (*cThisPtr) */
cThisLine[lIndex] = '\0'; /* Terminate the string */
++lLineCount; /* Increment the line counter */
lLineLen = strlen(cThisLine); /* Get length of line */
/* THIS is where I look for the matches to the patterns for my info. */
// printf("TEST: Printing 1 line\n%s", cThisLine);
// exit(0);
if(strstr(cThisLine,title)!= NULL && tfound == false)
{
printf("TEST: Looking for title info.\n");
match = strstr(cThisLine,">");
//printf("TEST: match first points to %c\n", *match);
//exit(0);
j = 0;
match++;
//printf("TEST: match points to %c\n", *match);
while(*match!='<')
{
//pridntf("TEST: match is %c\n", *match);
//printf("TEST: %c", *match);
buffer[j] = *match;
//printf("TEST: %c", buffer);
j++;
match++;
}
lNextLineCount = lLineCount;
do
{
lNextLineCount = lNextLineCount + 1;
readaheadone(cFile, lNextLineCount, cNextLinePtr, lbuf);
strcpy(cNextLine, lbuf->bline);
cNextLinePtr = cNextLine;
printf("TEST: the current line is - %s\nthe next line is %s\n",cThisLine,cNextLine);
//printf("TEST: Before test exit");
//exit(0);
if(strstr(cNextLinePtr,ending)!=NULL)
{
printf("TEST: Author Info spans more than 1 line.\n");
match = strstr(cThisLine,">");
j++; //i DON'T RESET COUNTER SO IT JUST KEEPS FILLING THE BUFFER AFTER LEAVING A SPACE
match++;
//printf("TEST: match points to %c\n", *match);
while(*match!='<')
{
//pridntf("TEST: match is %c\n", *match);
//printf("TEST: %c", *match);
buffer[j] = *match;
//printf("TEST: %c", buffer);
j++;
match++;
}
}
} while(strstr(cNextLinePtr,ending)!=NULL);
strcpy((*artIn[0]).title, buffer);
printf("The title is: %s\n", buffer);//artinfo[0].author);
printf("The title is: %s\n", (*artIn[0]).title);
tfound = true;
}
if(strstr(cThisLine,author)!= NULL && afound == false)
{
printf("TEST: Looking for author info.\n");
match = strstr(cThisLine,">");
}
Everything seems to work just fine until its reaches the: strcpy((*artIn[0]).title, buffer); and printf("The title is: %s\n", ((*artIn[0]).title); statements. I always get an error and a stack dump - i.e. 1 [main]Parst_Text 7296 open_stackdumpfile: Dumping stack trace to Parse_Text.exe.stackdump
I am not really sure what I am doing wrong - I think it is the call to access the member of the struct array as if I remove these statements the program runs without flaw. I am not sure if I am just putting too much on the stack or how to use the stack dump to figure out the problem. All advice is appreciated but please keep it constructive. Thanks. Also please let me know if I overloaded this question as I wasn't sure how much detail to provide.
EDIT: as per request here is the function which calls reader parser
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h> //for close()
#include <ctype.h> //for toupper()
#include <stdbool.h> //for bool type
#include <errno.h> //where the standard error is written for calls to OS
#include "file_table.h"
#define BUFSIZE 1024
#define CR 13 /* Decimal code of Carriage Return char */
#define LF 10 /* Decimal code of Line Feed char */
#define EOF_MARKER 26 /* Decimal code of DOS end-of-file marker */
void fillFileTable(char *filedir, ftable *table, bool populate, ftinfo *info);
bool readerParser(FILE *InputFile, FILE *OutputFile, textlbuf *lbuf, artinfo *artIn[]);
void readaheadone(char *cFile, long nextLineCount ,char *currentPtr, textlbuf *lbuf);
int main()
{
/*Define variables & Instantiate Structs.*/
ftable files[128];
ftinfo info;
artinfo artIn[128] = {};
textlbuf store[1];
char buffer[BUFSIZE];
char dir[260] = "C:/DTEST/Parse_Text/91_1_text"; //would be better if user could enter this - fix for later
ftinfo *fti = &info;
textlbuf *lbuf = &store;
FILE *fp, *op; //fp is input file, op is output file
int i, j, k;
bool iReadReturn;
/*Clear Out Memory Structures*/
memset(&files,0,sizeof(files));
memset(&info,0,sizeof(info));
memset(&artIn,0,sizeof(artIn));
memset(&buffer,0,sizeof(buffer));
memset(&store,0,sizeof(store));
/*Fill the File Table*/
printf("TEST: Preparing to fill the file table...\n");
fillFileTable(dir,files,true,fti);
if(info.success == false)
{
printf("Something went wrong. Now exiting");
exit(1);
}
printf("File table has been filled: %s\n",info.notes);
printf("File table contains: %d\n", info.fileCount);
printf("TEST: 'fillFileTable' is successful? --- %s\n", info.success?"true":"false");
for(i=0;i<info.fileCount;i++)
{
if(files[i].type == 'd')
printf("File Folder is: %s\t its size is %d\n",files[i].fileName,files[i].fileSize);
else
printf("File is: %s\t its size is %d\n",files[i].fileName,files[i].fileSize);
}
printf("\n\n");
//printf("TESTd: Exiting after file table printout.\n\n"); exit(0);
op=fopen("./test_Out.txt", "a");
if (op == NULL ) /* Could not open file */
{
printf("Error opening output file: %s (%u)\n", strerror(errno), errno);
return 1;
}
//for(i=0;i<info.fileCount;i++) //Figure out how to loop through all files - improvement for later
fp=fopen("./91_1_text/test1.txt", "r");
if (fp == NULL ) /* Could not open file */
{
printf("Error opening input file: %s (%u)\n", strerror(errno), errno);
return 1;
}
iReadReturn = readerParser(fp, op, lbuf, artIn); /* Read the file and print output */
if (iReadReturn == false)
{
printf("ERROR: The file did not read correctly.\n");
exit(1);
}
k = fclose(fp);
if (k != 0)
exit(k);
k = fclose(op);
if (k != 0)
exit(k);
printf("Program Completed Successfuly.\n");
return 0;
}
With this function declaration:
bool readerParser(FILE *input, FILE *output, textlbuf *lbuf, artinfo *artIn[])
the 4th argument will be an array of pointers to artinfo structures, not a pointer to an array of artinfo structures. When it tries to de-reference these supposed pointers, it fails.
Instead it should be:
bool readerParser(FILE *input, FILE *output, textlbuf *lbuf, artinfo (*artIn)[])
In addition, fixing these would at least make your program more robust.
There does not seem to be any check for overflowing buffer
You do not explicitly place a null character at the end of buffer. Although you do memset it before entering your loop, if it did overflow then not only might it be too long, it might also not be null terminated.
You should use strncpy instead of strcpy, otherwise you run the risk of overflowing the space allocated in the destination string. Also as noted by Matt, you should manually add a null character to the end of your string after calling strncpy.
There are already many suggestions on how you can improve the robustness of your code. I'm going to answer to the main problem you mentioned in your original post.
You said,
Everything seems to work just fine until its reaches the: strcpy((*artIn[0]).title, buffer); and printf("The title is: %s\n", ((*artIn[0]).title); statements. I always get an error and a stack dump - i.e. 1 [main]Parst_Text 7296 open_stackdumpfile: Dumping stack trace to Parse_Text.exe.stackdump I am not really sure what I am doing wrong
The culprit for that problem is that you have
bool readerParser(FILE *input, FILE *output, textlbuf *lbuf, artinfo *artIn[])
but when you are calling the function, you are using:
readerParser(fp, op, lbuf, artIn);
I am surprised that the compiler didn't flag a warning or an error. artIn is declared as:
artinfo artIn[128] = {};
When you use artIn in a function call, it degrades to a pointer of type artinfo*. It would be good when the argument type of an argument is artinfo* artIn or artinfo artIn[] but not artinfo* artIn[].
You should change the type of artIn in readerParser, both in the declaration and the definition.
bool readerParser(FILE *input, FILE *output, textlbuf *lbuf, artinfo artIn[])
And then replace all usages of *artIn in that function with just artIn.
Hope this helps.

C, Segmentation fault parsing large csv file

I wrote a simple program that would open a csv file, read it, make a new csv file, and only write some of the columns (I don't want all of the columns and am hoping removing some will make the file more manageable). The file is 1.15GB, but fopen() doesn't have a problem with it. The segmentation fault happens in my while loop shortly after the first progress printf().
I tested on just the first few lines of the csv and the logic below does what I want. The strange section for when index == 0 is due to the last column being in the form (xxx, yyy)\n (the , in a comma separated value file is just ridiculous).
Here is the code, the while loop is the problem:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char** argv) {
long size;
FILE* inF = fopen("allCrimes.csv", "rb");
if (!inF) {
puts("fopen() error");
return 0;
}
fseek(inF, 0, SEEK_END);
size = ftell(inF);
rewind(inF);
printf("In file size = %ld bytes.\n", size);
char* buf = malloc((size+1)*sizeof(char));
if (fread(buf, 1, size, inF) != size) {
puts("fread() error");
return 0;
}
fclose(inF);
buf[size] = '\0';
FILE *outF = fopen("lessColumns.csv", "w");
if (!outF) {
puts("fopen() error");
return 0;
}
int index = 0;
char* currComma = strchr(buf, ',');
fwrite(buf, 1, (int)(currComma-buf), outF);
int progress = 0;
while (currComma != NULL) {
index++;
index = (index%14 == 0) ? 0 : index;
progress++;
if (progress%1000 == 0) printf("%d\n", progress/1000);
int start = (int)(currComma-buf);
currComma = strchr(currComma+1, ',');
if (!currComma) break;
if ((index >= 3 && index <= 10) || index == 13) continue;
int end = (int)(currComma-buf);
int endMinusStart = end-start;
char* newEntry = malloc((endMinusStart+1)*sizeof(char));
strncpy(newEntry, buf+start, endMinusStart);
newEntry[end+1] = '\0';
if (index == 0) {
char* findNewLine = strchr(newEntry, '\n');
int newLinePos = (int)(findNewLine-newEntry);
char* modifiedNewEntry = malloc((strlen(newEntry)-newLinePos+1)*sizeof(char));
strcpy(modifiedNewEntry, newEntry+newLinePos);
fwrite(modifiedNewEntry, 1, strlen(modifiedNewEntry), outF);
}
else fwrite(newEntry, 1, end-start, outF);
}
fclose(outF);
return 0;
}
Edit: It turned out the problem was that the csv file had , in places I was not expecting which caused the logic to fail. I ended up writing a new parser that removes lines with the incorrect number of commas. It removed 243,875 lines (about 4% of the file). I'll post that code instead as it at least reflects some of the comments about free():
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char** argv) {
long size;
FILE* inF = fopen("allCrimes.csv", "rb");
if (!inF) {
puts("fopen() error");
return 0;
}
fseek(inF, 0, SEEK_END);
size = ftell(inF);
rewind(inF);
printf("In file size = %ld bytes.\n", size);
char* buf = malloc((size+1)*sizeof(char));
if (fread(buf, 1, size, inF) != size) {
puts("fread() error");
return 0;
}
fclose(inF);
buf[size] = '\0';
FILE *outF = fopen("uniformCommaCount.csv", "w");
if (!outF) {
puts("fopen() error");
return 0;
}
int numOmitted = 0;
int start = 0;
while (1) {
char* currNewLine = strchr(buf+start, '\n');
if (!currNewLine) {
puts("Done");
break;
}
int end = (int)(currNewLine-buf);
char* entry = malloc((end-start+2)*sizeof(char));
strncpy(entry, buf+start, end-start+1);
entry[end-start+1] = '\0';
int commaCount = 0;
char* commaPointer = entry;
for (; *commaPointer; commaPointer++) if (*commaPointer == ',') commaCount++;
if (commaCount == 14) fwrite(entry, 1, end-start+1, outF);
else numOmitted++;
free(entry);
start = end+1;
}
fclose(outF);
printf("Omitted %d lines\n", numOmitted);
return 0;
}
you're malloc'ing but never freeing. possibly you run out of memomry, one of your mallocs returns NULL, and the subsequent call to str(n)cpy segfaults.
adding free(newEntry);, free(modifiedNewEntry); immediately after the respective fwrite calls should solve your memory shortage.
also note that inside your loop you compute offsets into the buffer buf which contains the whole file. these offsets are held in variables of type int whose maximum value on your system may be too small for the numbers you are handling. also note that adding large ints may result in a negative value which is another possible cause of the segfault (negative offsets into buf take you to some address outside the buffer possibly not even readable).
The malloc(3) function can (and sometimes does) fail.
At least code something like
char* buf = malloc(size+1);
if (!buf) {
fprintf(stderr, "failed to malloc %d bytes - %s\n",
size+1, strerror(errno));
exit (EXIT_FAILURE);
}
And I strongly suggest to clear with memset(buf, 0, size+1) the successful result of a malloc (or otherwise use calloc ....), not only because the following fread could fail (which you are testing) but to ease debugging and reproducibility.
and likewise for every other calls to malloc or calloc (you should always test them against failure)....
Notice that by definition sizeof(char) is always 1. Hence I removed it.
As others pointed out, you have a memory leak because you don't call free appropriately. A tool like valgrind could help.
You need to learn how to use the debugger (e.g. gdb). Don't forget to compile with all warnings and debugging information (e.g. gcc -Wall -g). And improve your code till you get no warnings.
Knowing how to use a debugger is an essential required skill when programming (particularly in C or C++). That debugging skill (and ability to use the debugger) will be useful in every C or C++ program you contribute to.
BTW, you could read your file line by line with getline(3) (which can also fail and you should test that).

Resources