Skip to content

fix(sourceanalysis): return an error instead of exiting when an rlib has no object file - #2977

Open
kobihikri wants to merge 2 commits into
google:mainfrom
kobihikri:fix/rlib-archive-eof-no-fatal
Open

fix(sourceanalysis): return an error instead of exiting when an rlib has no object file#2977
kobihikri wants to merge 2 commits into
google:mainfrom
kobihikri:fix/rlib-archive-eof-no-fatal

Conversation

@kobihikri

Copy link
Copy Markdown

Overview

Fixes #2976.

extractRlibArchive calls log.Fatalf on any error from the archive iterator, including the
ordinary io.EOF that ends every ar archive. An ar archive with no /0 member and no .rcgu.o/
member walks the loop to end-of-archive and terminates the whole osv-scanner process.

This came out of GHSA-2f6x-xr4j-f2h7. @another-rex judged it a regular bug rather than a
vulnerability and I agree with him — the process exits non-zero, so nothing is silently hidden.
Opening it here as the bug it is.

Details

Two things were wrong, and both are fixed by returning the error:

1. One artifact ended the entire scan. The caller is already written to survive this:

buf, err := extractRlibArchive(path)
if err != nil {
    cmdlogger.Errorf("failed to analyse '%s': %s", path, err)
    continue
}

log.Fatalf is os.Exit(1), so it exits before that error can be returned and the continue
never runs.

2. The exit code was wrong. docs/output.md reserves 1 for "packages were found when
scanning, and there are vulnerabilities or findings"
and 127 for General Error. log.Fatalf
exits 1, so an internal failure was reported to CI through a result-related code, and no output
was produced. Letting the scan finish normally removes the ambiguity.

The change treats end-of-archive as "this is not an rlib we can analyse" and returns an error;
any other error is wrapped and returned. The log import goes with it — this was the only
log.Fatalf in non-test library code.

No malformed or hostile input is needed to hit this: a well-formed ar archive that simply is not a
Rust rlib is enough (ar rc plain.a a.txt).

Testing

  • Added Test_extractRlibArchive_noObjectFile, which builds a minimal GNU ar archive by hand
    (so the test needs no ar binary on the machine running it) and asserts an error is returned.

  • Verified the test actually catches the regression. Against the unpatched rust.go it does
    not merely fail an assertion — the test binary is killed mid-test by os.Exit(1):

    === RUN   Test_extractRlibArchive_noObjectFile
    2026/08/10 08:50:54 EOF
    FAIL    github.com/google/osv-scanner/v2/internal/sourceanalysis   0.005s
    

    With the fix: --- PASS: Test_extractRlibArchive_noObjectFile (0.00s).

  • The existing Test_extractRlibArchive cases (simple.rlib, medium.rlib) still pass; the new
    fixture is written to t.TempDir() so it is not picked up by that directory-driven test.

  • go test ./internal/sourceanalysis/... — ok.

  • golangci-lint at your pinned v2.11.4 on the package — 0 issues. gofmt -l clean, go vet
    clean.

All run in a golang:1.26 container matching go.mod.

Checklist

  • I have signed the Contributor License Agreement.
  • I have run the linter using ./scripts/run_lints.sh. (golangci-lint v2.11.4 on the changed package — 0 issues)
  • I have run the unit tests using ./scripts/run_tests.sh. (go test ./internal/sourceanalysis/... — ok)
  • I have made my commits and PR title follow the Conventional Commits specification.

I used an AI assistant while investigating this; I read the code paths, wrote the test, and ran the
verification myself.

…has no object file

extractRlibArchive called log.Fatalf on any error from the archive iterator,
including the io.EOF that ends every ar archive. An archive with no "/0" member
and no ".rcgu.o/" member walks the loop to end-of-archive and exits the process.

The caller at rust.go:53-57 already logs the error and continues to the next
artifact, but log.Fatalf exits before the error can be returned, so one unrelated
build artifact ends the whole scan.

It also reports the wrong exit code. log.Fatalf exits 1, which docs/output.md
reserves for "packages were found when scanning, and there are vulnerabilities or
findings" — a result-related code. An internal failure should be 127.

Treat end-of-archive as "this is not an rlib we can analyse" and return an error,
letting the existing continue skip the artifact and the scan finish normally.

This was the only log.Fatalf in non-test library code.

Fixes google#2976
@G-Rath G-Rath closed this Aug 10, 2026
@G-Rath

G-Rath commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator

Please read our contributing guide before opening pull requests

@another-rex another-rex reopened this Aug 11, 2026
@another-rex
another-rex requested a review from G-Rath August 11, 2026 03:42

@G-Rath G-Rath left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The code change and test look fine, but could you scale back the comments?

Personally I'd say the test is a nice extra bit of coverage rather than guarding against a specific "fix" - the fact that this was a log.Fatal previously is discoverable from the git history, and us returning an error rather than exiting immediately is very standard behaviour so shouldn't need to be called out anywhere.

Drop the comments describing the previous log.Fatal behaviour and the one
framing the test as guarding a specific fix; the git history carries that.
Code and test logic are unchanged.

Signed-off-by: Kobi Hikri <kobi.hikri@gmail.com>
@kobihikri

Copy link
Copy Markdown
Author

Thanks — that's fair, the git history does carry it.

I've dropped the comments narrating the old log.Fatal and the one framing the test as guarding the fix, and trimmed the note above the hand-built archive. Code and test logic are unchanged.

Re-ran at your pinned golangci-lint v2.11.4 (0 issues), gofmt and go vet clean, and both Test_extractRlibArchive and Test_extractRlibArchive_noObjectFile pass in a golang:1.26 container matching go.mod.

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.

extractRlibArchive exits the process via log.Fatalf on io.EOF, reporting an internal error as exit code 1 ("vulnerabilities or findings")

3 participants