2013-02-15 3 views
2

Вот кусок кода c, который я написал после тестирования некоторых материалов.Stdin не покраснел после обычной манекен-программы

Я знаю, что это не проблема уязвимости, но я не понимаю, почему stdin не сбрасывается после нормального возврата программы, в тот момент, когда запрос возвращает stdin, stdout, stderr. Я имею в виду, почему оставшиеся символы на stdin перенаправляются на stdout после окончания обычного выполнения программы и не краснеют?

$cat dummy.c 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <unistd.h> 
#include <errno.h> 

int main(){ 

    char rbuf[100]; 

     if (read(0, rbuf,5) == -1){ 
     perror("learn to count"); 
     printf("errno = %d.\n", errno); 
     exit(1); 
    } 
     //printf("rbuf : %s\n",rbuf); 
    return 1; 
} 

Вот исполнение:

$ gcc -o dummy dummy.c 
$ ./dummy 
AAAAA /bin/sh 
$ /bin/sh 
sh-3.2$ exit 
exit 
$ 

Я думаю, это просто остальные строки из стандартного ввода, напечатанной на сизой стандартный вывод, который является приглашение. Кроме того, линия в конце, она каким-то образом эмулирует ввод, нажатый пользователем для выполнения команды. Что происходит? Мне просто интересно узнать об этом больше.

ответ

1

Да, ваше предположение верно, эти дополнительные символы в stdin:

сделать это:

void flush_stdin() 
{ 
    while(getchar() != '\n'); 
} 

Примечание: не используйте fflush() на stdin, потому что это неопределенное поведение

редактировать

stdin подключен к терминалу, который запускает программу (которая составляет bash). Это запустит новую программу dummy, а stdin из dummy подключен к stdin от bash.

Оттуда dummy процесс read с пятью символами, пренебрегает другими (оставляя их в буфере stdin). Когда элемент управления возвращается к bash, он ждет, пока в buffer не будет прочитан один символ. Низкий и вот, в буфере stdin есть символы, поэтому программа - вместо ожидания, начинает читать с stdin, а так как stdin в конце содержит \n, процесс фактически выполняется. Это начинается /bin/sh. Остальное до /bin/sh, чтобы волноваться!

+0

Спасибо за ваш ответ, но я знаю, что могу рушить вручную. Мой вопрос был не «Могу ли я его рушить вручную и как», но «Почему это не делается ОС или что-то еще после нормального возврата моей программы». Поскольку перенаправление stdin, stdout и stderr должно выполняться, когда приглашение возвращает руку, но все же stdin автоматически не очищается. Так что мне все еще интересно узнать об этом :) – user2075640

+0

Поскольку ОС ожидает, что исполняемые файлы будут потребляться во входном буфере, адресованном исполняемому файлу. Входной буфер - это просто очередь ожидающих потребления данных. Нет информации о том, какой исполняемый файл может и не может использовать эти данные. Таким образом, ОС не может этого сделать –

0

Для выполнения вашей программы оболочка вызывает fork (2) для создания дочернего процесса, а в дочернем процессе вызывает exec (3), чтобы заменить себя на «фиктивную» программу.

Я полагаю, есть что-то вроде этого в исходном коде оболочки (если она написана на C):

if (fork() == 0) 
    execlp(program, arguments) 

дочерний процесс наследует дескрипторы файлов родительского; в этом случае оболочка. Таким образом, дочерний процесс имеет тот же stdin/stdout, что и оболочка, выполняющая его, что является виртуальным терминалом.

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

Когда программа выходит, оболочка получает свой stdin назад. Любые дополнительные символы, которые не были прочитаны вашей программой, перейдут в оболочку.И тогда, конечно, оболочка просто рассматривает их как команду.

Если попытаться использовать fgetc (3) вместо чтения (2) сначала появляется лишние символы теряются, не послал к корпусу ... но, если вы unbuffer STDIN, вы получите тот же эффект используя fgetc (2), то есть: дополнительные символы возвращаются в оболочку.

char rbuf[100]; 
setbuf(stdin, NULL); // with this line - same effect as using read(2) 
        // without it - extra characters are lost 
for (int i = 0; i < 5; ++i) 
    rbuf[i] = (char)fgetc(stdin); 

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

+0

Извините, я не видел, что вышеупомянутый ответ уже в основном сказал то же самое в редактировании. – szmoore