Skip to content

ReadArgs: read the command line from the Input() buffer, as AmigaDOS does - #205

Merged
sidick merged 1 commit into
sidick:mainfrom
codewiz:readargs-own-copy
Oct 24, 2026
Merged

sidick merged 1 commit into
sidick:mainfrom
codewiz:readargs-own-copy

Conversation

@codewiz

@codewiz codewiz commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

ReadArgs(NULL) used to parse the guest's A0/D0 command-line buffer. That buffer belongs to the program, and C startup code edits it in place while splitting it into argv: vbcc's writes a NUL over the trailing '\n'. A vbcc-built program run as prog LIST therefore got LIST\0, and prog ITER 1 failed with "Bad number". The same programs work under vamos and on AmigaOS.

On AmigaOS, ReadArgs never looks at that buffer. RunCommand puts the arguments into the buffer of the process's Input() filehandle, and ReadArgs reads them from there:

  • RunCommand autodoc: "RunCommand also takes care of setting up the current input filehandle in such a way that ReadArgs() can be used in the program, and restores the state of the buffering before returning." It also says the argument string must end with a newline "to work properly with ReadArgs()".
  • ReadArgs autodoc: "Normally gets the arguments by reading buffered IO from Input(), but also can be made to parse a string."
  • ReadItem autodoc: with no CSource it "uses FGetC(Input())".
  • AROS does the same, and cites Ralph Babel's Amiga Guru Book for it:
    • rom/dos/runcommand.c calls vbuf_inject(Input(), argptr, argsize) before running the command and flushes Input() after it returns;
    • rom/dos/createnewproc.c does the same for NP_Arguments;
    • rom/dos/readargs.c reads from Input() when no RDA_Source is given: "Take arguments from input stream. They were injected there by either runcommand.c or createnewproc.c".

This PR does the same:

  • DosState::cmdline/cmdline_pos become input_buf/input_pos, the bytes in the Input() buffer. Runtime::new puts the process's command line there.
  • RunCommand puts the child's arguments there. When the child returns, it restores the caller's buffer and position, as the autodoc says. sidick's review: it first checks that argptr + argsize lies inside guest memory. If it doesn't, it returns -1 with ERROR_LINE_TOO_LONG, before allocating or copying anything.
  • ReadArgs(NULL) reads from input_buf. When that's used up, it sees an empty line rather than waiting on host stdin, as AROS does for an interactive Input() with an empty buffer.
  • FGetC, FGets and FRead on the current Input() return the remaining buffered bytes before host stdin, through a new DosState::read_buffered_byte. Plain Read bypasses the buffer, as on AmigaOS, so a program reading stdin with Read never sees its arguments.

Tests, all new or updated:

  • the_command_line_is_also_in_the_input_buffer_for_readargs;
  • buffered_reads_of_input_return_the_command_line_first;
  • run_command_rejects_arguments_past_guest_memory;
  • the existing run_command_resets_readargs_cursor_for_the_child_instead_of_inheriting_the_callers, now on input_pos.

cargo test --workspace otherwise has the same two failures as main (pending_host_break_folds_into_check_signal, pending_host_break_folds_into_wait). Checked with BenchWork's vbcc and gcc builds: LIST, REPEAT 1 x25519, -h and REPEAT=0 all behave as under vamos. Rebased on main, which now has #204.

🤖 Generated with Claude Code

@sidick sidick left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In run_command_handler, copying param_len bytes directly into a host Vec lets a guest supply an extremely large length and trigger a huge allocation/read loop, potentially exhausting the host. Please validate the length against the available guest memory (and reject lengths that cannot be safely copied) before allocating.

Comment thread crates/volamos-core/src/dosseg.rs Outdated
…does

RunCommand stuffs the arguments into the buffer of Input() and restores
it when the command returns, and ReadArgs, FGetC, FGets and FRead read
them from there; ReadArgs no longer parses the guest's A0 buffer, which
C startup code edits (vbcc's writes a NUL over the '\n'). RunCommand
refuses an argument range past guest memory.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
@codewiz codewiz changed the title ReadArgs: parse a copy of the command line, not the guest's buffer ReadArgs: read the command line from the Input() buffer, as AmigaDOS does Oct 24, 2026
@codewiz
codewiz requested a review from sidick October 24, 2026 07:58
@codewiz

codewiz commented Oct 24, 2026

Copy link
Copy Markdown
Contributor Author

PTAL

@sidick
sidick merged commit 11cc662 into sidick:main Oct 24, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants