1
2
3
4
5 package out_test
6
7 import (
8 "bufio"
9 "bytes"
10 "fmt"
11 "internal/goarch"
12 "internal/testenv"
13 "os"
14 "path/filepath"
15 "regexp"
16 "strconv"
17 "strings"
18 "testing"
19 )
20
21
22
23
24 func TestDisallowSmuggledCode(t *testing.T) {
25 testenv.MustHaveGoRun(t)
26 testenv.MustHaveCGO(t)
27 objDir := cgo(t, "comments.go")
28
29 file, err := os.Open(filepath.Join(objDir, "_cgo_export.h"))
30 if err != nil {
31 t.Fatal(err)
32 }
33 defer file.Close()
34
35 scanner := bufio.NewScanner(file)
36 for scanner.Scan() {
37 line := strings.TrimSpace(scanner.Text())
38 if strings.Contains(line, `"Hello, I am exploiting CVE-2025-61732!\n"`) {
39 t.Fatalf(`got %q, want ""`, line)
40 }
41 }
42 if err := scanner.Err(); err != nil {
43 t.Fatal(err)
44 }
45 }
46
47 type methodAlign struct {
48 Method string
49 Align int
50 }
51
52 var wantAligns = map[string]int{
53 "ReturnEmpty": 1,
54 "ReturnOnlyUint8": 1,
55 "ReturnOnlyUint16": 2,
56 "ReturnOnlyUint32": 4,
57 "ReturnOnlyUint64": goarch.PtrSize,
58 "ReturnOnlyInt": goarch.PtrSize,
59 "ReturnOnlyPtr": goarch.PtrSize,
60 "ReturnByteSlice": goarch.PtrSize,
61 "ReturnString": goarch.PtrSize,
62 "InputAndReturnUint8": 1,
63 "MixedTypes": goarch.PtrSize,
64 }
65
66
67
68
69 func TestAligned(t *testing.T) {
70 testenv.MustHaveGoRun(t)
71 testenv.MustHaveCGO(t)
72 objDir := cgo(t, "aligned.go")
73
74 haveAligns, err := parseAlign(filepath.Join(objDir, "_cgo_export.c"))
75 if err != nil {
76 t.Fatal(err)
77 }
78
79
80 if len(haveAligns) != len(wantAligns) {
81 t.Fatalf("have %d methods with aligned, want %d", len(haveAligns), len(wantAligns))
82 }
83
84 for i := range haveAligns {
85 method := haveAligns[i].Method
86 haveAlign := haveAligns[i].Align
87
88 wantAlign, ok := wantAligns[method]
89 if !ok {
90 t.Errorf("method %s: have aligned %d, want missing entry", method, haveAlign)
91 } else if haveAlign != wantAlign {
92 t.Errorf("method %s: have aligned %d, want %d", method, haveAlign, wantAlign)
93 }
94 }
95 }
96
97
98
99
100 func cgo(t *testing.T, testFile string) string {
101 objDir := t.TempDir()
102 testdata, err := filepath.Abs("testdata")
103 if err != nil {
104 t.Fatal(err)
105 }
106
107 cmd := testenv.Command(t, testenv.GoToolPath(t), "tool", "cgo",
108 "-objdir", objDir,
109 filepath.Join(testdata, testFile))
110
111 cmd.Stderr = new(bytes.Buffer)
112 if err = cmd.Run(); err != nil {
113 t.Fatalf("%#q: %v\n%s", cmd, err, cmd.Stderr)
114 }
115
116 return objDir
117 }
118
119 func parseAlign(filename string) ([]methodAlign, error) {
120 file, err := os.Open(filename)
121 if err != nil {
122 return nil, fmt.Errorf("failed to open file: %w", err)
123 }
124 defer file.Close()
125
126 var results []methodAlign
127 scanner := bufio.NewScanner(file)
128
129
130 funcRegex := regexp.MustCompile(`^struct\s+(\w+)_return\s+(\w+)\(`)
131
132 simpleFuncRegex := regexp.MustCompile(`^Go\w+\s+(\w+)\(`)
133
134 voidFuncRegex := regexp.MustCompile(`^void\s+(\w+)\(`)
135
136 alignRegex := regexp.MustCompile(`__attribute__\(\(aligned\((\d+)\)\)\)`)
137
138 var currentMethod string
139
140 for scanner.Scan() {
141 line := strings.TrimSpace(scanner.Text())
142
143
144 if matches := funcRegex.FindStringSubmatch(line); matches != nil {
145 currentMethod = matches[2]
146 } else if matches := simpleFuncRegex.FindStringSubmatch(line); matches != nil {
147
148 currentMethod = matches[1]
149 } else if matches := voidFuncRegex.FindStringSubmatch(line); matches != nil {
150
151 currentMethod = matches[1]
152 }
153
154
155 if alignMatches := alignRegex.FindStringSubmatch(line); alignMatches != nil && currentMethod != "" {
156 alignStr := alignMatches[1]
157 align, err := strconv.Atoi(alignStr)
158 if err != nil {
159
160 currentMethod = ""
161 continue
162 }
163 results = append(results, methodAlign{
164 Method: currentMethod,
165 Align: align,
166 })
167 currentMethod = ""
168 }
169 }
170
171 if err := scanner.Err(); err != nil {
172 return nil, fmt.Errorf("error reading file: %w", err)
173 }
174
175 return results, nil
176 }
177
View as plain text