Click here to Skip to main content
15,887,175 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I have written a simple c program as below where we are trying to read line by line data by using fgets() and we skipping the lines which doesn't start with character '$' , the problem I'm facing is I'm getting error as fgets: Cannot allocate memory at the 4th line and it is happening randomly

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

#define MAX_BUFFER_SIZE_5000 5000

size_t CustomGetLine(char *dPtr, size_t *n, FILE *stream, char cStartChar,uint32_t offset )
{
    char *result;

    // Read a line from the stream using fgets
    result = fgets(dPtr, *n, stream);
    perror("fgets");

    if (result != NULL)
    {
        // Increment the offset by the length of the line
        offset += strlen(dPtr);
        
        // Check if the first character of the line matches cStartChar
        if (dPtr[0] != cStartChar)
        {
            // Skip this line by reading the next one
            return CustomGetLine(dPtr, n, stream, cStartChar, offset);
        }
        
        // Return the length of the string read
        return strlen(dPtr);
    }


    return 0; // Return 0 if fgets fails
}

int main()
{
    uint32_t u32Offset = 0, uPktlen = 0;
    size_t PtrSize = MAX_BUFFER_SIZE_5000;
    FILE *pCurrFile = fopen("test.txt", "r");
    
    char *tempbuf = (char *)malloc(MAX_BUFFER_SIZE_5000);
    
    if (pCurrFile != NULL && tempbuf != NULL)
    {
        //printf("File opened successfully.\n");
        fseek(pCurrFile, u32Offset, SEEK_SET);
        
        
        while (uPktlen = CustomGetLine(tempbuf, &PtrSize, pCurrFile, '$', u32Offset))
        {
            printf("uPktlen before 0 = %d\n", uPktlen);
            printf("%s\n", tempbuf);
            u32Offset += uPktlen;
        }
        printf("uPktlen before 0 = %d\n", uPktlen);
        
        fclose(pCurrFile);
    }
    else
    {
        printf("Error: Unable to open file or allocate memory.\n");
    }
    
    if (tempbuf != NULL)
    {
        free(tempbuf);
        tempbuf = NULL;
    }

    return 0;
}


File Data is :
$BDEFGHOP,2.3,307,T139226500,1,060324130447,685,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0.0000,0.0000,0.0000,0.0000,0.0000,0.0000,0.0000,0.0000,0.00,0.00,37.00,30,1,16,1,0,1,0,1,0,0,0,0,0,0,0,1,0,0,0,5,20,NONE,1,2,0,0,0,0.00,0.00,0.000,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,1328,0,0.00,0.00,0.00,20,NONE,1,2,0,0,0,0.00,0.00,0.000,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0,0,0.00,0.00,0.00,20,NONE,1,2,0,0,0,0.02,0.05,0.000,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,5,15,0.00,0.00,0.00,20,NONE,1,2,0,0,0,0.00,0.00,0.000,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0,0,0.00,0.00,0.00,20,NONE,1,2,0,0,0,0.00,0.00,0.000,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0,0,0.00,0.00,0.00,1,30001,3,2,0.00000,0.00000,0.00,0.00,3,0,0,0,0,0.00,0.00,0,0,0,0,0,1,20001,DEEPSEA,2,0,0,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0,0,0,0.00,0.00,0.00,0,0,0,0.00,0.00,0.00,0.00,0.00,0,0.00,0.00,0,0,0,0,0.00,0.00,0.00,0.00,0.00,0,0.00,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,50,NONE,2,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0,1,497614,0,9552,911111972,0,6453691,0,0,0,11386038,8727133,0,0,0,0,0,228549
$BDEFGHOP,2.3,307,T139226500,1,060324130547,686,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0.0000,0.0000,0.0000,0.0000,0.0000,0.0000,0.0000,0.0000,0.00,0.00,37.00,30,1,16,1,0,1,0,1,0,0,0,0,0,0,0,1,0,0,0,5,20,NONE,1,2,0,0,0,0.00,0.00,0.000,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,1328,0,0.00,0.00,0.00,20,NONE,1,2,0,0,0,0.00,0.00,0.000,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0,0,0.00,0.00,0.00,20,NONE,1,2,0,0,0,0.02,0.05,0.000,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,5,15,0.00,0.00,0.00,20,NONE,1,2,0,0,0,0.00,0.00,0.000,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0,0,0.00,0.00,0.00,20,NONE,1,2,0,0,0,0.00,0.00,0.000,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0,0,0.00,0.00,0.00,1,30001,3,2,0.00000,0.00000,0.00,0.00,3,0,0,0,0,0.00,0.00,0,0,0,0,0,1,20001,DEEPSEA,2,0,0,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0,0,0,0.00,0.00,0.00,0,0,0,0.00,0.00,0.00,0.00,0.00,0,0.00,0.00,0,0,0,0,0.00,0.00,0.00,0.00,0.00,0,0.00,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,50,NONE,2,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0,1,497674,0,9552,911111972,0,6453751,0,0,0,11386098,8727133,0,0,0,0,0,228549
$BDEFGHOP,2.3,307,T139226500,1,060324130647,687,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0.0000,0.0000,0.0000,0.0000,0.0000,0.0000,0.0000,0.0000,0.00,0.00,38.00,30,1,16,1,0,1,0,1,0,0,0,0,0,0,0,1,0,0,0,5,20,NONE,1,2,0,0,0,0.00,0.00,0.000,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,1328,0,0.00,0.00,0.00,20,NONE,1,2,0,0,0,0.00,0.00,0.000,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0,0,0.00,0.00,0.00,20,NONE,1,2,0,0,0,0.02,0.05,0.000,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,5,15,0.00,0.00,0.00,20,NONE,1,2,0,0,0,0.00,0.00,0.000,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0,0,0.00,0.00,0.00,20,NONE,1,2,0,0,0,0.00,0.00,0.000,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0,0,0.00,0.00,0.00,1,30001,3,2,0.00000,0.00000,0.00,0.00,3,0,0,0,0,0.00,0.00,0,0,0,0,0,1,20001,DEEPSEA,2,0,0,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0,0,0,0.00,0.00,0.00,0,0,0,0.00,0.00,0.00,0.00,0.00,0,0.00,0.00,0,0,0,0,0.00,0.00,0.00,0.00,0.00,0,0.00,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,50,NONE,2,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0,1,497735,0,9552,911111972,0,6453811,0,0,0,11386158,8727133,0,0,0,0,0,228549
,1,060324130747,688,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0.0000,0.0000,0.0000,0.0000,0.0000,0.0000,0.0000,0.0000,0.00,0.00,38.00,30,1,16,1,0,1,0,1,0,0,0,0,0,0,0,1,0,0,0,5,20,NONE,1,2,0,0,0,0.00,0.00,0.000,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,1328,0,0.00,0.00,0.00,20,NONE,1,2,0,0,0,0.00,0.00,0.000,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0,0,0.00,0.00,0.00,20,NONE,1,2,0,0,0,0.02,0.05,0.000,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,5,15,0.00,0.00,0.00,20,NONE,1,2,0,0,0,0.00,0.00,0.000,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0,0,0.00,0.00,0.00,20,NONE,1,2,0,0,0,0.00,0.00,0.000,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0,0,0.00,0.00,0.00,1,30001,3,2,0.00000,0.00000,0.00,0.00,3,0,0,0,0,0.00,0.00,0,0,0,0,0,1,20001,DEEPSEA,2,0,0,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0,0,0,0.00,0.00,0.00,0,0,0,0.00,0.00,0.00,0.00,0.00,0,0.00,0.00,0,0,0,0,0.00,0.00,0.00,0.00,0.00,0,0.00,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,50,NONE,2,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0,1,497795,0,9552,911111972,0,6453871,0,0,0,11386218,8727133,0,0,0,0,0,228549
$BDEFGHOP,2.3,307,T139226500,1,060324130848,689,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0.0000,0.0000,0.0000,0.0000,0.0000,0.0000,0.0000,0.0000,0.00,0.00,38.00,30,1,16,1,0,1,0,1,0,0,0,0,0,0,0,1,0,0,0,5,20,NONE,1,2,0,0,0,0.00,0.00,0.000,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,1328,0,0.00,0.00,0.00,20,NONE,1,2,0,0,0,0.00,0.00,0.000,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0,0,0.00,0.00,0.00,20,NONE,1,2,0,0,0,0.02,0.05,0.000,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,5,15,0.00,0.00,0.00,20,NONE,1,2,0,0,0,0.00,0.00,0.000,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0,0,0.00,0.00,0.00,20,NONE,1,2,0,0,0,0.00,0.00,0.000,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0,0,0.00,0.00,0.00,1,30001,3,2,0.00000,0.00000,0.00,0.00,3,0,0,0,0,0.00,0.00,0,0,0,0,0,1,20001,DEEPSEA,2,0,0,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0,0,0,0.00,0.00,0.00,0,0,0,0.00,0.00,0.00,0.00,0.00,0,0.00,0.00,0,0,0,0,0.00,0.00,0.00,0.00,0.00,0,0.00,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,50,NONE,2,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0,1,497855,0,9552,911111972,0,6453932,0,0,0,11386278,8727133,0,0,0,0,0,228549
$BDEFGHOP,2.3,307,T139226500,1,060324130948,690,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0.0000,0.0000,0.0000,0.0000,0.0000,0.0000,0.0000,0.0000,0.00,0.00,38.00,30,1,16,1,0,1,0,1,0,0,0,0,0,0,0,1,0,0,0,5,20,NONE,1,2,0,0,0,0.00,0.00,0.000,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,1328,0,0.00,0.00,0.00,20,NONE,1,2,0,0,0,0.00,0.00,0.000,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0,0,0.00,0.00,0.00,20,NONE,1,2,0,0,0,0.02,0.05,0.000,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,5,15,0.00,0.00,0.00,20,NONE,1,2,0,0,0,0.00,0.00,0.000,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0,0,0.00,0.00,0.00,20,NONE,1,2,0,0,0,0.00,0.00,0.000,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0,0,0.00,0.00,0.00,1,30001,3,2,0.00000,0.00000,0.00,0.00,3,0,0,0,0,0.00,0.00,0,0,0,0,0,1,20001,DEEPSEA,2,0,0,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0,0,0,0.00,0.00,0.00,0,0,0,0.00,0.00,0.00,0.00,0.00,0,0.00,0.00,0,0,0,0,0.00,0.00,0.00,0.00,0.00,0,0.00,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,50,NONE,2,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0,1,497915,0,9552,911111972,0,6453992,0,0,0,11386339,8727133,0,0,0,0,0,228549


What I have tried:

I have tried checking the heap memory, buffer overflow is also not happening since the data is within 2000 bytes.
Posted
Comments
Rick York 7-Mar-24 1:27am    
I don't see how the program is allocating memory more than once - right after the file is opened.

Incidentally, I would check for the allocation and open errors separately so you know exactly which one happened.
Richard MacCutchan 7-Mar-24 4:16am    
Since you are calling perror even when no error occurred you are printing incorrect error messages. And most of those messages will be based on some random value in the error code variable.

I compiled your code, getting just the following warning:
warning: suggest parentheses around assignment used as truth value [-Wparentheses]
    50 |         while (uPktlen = CustomGetLine(tempbuf, &PtrSize, pCurrFile, '$', u32Offset))

anyway it runs fine (no errors) on my Linux box.

Why do you call perror even on fgets succeess?
 
Share this answer
 
have compiled your code on Windows and there are no memory allocation issues found. fgets do not allocate additional memory rather it simply copy content from the file stream into the source pointer. Since you already have allocated 5000 bytes of memory using malloc and reusing the space all the time, therefore it should not create any memory issues.

Check your environment, the problem seems to be in your environment. Your code is running okay in both Linux, Windows and Online.
 
Share this answer
 
You have a potential hazard in your CustomGetLine function, in the following lines:
C++
if (dPtr[0] != cStartChar)
{
    // Skip this line by reading the next one
    return CustomGetLine(dPtr, n, stream, cStartChar, offset);
}

A function repeatedly calling itself is known as recursion and could lead to problems if the data is large.
 
Share this answer
 
Comments
CPallini 7-Mar-24 6:45am    
5. Good catch!
Richard MacCutchan 7-Mar-24 8:25am    
Thanks, it's not often that I see things before you.
Rick York 7-Mar-24 10:48am    
It is a potential hazard but I don't think it is anything to worry about because very little is pushed on the stack. However, this is one instance of pointless recursion. It makes little sense for that code to be recursive instead of just using a while loop.
Richard MacCutchan 7-Mar-24 11:14am    
Yes, I completely understand that. My point in posting this was to bring the issue to the OP's attention. If that is the sort of code that they later push into some large operational application, then all hell could break loose.
Rick York 7-Mar-24 11:35am    
Yes, and the embedded tag was used here so it is likely that it doesn't have a 1MB stack like a desktop program would so problems would happen much quicker.
You've tagged this with "embedded", so maybe you are running into malloc problems when using fgets. Maybe a better solution would be to use low level open() and read()

Something like:
C
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>


/* assumes that the file is terminated with a new-line '\n' */
ssize_t getaline(int fd, char *buff, size_t max)
{
    off_t pos = lseek(fd, 0, SEEK_CUR); /* find current posn in file */
    
    ssize_t len = read(fd, buff, max); /* read into buff */
    if(len == -1) 
    {
        /* read failed, errno should be set by read()*/
        return -1;
    }
    else if ( len == 0 ) {
        /* end of file, */
        buff[0] = 0;
        return 0;
    }

    char *ptr = strchr(buff, '\n');
    if(ptr == NULL)
    {
        /* ? no newline in string ... do something? */
        return 0;
    }
    
    *ptr = '\0';                /* remove newline from buffer*/

    ssize_t blen = ptr - buff;  /* calculate string length */

    lseek(fd, pos + blen + 1, SEEK_SET); /* move file to new offset for next read */

    return blen; 
}
    
/* sample usage */
int main()
{
    int fd = open("data", O_RDONLY); /* open(2) a file */

    if(fd == -1) {
        perror("data");
        return 0;
    }

    /* read and print loop */
    char buff[4096];
    while( getaline(fd, buff,4096) > 0 ) {
        printf("%s\n", buff);
    }

    close(fd);
}
This might look a bit odd, since we lseek back and forth in the file, but it is much faster, assuming reasonable seek times, than a naive approach like
C
char c;
do
{
    read(f, &c 1);
}
while (c != '\n');
You might be able to do something really clever like use a static buffer, so you could read in one disk block at a time and use that as a cache, so successive calls to getaline only need to read from the file when the buffer no longer contains an unseen new-line.
 
Share this answer
 
The program cannot function in the above form. It is immediately apparent that the offset would have to be a reference if the main program is to work sensibly as suggested. In addition, it seems urgently necessary to use a size_t as the data type for the offset, as strlen returns this and there is also a risk of overflow when adding up. However, there is no reason why the length n should be passed as a reference and not as a value. Since fgets also expects an int, size_t would be too large and there is a risk that it would not fit. The use of an unsigned int would be more suitable. I would avoid recursion, as it is of little use here, but has a negative effect on the stack and runtime.
Without recursion you save a fgets and the program becomes shorter and more readable. It also makes sense to initialize the data buffer with 0.
C
//size_t CustomGetLine(char* dPtr, size_t* n, FILE* stream, char cStartChar, uint32_t offset)
size_t CustomGetLine(char* dPtr, unsigned n, FILE* stream, char cStartChar, size_t* offset)
{
    char* result;
    dPtr[0] = (char)0;

    // Check if the first character of the line matches cStartChar
    while (dPtr[0] != cStartChar) {
        // Read a line from the stream using fgets
        result = fgets(dPtr, n, stream);
        if (result == NULL) {
            if (ferror(stream)) {
                perror("fgets");
            }
            return 0; // Return 0 if fgets fails
        }
        // Increment the offset by the length of the line
        offset += strlen(dPtr);
        }
    return strlen(dPtr); // Return the length of the string read
}

Since the source code was tagged with "embedded", as k5054 has already noted, it may be necessary to allocate the buffer statically.
C
#define MAX_BUFF_SIZE 5000

// char* tempbuf = (char*)malloc(MAX_BUFF_SIZE);
// if (tempbuf == NULL) {
//    perror("Error: Unable to allocate memory.\n");
// }
char tempbuf[MAX_BUFF_SIZE];
 
Share this answer
 
v3

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900