Given that CMD.EXE is woefully under-documented, I'm not sure what the expected behavior should be. I certainly haven't seen any documentation as to what the expected behavior is. So I think you will be hard pressed to find anyone that could give a definitive answer as to whether any of the behaviors are a bug. But I agree it certainly is inconsistent, and seems like at least a design flaw to me.
I wouldn't characterize the situation as chaotic in that the behavior of a particular command seems to be reproducible. But CMD.EXE is inconsistent in that I can't see any way to predict how any one command behaves without testing.
I don't have any explanations, but I do have some refined classifications of behaviors.
Redirection of stdout or stderr to stdin works perfectly fine as long as no command actually tries to write anything to the redirected output. The strange behavior only occurs when an internal command attempts to write to stdout or stderr after it has been redirected to stdin.
I extended your tests, and have seen the following distinct behaviors:
I haven't done exhaustive testing, but every internal command I tested that writes to stderr will immediately terminate the command session if stderr has been redirected to stdin. Examples include:
cd invalidPath 2>&0
vol x 2>&0
copy nonExistentFile 2>&0
move nonExistentFile 2>&0
set nonExistentVariable 2>&0
dir nonExistentFile 2>&0
What you thought was an exception actually never writes to stderr. Try the following without redirection and you will see there is no error message:
dir nonExistentFIle *
So there is no reason for the command to terminate the command session if stderr is redirected to stdin.
DIR only prints an error message if it fails to find any matching file across all the supplied file masks.
:: This prints an error message
dir nonExistentFile1 nonExistentFile2
:: So this terminates the command session
dir nonExistentFile1 nonExistentFile2 2>&0
Here are the behaviors I have seen for redirected stdout:
1) The output dissapears into the ether, without any error message.
copy /-y file1 existingFile2 >&0
move /-y file1 existingFile2 >&0
2) The output fails and an error message is displayed to stderr. A single command can generate multiple failure messages, one for each failed attempt to write to stdout.
echo Hello >&0
:: This generates 2 error messages, one for the time,
:: and another for the subsequent empty line
time /t >&0
3) The output fails, and batch processing is terminated. Active SETLOCAL remain in effect, even after batch termination, if the error occurs within a CALLed subroutine. In this regard, it behaves much like a fatal syntax error.
So far I have only seen one command exhibit this behavior:
I would expect the DIR command to generate an error message for each attempted line of output. But it seems to terminate after failing on the first line, and batch processing also is aborted.
4) Some commands exhibit multiple behaviors.
:: This SET command generates an error message for each
:: defined variable (behavior 2)
:: But this SET command fails to display the prompt without
:: error message (behavior 1). Note that the echo of user input
:: is written directly to :con. It does not use stdout or stderr.
set "var=prompt" >&0
:: A single PAUSE exhibits both behaviors 1 and 2. The prompt to
:: press a key simply dissapears, and the echo of the user input
:: generates an error. Note that in this case, the echo of user
:: input is written to stdout.