debug/elf: return FormatError when reading short files

NewFile returns the raw error from ReadAt when failing to read the
ELF identifier, typically io.EOF for empty or short files. This breaks
the API contract that all parsing failures should return *FormatError.

Wrap the error in FormatError for consistency with other error paths.

Fixes #76338

Change-Id: Ic4ed77316fcc459ce8cbe9e9506d7cf8e9286623
Reviewed-on: https://go-review.googlesource.com/c/go/+/736600
Reviewed-by: Michael Pratt <mpratt@google.com>
Reviewed-by: Carlos Amedee <carlos@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Auto-Submit: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
Mark F
2026-01-15 13:19:10 +01:00
committed by Gopher Robot
parent 8e3104dc26
commit 858d4bf851
2 changed files with 45 additions and 1 deletions

View File

@@ -290,7 +290,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
// Read and decode ELF identifier
var ident [16]uint8
if _, err := r.ReadAt(ident[0:], 0); err != nil {
return nil, err
return nil, &FormatError{0, "cannot read ELF identifier", err}
}
if ident[0] != '\x7f' || ident[1] != 'E' || ident[2] != 'L' || ident[3] != 'F' {
return nil, &FormatError{0, "bad magic number", ident[0:4]}

View File

@@ -17,6 +17,7 @@ import (
"net"
"os"
"path"
"path/filepath"
"reflect"
"runtime"
"slices"
@@ -1622,3 +1623,46 @@ func BenchmarkSymbols32(b *testing.B) {
}
}
}
func TestOpenEmptyFile(t *testing.T) {
name := filepath.Join(t.TempDir(), "empty")
if err := os.WriteFile(name, nil, 0o644); err != nil {
t.Fatal(err)
}
_, err := Open(name)
if err == nil {
t.Fatal("Open on empty file: got nil error, want non-nil")
}
var formatErr *FormatError
if !errors.As(err, &formatErr) {
t.Errorf("Open on empty file: got %T (%v), want *FormatError", err, err)
}
}
func TestNewFileShortReader(t *testing.T) {
tests := []struct {
name string
data []byte
}{
{"empty", []byte{}},
{"one byte", []byte{0x7f}},
{"four bytes", []byte{0x7f, 'E', 'L', 'F'}},
{"fifteen bytes", make([]byte, 15)},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
_, err := NewFile(bytes.NewReader(tt.data))
if err == nil {
t.Fatal("NewFile with short data: got nil error, want non-nil")
}
var formatErr *FormatError
if !errors.As(err, &formatErr) {
t.Errorf("NewFile with short data: got %T (%v), want *FormatError", err, err)
}
})
}
}