diff options
| author | Ian Lance Taylor <iant@golang.org> | 2026-03-23 04:38:52 -0700 |
|---|---|---|
| committer | Gopher Robot <gobot@golang.org> | 2026-03-25 06:14:20 -0700 |
| commit | e3bda445164c764aa95c7df271dff2170fa1a7ce (patch) | |
| tree | 0a3b39380692cacc59ea0bf3400072af03b846e1 /src/debug/elf/file_test.go | |
| parent | cbc2d06c9ba8285bb60f1055b44d4d1e742ca734 (diff) | |
| download | go-e3bda445164c764aa95c7df271dff2170fa1a7ce.tar.xz | |
debug/elf: handle program header count overflow
ELF files only have a 16-bit count for program headers.
To handle the very rare case of larger files,
a large program header count is stored as 0xffff
and the first section header info field holds the actual count.
Fixes #78217
Change-Id: I35c7e15025a9677473cb43d09a41f17f75443731
Reviewed-on: https://go-review.googlesource.com/c/go/+/758040
Reviewed-by: David Chase <drchase@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Diffstat (limited to 'src/debug/elf/file_test.go')
| -rw-r--r-- | src/debug/elf/file_test.go | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/src/debug/elf/file_test.go b/src/debug/elf/file_test.go index aef9967c78..e99844639a 100644 --- a/src/debug/elf/file_test.go +++ b/src/debug/elf/file_test.go @@ -5,6 +5,7 @@ package elf import ( + "bufio" "bytes" "compress/gzip" "compress/zlib" @@ -16,6 +17,7 @@ import ( "math/rand" "net" "os" + "os/exec" "path" "path/filepath" "reflect" @@ -1666,3 +1668,86 @@ func TestNewFileShortReader(t *testing.T) { }) } } + +func TestLargeNumberOfSegments(t *testing.T) { + switch runtime.GOOS { + case "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "solaris": + default: + t.Skipf("ELF binaries not generated on %s", runtime.GOOS) + } + + if testing.Short() { + // The GNU linker takes a long time to run this test. + t.Skip("skipping slow test in short mode") + } + + t.Parallel() + + tempDir := t.TempDir() + scriptFile := filepath.Join(tempDir, "script") + f, err := os.Create(scriptFile) + if err != nil { + t.Fatal(err) + } + b := bufio.NewWriter(f) + + // These script segments work for GNU ld. + const scriptStart = ` +PHDRS { + headers PT_PHDR PHDRS; + text PT_LOAD FILEHDR PHDRS; + dynamic PT_DYNAMIC; +` + const scriptEnd = ` +} +SECTIONS { + .sec1 : { *(.sec1) } :hdr1 +} +` + + fmt.Fprintf(b, scriptStart) + const phdrCount = 70000 + for i := range phdrCount { + fmt.Fprintf(b, "\thdr%d PT_LOAD;", i) + } + fmt.Fprintf(b, scriptEnd) + + if err := b.Flush(); err != nil { + t.Fatal(err) + } + if err := f.Close(); err != nil { + t.Fatal(err) + } + + const cCode = ` +int main(int argc, char **argv) { return 0; } +` + cFile := filepath.Join(tempDir, "x.c") + if err := os.WriteFile(cFile, []byte(cCode), 0o644); err != nil { + t.Fatal(err) + } + + cc := os.Getenv("CC") + if cc == "" { + cc = "gcc" + } + oFile := filepath.Join(tempDir, "x.exe") + + out, err := exec.Command(cc, "-o", oFile, "-T", scriptFile, cFile).CombinedOutput() + if len(out) > 0 { + t.Logf("%s", out) + } + if err != nil { + t.Skipf("skipping test because generating test case failed: %v", err) + } + + ef, err := Open(oFile) + if err != nil { + t.Fatalf("failed to open test file: %v", err) + } + got := len(ef.Progs) + if got < phdrCount { + t.Errorf("got %d program headers, expected at least %d", got, phdrCount) + } + t.Logf("output file has %d segments", got) +} |
