Skip to content

Commit fa13731

Browse files
ZekeLugopherbot
authored andcommitted
debug/elf: return error on reading from SHT_NOBITS sections
An SHT_NOBITS section contains no bytes and occupies no space in the file. This change makes it return an error on reading from this section so that it will force the caller to check for an SHT_NNOBITS section. We have considered another option to return "nil, nil" for the Data method. It's abandoned because it might lead a program to simply do the wrong thing, thinking that the section is empty. Please note that it breaks programs which expect a byte slice with the length described by the sh_size field. There are two reasons to introduce this breaking change: 1. SHT_NOBITS means no data and it's unnecessary to allocate memory for it; 2. it could result in an OOM if the file is corrupted and has a huge sh_size. Fixes #54967. Change-Id: I0c3ed4e097214fe88413d726a89122105ad45d4f GitHub-Last-Rev: 994c12d GitHub-Pull-Request: #54994 Reviewed-on: https://go-review.googlesource.com/c/go/+/429601 Run-TryBot: Ian Lance Taylor <[email protected]> Auto-Submit: Dmitri Shuralyov <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: Dmitri Shuralyov <[email protected]>
1 parent a451713 commit fa13731

File tree

3 files changed

+33
-29
lines changed

3 files changed

+33
-29
lines changed

src/debug/elf/elf_test.go

-22
Original file line numberDiff line numberDiff line change
@@ -47,25 +47,3 @@ func TestNames(t *testing.T) {
4747
}
4848
}
4949
}
50-
51-
func TestNobitsSection(t *testing.T) {
52-
const testdata = "testdata/gcc-amd64-linux-exec"
53-
f, err := Open(testdata)
54-
if err != nil {
55-
t.Fatalf("could not read %s: %v", testdata, err)
56-
}
57-
defer f.Close()
58-
bss := f.Section(".bss")
59-
bssData, err := bss.Data()
60-
if err != nil {
61-
t.Fatalf("error reading .bss section: %v", err)
62-
}
63-
if g, w := uint64(len(bssData)), bss.Size; g != w {
64-
t.Errorf(".bss section length mismatch: got %d, want %d", g, w)
65-
}
66-
for i := range bssData {
67-
if bssData[i] != 0 {
68-
t.Fatalf("unexpected non-zero byte at offset %d: %#x", i, bssData[i])
69-
}
70-
}
71-
}

src/debug/elf/file.go

+9-7
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,8 @@ type Section struct {
102102
// Data reads and returns the contents of the ELF section.
103103
// Even if the section is stored compressed in the ELF file,
104104
// Data returns uncompressed data.
105+
//
106+
// For an SHT_NOBITS section, Data always returns a non-nil error.
105107
func (s *Section) Data() ([]byte, error) {
106108
return saferio.ReadData(s.Open(), s.Size)
107109
}
@@ -118,9 +120,12 @@ func (f *File) stringTable(link uint32) ([]byte, error) {
118120
// Open returns a new ReadSeeker reading the ELF section.
119121
// Even if the section is stored compressed in the ELF file,
120122
// the ReadSeeker reads uncompressed data.
123+
//
124+
// For an SHT_NOBITS section, all calls to the opened reader
125+
// will return a non-nil error.
121126
func (s *Section) Open() io.ReadSeeker {
122127
if s.Type == SHT_NOBITS {
123-
return io.NewSectionReader(&zeroReader{}, 0, int64(s.Size))
128+
return io.NewSectionReader(&nobitsSectionReader{}, 0, int64(s.Size))
124129
}
125130
if s.Flags&SHF_COMPRESSED == 0 {
126131
return io.NewSectionReader(s.sr, 0, 1<<63-1)
@@ -1602,11 +1607,8 @@ func (f *File) DynString(tag DynTag) ([]string, error) {
16021607
return all, nil
16031608
}
16041609

1605-
type zeroReader struct{}
1610+
type nobitsSectionReader struct{}
16061611

1607-
func (*zeroReader) ReadAt(p []byte, off int64) (n int, err error) {
1608-
for i := range p {
1609-
p[i] = 0
1610-
}
1611-
return len(p), nil
1612+
func (*nobitsSectionReader) ReadAt(p []byte, off int64) (n int, err error) {
1613+
return 0, errors.New("unexpected read from SHT_NOBITS section")
16121614
}

src/debug/elf/file_test.go

+24
Original file line numberDiff line numberDiff line change
@@ -945,6 +945,30 @@ func TestNoSectionOverlaps(t *testing.T) {
945945
}
946946
}
947947

948+
func TestNobitsSection(t *testing.T) {
949+
const testdata = "testdata/gcc-amd64-linux-exec"
950+
f, err := Open(testdata)
951+
if err != nil {
952+
t.Fatalf("could not read %s: %v", testdata, err)
953+
}
954+
defer f.Close()
955+
956+
wantError := "unexpected read from SHT_NOBITS section"
957+
bss := f.Section(".bss")
958+
959+
_, err = bss.Data()
960+
if err == nil || err.Error() != wantError {
961+
t.Fatalf("bss.Data() got error %q, want error %q", err, wantError)
962+
}
963+
964+
r := bss.Open()
965+
p := make([]byte, 1)
966+
_, err = r.Read(p)
967+
if err == nil || err.Error() != wantError {
968+
t.Fatalf("r.Read(p) got error %q, want error %q", err, wantError)
969+
}
970+
}
971+
948972
// TestLargeNumberOfSections tests the case that a file has greater than or
949973
// equal to 65280 (0xff00) sections.
950974
func TestLargeNumberOfSections(t *testing.T) {

0 commit comments

Comments
 (0)