Fix SkipWhitespace returning early EOF on whitespace-only chunks#2461
Fix SkipWhitespace returning early EOF on whitespace-only chunks#2461gabrielrondon wants to merge 1 commit intostellar:mainfrom
Conversation
When a read() call returns a buffer containing only whitespace bytes, SkipWhitespace returns Ok(0) which the Read trait interprets as EOF. This causes silent truncation of base64 input containing whitespace (e.g., newlines from terminal paste or file formatting). Fix by looping until at least one non-whitespace byte is found or the inner reader returns true EOF. Closes stellar#2431
There was a problem hiding this comment.
Pull request overview
This PR fixes SkipWhitespace::read() in the tx XDR input path so it won’t incorrectly signal EOF (Ok(0)) when a read chunk contains only whitespace, preventing silent truncation of base64-encoded XDR read from stdin/args.
Changes:
- Update
SkipWhitespace<R>::read()to keep reading until it produces at least one non-whitespace byte or the inner reader reaches true EOF. - Add unit tests for
SkipWhitespacebehavior.
| #[test] | ||
| fn skip_whitespace_preserves_content() { | ||
| let input = Cursor::new(b"helloworld"); | ||
| let mut reader = SkipWhitespace::new(input); | ||
| let mut result = String::new(); | ||
| reader.read_to_string(&mut result).unwrap(); | ||
| assert_eq!(result, "helloworld"); | ||
| } | ||
|
|
||
| #[test] | ||
| fn skip_whitespace_strips_all_whitespace_types() { | ||
| let input = Cursor::new(b"hello \t\n\r world"); | ||
| let mut reader = SkipWhitespace::new(input); | ||
| let mut result = String::new(); | ||
| reader.read_to_string(&mut result).unwrap(); | ||
| assert_eq!(result, "helloworld"); | ||
| } |
There was a problem hiding this comment.
The new unit tests don’t exercise the bug fixed by the loop: the failure only happens when the inner reader returns a chunk that contains only whitespace but more non-whitespace bytes arrive in a later read. Cursor typically reads the whole buffer in one call, so these tests would also pass with the previous (buggy) implementation. Consider adding a test with a chunked/step reader (e.g., returns b"AAAA", then b"\n\n", then b"BBBB") to ensure SkipWhitespace::read() does not signal EOF early, and/or an integration test in soroban-test that pipes multi-line base64 into stellar tx hash/tx sign/tx send.
What
Fix
SkipWhitespace::read()signaling EOF when a read chunk contains only whitespace bytes. Add unit tests for the reader.Why
When base64 XDR input contains whitespace (e.g., newlines from terminal paste or multiline file),
read()returnsOk(0)for whitespace-only chunks. TheReadtrait interpretsOk(0)as EOF, causing silent truncation and subsequent XDR decode errors.The fix loops until at least one non-whitespace byte is found or the inner reader returns true EOF.
Affects all commands using
tx_envelope_from_input():tx hash,tx sign,tx send,tx simulate,tx op add.Known limitations
The upstream
stellar-xdrcrate has the same bug in its ownSkipWhitespace(used bytx decode). This PR only fixes thestellar-clicopy. The upstream fix should be tracked separately instellar/rs-stellar-xdr.Closes #2431