You're thinking about the standard file descriptors the wrong way.
STDIN points to an input device. If you obtain the STDIN belonging to another process, you could use it to steal that process's input. You're not supposed to write to it, and if you do, there's no particular reason to expect that output to wind up being read by the target process; that will only happen if the device happens to loops its output back to its input.
Similarly, STDOUT points to an output device. If you obtain the STDOUT belonging to another process, you could use it to generate output that will go to the same file or terminal that the other process is using. You shouldn't read from it, and if you do, you're unlikely to see the process's output.
In this particular scenario, as Håkan already pointed out, both STDIN and STDOUT point to the same device, so while you shouldn't write to STDIN, if you do it has the same effect as writing to STDOUT, i.e., it sends your output directly to the terminal. If the standard file descriptors were anything else, e.g., if you were using file redirections or piping, then writing to STDIN would not be the same as writing to STDOUT.
Think of it this way: if your process wrote to its own standard input, you wouldn't in general expect to see that output as new input. The fact that it is a different process doing the writing doesn't change that.
In particular, if your process is running on a virtual terminal (without any redirections) then when you write to standard output you expect that output to be displayed on the terminal, not fed back into your input. The fact that you incorrectly use the standard input file descriptor for the terminal rather than the standard output file descriptor won't change that, and it won't matter which process is doing the writing either. (*)
It may be instructive to consider some specific examples where a process writes to its own standard input.
What if standard input has been redirected from a file?
foo@bar:~/test$ cat hello
hi
foo@bar:~/test$ (cat; echo hello there > /dev/stdin; cat) < hello
hi
lo there
The contents of the file are overwritten; if the process did not finish reading the file first, or if the file is now longer than it was before, it will then read some or all of the content that it just wrote. Note that because we've already read "hi" and a newline, when we keep reading we skip the first three characters of "hello there".
What if standard input is a pipe?
foo@bar:~/test$ echo weird | (echo hello > /dev/stdin; cat)
weird
hello
Apparently a Linux pipe device does in fact loop its output back to its input, but I'm not sure whether this behaviour is guaranteed by POSIX or depends on the specific implementation. I'd avoid making use of this trick if I was you!
So what is the proper way to send a process some input?
Well, one option is described in this answer.
Another is to use a pipe correctly, e.g.,
echo I'm sending some input | cat > myinput
Here the echo
process is sending input to the cat
process. This is guaranteed to work properly because echo
is sending the data to a file descriptor pointing to one end of the pipe and cat
is receiving the data from a file descriptor pointing to the other end of the pipe.
In both cases the principle is the same. The target process is reading from a specific device, and we need to cause that device to generate the output we want. How we might do that depends on what the device is.
(*) The virtual terminal could have been designed so as to provide different devices for the shell's standard input and standard output, and the device attached to the standard input could have been programmed to loop any characters written to it back into the input stream. But it doesn't have to work that way, and as it happens, it doesn't, perhaps because the primary design goal for the first virtual terminals was to behave in the same way as the old-fashioned physical terminals which they were replacing.