Почему эта программа segfaulting? - PullRequest
4 голосов
/ 31 августа 2010

Я написал программу под названием Mathtext . Эта программа задает «стиль» обычного текста, смещая определенные диапазоны символов в диапазоны Юникода, такие как «математические буквенные символы», для получения курсива обычного текста, полужирного шрифта, засечек и т. Д.

Он работает как построчный интерпретатор, как оболочка, выводя переведенную строку после ее ввода. Это означает, что файлы могут быть cat / переданы для перевода всего файла, а также тот факт, что вы можете «выйти» из «оболочки», нажав ^ D, что обнаруживается при нажатии stdin на EOF.

Все работает. Однако, когда я нажимаю ^ D и выхожу, происходит сбой. Я до сих пор не могу понять, что является причиной этого.

Компиляция с -g -O0 немного помогает; Теперь я знаю, что проблема возникает из-за strlen-вызова transpose при нажатии ^ D. Однако никогда нельзя вызывать транспонирование во время ^ D, так как eof верно!

Program received signal SIGSEGV, Segmentation fault.
__strlen_sse2 () at ../sysdeps/x86_64/multiarch/../strlen.S:31
31    ../sysdeps/x86_64/multiarch/../strlen.S: No such file or directory.
    in ../sysdeps/x86_64/multiarch/../strlen.S
(gdb) where
#0  __strlen_sse2 () at ../sysdeps/x86_64/multiarch/../strlen.S:31
#1  0x0000000000400b0e in transpose (s=0x0, capsDelta=120263, smallDelta=120257, numDelta=0) at mathtext.c:58
#2  0x0000000000400e2b in main (argc=2, argv=0x7fffffffe4b8) at mathtext.c:92

Ответы [ 3 ]

3 голосов
/ 31 августа 2010

В большинстве случаев использование feof() является ошибкой - и эта программа прекрасно демонстрирует это в этом основном цикле:

char temp[1048576];
do {
    if (!strcmp(argv[1], "serifb"))
        transpose(fgets(temp, 1048576, stdin), 119808 - 'A', 119834 - 'a', 120782 - '0');
    else if (!strcmp(argv[1], "serifi"))
        transpose(fgets(temp, 1048576, stdin), 119860 - 'A', 119886 - 'a', 0);
    else if (!strcmp(argv[1], "serifbi"))
        transpose(fgets(temp, 1048576, stdin), 119912 - 'A', 119938 - 'a', 0);
    else if (!strcmp(argv[1], "sans"))
        transpose(fgets(temp, 1048576, stdin), 120224 - 'A', 120250 - 'a', 120802 - '0');
    else if (!strcmp(argv[1], "sansb"))
        transpose(fgets(temp, 1048576, stdin), 120276 - 'A', 120302 - 'a', 120812 - '0');
    else if (!strcmp(argv[1], "sansi"))
        transpose(fgets(temp, 1048576, stdin), 120328 - 'A', 120354 - 'a', 0);
    else if (!strcmp(argv[1], "sansbi"))
        transpose(fgets(temp, 1048576, stdin), 120380 - 'A', 120406 - 'a', 0);
    else if (!strcmp(argv[1], "mono"))
        transpose(fgets(temp, 1048576, stdin), 120432 - 'A', 120458 - 'a', 120822 - '0');
    else if (!strcmp(argv[1], "fullwidth"))
        transposeBlock(fgets(temp, 1048576, stdin), '!', '~', 65281 - '!');
    else return help();
} while(!feof(stdin));

В конце файла fgets() вернет NULL, итогда следующий вызов feof() вернет true.Таким образом, правильный подход - проверить возвращаемое значение вашей входной функции - и поскольку вы все равно выполняете этот тест, нет необходимости вызывать feof() (если вы не хотите отличить ошибку файла от конца файла).

char temp[1048576];
while (fgets(temp, sizeof temp, stdin) != NULL) {
    if (!strcmp(argv[1], "serifb"))
        transpose(temp, 119808 - 'A', 119834 - 'a', 120782 - '0');
    else if (!strcmp(argv[1], "serifi"))
        transpose(temp, 119860 - 'A', 119886 - 'a', 0);
    else if (!strcmp(argv[1], "serifbi"))
        transpose(temp, 119912 - 'A', 119938 - 'a', 0);
    else if (!strcmp(argv[1], "sans"))
        transpose(temp, 120224 - 'A', 120250 - 'a', 120802 - '0');
    else if (!strcmp(argv[1], "sansb"))
        transpose(temp, 120276 - 'A', 120302 - 'a', 120812 - '0');
    else if (!strcmp(argv[1], "sansi"))
        transpose(temp, 120328 - 'A', 120354 - 'a', 0);
    else if (!strcmp(argv[1], "sansbi"))
        transpose(temp, 120380 - 'A', 120406 - 'a', 0);
    else if (!strcmp(argv[1], "mono"))
        transpose(temp, 120432 - 'A', 120458 - 'a', 120822 - '0');
    else if (!strcmp(argv[1], "fullwidth"))
        transposeBlock(temp, '!', '~', 65281 - '!');
    else return help();
}
3 голосов
/ 31 августа 2010

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

1 голос
/ 31 августа 2010

feof не может предсказать будущее.Он не знает, что это конец файла, пока вы на самом деле не нажмете клавишу ^ D, когда ваша программа вернется в ожидании ввода в fgets.Чтение файла не приведет к ошибке, потому что все входные данные уже присутствуют в начале.Проверьте NULL в вашей функции транспонирования.

...