Source file src/debug/dwarf/fuzz_test.go

     1  // Copyright 2026 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package dwarf_test
     6  
     7  import (
     8  	"debug/dwarf"
     9  	"debug/elf"
    10  	"debug/macho"
    11  	"os"
    12  	"path/filepath"
    13  	"strings"
    14  	"testing"
    15  )
    16  
    17  func FuzzReader(f *testing.F) {
    18  	if testing.Short() {
    19  		f.Skip("Skipping in short mode")
    20  	}
    21  
    22  	dwarfSuffix := func(name string) string {
    23  		switch {
    24  		// ELF prefixes, see dwarfSuffix in debug/elf.DWARF
    25  		case strings.HasPrefix(name, ".debug_"):
    26  			return name[7:]
    27  		case strings.HasPrefix(name, ".zdebug_"):
    28  			return name[8:]
    29  		// machO prefixes, see dwarfSuffix in debug/macho.DWARF
    30  		case strings.HasPrefix(name, "__debug_"):
    31  			return name[8:]
    32  		case strings.HasPrefix(name, "__zdebug_"):
    33  			return name[9:]
    34  		default:
    35  			return ""
    36  		}
    37  	}
    38  
    39  	testdata, err := os.ReadDir("testdata")
    40  	if err != nil {
    41  		f.Fatalf("failed to read testdata directory: %s", err)
    42  	}
    43  	for _, de := range testdata {
    44  		if de.IsDir() {
    45  			continue
    46  		}
    47  
    48  		var abbrev, info, line []byte
    49  
    50  		ext := filepath.Ext(de.Name())
    51  		name := filepath.Join("testdata", de.Name())
    52  
    53  		switch {
    54  		case strings.HasPrefix(ext, ".elf"):
    55  			e, err := elf.Open(name)
    56  			if err != nil {
    57  				f.Fatal(err)
    58  			}
    59  
    60  			for _, s := range e.Sections {
    61  				switch dwarfSuffix(s.Name) {
    62  				case "abbrev":
    63  					abbrev, _ = s.Data()
    64  				case "info":
    65  					info, _ = s.Data()
    66  				case "line":
    67  					line, _ = s.Data()
    68  				}
    69  			}
    70  		case strings.HasPrefix(ext, ".macho"):
    71  			m, err := macho.Open(name)
    72  			if err != nil {
    73  				f.Fatal(err)
    74  			}
    75  
    76  			for _, s := range m.Sections {
    77  				switch dwarfSuffix(s.Name) {
    78  				case "abbrev":
    79  					abbrev, _ = s.Data()
    80  				case "info":
    81  					info, _ = s.Data()
    82  				case "line":
    83  					line, _ = s.Data()
    84  				}
    85  			}
    86  		default:
    87  			continue
    88  		}
    89  
    90  		if len(abbrev) > 0 || len(info) > 0 || len(line) > 0 {
    91  			f.Add(abbrev, info, line)
    92  		}
    93  	}
    94  
    95  	// A DWARF 4 compile unit with a line program containing a
    96  	// DW_LNS_set_file instruction with a file index of math.MaxUint64.
    97  	f.Add(
    98  		[]byte{
    99  			1, 0x11, 0,
   100  			0x10, 0x17,
   101  			0, 0,
   102  			0,
   103  		},
   104  		[]byte{
   105  			0x0c, 0, 0, 0,
   106  			4, 0,
   107  			0, 0, 0, 0,
   108  			8,
   109  			1,
   110  			0, 0, 0, 0,
   111  		},
   112  		[]byte{
   113  			0x25, 0, 0, 0,
   114  			4, 0,
   115  			0x14, 0, 0, 0,
   116  			1, 1, 1, 0, 1, 13,
   117  			0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1,
   118  			0, 0,
   119  			4,
   120  			0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1,
   121  		},
   122  	)
   123  
   124  	f.Fuzz(func(t *testing.T, abbrev, info, line []byte) {
   125  		d, err := dwarf.New(abbrev, nil, nil, info, line, nil, nil, nil)
   126  		if err != nil {
   127  			return
   128  		}
   129  
   130  		r := d.Reader()
   131  		for {
   132  			e, err := r.Next()
   133  			if err != nil || e == nil {
   134  				return
   135  			}
   136  			if e.Tag != dwarf.TagCompileUnit {
   137  				continue
   138  			}
   139  			lr, err := d.LineReader(e)
   140  			if err != nil || lr == nil {
   141  				continue
   142  			}
   143  			var lineEntry dwarf.LineEntry
   144  			for {
   145  				if err := lr.Next(&lineEntry); err != nil {
   146  					break
   147  				}
   148  			}
   149  		}
   150  	})
   151  }
   152  

View as plain text