Source file src/debug/buildinfo/search_test.go

     1  // Copyright 2024 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 buildinfo
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	"io"
    11  	"testing"
    12  )
    13  
    14  type byteExe struct {
    15  	b []byte
    16  }
    17  
    18  func (x *byteExe) DataReader(addr uint64) (io.ReaderAt, error) {
    19  	if addr >= uint64(len(x.b)) {
    20  		return nil, fmt.Errorf("ReadData(%d) out of bounds of %d-byte slice", addr, len(x.b))
    21  	}
    22  	return bytes.NewReader(x.b[addr:]), nil
    23  }
    24  
    25  func (x *byteExe) DataStart() (uint64, uint64) {
    26  	return 0, uint64(len(x.b))
    27  }
    28  
    29  func TestSearchMagic(t *testing.T) {
    30  	tests := []struct {
    31  		name    string
    32  		data    []byte
    33  		want    uint64
    34  		wantErr error
    35  	}{
    36  		{
    37  			name: "beginning",
    38  			data: func() []byte {
    39  				b := make([]byte, buildInfoHeaderSize)
    40  				copy(b, buildInfoMagic)
    41  				return b
    42  			}(),
    43  			want: 0,
    44  		},
    45  		{
    46  			name: "offset",
    47  			data: func() []byte {
    48  				b := make([]byte, 512)
    49  				copy(b[4*buildInfoAlign:], buildInfoMagic)
    50  				return b
    51  			}(),
    52  			want: 4 * buildInfoAlign,
    53  		},
    54  		{
    55  			name: "second_chunk",
    56  			data: func() []byte {
    57  				b := make([]byte, 4*searchChunkSize)
    58  				copy(b[searchChunkSize+4*buildInfoAlign:], buildInfoMagic)
    59  				return b
    60  			}(),
    61  			want: searchChunkSize + 4*buildInfoAlign,
    62  		},
    63  		{
    64  			name: "second_chunk_short",
    65  			data: func() []byte {
    66  				// Magic is 64-bytes into the second chunk,
    67  				// which is short; only exactly long enough to
    68  				// hold the header.
    69  				b := make([]byte, searchChunkSize+4*buildInfoAlign+buildInfoHeaderSize)
    70  				copy(b[searchChunkSize+4*buildInfoAlign:], buildInfoMagic)
    71  				return b
    72  			}(),
    73  			want: searchChunkSize + 4*buildInfoAlign,
    74  		},
    75  		{
    76  			name: "missing",
    77  			data: func() []byte {
    78  				b := make([]byte, buildInfoHeaderSize)
    79  				return b
    80  			}(),
    81  			wantErr: errNotGoExe,
    82  		},
    83  		{
    84  			name: "too_short",
    85  			data: func() []byte {
    86  				// There needs to be space for the entire
    87  				// header, not just the magic.
    88  				b := make([]byte, len(buildInfoMagic))
    89  				copy(b, buildInfoMagic)
    90  				return b
    91  			}(),
    92  			wantErr: errNotGoExe,
    93  		},
    94  		{
    95  			name: "misaligned",
    96  			data: func() []byte {
    97  				b := make([]byte, 512)
    98  				copy(b[7:], buildInfoMagic)
    99  				return b
   100  			}(),
   101  			wantErr: errNotGoExe,
   102  		},
   103  		{
   104  			name: "misaligned_across_chunk",
   105  			data: func() []byte {
   106  				// Magic crosses chunk boundary. By definition,
   107  				// it has to be misaligned.
   108  				b := make([]byte, 2*searchChunkSize)
   109  				copy(b[searchChunkSize-8:], buildInfoMagic)
   110  				return b
   111  			}(),
   112  			wantErr: errNotGoExe,
   113  		},
   114  		{
   115  			name: "header_across_chunk",
   116  			data: func() []byte {
   117  				// The magic is aligned within the first chunk,
   118  				// but the rest of the 32-byte header crosses
   119  				// the chunk boundary.
   120  				b := make([]byte, 2*searchChunkSize)
   121  				copy(b[searchChunkSize-buildInfoAlign:], buildInfoMagic)
   122  				return b
   123  			}(),
   124  			want: searchChunkSize - buildInfoAlign,
   125  		},
   126  	}
   127  	for _, tc := range tests {
   128  		t.Run(tc.name, func(t *testing.T) {
   129  			x := &byteExe{tc.data}
   130  			dataAddr, dataSize := x.DataStart()
   131  			addr, err := searchMagic(x, dataAddr, dataSize)
   132  			if tc.wantErr == nil {
   133  				if err != nil {
   134  					t.Errorf("searchMagic got err %v want nil", err)
   135  				}
   136  				if addr != tc.want {
   137  					t.Errorf("searchMagic got addr %d want %d", addr, tc.want)
   138  				}
   139  			} else {
   140  				if err != tc.wantErr {
   141  					t.Errorf("searchMagic got err %v want %v", err, tc.wantErr)
   142  				}
   143  			}
   144  		})
   145  	}
   146  }
   147  

View as plain text