segfault на fgets ... иногда - PullRequest
       17

segfault на fgets ... иногда

0 голосов
/ 27 марта 2012

Я получаю сегментацию от fgets, но только иногда. Это чужой код, и я не понимаю make-файл, поэтому я отлаживаю с помощью операторов printf ... Я помещаю это в две части основной функции: (Я создаю переменные * f и строку только один раз, но я fopen и fclose файл оба раза.)

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);

, что дает мне два разных выхода:

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)

Я проверяю, правильно ли открыт файл, и защищаюсь от чтения большего количества символов, чем уместится в «строке». Я видел на одном форуме, что имя файла не должно быть длиннее 49 символов ... но а) это странное ограничение и б) почему оно работает в первый раз?

Кто-нибудь знает, что еще я мог проверить?

Ответы [ 3 ]

1 голос
/ 27 марта 2012

Если это не слишком хлопотно, вы можете, но думаю, вы знаете, сделать что-то вроде;

Можно немного украсить, но :

#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;
}

Пример вывода:

./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 голосов
/ 27 марта 2012

Из вашей распечатки:

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)

У вас есть «f до входа в профиль плотности» вместо «f из eval_args», но «f до входа в профиль плотности» не существует в источникепри условии, я думаю, что вы не используете тот же код.

и для комментария "//... обрабатывать ошибку ... // (обычно просто вызовите abort () или возвратите -1" естьнет кода для его обработки, поэтому он все еще может выйти из строя и выполнить coredump.

Из описания возврата из fgets:

После успешного завершения fgets () должен вернуть s. Если поток находится вконец файла, должен быть установлен индикатор конца файла для потока, и fgets () должен вернуть нулевой указатель. Если возникает ошибка чтения, должен быть установлен индикатор ошибки для потока, fgets () должен вернутьнулевой указатель, и должен установить errno для обозначения ошибки.

Таким образом, EOF или что-то плохое сделало бы этот printf coredump.

Я предлагаю что-то вроде:

    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");
0 голосов
/ 27 марта 2012

Из вашего описания, вероятная причина, может быть, вторая fgets не удалась, поэтому она возвращает NULL, что вызвало ошибку сегмента.Тогда почему второй fgets терпит неудачу?Вы можете взглянуть на это ...

Ссылаясь на fgets spec:

В случае успеха функция возвращает тот же параметр str.Если обнаружен конец файла и символы не были прочитаны, содержимое str остается неизменным и возвращается нулевой указатель.Если возникает ошибка, возвращается нулевой указатель.Используйте либо ferror, либо feof, чтобы проверить, произошла ли ошибка или достигнут конец файла.http://www.cplusplus.com/reference/clibrary/cstdio/fgets/

Поэтому обычно не рекомендуется напрямую использовать возвращаемое значение fgets.

...