-1

I am trying to create an antivirus software, in order to learn how file streams work in c. The error occurs in the function read_file();, in which windows sends an error messages saying that the executable is not responding, and then the program terminates execution...

Code::Blocks soon says at the end of the program execution something similar to the following:

Process returned -1073741819 (0xC0000005)   execution time : 3.756 s
Press any key to continue...

I am susupecting that this is a memory error, in which too much memory is being allocated, however I am not sure.

Here is the code:

/*
*Name: ZKjm310
*Objective: Create an antivirus, by comparing file hashes
*Date: 2/3/18
*/

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdbool.h>
//#include "sha256.h" // separate header file for creating sha256 hashes

//file path for virus definitions
#define PATH "C:\\Users\\matth\\Box Sync\\Programmming\\Workspaces\\Personal\\C+CPP Projects\\VirusAnti\\Test.txt"

char* read_defs()
{
    char* virus_defs = (char*)malloc(sizeof(char) * 1000000); // allocates memory to store virus definitions
    FILE *fp; // main virus definitions file
    fp = fopen(PATH, "rb");
    if(fp == NULL)
    {
        printf("[ERROR] Could not find virus definitions! :\'\(");
        pause();
        free(virus_defs);
        exit(1);
    }
    int i = 0; // iterator, iterates through virus_defs, for adding definitions
    while(!feof(fp))
    {
        // reads virus definitions from file
        char read_memory;
        read_memory = fgetc(fp);
        virus_defs[i] = read_memory;
        i++;
    }
    fclose(fp);
    return virus_defs; // returns read virus definitions
}

void pause()
{
    // pauses program by asking "Press <enter> to continue..." and user presses enter
    char x[2];
    printf("\nPress <enter> to continue...\n");
    fgets(x, sizeof(x), stdin);
}

char* read_file(char* fname)
{
    // reads file and returns char* for file content
    FILE *file;
    char* file_content = (char*)malloc(sizeof(char) * 100000000);
    file = fopen(fname, "rb");
    if(file == NULL)
    {
        return NULL;
    }
    int i = 0;
    while(!feof(file));
    {
        char read_memory;
        read_memory = fgetc(file);
        file_content[i] = read_memory;
        i++;
    }
    fclose(file);
    return file_content;
}

int main(int argc, char* argv[])
{
    bool isRunning = true;
    printf("[INFO] Loading virus definitions");
    char* virus_defs = read_defs();
    printf("\n[INFO] Virus definitions loaded!\n");
    printf("[INFO] Getting ready to scan files...\n");
    printf("[INFO] Virus Definitions:\n%s\n", virus_defs);
    while(isRunning)
    {
        char _fname[500];
        printf("Enter file to scan:\n");
        fgets(_fname, sizeof(_fname), stdin);
        const char* fname = _fname;
        char* file_read = read_file(fname);
        printf("File content read:\n%s\n", file_read);
    }
    return 0;
}

Please Note: The application is not fully completed, and I am currently working on the reading and the hashing of some files. This program is only to be created in order to understand file streams in c, and will not be used for commercial use.

  • 3
    Read [why `while(!feof(fp))` is always wrong](https://stackoverflow.com/questions/5431941/why-is-while-feof-file-always-wrong). Instead `while (fgetc(fp) != EOF)` is a more correct option. – Iharob Al Asimi Feb 04 '18 at 01:26
  • I did that, however, I spotted an error, in the same function, in which, `if(fp != NULL)`, I fixed it to `if(fp == NULL)`, however, I keep on getting a null pointer returned, even if the file is there... – John Smith Feb 04 '18 at 01:33
  • @user3121023, it depends.. – Andrejs Cainikovs Feb 04 '18 at 01:39
  • Use `perror()` to learn why `fopen()` returned `NULL`. That should help you go on debugging. – Iharob Al Asimi Feb 04 '18 at 01:40
  • It says `Invalid argument`... – John Smith Feb 04 '18 at 01:45
  • I found the error, fgets() says \n is a valid character, so I have to do this: `_fname[strlen(_fname) - 1] = '\0';` int `int main()`. I also had to also `#include ` – John Smith Feb 04 '18 at 01:48
  • 1
    Just an observation, but there are a heck of a lot easier ways to *"learn how file streams work in c"* than by jumping into a complex example. Instead, learn how things work with short *unit-test* type code that focuses only on the task at hand. Once you have mastered one aspect, then begin combining what you know into more complex examples. Doing it the way you have started, just invites too many unrelated issues that do nothing by cloud the topic of interest. – David C. Rankin Feb 04 '18 at 03:06
  • Note that you should not create function or variable names that start with an underscore, in general. [C11 §7.1.3 Reserved identifiers](https://port70.net/~nsz/c/c11/n1570.html#7.1.3) says (in part): — _All identifiers that begin with an underscore and either an uppercase letter or another underscore are always reserved for any use._ — _All identifiers that begin with an underscore are always reserved for use as identifiers with file scope in both the ordinary and tag name spaces._ See also [What does double underscore (`__const`) mean in C?](https://stackoverflow.com/a/1449301/15168) – Jonathan Leffler Feb 04 '18 at 08:15
  • Thank you all for the help, it is much appreciated! – John Smith Feb 04 '18 at 16:59

1 Answers1

1

John, if you are still stuck, the standard way to read a binary file into storage, is to open the file and use fseek to seek the end of file and use ftell to determine the number of bytes. A second call to fseek (or rewind) will return the file position to the beginning. You then allocate storage for the entire file (to the precise size needed) and then you can make a single call to fread to read the file into storage.

Since you are doing this in a function, it is helpful to pass a pointer to the function that can be updated with the number of bytes so that after return the size of your buffer is available back in the calling function.

A short example reworking your read_file function could be:

char *read_file (char* fname, size_t *nbytes)
{
    long bytes = 0;
    char* file_content;
    FILE *file = fopen(fname, "rb");

    if (!file)          /* validate file open for reading */
        return NULL;

    fseek (file, 0, SEEK_END);              /* fseek end of file */
    if ((bytes = ftell (file)) == -1) {     /* get number of bytes */
        fprintf (stderr, "error: unable to determine file length.\n");
        return NULL;
    }
    fseek (file, 0, SEEK_SET);              /* fseek beginning of file */

    /* allocate memory for file */
    if (!(file_content = malloc (bytes))) { /* allocate/validate memory */
        perror ("malloc - virtual memory exhausted");
        return NULL;
    }

    /* read all data into file in single call to fread */
    if (fread (file_content, 1, (size_t)bytes, file) != (size_t)bytes) {
        fprintf (stderr, "error: failed to read %ld-bytes from '%s'.\n", 
                bytes, fname);
        return NULL;
    }
    fclose (file);              /* close file */
    *nbytes = (size_t)bytes;    /* update nbytes making size avialable */

    return file_content;        /* return pointer to caller */
}

A short driver program for testing would just pass the filename as the first argument and along to your read_file function and display the number of bytes successfully read, e.g.

#include <stdio.h>
#include <stdlib.h>

char *read_file (char* fname, size_t *nbytes);

int main (int argc, char **argv) {

    size_t nbytes;
    char *content;

    if (argc < 2) {     /* validate required argument givent */
        fprintf (stderr, "error: insufficient input. filename req'd.\n");
        return 1;
    }

    if ((content = read_file (argv[1], &nbytes))) { /* read/validate */
        printf ("read %zu bytes of data from %s\n", nbytes, argv[1]);
        free (content);
    }

    return 0;
}
...

Example Input File

$ ls -l ../dat/100000int.bin
-rw-r--r-- 1 david david 400000 Dec 13 11:39 ../dat/100000int.bin

Example Use/Output

$ ./bin/freadbinfile ../dat/100000int.bin
read 400000 bytes of data from ../dat/100000int.bin

Look things over and let me know if you have any questions.

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85