Ошибка сегментации при использовании функции wrefresh ncurses в C - PullRequest
0 голосов
/ 11 ноября 2019

Прежде всего, я создаю два окна с ncurses: одно для передачи и одно для приема. В основном, один, чтобы написать команду, а другой, чтобы напечатать команду. Чтобы записать ввод в окне приема, я выполнил небольшую функцию, чтобы объединить строку, уже находящуюся в окне приема, и строку, написанную пользователем (я думаю, что проблема там).

Итак, когда я запускаю код, программа завершается сбоем и отображает код ошибки сегментации, выгруженный в строку wrefresh(winReception);

Но странно то, что если на входе 7 символов или меньшеработает, если 8 или больше, он ломается.

Я использую Code :: Blocks

Скриншоты здесь: https://imgur.com/a/zEwBs1k

Вот код:

//Global variables
WINDOW * winReception;
WINDOW * winTransmission;
char * command;
char mesg[] = "Enter a command";
//variable to stock the input in reception window
char *textinwindow = "";

//main
int main(int argc, char* argv[])
{
    initscr();

    /* WINDOW RECEPTION */
    winReception = newwin(15, 0, 0, 0);
    wrefresh(winReception);


    /* WINDOW TRANSMISSION*/
    winTransmission= newwin(8, 0, 15, 0);
    wrefresh(winTransmission);
    mvwprintw(winTransmission, 1, 2, mesg);

    wgetstr(winTransmission, &command);
    verifInput(&command);

    free(textinwindow);

    exit(0);
}

//concat function (where I think the bug is)
char* concat(char *s1, char *s2)
{
    char *result = (char *) malloc(strlen(s1) + strlen(s2) + 1);
    strcpy(result, s1);
    strcat(result, "\n ");
    strcat(result, s2);

    return result;
}

//verifInput (where the program fails)
void verifInput (char* cmd)
{
    /* WINDOW RECEPTION */
    textinwindow = concat(textinwindow, cmd);
    mvwprintw(winReception, 1, 2, textinwindow);
    wrefresh(winReception);

    /* WINDOW TRANSMISSION*/
    touchwin(winTransmission);
    wclear(winTransmission);
    wrefresh(winTransmission); //Program fails here
    mvwprintw(winTransmission, 1, 2, mesg);

    wgetstr(winTransmission, &command);
    verifInput(&command);
}

1 Ответ

0 голосов
/ 11 ноября 2019

Здесь было несколько проблем, как отмечено в комментариях, но основной была совершенно неправильное использование wgetstr(), потому что он принимает ввод от пользователя и помещает его в буфер, но вы не выделили буфер,Мы не знаем, каково значение command, поэтому он хранит данные в случайной памяти.

Неправильный способ исправить это:

char command[256];
wgetstr(winTransmission, command); // NO

, потому что, хотя вы быпредоставляя место для хранения ввода пользователя, wgetstr() не знает, насколько велик буфер, и если пользователь вводит слишком много, он также перезапишет память там. Не хорошо.

Вместо этого мы будем использовать ограниченную версию wgetnstr(), которая принимает буфер и число

char command[256];
wgetnstr(winTransmission, command, sizeof command); // YES

Теперь он никогда не будет перезаписывать буфер!

Другие проблемы: хотя вы освобождаете память textinwindow в конце кода, каждый раз, когда вы вызываете concat() old значение textinwindow - чтоТакже выделяется память - выбрасывается. Это точно утечка памяти.

Наконец, небольшая проблема. Поскольку mvwprintw() принимает строку формата printf, передаваемое вами значение приходит от пользователя и может содержать токен %s. Ничего хорошего из этого не получается. Вместо этого:

    mvwprintw(winReception, 1, 2, "%s", textinwindow);

, что означает, что любой фанк % в строке ввода пользователя не вызовет хаос.

Вот что я придумал:

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

//Global variables
WINDOW * winReception;
WINDOW * winTransmission;

char command[256];

const char mesg[] = "Enter a command";
//variable to stock the input in reception window
char *textinwindow = 0;

void verifInput (const char* cmd);

//main
int main(int argc, char* argv[])
{
    initscr();

    /* WINDOW RECEPTION */
    winReception = newwin(15, 0, 0, 0);
    wrefresh(winReception);


    /* WINDOW TRANSMISSION*/
    winTransmission= newwin(8, 0, 15, 0);
    wrefresh(winTransmission);
    mvwprintw(winTransmission, 1, 2, mesg);

    wgetnstr(winTransmission, command, sizeof command);
    verifInput(command);

    free(textinwindow);

    exit(0);
}

//concat function (where I think the bug is)
char* concat(const char *s1, const char *s2)
{
    // 2 = newline + space
    // 1 = final NUL byte
    char *result = (char *) malloc(strlen(s1) + 2 + strlen(s2) + 1);
    strcpy(result, s1);
    strcat(result, "\n ");
    strcat(result, s2);

    return result;
}

//verifInput (where the program fails)
void verifInput (const char* cmd)
{

    // free up old memory except for the first time
    if (textinwindow == 0)
        textinwindow = concat("", cmd);
    else
    {
        char *save = textinwindow;
        textinwindow = concat(textinwindow, cmd);
        free(save);
    }

    /* WINDOW RECEPTION */
    mvwprintw(winReception, 1, 2, "%s", textinwindow);
    wrefresh(winReception);

    /* WINDOW TRANSMISSION*/
    touchwin(winTransmission);
    wclear(winTransmission);
    wrefresh(winTransmission); //Program fails here
    mvwprintw(winTransmission, 1, 2, mesg);

    wgetnstr(winTransmission, command,  sizeof command);
    verifInput(command);
}
...