Ошибка сегментации на сервере, а не на локальной машине - PullRequest
3 голосов
/ 13 марта 2010

Как указано в заголовке, программа работает на моем локальном компьютере (Ubuntu 9.10), но не на сервере (Linux). Это хостинговый пакет Godaddy.

Пожалуйста, помогите ..

Вот код:

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

int main(int argc, char **argv)
{
    long offset;
    FILE *io;
    unsigned char found;
    unsigned long loc;

    if (argc != 2)
    {
        printf("syntax: find 0000000\n");
        return 255;
    }

    offset = atol(argv[1]) * (sizeof(unsigned char)+sizeof(unsigned long));

    io = fopen("index.dat","rb");
    fseek(io,offset,SEEK_SET);
    fread(&found,sizeof(unsigned char),1,io);
    fread(&loc,sizeof(unsigned long),1,io);

    if (found == 1)
        printf("%d\n",loc);
    else
        printf("-1\n");

    fclose(io);

    return 0;
}

РЕДАКТИРОВАТЬ: Это не моя программа. Я хотел бы знать достаточно C, чтобы исправить это, но я в срок. Эта программа предназначена для поиска первого вхождения 7-значного числа в последовательности PI, index.dat содержит огромное число массива => позиция.

http://jclement.ca/fun/pi/search.cgi

РЕДАКТИРОВАТЬ 2: Я использовал обновленный код с тестом для нулевого указателя, все еще получая те же результаты. Программа работает нормально на моей локальной машине, эта ошибка происходит только на сервере.

Ответы [ 11 ]

5 голосов
/ 13 марта 2010

Скорее всего, сбой fopen - вы не проверяете его возвращаемое значение, чтобы увидеть, действительно ли вы получили действительный указатель. (Вы получаете segfault, когда пытаетесь использовать этот пустой указатель в следующей строке.)

2 голосов
/ 13 сентября 2012

Я только что столкнулся с этой проблемой с Godaddy и обнаружил, что FTP-клиент загружал в ASCII, а не Binary. Я изменил расширение на .bin перед загрузкой, и теперь оно работает нормально.

2 голосов
/ 13 марта 2010

Возможно, размеры unsigned long на машинах не одинаковы.

Что печатает следующая программа на ваших машинах?

#include <stdio.h>

int main(void)
{
    printf("%zu\n", sizeof(unsigned long));
    return 0;
}

Компилировать с gcc -std=c99 file.c. Если напечатанные размеры действительно отличаются, то вам нужно заменить unsigned long на uint32_t и добавить #include <inttypes.h> в начале вашей программы:

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

int main(int argc, char **argv)

{
    long offset;
    FILE *io;
    unsigned char found;
    uint32_t loc;

    if (argc != 2)
    {
        printf("syntax: find 0000000\n");
        return 255;
    }
    /* sizeof(unsigned char) is 1, and I am assuming you wanted
       sizeof(unsigned long) to be 4.  But see below. */
    offset = strtol(argv[1], NULL, 0) * (1+4);

    if ((io = fopen("index.dat", "rb")) == NULL) {
        fprintf(stderr, "Cannot open file\n");
        return EXIT_FAILURE;
    }
    if (fseek(io, offset, SEEK_SET) == -1) {
        fprintf(stderr, "Error seeking\n");
        perror(NULL);
        return EXIT_FAILURE;
    }
    if (fread(&found, 1, 1, io) != 1) {
        fprintf(stderr, "Error in first fread\n");
        return EXIT_FAILURE;
    }
    /* using sizeof loc makes sure that the correct size if always used,
       irrespective of the type of loc */
    if (fread(&loc, sizeof loc, 1, io) != 1) {
        fprintf(stderr, "Error in second fread\n");
        return EXIT_FAILURE;
    }
    if (found == 1)
        printf("%" PRIu32 "\n", loc);
    else
        printf("-1\n");
    fclose(io);

    return 0;
}

Выше предполагается, что "правильно работающая" программа имеет 4 байта unsigned long. Если нет, вам нужно заменить 4 в программе на любой размер unsigned long на правильном компьютере.

Если это является причиной разницы, то теперь вы знаете одну из проблем с чтением и записью двоичных данных: вы должны быть очень осторожны с размерами, порядком байтов и т.д.

1 голос
/ 13 марта 2010

Я предполагаю, что sizeof(long) на сервере равно 8 (из-за того, что это 64-разрядная система), по сравнению с 4 на вашем локальном компьютере (предполагается, что это 32-разрядный компьютер). Таким образом, ваше вычисленное смещение в файле будет неправильным с коэффициентом 2. Если вам нужно перейти к определенному смещению в файле, вы должны использовать типы фиксированного размера - т.е. uint32_t и т. П.

1 голос
/ 13 марта 2010

Мое первоначальное предположение, что файл не удалось открыть, и поэтому io имеет значение NULL.

Но Уэйд прав: сначала вы должны добавить некоторую обработку ошибок в вашу программу - как минимум, которая даст вам (и нам) лучшее представление о том, что происходит не так.

0 голосов
/ 14 марта 2010

Я думаю, что вы читаете за пределами файла. Я добавил часть, чтобы проверить размер файла и убедиться, что вы читаете в пределах файла.

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

int main(int argc, char **argv)
{
    long offset;
    FILE *io;
    unsigned char found;
    unsigned long loc;

    if (argc != 2)
    {
        printf("syntax: find 0000000\n");
        return 255;
    }

    offset = atol(argv[1]) * (sizeof(unsigned char)+sizeof(unsigned long));

    io = fopen("index.dat","rb");
if (io==NULL) {fputs ("File error",stdout); exit (1);}
fseek (io , 0 , SEEK_END);
long fileSize = ftell (io);
long offsetEnd = offset+sizeof(unsigned char)+sizeof(unsigned long);
printf("file size: %d\nseek: %d\nseekEnd: %d\n",fileSize,offset,offsetEnd);

if (offsetEnd> fileSize) {fputs ("Reading outside of file...",stdout); exit (1);}

    fseek(io,offset,SEEK_SET);
    fread(&found,sizeof(unsigned char),1,io);
    fread(&loc,sizeof(unsigned long),1,io);

    if (found == 1)
        printf("%d\n",loc);
    else
        printf("-1\n");

    fclose(io);

    return 0;
}
0 голосов
/ 13 марта 2010

Можете ли вы запустить GDB на сервере? Если это так, соберите с включенной отладкой (опция -g для gcc) и запустите ее в gdb. Это скажет вам, где программа терпит неудачу. Вот как (замените материал в <> соответствующей информацией):

# gdb <program>

(gdb) set args <arg>
(gdb) run

GDB поймает segfault и покажет строку, где он упал.

0 голосов
/ 13 марта 2010

Измените среднюю часть вашего кода на:

fseek(io,offset,SEEK_SET);
printf("fseek worked\n");
fread(&found,sizeof(unsigned char),1,io);
printf("fread 1 worked\n");
fread(&loc,sizeof(unsigned long),1,io);
printf("fread 2 worked\n");

и посмотрите, какие строки будут напечатаны при запуске программы. Это должно дать вам подсказку о том, где именно проблема.

Редактировать: Когда я говорю, что вызов функции "сработал", я имею в виду "не вызвал segfault". В идеале вы хотели бы проверять каждый вызов fseek и fread, чтобы убедиться, что они не сталкивались с какими-либо ошибками, но вы упомянули, что у вас крайний срок, так что это всего лишь быстрая и грязная трассировка ошибок выследить ошибку.

0 голосов
/ 13 марта 2010

Может быть, «index.dat» не на вашем сервере, но на вашем компьютере.Так как вы открываете его с помощью «rb» и не проверяете io после fopen, это вполне может сделать.

0 голосов
/ 13 марта 2010

Во-первых, вы не указали нам контекст, в котором произошла ошибка.

Во-вторых, прежде чем люди будут тратить на это время, нужно добавить проверку ошибок.

...