When matching mappings to segments, skip over segments with zero file size. (#644)

Segments with no file bits can have any file offset value, which can make them
appear to overlap other segments that start at those offsets.

This change prevents us from matching any mapping to such segments with zero
file content. But such segments would be loaded into anonymous mappings, which
we cannot symbolize anyway.
diff --git a/internal/elfexec/elfexec.go b/internal/elfexec/elfexec.go
index 16ff245..e0f3f7e 100644
--- a/internal/elfexec/elfexec.go
+++ b/internal/elfexec/elfexec.go
@@ -285,10 +285,11 @@
 }
 
 // ProgramHeadersForMapping returns the program segment headers that overlap
-// the runtime mapping with file offset mapOff and memory size mapSz.
+// the runtime mapping with file offset mapOff and memory size mapSz. We skip
+// over segments zero file size because their file offset values are unreliable.
 // Even if overlapping, a segment is not selected if its aligned file offset is
-// greater than the mapping file offset, or if the mappings includes the last
-// page of the segment, but not the full segment, and the mapping includes
+// greater than the mapping file offset, or if the mapping includes the last
+// page of the segment, but not the full segment and the mapping includes
 // additional pages after the segment end.
 // The function returns a slice of pointers to the headers in the input
 // slice, which are valid only while phdrs is not modified or discarded.
@@ -308,11 +309,17 @@
 	var headers []*elf.ProgHeader
 	for i := range phdrs {
 		p := &phdrs[i]
+		// Skip over segments with zero file size. Their file offsets can have
+		// arbitrary values, see b/195427553.
+		if p.Filesz == 0 {
+			continue
+		}
 		segLimit := p.Off + p.Memsz
 		// The segment must overlap the mapping.
 		if p.Type == elf.PT_LOAD && mapOff < segLimit && p.Off < mapLimit {
 			// If the mapping offset is strictly less than the page aligned segment
-			// offset, then this mapping comes from a different segment.
+			// offset, then this mapping comes from a differnt segment, fixes
+			// b/179920361.
 			alignedSegOffset := uint64(0)
 			if p.Off > (p.Vaddr & pageOffsetMask) {
 				alignedSegOffset = p.Off - (p.Vaddr & pageOffsetMask)
diff --git a/internal/elfexec/elfexec_test.go b/internal/elfexec/elfexec_test.go
index bc2ee9e..fe6fc9c 100644
--- a/internal/elfexec/elfexec_test.go
+++ b/internal/elfexec/elfexec_test.go
@@ -202,7 +202,7 @@
 			wantHeaders: nil,
 		},
 		{
-			desc:  "tiny file, 4KB at offset 0 matches both headers",
+			desc:  "tiny file, 4KB at offset 0 matches both headers, b/178747588",
 			phdrs: tinyHeaders,
 			pgoff: 0,
 			memsz: 0x1000,
@@ -307,7 +307,7 @@
 			wantHeaders: []*elf.ProgHeader{{Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_W, Off: 0xe10, Vaddr: 0x600e10, Paddr: 0x600e10, Filesz: 0x230, Memsz: 0x238, Align: 0x200000}},
 		},
 		{
-			desc:        "medium file large mapping that includes all address space matches executable segment",
+			desc:        "medium file large mapping that includes all address space matches executable segment, b/179920361",
 			phdrs:       mediumHeaders,
 			pgoff:       0,
 			memsz:       0xd6e000,
@@ -342,12 +342,26 @@
 			wantHeaders: []*elf.ProgHeader{{Type: elf.PT_LOAD, Flags: elf.PF_X + elf.PF_R, Off: 0x0, Vaddr: 0x7f0000000000, Paddr: 0x7f0000000000, Filesz: 0xbc64d5, Memsz: 0xbc64d5, Align: 0x1000}},
 		},
 		{
-			desc:        "ffmpeg headers, split mapping for executable segment matches executable segment",
+			desc:        "ffmpeg headers, split mapping for executable segment matches executable segment, b/193176694",
 			phdrs:       ffmpegHeaders,
 			pgoff:       0,
 			memsz:       0x48d8000,
 			wantHeaders: []*elf.ProgHeader{{Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_X, Off: 0, Vaddr: 0x200000, Paddr: 0x200000, Filesz: 0x48d8410, Memsz: 0x48d8410, Align: 0x200000}},
 		},
+		{
+			desc: "segments with no file bits (b/195427553), mapping for executable segment matches executable segment",
+			phdrs: []elf.ProgHeader{
+				{Type: elf.PT_LOAD, Flags: elf.PF_R, Off: 0x0, Vaddr: 0x0, Paddr: 0x0, Filesz: 0x115000, Memsz: 0x115000, Align: 0x1000},
+				{Type: elf.PT_LOAD, Flags: elf.PF_X + elf.PF_R, Off: 0x115000, Vaddr: 0x115000, Paddr: 0x115000, Filesz: 0x361e15, Memsz: 0x361e15, Align: 0x1000},
+				{Type: elf.PT_LOAD, Flags: elf.PF_W + elf.PF_R, Off: 0x0, Vaddr: 0x477000, Paddr: 0x477000, Filesz: 0x0, Memsz: 0x33c, Align: 0x1000},
+				{Type: elf.PT_LOAD, Flags: elf.PF_R, Off: 0x0, Vaddr: 0x478000, Paddr: 0x478000, Filesz: 0x0, Memsz: 0x47dc28, Align: 0x1000},
+				{Type: elf.PT_LOAD, Flags: elf.PF_R, Off: 0x477000, Vaddr: 0x8f6000, Paddr: 0x8f6000, Filesz: 0x140, Memsz: 0x140, Align: 0x1000},
+				{Type: elf.PT_LOAD, Flags: elf.PF_W + elf.PF_R, Off: 0x478000, Vaddr: 0x8f7000, Paddr: 0x8f7000, Filesz: 0x38, Memsz: 0x38, Align: 0x1000},
+			},
+			pgoff:       0x115000,
+			memsz:       0x362000,
+			wantHeaders: []*elf.ProgHeader{{Type: elf.PT_LOAD, Flags: elf.PF_X + elf.PF_R, Off: 0x115000, Vaddr: 0x115000, Paddr: 0x115000, Filesz: 0x361e15, Memsz: 0x361e15, Align: 0x1000}},
+		},
 	} {
 		t.Run(tc.desc, func(t *testing.T) {
 			gotHeaders := ProgramHeadersForMapping(tc.phdrs, tc.pgoff, tc.memsz)