2016-05-09 11 views
-1

Я пытаюсь создать интерфейс чата в своей программе на языке C. Программа использует два фикса для связи с раздвоенным xterm, управляя командами cat fifo_out и tee fifo_in > /dev/null в то же время. Затем поток открывается для чтения ввода в * fifo_in , исходящий от терминала, благодаря tee, в то же время другой поток печатает сообщение в fifo_out, и все будет отображаться в xterm.Печать и чтение с xterm в многопоточной программе C с использованием cat, tee и fifos

Все, кажется, работает очень хорошо ... За исключением случаев, когда сообщение было напечатано при написании некоторого текста в терминале, разделение введенного текста на две части. Это вызовет segfault!

У вас есть идеи, почему так происходит?

Вот минимальный пример:

int open_terminal(pid_t *pid, int *pipe) 
{ 
    mkfifo("fifo_in", 0600); 
    mkfifo("fifo_out", 0600); 
    pid_t p = fork(); 
    int fd_in, fd_out; 
    switch (p) { 
    case -1: 
     return -1; 
    case 0: 
     execlp("xterm", "xterm", "-e", "cat fifo_out & tee fifo_in > /dev/null", NULL); 
     exit(EXIT_FAILURE); 
     break; 
    default: 
     if ((fd_in = open("fifo_in", O_RDONLY)) == - 1) 
      return -1; 
     if ((fd_out = open("fifo_out", O_WRONLY)) == - 1) 
      return -1; 
     *pid = p; 
     pipe[0] = fd_in; pipe[1] = fd_out; 
     return 0; 
    } 
    return -1; 
} 


void *message_thread(void *args) 
{ 
    int *fd_out = (int *)args; 
    while (1) { 
    dprintf(*fd_out, "You're awesome!\n"); 
    sleep(5); 
    } 
} 


void *input_thread(void *args) 
{ 
    int *fd_in = (int *)args; 
    FILE *f = fdopen(*fd_in, "r"); 
    while (1) { 
    size_t n; 
    char *line; 
    getline(&line, &n, f); 
    printf("Read: %s", line); 
    free(line); 
    if(strcmp(line, "exit\n") == 0) 
     return NULL; 
    } 
} 


int main(int argc, char *argv[]) 
{ 
    pid_t pid; 
    int pipe[2]; 
    if (open_terminal(&pid, pipe) == -1) { 
    printf("Can't open terminal.\n"); 
    return 1; 
    } 
    pthread_t mt, it; 
    pthread_create(&mt, NULL, message_thread, &pipe[1]); 
    pthread_create(&it, NULL, input_thread, &pipe[0]); 

    pthread_join(it, NULL); 

    return 0; 
} 

Чтобы воспроизвести мои условия, запустить программу ввода какой-либо текст, ждать, пока какой-нибудь текст не печатается после вашего текста введите еще раз и ввести.

+0

Вы также можете посмотреть команду 'unlink', чтобы очистить фифы при выходе из программы. Если это имеет какое-либо значение, вы также можете обрезать конечный '' \ n'' из ввода с 'getline'. Поскольку 'getline' возвращает количество прочитанных символов (включая' '\ n''), вы можете просто использовать return (например,' nchr = getline (... ', а затем' line [- nchr] = 0; 'для удаления' '\ n''. Вам тогда не нужны такие странные тесты, как' strcmp (строка, «exit \ n») ' –

ответ

1

Из функции input_thread:

free(line); 
if(strcmp(line, "exit\n") == 0) 

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

И это еще не все, потому что вы передаете неинициализированный указатель и размер для функции getline, он не будет на самом деле выделить память, так как неинициализированные локальные переменные имеют неопределенными значение (это будет, казалось бы, случайные и не очень вероятно, равна нулю или NULL). Явно инициализируйте переменные до нуля и NULL, а функция getline выделит необходимую память. Использование неинициализированных локальных (нестатических) переменных для чего-либо другого, кроме инициализации, также приводит к неопределенному поведению.

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

+0

Упс,' free' не в нужном месте, я didn Это не так, но в реальной программе это не так. Реальная причина была в другом, неинициализированном 'size_t'. Спасибо. –