aboutsummaryrefslogtreecommitdiff
path: root/src/debug/elf/file_test.go
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2026-03-23 04:38:52 -0700
committerGopher Robot <gobot@golang.org>2026-03-25 06:14:20 -0700
commite3bda445164c764aa95c7df271dff2170fa1a7ce (patch)
tree0a3b39380692cacc59ea0bf3400072af03b846e1 /src/debug/elf/file_test.go
parentcbc2d06c9ba8285bb60f1055b44d4d1e742ca734 (diff)
downloadgo-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.go85
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)
+}