0
votes

I'm getting a segmentation from fgets, but only sometimes. It's someone else's code, and I don't understand the makefile, so I'm debugging with printf statements... I put this at two parts of the main function: (I only create the variables *f and line once, but I fopen and fclose the file both times.)

FILE *f = NULL;
char line[1000];
if ((f=fopen(filename,"r+"))==NULL)
{
     printf("Error opening file\n");
     f=0;//...handle error... //(usually just call abort() or return -1
}
//f = rfopen(fname, "r+");
printf("f from eval_args: %d, filename %s\n",f,filename);
printf("trying to read from file...\n");
printf("%s\n",fgets(line, sizeof (line), f));
printf("...succeeded\n");
fclose(f);

which gives me two different outputs:

f from eval_args: 4609600, filename /correct/path/to/file
trying to read from file...
 100

...succeeded

f prior to entering density profile: 4609600, filename /correct/path/to/file
trying to read from file...
Segmentation fault (core dumped)

I check that the file is correctly opened, and guard against reading more characters than will fit in 'line'. I saw in one forum that the filename shouldn't be more than 49 characters long... but a) that's a strange restriction and b) why does it work the first time?

Does anyone know what else I could check?

3
Doesn't printf() print (null) upon encountering a NULL string?user529758
Could you post a small compilable program that reproduces the problem?hmjd
First you should put the fgets as a separate statement, and then you should use the debugger to help you locate and examine the error.Some programmer dude
thanks for the suggestions @Joachim, I put fgets on its own line and the segfault is definitely there. Now I've just got to figure out why that low-level function gives non-reproducible behaviour for identical input...craq
@H2CO3, from a quick google search, it seems it's not well defined, but for me, printf("%s \n",NULL) also causes a segfault, so I may have had two issues before.craq

3 Answers

1
votes

If it is not to much of a hassle you could, but guess you know, do something like;

Could be beautified a bit, but:

#include <stdio.h>
#include <stdarg.h>

#define MAX_LINE    1024

void dbg_fprnt(FILE *fh, char *fmt, ...)
{
    char buf[MAX_LINE];
    char inf[MAX_LINE] = {0};
    va_list args;

    if (fmt && *fmt) {
        va_start(args, fmt);
        va_end(args);
        vsprintf(inf, fmt, args);
    }

    buf[0] = '\n';
    buf[1] = '\0';
    if (ferror(fh)) {
        fprintf(stderr, " * ERR, ferror() --- \n");
    } else if (fh == NULL) {
        fprintf(stderr,
            " * DBG PRNT ERR;; Trying to print from NULL ---\n");
    /* else if (and so forth) */
    } else {
        if (fgets(buf, MAX_LINE, fh) == NULL) {
            perror(" * ERR DBG PRNTF FGETS, --");
        }
    }
    printf("%-15s FC:: %s", inf, buf);
}

int main(void)
{
    char *fn = "lorem_ipsum";
    FILE *fh;

    if ((fh = fopen(fn, "r")) == NULL) {
        fprintf(stderr,
            "Unable to open '%s' for read.\n",
            fn);
        return 1;
    }

    setbuf(stdout, NULL);

    dbg_fprnt(fh, "SOME LINE: %d", 123);
    dbg_fprnt(fh, "%s", "SASA");
    dbg_fprnt(fh, "");
    dbg_fprnt(fh, NULL);
    dbg_fprnt(fh, "%s %d !", "Woot", 33);
    dbg_fprnt(fh, "@%d :::", __LINE__);
    fclose(fh);
    dbg_fprnt(fh, "@%d :::", __LINE__);


    return 0;
}

Sample output:

./fe
SOME LINE: 123  FC:: Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod 
SASA            FC:: tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
                FC:: quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo 
                FC:: consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse 
Woot 33 !       FC:: cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non 
@52 :::         FC:: proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
 * ERR DBG PRNTF FGETS, --: Bad file descriptor
@54 :::         FC:: 
0
votes

From your description, the probable reason maybe the second fgets doesn't success, so it returns NULL, which caused a segment fault. Then why the second fgets fail? You may take a look at it...

Referring to fgets spec:

On success, the function returns the same str parameter. If the End-of-File is encountered and no characters have been read, the contents of str remain unchanged and a null pointer is returned. If an error occurs, a null pointer is returned. Use either ferror or feof to check whether an error happened or the End-of-File was reached. http://www.cplusplus.com/reference/clibrary/cstdio/fgets/

So generally it's not a good practice to directly use the return value of fgets.

0
votes

From your print out:

f from eval_args: 4609600, filename /correct/path/to/file
trying to read from file...
 100

...succeeded

f prior to entering density profile: 4609600, filename /correct/path/to/file
trying to read from file...
Segmentation fault (core dumped)

You have "f prior to entering density profile" instead of "f from eval_args", but "f prior to entering density profile" does not exist in the source your provided, I think you are not running the same code.

and for the comment "//...handle error... //(usually just call abort() or return -1" there is no code to handle it, so it can still go down and coredump.

From description of return from fgets:

Upon successful completion, fgets() shall return s. If the stream is at end-of-file, the end-of-file indicator for the stream shall be set and fgets() shall return a null pointer. If a read error occurs, the error indicator for the stream shall be set, fgets() shall return a null pointer, and shall set errno to indicate the error.

So an EOF or anything bad would make that printf coredump.

I suggest something along the lines of:

    FILE *f = fopen(filename,"r+");
    if (f) {
        char line[1000];
        printf("f from eval_args: %p, filename %s\n",f,filename);
        printf("trying to read from file...\n");
        while(fgets(line, sizeof (line), f)) printf("%s",line);
        fclose(f);
    }
    else printf("Error opening file\n");