Question

J'ai développé du code ANSI C sur mon Mac, mais lorsque je l'ai essayé sur les serveurs Linux de notre école, j'ai un segfault.

La ligne qui me pose problème est un getc à partir d'un pointeur de fichier.

Le fichier existe.

Voici la méthode en question:

// inits lists with all data in fp file pointer
// returns # of lines read
int init_intlists(FILE *fp, INTLIST *lists[]) {
    int c, ctr;

    ctr = 0;

    // need to use a linked list to store current number
    // for non 1-digit numbers...
    INTLIST *cur_num = NULL;
    int cur_num_len = 0;
    while ((c = getc(fp)) != EOF){
        if(c != '\n' && c != ' '){
            c = c - 48;
            if(cur_num == NULL){
                cur_num = init_intlist(c);
            } else {
                list_append(cur_num, &c);
            }
            cur_num_len++;
        } else if(c == ' ' || c == '\n'){
            // we reached a space, meaning we finished
            // reading a contiguous block of digits
            // now we need to figure out what we actually read...
            int num = 0;
            INTLIST *ptr;
            ptr = cur_num;
            while(cur_num_len != 0){
                cur_num_len--;
                num += pow(10, cur_num_len) * ptr->datum;
                ptr = ptr->next;
            }    

            if(lists[ctr] == NULL){
                // init new list
                lists[ctr] = init_intlist(num);
            } else {
                // append to existing
                list_append(lists[ctr], &num);
            }

            // clear cur_num to read the next one
            cur_num_len = 0;
            list_delete(cur_num);
            cur_num = NULL;
        }

        if(c == '\n') {
            // newline reached - increment to fill in next list
            ctr++;
        }
    }    

    return ctr;
}

L'appel à init_intlists qui provoque le segfault commence ainsi:

    FILE *fp = (FILE *)malloc(sizeof(FILE));
    FILE *base_vector_fp = (FILE *)malloc(sizeof(FILE));

    parse_args(argc, argv, fp, base_vector_fp);

    if(fp == NULL || base_vector_fp == NULL){
        fprintf(stderr, "Critical error, could not load input files\n");
        return 1;
    }

    INTLIST *lines[MAX_LINES] = {};
    INTLIST *base_vectors[MAX_LINES] = {};

    int lines_read = init_intlists(fp, lines);

et parse_args ressemble à:

FILE *load_file(char *filename) {
    FILE *fp;

    fp = fopen(filename, "r");

    if(fp == NULL){
        fprintf(stderr, "File %s does not seem to exist.\n", filename);
        return NULL;
    }

    // XXX Does this memory leak?
    // fp is never fclose()'d
    return fp;
}

void parse_args(int argc, char *argv[], FILE *fp, FILE *base_vector_fp) {
    char *prog = argv[0];
    if (argc != 3){
        fprintf(stderr, "Wrong number of arguments supplied.\nUse: %s <data_filename>     <base_vector_filename>\n", prog);
        free(fp);
        free(base_vector_fp);
        fp = NULL;
        base_vector_fp = NULL;
        exit(1);
    }

    char *filename = argv[1];
    *fp = *load_file(filename);

    char *base_vector_filename = argv[2];
    *base_vector_fp = *load_file(base_vector_filename);
}

Ainsi, lorsque j'essaie d'invoquer cela sur mon Mac, cela fonctionne parfaitement, le fichier est lu comme il se doit et je suis capable de l'exploiter et d'obtenir les réponses correctes pour mon travail.

Cependant, lorsque j'essaie de l'exécuter sous Linux, un segfault apparaît quand il tente de getc dans le sous-programme init_intlists .

J'ai vérifié que les fichiers que je fournis pour l'entrée existent et sont lisibles par tout le monde (umask 755). J'ai essayé avec des chemins absolus et relatifs. J'ai également essayé plusieurs fichiers d'entrée différents.

J'ai essayé d'utiliser gcc 4.2 et gcc 3.4 sur le serveur Linux et les deux produisent un exécutable binaire qui provoquera un segfault avec n'importe quel fichier d'entrée donné.

Voici les informations de version entre les deux versions différentes de gcc:

Mac OS X:

me@dinosaurhunter ~> gcc -v
Using built-in specs.
Target: i686-apple-darwin9
Configured with: /var/tmp/gcc/gcc-5465~16/src/configure --disable-checking -enable-werror --prefix=/usr --mandir=/share/man --enable-languages=c,objc,c++,obj-c++ --program-transform-name=/^[cg][^.-]*$/s/$/-4.0/ --with-gxx-include-dir=/include/c++/4.0.0 --with-slibdir=/usr/lib --build=i686-apple-darwin9 --with-arch=apple --with-tune=generic --host=i686-apple-darwin9 --target=i686-apple-darwin9
Thread model: posix
gcc version 4.0.1 (Apple Inc. build 5465)

Linux:

me@janus:~/assignment_1$ gcc -v
Using built-in specs.
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --enable-languages=c,c++,fortran,objc,obj-c++,treelang --prefix=/usr --enable-shared --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --enable-nls --with-gxx-include-dir=/usr/include/c++/4.2 --program-suffix=-4.2 --enable-clocale=gnu --enable-libstdcxx-debug --enable-objc-gc --enable-mpfr --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.2.4 (Ubuntu 4.2.4-1ubuntu4)

J'appelle le compilateur en utilisant le même Makefile sous OS X et Linux. L’appel de fin de gcc se présente comme suit:

gcc  -Wall -g  -c src/common_file_io.c src/main.c src/intlist.c
gcc  -Wall -g  common_file_io.o main.o intlist.o -lreadline -lm  -o bin/myprogram 

Des idées? Je suis complètement perdu, tout comme mon professeur.

Était-ce utile?

La solution

Les autres réponses sont correctes - traitez un FILE * comme un descripteur opaque que vous copiez, ne tentez pas de copier son contenu. Plus précisément, vous pouvez corriger votre code comme suit:

Supprimez l'appel de malloc lorsque vous initialisez fp et base_vector_fp :

FILE *fp = NULL;
FILE *base_vector_fp = NULL;

Passez un pointeur sur ces pointeurs vers parse_args , afin qu'il puisse mettre à jour les valeurs du pointeur:

parse_args(argc, argv, &fp, &base_vector_fp);

Et changez parse_args pour mettre à jour les objets FILE * dans l'appelant, plutôt que d'essayer de travailler avec les objets FILE :

void parse_args(int argc, char *argv[], FILE **fp, FILE **base_vector_fp) {
    char *prog = argv[0];
    if (argc != 3){
        fprintf(stderr, "Wrong number of arguments supplied.\nUse: %s <data_filename>     <base_vector_filename>\n", prog);
        exit(1);
    }

    char *filename = argv[1];
    *fp = load_file(filename);

    char *base_vector_filename = argv[2];
    *base_vector_fp = load_file(base_vector_filename);
}

Autres conseils

Vous n'êtes pas censé allouer vos propres objets FILE , ce sont généralement des objets opaques gérés par libc. Ne les free () non plus, cela est fait par fclose (3) . Bien que théoriquement, vous puissiez en affecter un, créer une structure et le faire fonctionner, il serait préférable de ne pas lutter contre la bibliothèque et de simplement faire passer la référence comme tout le monde. La bibliothèque peut conserver ou ne pas conserver l’état qui ne se trouve pas dans la structure FILE, et jeter un coup d’œil furtif à l'intérieur ou déréférencer toute la structure est un style suffisamment mauvais pour que les développeurs puissent réellement en déduire que vous ne le faites jamais.

Si vous souhaitez renvoyer un FILE * , vous pouvez soit l'utiliser comme valeur de retour comme vous l'avez fait dans un cas, soit utiliser un pointeur double-indirect: FILE * fp; f (& amp; fp); .

Hmm, je viens de remarquer que C99 le spécifie dans 7.19.13 :

  

6 L'adresse de l'objet FILE utilisé   pour contrôler un flux peut être   important; une copie d'un objet FILE   ne doit pas servir à la place du   original.

Avec cela, ils notifient qu'un FICHIER * peut vraiment être un cookie magique.

Vous ne devriez pas copier le résultat de fopen () dans un objet FILE . En fait, vous ne devriez pas malloc dans un FILE du tout. Vous devez toujours utiliser fopen () pour allouer l'objet de contrôle FILE .

L'objet FILE est opaque et contient en réalité beaucoup d'éléments masqués par de simples mortels. L’implémentation est libre d’y mettre toutes sortes de choses, telles que des pointeurs vers d’autres structures de contrôle, etc.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top