ANSI C getc는 Linux에서는 segfault를 발생시키지만 OS X에서는 발생하지 않습니다.

StackOverflow https://stackoverflow.com/questions/1633987

문제

Mac에서 개발한 ANSI C 코드가 있는데 학교의 Linux 서버에서 실행하려고 하면 세그폴트가 발생합니다.

나에게 문제를 일으키는 특정 라인은 getc 파일 포인터에서.

파일이 존재합니다.

문제의 방법은 다음과 같습니다.

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

에 대한 호출 init_intlists segfault가 다음과 같이 시작됩니다.

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

그리고 parse_args 다음과 같습니다:

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

그래서 Mac에서 이것을 호출하려고 하면 완벽하게 작동하고 파일을 정상적으로 읽으며 작업을 수행하고 내 과제에 대한 올바른 답을 얻을 수 있습니다.

그러나 Linux에서 실행하려고 하면 세그폴트가 발생합니다. getc 에서 init_intlists 서브루틴.

입력용으로 제공한 파일이 존재하고 누구나 읽을 수 있음(umask 755)을 확인했습니다.절대 경로와 상대 경로를 모두 사용해 보았습니다.여러 가지 다른 입력 파일도 시도했습니다.

나는 사용해 보았습니다. gcc 4.2 그리고 gcc 3.4 Linux 서버에서 둘 다 주어진 입력 파일에 세그폴트를 일으키는 바이너리 실행 파일을 생성합니다.

다음은 서로 다른 두 gcc 버전 간의 버전 정보입니다.

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

리눅스:

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)

나는 동일한 것을 사용하여 컴파일러를 호출합니다. Makefile OS X와 ​​Linux 모두에서.마지막 호출 gcc 다음과 같이 표시됩니다.

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 

어떤 아이디어가 있나요?나는 교수와 마찬가지로 완전히 당황했습니다.

도움이 되었습니까?

해결책

다른 답변은 정확합니다. FILE * 복사할 수 있는 불투명 핸들이므로 내용을 복사하려고 하지 마세요.특히 다음과 같이 코드를 수정할 수 있습니다.

다음 호출을 제거하세요. malloc 초기화할 때 fp 그리고 base_vector_fp:

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

이 포인터에 대한 포인터를 전달합니다. parse_args, 포인터 값을 업데이트할 수 있도록:

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

그리고 변화 parse_args 업데이트하려면 FILE * 호출자에 있는 개체를 사용하려고 시도하기보다는 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);
}

다른 팁

당신은 당신 자신을 할당해서는 안됩니다 FILE 객체는 일반적으로 libc에 의해 관리되는 불투명 객체입니다.하지 않다 free() 그들 중 어느 쪽이든 그건 다 됐어 fclose(3).이론적으로는 하나를 할당하고 구조 할당을 수행하여 작동하게 할 수 있지만 라이브러리와 싸우지 않고 다른 사람들처럼 참조를 전달하는 것이 더 좋습니다.라이브러리는 FILE 구조에 없는 상태를 유지할 수도 있고 유지하지 않을 수도 있으며, 전체 구조체를 들여다보거나 역참조하는 것은 구현자가 실제로 그렇게 하지 않을 것이라고 가정할 만큼 충분히 나쁜 스타일입니다.

당신이 반환하려는 경우 FILE * 한 경우처럼 반환 포인터 값으로 사용하거나 이중 간접 포인터를 사용할 수 있습니다. FILE *fp; f(&fp);.

흠, 방금 C99가 실제로 이것을 7.19.13:

6 스트림을 제어하는 ​​데 사용되는 파일 개체의 주소가 중요 할 수 있습니다.파일 객체의 사본은 원본 대신에 제공 될 필요가 없습니다.

이를 통해 그들은 다음과 같은 통지를 보내고 있습니다. FILE * 정말 마법의 쿠키일 수도 있습니다.

결과를 복사하면 안 됩니다.fopen()으로FILE이의를 제기하고 실제로는 안 됩니다.mallocFILE전혀 개체.항상 사용해야합니다fopen()할당하다FILE제어 객체.

그만큼FILE물체는 불투명하며, 사실 그것은 단순한 필사자에게는 숨겨져 있는 많은 것을 담고 있습니다.구현에는 다른 제어 구조에 대한 포인터 등 모든 종류의 항목을 자유롭게 넣을 수 있습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top