1

I've read a few postings regarding this, but I'm a beginner coder and having a difficult time making sense of memory management and debug process. I feel pretty stuck, not sure where to look for the answers. I would really appreciate any help/pointers to understand this concept and ways to resolve the bugs. FYI, I haven't even learned to use debug console/programs of any kind yet.

In this code, my goal is to create a function that can open a text file with a given name in read-only mode and return the char * to the address of memory with the entire content of the file.

This code ran as intended with a short test file, but consistently had "corrupted size vs. prev_size Aborted" error at the 12th run of realloc function.

Below is the entire code and output with test runs for both short and long texts.

=== Code ====

/////////////////////////////////////////////////////////////
/////                                                   /////
///// FILE I/O
///// Character Type, Read only mode 
///// Fixed Buffer Size by #define STR_BUFFER size
/////                                                   /////
/////////////////////////////////////////////////////////////
// USE: ./fopenRfixedsize argument
// Example: ./fopenRfixedsize filename
// Description: 
//  - argument is the filename
//  - only one argument allowed
// ,or char *fopenRfixedsize(char *fName[]);
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>


#ifndef STR_BUFFER
    #define STR_BUFFER 25000
#endif


FILE *fRead;


char *fopenRfixedsize(char *fName[]);


///////////////////////////////////////////////////////////////////////////////////////////////////
// temp main function for individual module testing
int main(int argc, char *argv[])
{
    if (argc != 2) // input limited to single file name only
    {
        printf("Usage: ./fopenRfixedsize filename\n");
        exit (1);
    }
    printf("%s", fopenRfixedsize(&argv[1]));
    return 0;
}
///////////////////////////////////////////////////////////////////////////////////////////////////


// parent, sole primary function for fopenRfixedsize()
char *fopenRfixedsize(char *fName[])
{
    errno = 0; // initialize errno

    char *fContent = (char *) malloc (sizeof(char));
    fContent[0] = '\0';
    fRead = fopen(*fName, "r"); // open file
    if (fRead) // if fopen returned value other than 0, file open successful.
    {
        // create memory space to read file, fixed size #define STR_BUFFER 'size'
        char *sBuffer = (char *) malloc (STR_BUFFER * sizeof(char)); 
        if(sBuffer == 0)
        {
            printf("Memory allocation error (sBuffer): %d\n", errno);
            free(sBuffer);
            fclose(fRead);
            return "\0";
        }
        while(!feof(fRead)) // feof is not 0 == fRead is not at EOF (End of File)
        {
            // read file and store to the buffer,
            //  - until fRead points EOF or until string size reaches STR_BUFFER
            fgets(sBuffer, STR_BUFFER, fRead); 
            if (!feof(fRead)) // if feof == 0, fRead is at EOF (End of File)
            {
                //////////////////////////////////////////////////////////////////////////////////////////////////////
                // debug line, 1/3
                printf("==========================\n");
                printf("=== Beginning of Cycle ===\n");
                printf("==========================\n");
                printf("strlen(fContent): %d, strlen(sBuffer): %d\n", (int)strlen(fContent), (int)strlen(sBuffer));
                printf("fContent: %s", fContent);
                if (strlen(fContent) == 0) printf("\n");
                printf("sBuffer: %s", sBuffer);
                printf("\n");
                // debug line ends, 1/3
                //////////////////////////////////////////////////////////////////////////////////////////////////////

                fContent = (char *) realloc (fContent, (strlen(fContent) * sizeof(char) + strlen(sBuffer) * sizeof(char)));
                
                //////////////////////////////////////////////////////////////////////////////////////////////////////
                // debug line, 2/3
                printf("realloc with size %d successful\n", (int)(strlen(fContent) * sizeof(char) + strlen(sBuffer) * sizeof(char)));
                // debug line ends, 2/3
                //////////////////////////////////////////////////////////////////////////////////////////////////////

                if(fContent == 0)
                {
                    printf("Memory allocation error (fContent): %d\n", errno); 
                    free(fContent);
                    free(sBuffer);
                    fclose(fRead);
                    return "\0";
                }
                strcat(fContent, sBuffer);
                
                /////////////////////////////////////////////////////////////////////////////////////////////////////
                // debug line, 3/3
                printf("strcat(fContent, sBuffer) complete\n");
                printf("\n");
                printf("fContent: %s", fContent);
                printf("sBuffer: %s", sBuffer);
                printf("==========================\n");
                printf("===    End of Cycle    ===\n");
                printf("==========================\n");
                printf("\n");
                // debug line end, 3/3
                ////////////////////////////////////////////////////////////////////////////////////////////////////
            }
        }
        free(sBuffer);
    }
    else // of fopen returns 0, NULL pointer
    {
        printf("Cannot open the file ");
        printf("(Error Number: %d)\n", errno); // print errno message for debug
    }
    fclose(fRead); // close open files prior exiting program.
    return fContent;
}

=== output 1, small size text file ===

./fopenRfixedsize ftest.txt

==========================
=== Beginning of Cycle ===
==========================
strlen(fContent): 0, strlen(sBuffer): 42
fContent: 
sBuffer: Really trying to get this thing work.....

realloc with size 42 successful
strcat(fContent, sBuffer) complete

fContent: Really trying to get this thing work.....
sBuffer: Really trying to get this thing work.....
==========================
===    End of Cycle    ===
==========================

==========================
=== Beginning of Cycle ===
==========================
strlen(fContent): 42, strlen(sBuffer): 42
fContent: Really trying to get this thing work.....
sBuffer: Why is this so hard for me .... grrr.....

realloc with size 84 successful
strcat(fContent, sBuffer) complete

fContent: Really trying to get this thing work.....
Why is this so hard for me .... grrr.....
sBuffer: Why is this so hard for me .... grrr.....
==========================
===    End of Cycle    ===
==========================

Really trying to get this thing work.....
Why is this so hard for me .... grrr.....

=== output 2, large size text file ===

./fopenRfixedsize sorted5000.txt

==========================
=== Beginning of Cycle ===
==========================
strlen(fContent): 0, strlen(sBuffer): 2
fContent: 
sBuffer: 1

realloc with size 2 successful
strcat(fContent, sBuffer) complete

fContent: 1
sBuffer: 1
==========================
===    End of Cycle    ===
==========================

==========================
=== Beginning of Cycle ===
==========================
strlen(fContent): 2, strlen(sBuffer): 2
fContent: 1
sBuffer: 2

realloc with size 4 successful
strcat(fContent, sBuffer) complete

fContent: 1
2
sBuffer: 2
==========================
===    End of Cycle    ===
==========================

==========================
=== Beginning of Cycle ===
==========================
strlen(fContent): 4, strlen(sBuffer): 2
fContent: 1
2
sBuffer: 3

realloc with size 6 successful
strcat(fContent, sBuffer) complete

fContent: 1
2
3
sBuffer: 3
==========================
===    End of Cycle    ===
==========================

==========================
=== Beginning of Cycle ===
==========================
strlen(fContent): 6, strlen(sBuffer): 2
fContent: 1
2
3
sBuffer: 4

realloc with size 8 successful
strcat(fContent, sBuffer) complete

fContent: 1
2
3
4
sBuffer: 4
==========================
===    End of Cycle    ===
==========================

==========================
=== Beginning of Cycle ===
==========================
strlen(fContent): 8, strlen(sBuffer): 2
fContent: 1
2
3
4
sBuffer: 5

realloc with size 10 successful
strcat(fContent, sBuffer) complete

fContent: 1
2
3
4
5
sBuffer: 5
==========================
===    End of Cycle    ===
==========================

==========================
=== Beginning of Cycle ===
==========================
strlen(fContent): 10, strlen(sBuffer): 2
fContent: 1
2
3
4
5
sBuffer: 6

realloc with size 12 successful
strcat(fContent, sBuffer) complete

fContent: 1
2
3
4
5
6
sBuffer: 6
==========================
===    End of Cycle    ===
==========================

==========================
=== Beginning of Cycle ===
==========================
strlen(fContent): 12, strlen(sBuffer): 2
fContent: 1
2
3
4
5
6
sBuffer: 7

realloc with size 14 successful
strcat(fContent, sBuffer) complete

fContent: 1
2
3
4
5
6
7
sBuffer: 7
==========================
===    End of Cycle    ===
==========================

==========================
=== Beginning of Cycle ===
==========================
strlen(fContent): 14, strlen(sBuffer): 2
fContent: 1
2
3
4
5
6
7
sBuffer: 8

realloc with size 16 successful
strcat(fContent, sBuffer) complete

fContent: 1
2
3
4
5
6
7
8
sBuffer: 8
==========================
===    End of Cycle    ===
==========================

==========================
=== Beginning of Cycle ===
==========================
strlen(fContent): 16, strlen(sBuffer): 2
fContent: 1
2
3
4
5
6
7
8
sBuffer: 9

realloc with size 18 successful
strcat(fContent, sBuffer) complete

fContent: 1
2
3
4
5
6
7
8
9
sBuffer: 9
==========================
===    End of Cycle    ===
==========================

==========================
=== Beginning of Cycle ===
==========================
strlen(fContent): 18, strlen(sBuffer): 3
fContent: 1
2
3
4
5
6
7
8
9
sBuffer: 10

realloc with size 21 successful
strcat(fContent, sBuffer) complete

fContent: 1
2
3
4
5
6
7
8
9
10
sBuffer: 10
==========================
===    End of Cycle    ===
==========================

==========================
=== Beginning of Cycle ===
==========================
strlen(fContent): 21, strlen(sBuffer): 3
fContent: 1
2
3
4
5
6
7
8
9
10
sBuffer: 11

realloc with size 24 successful
strcat(fContent, sBuffer) complete

fContent: 1
2
3
4
5
6
7
8
9
10
11
sBuffer: 11
==========================
===    End of Cycle    ===
==========================

==========================
=== Beginning of Cycle ===
==========================
strlen(fContent): 24, strlen(sBuffer): 3
fContent: 1
2
3
4
5
6
7
8
9
10
11
sBuffer: 12

corrupted size vs. prev_size
Aborted

======

Thank you for your time looking at this I will be looking forward to getting some advice from you.

Sincerely. J.

JLee
  • 13
  • 2
  • Run your code through valgrind. If you're mismanaging memory it will tell you where. – dbush Jan 06 '22 at 22:03
  • Among other things: https://stackoverflow.com/questions/5431941/why-is-while-feof-file-always-wrong – Joe Jan 06 '22 at 22:04
  • String concatenation resizing requires including an additional slot space for the terminator, in addition to the lengths of the two strings. You're realloc is only including the two string lengths (which do NOT account for terminating nulchars). Therefore, `strcat` will guarantee blasting one char into unaccounted space, therefore invoking *undefined behaviour*. The `realloc` size should be `1 + strlen(fContent) + strlen(sBuffer)` (since `sizeof(char)` is always `1`, there's no need to include it unless you enjoy typing obtusely cryptic code). – WhozCraig Jan 06 '22 at 22:09
  • Probably unrelated, but returning either a static string (`"\0"`) or a dynamically allocated one from the same function is a really bad idea, because the caller needs to free it, but in case it is static, the `free` will fail. – Eugene Sh. Jan 06 '22 at 22:10
  • Thank you all for the comments! WhozCraig, appreciate your description and pointing out "sizeof(char) == 1" for me..., things my slow brain doesn't catch ... – JLee Jan 07 '22 at 01:37

1 Answers1

1

You are not allocating enough space for the null terminator: fContent = (char *) realloc (fContent, (strlen(fContent) * sizeof(char) + strlen(sBuffer) * sizeof(char))); should read:

fContent = realloc(fContent, strlen(fContent) + strlen(sBuffer) + 1);

Furthermore, you should move the call to fclose(fRead); to the end of the if block: as coded, fclose(fRead) will have undefined behavior if opening the file failed.

Retuning a string literal "\0", which should just be "", is problematic as the caller is expected to call free() on the result. You should return NULL to indicate an error.

Also read Why is “while ( !feof (file) )” always wrong?

Here is a modified version:

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

#ifndef STR_BUFFER
    #define STR_BUFFER 25000
#endif

char *fopenRfixedsize(const char *fName);

int main(int argc, char *argv[])
{
    if (argc != 2) // input limited to single file name only
    {
        printf("Usage: ./fopenRfixedsize filename\n");
        return 1;
    }
    printf("%s", fopenRfixedsize(argv[1]));
    return 0;
}

// parent, sole primary function for fopenRfixedsize()
char *fopenRfixedsize(const char *fName)
{
    FILE *fRead = fopen(fName, "r"); // open file
    if (fRead == NULL) {
        printf("Cannot open file %s: %s\n", fName, strerror(errno));
        return NULL;
    }
    // allocate memory space to read file, fixed size #define STR_BUFFER 'size'
    char *sBuffer = (char *)malloc(STR_BUFFER * sizeof(char)); 
    if (sBuffer == NULL) {
        printf("Memory allocation error (sBuffer): %s\n", strerror(errno));
        fclose(fRead);
        return NULL;
    }
    char *fContent = (char *)malloc(1);
    if (fContent == NULL) {
        printf("Memory allocation error (fContent): %s\n", strerror(errno));
        free(sBuffer);
        fclose(fRead);
        return NULL;
    }
    size_t len = 0;
    fContent[len] = '\0';

    while (fgets(sBuffer, STR_BUFFER, fRead)) {
       size_t len1 = strlen(sBuffer);
       fNewContent = (char *)realloc(fContent, len + len1 + 1);
       if (fNewContent == NULL) {
           printf("Memory reallocation error (fContent): %s\n", strerror(errno)); 
           free(fContent);
           free(sBuffer);
           fclose(fRead);
           return NULL;
       }
       fContent = fNewContent
       strcpy(fContent + len, sBuffer);
       len += len1;
    }
    free(sBuffer);
    fclose(fRead);
    return fContent;
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189
  • Beautiful! I really appreciate your little touch showing me better use of syntax as well ;) I will definitely look into that :-D Thank you so much chqrlie!!! J. – JLee Jan 06 '22 at 23:03
  • Got it! Thank you :-) – JLee Jan 10 '22 at 02:43