github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/pkg/build/linux_test.go (about) 1 // Copyright 2019 syzkaller project authors. All rights reserved. 2 // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. 3 4 //go:build linux 5 6 package build 7 8 import ( 9 "bytes" 10 "context" 11 "fmt" 12 "os" 13 "strings" 14 "testing" 15 "text/template" 16 17 "github.com/google/syzkaller/pkg/debugtracer" 18 "github.com/google/syzkaller/pkg/osutil" 19 "golang.org/x/sync/errgroup" 20 ) 21 22 func TestElfBinarySignature(t *testing.T) { 23 t.Parallel() 24 enumerateFlags(t, nil, []string{"-g", "-O1", "-O2", "-no-pie", "-static"}) 25 } 26 27 func TestQueryLinuxCompiler(t *testing.T) { 28 const goodDir = "./testdata/linux_compiler_ok" 29 const expectedCompiler = "gcc (Debian 10.2.1-6+build2) 10.2.1 20210110, GNU ld (GNU Binutils for Debian) 2.35.2" 30 ret, err := queryLinuxCompiler(goodDir) 31 if err != nil { 32 t.Fatalf("error: %v", err) 33 } 34 if ret != expectedCompiler { 35 t.Fatalf("got: %T, expected: %T", ret, expectedCompiler) 36 } 37 const badDir = "./testingData/non_existing_folder" 38 _, err = queryLinuxCompiler(badDir) 39 if err == nil { 40 t.Fatalf("expected an error, got none") 41 } 42 } 43 44 func enumerateFlags(t *testing.T, flags, allFlags []string) { 45 if len(allFlags) != 0 { 46 enumerateFlags(t, flags, allFlags[1:]) 47 enumerateFlags(t, append(flags, allFlags[0]), allFlags[1:]) 48 return 49 } 50 t.Run(strings.Join(flags, "-"), func(t *testing.T) { 51 t.Parallel() 52 sign1, sign2, sign3 := "", "", "" 53 g, _ := errgroup.WithContext(context.Background()) 54 g.Go(func() error { 55 var err error 56 sign1, err = sign(t, flags, false, false) 57 return err 58 }) 59 g.Go(func() error { 60 var err error 61 sign2, err = sign(t, flags, false, true) 62 return err 63 }) 64 g.Go(func() error { 65 var err error 66 sign3, err = sign(t, flags, true, false) 67 return err 68 }) 69 if err := g.Wait(); err != nil { 70 t.Error(err) 71 } 72 if sign1 != sign2 { 73 t.Errorf("signature has changed after a comment-only change") 74 } 75 if sign1 == sign3 { 76 t.Errorf("signature has not changed after a change") 77 } 78 }) 79 } 80 81 func sign(t *testing.T, flags []string, changed, comment bool) (string, error) { 82 buf := new(bytes.Buffer) 83 if err := srcTemplate.Execute(buf, SrcParams{Changed: changed, Comment: comment}); err != nil { 84 return "", fmt.Errorf("template exec failed: %w", err) 85 } 86 src := buf.Bytes() 87 bin, err := osutil.TempFile("syz-build-test") 88 if err != nil { 89 return "", fmt.Errorf("temp file creation error: %w", err) 90 } 91 defer os.Remove(bin) 92 cmd := osutil.Command("gcc", append(flags, "-pthread", "-o", bin, "-x", "c", "-")...) 93 cmd.Stdin = buf 94 out, err := cmd.CombinedOutput() 95 if err != nil { 96 return "", fmt.Errorf("compiler failed: %w\n%s\n\n%s", err, src, out) 97 } 98 sign, err := elfBinarySignature(bin, &debugtracer.TestTracer{T: t}) 99 if err != nil { 100 return "", fmt.Errorf("signature creation failed: %w", err) 101 } 102 return sign, nil 103 } 104 105 type SrcParams struct { 106 Changed bool 107 Comment bool 108 } 109 110 var srcTemplate = template.Must(template.New("").Parse(` 111 #include <stdio.h> 112 #include <pthread.h> 113 114 int main() { 115 int x = {{if .Changed}}0{{else}}1{{end}}; 116 {{if .Comment}} 117 // Some comment goes here. 118 // It affects line numbers in debug info. 119 {{end}} 120 printf("%d %p\n", x, pthread_create); 121 } 122 `))