Recursive Batch File Loops in MS-DOS 6.22
This article explains how the MS-DOS 6.22 command interpreter,
COMMAND.COM, manages execution loops triggered by recursive
batch file calls. It examines the technical differences between direct
file chaining and nested execution via the CALL command,
detailing file pointer tracking, internal memory allocation, nesting
depth limits, and the conditions that lead to system termination or
crashes.
Direct Chaining vs. Nested Invocation
The behavior of a recursive batch file in MS-DOS 6.22 depends
entirely on whether the script calls itself directly by name or uses the
CALL command.
When a batch file invokes itself directly (for example,
RECURSE.BAT executing the line RECURSE without
CALL), COMMAND.COM treats this as a transfer
of control rather than a subroutine. The shell terminates the current
batch context and initiates a new one from the beginning of the file. No
return address is saved, and no stack frame is allocated. This mechanism
is essentially a jump operation. Because memory structures are
overwritten rather than nested, a direct recursive call can run
indefinitely without exhausting conventional memory, forming an infinite
loop that can only be interrupted by the user pressing
Ctrl+C or Ctrl+Break.
Nested Execution with the CALL Command
When recursion is initiated using the CALL command (such
as CALL RECURSE.BAT), COMMAND.COM treats the
operation as a nested subroutine that must eventually return execution
to the line following the invocation.
To achieve this, COMMAND.COM maintains an internal batch
context block for every active nesting level. This block preserves:
- The full file path of the calling batch file.
- The file seek offset pointing to the next line to be executed upon return.
- Any active redirection states and command-line arguments.
Because each CALL allocates another context block, this
method does not execute in constant space. Instead, it systematically
consumes memory within the interpreter's internal structures.
Memory Limitations and Stack Exhaustion
Unlike modern command-line interpreters that support thousands of recursion levels, MS-DOS 6.22 operates within the strict boundaries of conventional memory (the first 640 KB of RAM) and uses a hardcoded batch nesting limit.
COMMAND.COM in version 6.22 allocates a fixed table for
nested batch processing. Once the recursive loop exceeds the maximum
supported nesting depth, the command interpreter fails to allocate a new
batch context. At this threshold, MS-DOS typically displays an error
message such as Out of environment space or simply halts
execution because it cannot allocate the required internal tracking
structures.
If free conventional memory is severely constrained before reaching
the software limit, recursive calls may fail earlier due to low-memory
conditions, corrupting the transient portion of COMMAND.COM
or destabilizing the operating system entirely.
File Pointer and Disk I/O Mechanics
MS-DOS 6.22 does not load batch files entirely into RAM. To minimize
memory usage, COMMAND.COM parses batch files line by line
directly from the storage media.
In a recursive loop:
- The shell reads a line from the storage device.
- It records the file offset pointer.
- Upon processing a recursive call, it opens a handle or re-seeks the file back to byte zero.
- With the
CALLcommand, every level of recursion preserves its respective seek offset on the internal stack.
Because the operating system constantly reads the file from disk or floppy drive during each cycle of the recursion, execution speed is heavily throttled by physical I/O latency. In rapid recursive loops running on floppy-based systems or slow hard drives, this behavior results in constant disk drive head activity until the recursion is manually halted or runs out of resources.