Skip to content

escargs: report a scan error instead of silently truncating - #95

Open
youdie006 wants to merge 1 commit into
alessio:masterfrom
youdie006:escargs-scan-error
Open

escargs: report a scan error instead of silently truncating#95
youdie006 wants to merge 1 commit into
alessio:masterfrom
youdie006:escargs-scan-error

Conversation

@youdie006

Copy link
Copy Markdown

escargs never reads scanner.Err(), so a scan error looks like end of input.

bufio.Scanner stops and records bufio.ErrTooLong on an item at or above
bufio.MaxScanTokenSize (64 KiB). The loop in main ends, the process exits 0, and the
items already written are the whole output. When the oversized item comes first, nothing
is written at all:

$ { head -c 65536 /dev/zero | tr '\0' 'a'; echo; echo safe1; echo safe2; } | escargs; echo "exit=$?"
exit=0

xargs, which escargs is modelled on, fails loudly on the same shape:

xargs: argument line too long   (exit 1)

This matters more here than in a typical filter: the output is meant to be substituted into
a shell command line, so a silently shortened argument list is a command that runs with the
wrong arguments and a success status.

The repo already treats this as an error everywhere else

  • fuzz_test.go:248 raises the cap with scanner.Buffer, and fuzz_test.go:256 treats
    scanner.Err() != nil as t.Fatalf - the test harness knows about both the 64 KiB limit
    and the error.
  • cmd/escargs/escargs.go already routes its other error source, os.Open for -a,
    through log.Fatal.
  • .agents/rules/code-style.md, under Error Handling: "Never ignore returned errors
    silently unless explicitly documented"
    , and CLI errors go through log.Fatal with the
    escargs: prefix - which is what this change does.

The change

main is not testable as it stands, so the scan loop moves into escape(w io.Writer, r io.Reader) error, which ends with return scanner.Err(). main reports it through the
existing log.Fatal path. Reading and writing behaviour is otherwise unchanged - the writes
keep the same _, _ = treatment used by usage().

$ { head -c 65536 /dev/zero | tr '\0' 'a'; echo; echo safe1; } | escargs; echo "exit=$?"
escargs: bufio.Scanner: token too long
exit=1

Normal input is byte-identical before and after.

I did not raise the scanner buffer. Failing loudly matches xargs and keeps the memory
policy your call; a scanner.Buffer bump can follow separately if you want oversized items
to pass through.

Test

cmd/escargs/escargs_test.go is new - table-driven with t.Parallel(), per
.agents/rules/testing-benchmarks.md. Reverting only return scanner.Err() to return nil:

--- FAIL: TestEscape/item_longer_than_the_scanner_buffer
    escargs_test.go:47: escape() error = <nil>, want bufio.Scanner: token too long

go test -race ./... passes on both packages, go vet and gofmt are clean.

One incidental change

.gitignore line 28 was escargs, which has no slash and so matches the cmd/escargs
directory, not just the built binary - any new file added there is ignored. Anchoring it
to /escargs keeps the root binary ignored (make escargs and make clean both use the
root path) and lets the test file be tracked.


Disclosure: this was found and prepared with AI assistance (Claude). The failing input, the
red-green check, and the full go test -race ./... run were executed locally.

bufio.Scanner stops and sets an error on an item at or above
bufio.MaxScanTokenSize (64 KiB). escargs never read scanner.Err(), so such
an input made it print the items it had already consumed and exit 0. When
the oversized item is the first one, the whole output is dropped and the
exit status still says success.

Extract the scan loop into escape() so it can return the error, and let
main() report it through the existing log.Fatal path, as the -a open error
already does.
@codacy-production

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 5 complexity · 0 duplication

Metric Results
Complexity 5
Duplication 0

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

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.

1 participant