Файловый менеджер - Редактировать - /var/www/html/testerrors.zip
Ðазад
PK ! I�X�� � badsym_test.gonu �[��� // Copyright 2020 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package errorstest import ( "bytes" "cmd/internal/quoted" "internal/testenv" "os" "os/exec" "path/filepath" "strings" "testing" "unicode" ) // A manually modified object file could pass unexpected characters // into the files generated by cgo. const magicInput = "abcdefghijklmnopqrstuvwxyz0123" const magicReplace = "\n//go:cgo_ldflag \"-badflag\"\n//" const cSymbol = "BadSymbol" + magicInput + "Name" const cDefSource = "int " + cSymbol + " = 1;" const cRefSource = "extern int " + cSymbol + "; int F() { return " + cSymbol + "; }" // goSource is the source code for the trivial Go file we use. // We will replace TMPDIR with the temporary directory name. const goSource = ` package main // #cgo LDFLAGS: TMPDIR/cbad.o TMPDIR/cbad.so // extern int F(); import "C" func main() { println(C.F()) } ` func TestBadSymbol(t *testing.T) { testenv.MustHaveGoBuild(t) testenv.MustHaveCGO(t) dir := t.TempDir() mkdir := func(base string) string { ret := filepath.Join(dir, base) if err := os.Mkdir(ret, 0755); err != nil { t.Fatal(err) } return ret } cdir := mkdir("c") godir := mkdir("go") makeFile := func(mdir, base, source string) string { ret := filepath.Join(mdir, base) if err := os.WriteFile(ret, []byte(source), 0644); err != nil { t.Fatal(err) } return ret } cDefFile := makeFile(cdir, "cdef.c", cDefSource) cRefFile := makeFile(cdir, "cref.c", cRefSource) ccCmd := cCompilerCmd(t) cCompile := func(arg, base, src string) string { out := filepath.Join(cdir, base) run := append(ccCmd, arg, "-o", out, src) output, err := exec.Command(run[0], run[1:]...).CombinedOutput() if err != nil { t.Log(run) t.Logf("%s", output) t.Fatal(err) } if err := os.Remove(src); err != nil { t.Fatal(err) } return out } // Build a shared library that defines a symbol whose name // contains magicInput. cShared := cCompile("-shared", "c.so", cDefFile) // Build an object file that refers to the symbol whose name // contains magicInput. cObj := cCompile("-c", "c.o", cRefFile) // Rewrite the shared library and the object file, replacing // magicInput with magicReplace. This will have the effect of // introducing a symbol whose name looks like a cgo command. // The cgo tool will use that name when it generates the // _cgo_import.go file, thus smuggling a magic //go:cgo_ldflag // pragma into a Go file. We used to not check the pragmas in // _cgo_import.go. rewrite := func(from, to string) { obj, err := os.ReadFile(from) if err != nil { t.Fatal(err) } if bytes.Count(obj, []byte(magicInput)) == 0 { t.Fatalf("%s: did not find magic string", from) } if len(magicInput) != len(magicReplace) { t.Fatalf("internal test error: different magic lengths: %d != %d", len(magicInput), len(magicReplace)) } obj = bytes.ReplaceAll(obj, []byte(magicInput), []byte(magicReplace)) if err := os.WriteFile(to, obj, 0644); err != nil { t.Fatal(err) } } cBadShared := filepath.Join(godir, "cbad.so") rewrite(cShared, cBadShared) cBadObj := filepath.Join(godir, "cbad.o") rewrite(cObj, cBadObj) goSourceBadObject := strings.ReplaceAll(goSource, "TMPDIR", godir) makeFile(godir, "go.go", goSourceBadObject) makeFile(godir, "go.mod", "module badsym") // Try to build our little package. cmd := exec.Command("go", "build", "-ldflags=-v") cmd.Dir = godir output, err := cmd.CombinedOutput() // The build should fail, but we want it to fail because we // detected the error, not because we passed a bad flag to the // C linker. if err == nil { t.Errorf("go build succeeded unexpectedly") } t.Logf("%s", output) for _, line := range bytes.Split(output, []byte("\n")) { if bytes.Contains(line, []byte("dynamic symbol")) && bytes.Contains(line, []byte("contains unsupported character")) { // This is the error from cgo. continue } // We passed -ldflags=-v to see the external linker invocation, // which should not include -badflag. if bytes.Contains(line, []byte("-badflag")) { t.Error("output should not mention -badflag") } // Also check for compiler errors, just in case. // GCC says "unrecognized command line option". // clang says "unknown argument". if bytes.Contains(line, []byte("unrecognized")) || bytes.Contains(output, []byte("unknown")) { t.Error("problem should have been caught before invoking C linker") } } } func cCompilerCmd(t *testing.T) []string { cc, err := quoted.Split(goEnv(t, "CC")) if err != nil { t.Skipf("parsing go env CC: %s", err) } if len(cc) == 0 { t.Skipf("no C compiler") } testenv.MustHaveExecPath(t, cc[0]) out := goEnv(t, "GOGCCFLAGS") quote := '\000' start := 0 lastSpace := true backslash := false s := string(out) for i, c := range s { if quote == '\000' && unicode.IsSpace(c) { if !lastSpace { cc = append(cc, s[start:i]) lastSpace = true } } else { if lastSpace { start = i lastSpace = false } if quote == '\000' && !backslash && (c == '"' || c == '\'') { quote = c backslash = false } else if !backslash && quote == c { quote = '\000' } else if (quote == '\000' || quote == '"') && !backslash && c == '\\' { backslash = true } else { backslash = false } } } if !lastSpace { cc = append(cc, s[start:]) } // Force reallocation (and avoid aliasing bugs) for tests that append to cc. cc = cc[:len(cc):len(cc)] return cc } func goEnv(t *testing.T, key string) string { out, err := exec.Command("go", "env", key).CombinedOutput() if err != nil { t.Logf("go env %s\n", key) t.Logf("%s", out) t.Fatal(err) } return strings.TrimSpace(string(out)) } PK ! �@� errors_test.gonu �[��� // Copyright 2017 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package errorstest import ( "bytes" "fmt" "internal/testenv" "os" "os/exec" "path/filepath" "regexp" "strconv" "strings" "testing" ) func path(file string) string { return filepath.Join("testdata", file) } func check(t *testing.T, file string) { t.Run(file, func(t *testing.T) { testenv.MustHaveGoBuild(t) testenv.MustHaveCGO(t) t.Parallel() contents, err := os.ReadFile(path(file)) if err != nil { t.Fatal(err) } var errors []*regexp.Regexp for i, line := range bytes.Split(contents, []byte("\n")) { if bytes.HasSuffix(line, []byte("ERROR HERE")) { re := regexp.MustCompile(regexp.QuoteMeta(fmt.Sprintf("%s:%d:", file, i+1))) errors = append(errors, re) continue } if _, frag, ok := bytes.Cut(line, []byte("ERROR HERE: ")); ok { re, err := regexp.Compile(fmt.Sprintf(":%d:.*%s", i+1, frag)) if err != nil { t.Errorf("Invalid regexp after `ERROR HERE: `: %#q", frag) continue } errors = append(errors, re) } if _, frag, ok := bytes.Cut(line, []byte("ERROR MESSAGE: ")); ok { re, err := regexp.Compile(string(frag)) if err != nil { t.Errorf("Invalid regexp after `ERROR MESSAGE: `: %#q", frag) continue } errors = append(errors, re) } } if len(errors) == 0 { t.Fatalf("cannot find ERROR HERE") } expect(t, file, errors) }) } func expect(t *testing.T, file string, errors []*regexp.Regexp) { dir, err := os.MkdirTemp("", filepath.Base(t.Name())) if err != nil { t.Fatal(err) } defer os.RemoveAll(dir) dst := filepath.Join(dir, strings.TrimSuffix(file, ".go")) cmd := exec.Command("go", "build", "-gcflags=-L -e", "-o="+dst, path(file)) // TODO(gri) no need for -gcflags=-L if go tool is adjusted out, err := cmd.CombinedOutput() if err == nil { t.Errorf("expected cgo to fail but it succeeded") } lines := bytes.Split(out, []byte("\n")) for _, re := range errors { found := false for _, line := range lines { if re.Match(line) { t.Logf("found match for %#q: %q", re, line) found = true break } } if !found { t.Errorf("expected error output to contain %#q", re) } } if t.Failed() { t.Logf("actual output:\n%s", out) } } func sizeofLongDouble(t *testing.T) int { testenv.MustHaveGoRun(t) testenv.MustHaveCGO(t) cmd := exec.Command("go", "run", path("long_double_size.go")) out, err := cmd.CombinedOutput() if err != nil { t.Fatalf("%#q: %v:\n%s", strings.Join(cmd.Args, " "), err, out) } i, err := strconv.Atoi(strings.TrimSpace(string(out))) if err != nil { t.Fatalf("long_double_size.go printed invalid size: %s", out) } return i } func TestReportsTypeErrors(t *testing.T) { for _, file := range []string{ "err1.go", "err2.go", "err5.go", "issue11097a.go", "issue11097b.go", "issue18452.go", "issue18889.go", "issue28721.go", "issue33061.go", "issue50710.go", } { check(t, file) } if sizeofLongDouble(t) > 8 { for _, file := range []string{ "err4.go", "issue28069.go", } { check(t, file) } } } func TestToleratesOptimizationFlag(t *testing.T) { for _, cflags := range []string{ "", "-O", } { cflags := cflags t.Run(cflags, func(t *testing.T) { testenv.MustHaveGoBuild(t) testenv.MustHaveCGO(t) t.Parallel() cmd := exec.Command("go", "build", path("issue14669.go")) cmd.Env = append(os.Environ(), "CGO_CFLAGS="+cflags) out, err := cmd.CombinedOutput() if err != nil { t.Errorf("%#q: %v:\n%s", strings.Join(cmd.Args, " "), err, out) } }) } } func TestMallocCrashesOnNil(t *testing.T) { testenv.MustHaveCGO(t) testenv.MustHaveGoRun(t) t.Parallel() cmd := exec.Command("go", "run", path("malloc.go")) out, err := cmd.CombinedOutput() if err == nil { t.Logf("%#q:\n%s", strings.Join(cmd.Args, " "), out) t.Fatalf("succeeded unexpectedly") } } func TestNotMatchedCFunction(t *testing.T) { file := "notmatchedcfunction.go" check(t, file) } PK ! 0ݜ14 4 argposition_test.gonu �[��� // Copyright 2021 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Issue 42580: cmd/cgo: shifting identifier position in ast package errorstest import ( "bytes" "fmt" "go/ast" "go/parser" "go/token" "internal/testenv" "os" "os/exec" "path/filepath" "strings" "testing" ) type ShortPosition struct { Line int Column int Visited bool } type IdentPositionInfo map[string][]ShortPosition type Visitor struct { identPosInfo IdentPositionInfo fset *token.FileSet t *testing.T } func (v *Visitor) Visit(node ast.Node) ast.Visitor { if ident, ok := node.(*ast.Ident); ok { if expectedPositions, ok := v.identPosInfo[ident.Name]; ok { gotMatch := false var errorMessage strings.Builder for caseIndex, expectedPos := range expectedPositions { actualPosition := v.fset.PositionFor(ident.Pos(), true) errorOccured := false if expectedPos.Line != actualPosition.Line { fmt.Fprintf(&errorMessage, "wrong line number for ident %s: expected: %d got: %d\n", ident.Name, expectedPos.Line, actualPosition.Line) errorOccured = true } if expectedPos.Column != actualPosition.Column { fmt.Fprintf(&errorMessage, "wrong column number for ident %s: expected: %d got: %d\n", ident.Name, expectedPos.Column, actualPosition.Column) errorOccured = true } if errorOccured { continue } gotMatch = true expectedPositions[caseIndex].Visited = true } if !gotMatch { v.t.Errorf(errorMessage.String()) } } } return v } func TestArgumentsPositions(t *testing.T) { testenv.MustHaveCGO(t) testenv.MustHaveExec(t) testdata, err := filepath.Abs("testdata") if err != nil { t.Fatal(err) } tmpPath := t.TempDir() dir := filepath.Join(tmpPath, "src", "testpositions") if err := os.MkdirAll(dir, 0755); err != nil { t.Fatal(err) } cmd := exec.Command("go", "tool", "cgo", "-srcdir", testdata, "-objdir", dir, "issue42580.go") cmd.Stderr = new(bytes.Buffer) err = cmd.Run() if err != nil { t.Fatalf("%s: %v\n%s", cmd, err, cmd.Stderr) } mainProcessed, err := os.ReadFile(filepath.Join(dir, "issue42580.cgo1.go")) if err != nil { t.Fatal(err) } fset := token.NewFileSet() f, err := parser.ParseFile(fset, "", mainProcessed, parser.AllErrors) if err != nil { fmt.Println(err) return } expectation := IdentPositionInfo{ "checkedPointer": []ShortPosition{ ShortPosition{ Line: 32, Column: 56, }, }, "singleInnerPointerChecked": []ShortPosition{ ShortPosition{ Line: 37, Column: 91, }, }, "doublePointerChecked": []ShortPosition{ ShortPosition{ Line: 42, Column: 91, }, }, } for _, decl := range f.Decls { if fdecl, ok := decl.(*ast.FuncDecl); ok { ast.Walk(&Visitor{expectation, fset, t}, fdecl.Body) } } for ident, positions := range expectation { for _, position := range positions { if !position.Visited { t.Errorf("Position %d:%d missed for %s ident", position.Line, position.Column, ident) } } } } PK ! '����T �T ptr_test.gonu �[��� // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Tests that cgo detects invalid pointer passing at runtime. package errorstest import ( "bytes" "flag" "fmt" "internal/testenv" "os" "os/exec" "path/filepath" "slices" "strings" "sync/atomic" "testing" ) var tmp = flag.String("tmp", "", "use `dir` for temporary files and do not clean up") // ptrTest is the tests without the boilerplate. type ptrTest struct { name string // for reporting c string // the cgo comment c1 string // cgo comment forced into non-export cgo file imports []string // a list of imports support string // supporting functions body string // the body of the main function extra []extra // extra files fail bool // whether the test should fail expensive bool // whether the test requires the expensive check } type extra struct { name string contents string } var ptrTests = []ptrTest{ { // Passing a pointer to a struct that contains a Go pointer. name: "ptr1", c: `typedef struct s1 { int *p; } s1; void f1(s1 *ps) {}`, body: `C.f1(&C.s1{new(C.int)})`, fail: true, }, { // Passing a pointer to a struct that contains a Go pointer. name: "ptr2", c: `typedef struct s2 { int *p; } s2; void f2(s2 *ps) {}`, body: `p := &C.s2{new(C.int)}; C.f2(p)`, fail: true, }, { // Passing a pointer to an int field of a Go struct // that (irrelevantly) contains a Go pointer. name: "ok1", c: `struct s3 { int i; int *p; }; void f3(int *p) {}`, body: `p := &C.struct_s3{i: 0, p: new(C.int)}; C.f3(&p.i)`, fail: false, }, { // Passing a pointer to a pointer field of a Go struct. name: "ptrfield", c: `struct s4 { int i; int *p; }; void f4(int **p) {}`, body: `p := &C.struct_s4{i: 0, p: new(C.int)}; C.f4(&p.p)`, fail: true, }, { // Passing a pointer to a pointer field of a Go // struct, where the field does not contain a Go // pointer, but another field (irrelevantly) does. name: "ptrfieldok", c: `struct s5 { int *p1; int *p2; }; void f5(int **p) {}`, body: `p := &C.struct_s5{p1: nil, p2: new(C.int)}; C.f5(&p.p1)`, fail: false, }, { // Passing the address of a slice with no Go pointers. name: "sliceok1", c: `void f6(void **p) {}`, imports: []string{"unsafe"}, body: `s := []unsafe.Pointer{nil}; C.f6(&s[0])`, fail: false, }, { // Passing the address of a slice with a Go pointer. name: "sliceptr1", c: `void f7(void **p) {}`, imports: []string{"unsafe"}, body: `i := 0; s := []unsafe.Pointer{unsafe.Pointer(&i)}; C.f7(&s[0])`, fail: true, }, { // Passing the address of a slice with a Go pointer, // where we are passing the address of an element that // is not a Go pointer. name: "sliceptr2", c: `void f8(void **p) {}`, imports: []string{"unsafe"}, body: `i := 0; s := []unsafe.Pointer{nil, unsafe.Pointer(&i)}; C.f8(&s[0])`, fail: true, }, { // Passing the address of a slice that is an element // in a struct only looks at the slice. name: "sliceok2", c: `void f9(void **p) {}`, imports: []string{"unsafe"}, support: `type S9 struct { p *int; s []unsafe.Pointer }`, body: `i := 0; p := &S9{p:&i, s:[]unsafe.Pointer{nil}}; C.f9(&p.s[0])`, fail: false, }, { // Passing the address of a slice of an array that is // an element in a struct, with a type conversion. name: "sliceok3", c: `void f10(void* p) {}`, imports: []string{"unsafe"}, support: `type S10 struct { p *int; a [4]byte }`, body: `i := 0; p := &S10{p:&i}; s := p.a[:]; C.f10(unsafe.Pointer(&s[0]))`, fail: false, }, { // Passing the address of a slice of an array that is // an element in a struct, with a type conversion. name: "sliceok4", c: `typedef void* PV11; void f11(PV11 p) {}`, imports: []string{"unsafe"}, support: `type S11 struct { p *int; a [4]byte }`, body: `i := 0; p := &S11{p:&i}; C.f11(C.PV11(unsafe.Pointer(&p.a[0])))`, fail: false, }, { // Passing the address of a static variable with no // pointers doesn't matter. name: "varok", c: `void f12(char** parg) {}`, support: `var hello12 = [...]C.char{'h', 'e', 'l', 'l', 'o'}`, body: `parg := [1]*C.char{&hello12[0]}; C.f12(&parg[0])`, fail: false, }, { // Passing the address of a static variable with // pointers does matter. name: "var1", c: `void f13(char*** parg) {}`, support: `var hello13 = [...]*C.char{new(C.char)}`, body: `parg := [1]**C.char{&hello13[0]}; C.f13(&parg[0])`, fail: true, }, { // Storing a Go pointer into C memory should fail. name: "barrier", c: `#include <stdlib.h> char **f14a() { return malloc(sizeof(char*)); } void f14b(char **p) {}`, body: `p := C.f14a(); *p = new(C.char); C.f14b(p)`, fail: true, expensive: true, }, { // Storing a pinned Go pointer into C memory should succeed. name: "barrierpinnedok", c: `#include <stdlib.h> char **f14a2() { return malloc(sizeof(char*)); } void f14b2(char **p) {}`, imports: []string{"runtime"}, body: `var pinr runtime.Pinner; p := C.f14a2(); x := new(C.char); pinr.Pin(x); *p = x; C.f14b2(p); pinr.Unpin()`, fail: false, expensive: true, }, { // Storing a Go pointer into C memory by assigning a // large value should fail. name: "barrierstruct", c: `#include <stdlib.h> struct s15 { char *a[10]; }; struct s15 *f15() { return malloc(sizeof(struct s15)); } void f15b(struct s15 *p) {}`, body: `p := C.f15(); p.a = [10]*C.char{new(C.char)}; C.f15b(p)`, fail: true, expensive: true, }, { // Storing a Go pointer into C memory using a slice // copy should fail. name: "barrierslice", c: `#include <stdlib.h> struct s16 { char *a[10]; }; struct s16 *f16() { return malloc(sizeof(struct s16)); } void f16b(struct s16 *p) {}`, body: `p := C.f16(); copy(p.a[:], []*C.char{new(C.char)}); C.f16b(p)`, fail: true, expensive: true, }, { // A very large value uses a GC program, which is a // different code path. name: "barriergcprogarray", c: `#include <stdlib.h> struct s17 { char *a[32769]; }; struct s17 *f17() { return malloc(sizeof(struct s17)); } void f17b(struct s17 *p) {}`, body: `p := C.f17(); p.a = [32769]*C.char{new(C.char)}; C.f17b(p)`, fail: true, expensive: true, }, { // Similar case, with a source on the heap. name: "barriergcprogarrayheap", c: `#include <stdlib.h> struct s18 { char *a[32769]; }; struct s18 *f18() { return malloc(sizeof(struct s18)); } void f18b(struct s18 *p) {} void f18c(void *p) {}`, imports: []string{"unsafe"}, body: `p := C.f18(); n := &[32769]*C.char{new(C.char)}; p.a = *n; C.f18b(p); n[0] = nil; C.f18c(unsafe.Pointer(n))`, fail: true, expensive: true, }, { // A GC program with a struct. name: "barriergcprogstruct", c: `#include <stdlib.h> struct s19a { char *a[32769]; }; struct s19b { struct s19a f; }; struct s19b *f19() { return malloc(sizeof(struct s19b)); } void f19b(struct s19b *p) {}`, body: `p := C.f19(); p.f = C.struct_s19a{[32769]*C.char{new(C.char)}}; C.f19b(p)`, fail: true, expensive: true, }, { // Similar case, with a source on the heap. name: "barriergcprogstructheap", c: `#include <stdlib.h> struct s20a { char *a[32769]; }; struct s20b { struct s20a f; }; struct s20b *f20() { return malloc(sizeof(struct s20b)); } void f20b(struct s20b *p) {} void f20c(void *p) {}`, imports: []string{"unsafe"}, body: `p := C.f20(); n := &C.struct_s20a{[32769]*C.char{new(C.char)}}; p.f = *n; C.f20b(p); n.a[0] = nil; C.f20c(unsafe.Pointer(n))`, fail: true, expensive: true, }, { // Exported functions may not return Go pointers. name: "export1", c: `#ifdef _WIN32 __declspec(dllexport) #endif extern unsigned char *GoFn21();`, support: `//export GoFn21 func GoFn21() *byte { return new(byte) }`, body: `C.GoFn21()`, fail: true, }, { // Returning a C pointer is fine. name: "exportok", c: `#include <stdlib.h> #ifdef _WIN32 __declspec(dllexport) #endif extern unsigned char *GoFn22();`, support: `//export GoFn22 func GoFn22() *byte { return (*byte)(C.malloc(1)) }`, body: `C.GoFn22()`, }, { // Passing a Go string is fine. name: "passstring", c: `#include <stddef.h> typedef struct { const char *p; ptrdiff_t n; } gostring23; gostring23 f23(gostring23 s) { return s; }`, imports: []string{"unsafe"}, body: `s := "a"; r := C.f23(*(*C.gostring23)(unsafe.Pointer(&s))); if *(*string)(unsafe.Pointer(&r)) != s { panic(r) }`, }, { // Passing a slice of Go strings fails. name: "passstringslice", c: `void f24(void *p) {}`, imports: []string{"strings", "unsafe"}, support: `type S24 struct { a [1]string }`, body: `s := S24{a:[1]string{strings.Repeat("a", 2)}}; C.f24(unsafe.Pointer(&s.a[0]))`, fail: true, }, { // Exported functions may not return strings. name: "retstring", c: `extern void f25();`, imports: []string{"strings"}, support: `//export GoStr25 func GoStr25() string { return strings.Repeat("a", 2) }`, body: `C.f25()`, c1: `#include <stddef.h> typedef struct { const char *p; ptrdiff_t n; } gostring25; extern gostring25 GoStr25(); void f25() { GoStr25(); }`, fail: true, }, { // Don't check non-pointer data. // Uses unsafe code to get a pointer we shouldn't check. // Although we use unsafe, the uintptr represents an integer // that happens to have the same representation as a pointer; // that is, we are testing something that is not unsafe. name: "ptrdata1", c: `#include <stdlib.h> void f26(void* p) {}`, imports: []string{"unsafe"}, support: `type S26 struct { p *int; a [8*8]byte; u uintptr }`, body: `i := 0; p := &S26{u:uintptr(unsafe.Pointer(&i))}; q := (*S26)(C.malloc(C.size_t(unsafe.Sizeof(*p)))); *q = *p; C.f26(unsafe.Pointer(q))`, fail: false, }, { // Like ptrdata1, but with a type that uses a GC program. name: "ptrdata2", c: `#include <stdlib.h> void f27(void* p) {}`, imports: []string{"unsafe"}, support: `type S27 struct { p *int; a [32769*8]byte; q *int; u uintptr }`, body: `i := 0; p := S27{u:uintptr(unsafe.Pointer(&i))}; q := (*S27)(C.malloc(C.size_t(unsafe.Sizeof(p)))); *q = p; C.f27(unsafe.Pointer(q))`, fail: false, }, { // Check deferred pointers when they are used, not // when the defer statement is run. name: "defer1", c: `typedef struct s28 { int *p; } s28; void f28(s28 *ps) {}`, body: `p := &C.s28{}; defer C.f28(p); p.p = new(C.int)`, fail: true, }, { // Check a pointer to a union if the union has any // pointer fields. name: "union1", c: `typedef union { char **p; unsigned long i; } u29; void f29(u29 *pu) {}`, imports: []string{"unsafe"}, body: `var b C.char; p := &b; C.f29((*C.u29)(unsafe.Pointer(&p)))`, fail: true, }, { // Don't check a pointer to a union if the union does // not have any pointer fields. // Like ptrdata1 above, the uintptr represents an // integer that happens to have the same // representation as a pointer. name: "union2", c: `typedef union { unsigned long i; } u39; void f39(u39 *pu) {}`, imports: []string{"unsafe"}, body: `var b C.char; p := &b; C.f39((*C.u39)(unsafe.Pointer(&p)))`, fail: false, }, { // Test preemption while entering a cgo call. Issue #21306. name: "preemptduringcall", c: `void f30() {}`, imports: []string{"runtime", "sync"}, body: `var wg sync.WaitGroup; wg.Add(100); for i := 0; i < 100; i++ { go func(i int) { for j := 0; j < 100; j++ { C.f30(); runtime.GOMAXPROCS(i) }; wg.Done() }(i) }; wg.Wait()`, fail: false, }, { // Test poller deadline with cgocheck=2. Issue #23435. name: "deadline", c: `#define US31 10`, imports: []string{"os", "time"}, body: `r, _, _ := os.Pipe(); r.SetDeadline(time.Now().Add(C.US31 * time.Microsecond))`, fail: false, }, { // Test for double evaluation of channel receive. name: "chanrecv", c: `void f32(char** p) {}`, imports: []string{"time"}, body: `c := make(chan []*C.char, 2); c <- make([]*C.char, 1); go func() { time.Sleep(10 * time.Second); panic("received twice from chan") }(); C.f32(&(<-c)[0]);`, fail: false, }, { // Test that converting the address of a struct field // to unsafe.Pointer still just checks that field. // Issue #25941. name: "structfield", c: `void f33(void* p) {}`, imports: []string{"unsafe"}, support: `type S33 struct { p *int; a [8]byte; u uintptr }`, body: `s := &S33{p: new(int)}; C.f33(unsafe.Pointer(&s.a))`, fail: false, }, { // Test that converting multiple struct field // addresses to unsafe.Pointer still just checks those // fields. Issue #25941. name: "structfield2", c: `void f34(void* p, int r, void* s) {}`, imports: []string{"unsafe"}, support: `type S34 struct { a [8]byte; p *int; b int64; }`, body: `s := &S34{p: new(int)}; C.f34(unsafe.Pointer(&s.a), 32, unsafe.Pointer(&s.b))`, fail: false, }, { // Test that second argument to cgoCheckPointer is // evaluated when a deferred function is deferred, not // when it is run. name: "defer2", c: `void f35(char **pc) {}`, support: `type S35a struct { s []*C.char }; type S35b struct { ps *S35a }`, body: `p := &S35b{&S35a{[]*C.char{nil}}}; defer C.f35(&p.ps.s[0]); p.ps = nil`, fail: false, }, { // Test that indexing into a function call still // examines only the slice being indexed. name: "buffer", c: `void f36(void *p) {}`, imports: []string{"bytes", "unsafe"}, body: `var b bytes.Buffer; b.WriteString("a"); C.f36(unsafe.Pointer(&b.Bytes()[0]))`, fail: false, }, { // Test that bgsweep releasing a finalizer is OK. name: "finalizer", c: `// Nothing to declare.`, imports: []string{"os"}, support: `func open37() { os.Open(os.Args[0]) }; var G37 [][]byte`, body: `for i := 0; i < 10000; i++ { G37 = append(G37, make([]byte, 4096)); if i % 100 == 0 { G37 = nil; open37() } }`, fail: false, }, { // Test that converting generated struct to interface is OK. name: "structof", c: `// Nothing to declare.`, imports: []string{"reflect"}, support: `type MyInt38 int; func (i MyInt38) Get() int { return int(i) }; type Getter38 interface { Get() int }`, body: `t := reflect.StructOf([]reflect.StructField{{Name: "MyInt38", Type: reflect.TypeOf(MyInt38(0)), Anonymous: true}}); v := reflect.New(t).Elem(); v.Interface().(Getter38).Get()`, fail: false, }, { // Test that a converted address of a struct field results // in a check for just that field and not the whole struct. name: "structfieldcast", c: `struct S40i { int i; int* p; }; void f40(struct S40i* p) {}`, support: `type S40 struct { p *int; a C.struct_S40i }`, body: `s := &S40{p: new(int)}; C.f40((*C.struct_S40i)(&s.a))`, fail: false, }, { // Test that we handle unsafe.StringData. name: "stringdata", c: `void f41(void* p) {}`, imports: []string{"unsafe"}, body: `s := struct { a [4]byte; p *int }{p: new(int)}; str := unsafe.String(&s.a[0], 4); C.f41(unsafe.Pointer(unsafe.StringData(str)))`, fail: false, }, { name: "slicedata", c: `void f42(void* p) {}`, imports: []string{"unsafe"}, body: `s := []*byte{nil, new(byte)}; C.f42(unsafe.Pointer(unsafe.SliceData(s)))`, fail: true, }, { name: "slicedata2", c: `void f43(void* p) {}`, imports: []string{"unsafe"}, body: `s := struct { a [4]byte; p *int }{p: new(int)}; C.f43(unsafe.Pointer(unsafe.SliceData(s.a[:])))`, fail: false, }, } func TestPointerChecks(t *testing.T) { testenv.MustHaveGoBuild(t) testenv.MustHaveCGO(t) var gopath string var dir string if *tmp != "" { gopath = *tmp dir = "" } else { d, err := os.MkdirTemp("", filepath.Base(t.Name())) if err != nil { t.Fatal(err) } dir = d gopath = d } exe := buildPtrTests(t, gopath, false) exe2 := buildPtrTests(t, gopath, true) // We (TestPointerChecks) return before the parallel subtest functions do, // so we can't just defer os.RemoveAll(dir). Instead we have to wait for // the parallel subtests to finish. This code looks racy but is not: // the add +1 run in serial before testOne blocks. The -1 run in parallel // after testOne finishes. var pending int32 for _, pt := range ptrTests { pt := pt t.Run(pt.name, func(t *testing.T) { atomic.AddInt32(&pending, +1) defer func() { if atomic.AddInt32(&pending, -1) == 0 { os.RemoveAll(dir) } }() testOne(t, pt, exe, exe2) }) } } func buildPtrTests(t *testing.T, gopath string, cgocheck2 bool) (exe string) { src := filepath.Join(gopath, "src", "ptrtest") if err := os.MkdirAll(src, 0777); err != nil { t.Fatal(err) } if err := os.WriteFile(filepath.Join(src, "go.mod"), []byte("module ptrtest\ngo 1.20"), 0666); err != nil { t.Fatal(err) } // Prepare two cgo inputs: one for standard cgo and one for //export cgo. // (The latter cannot have C definitions, only declarations.) var cgo1, cgo2 bytes.Buffer fmt.Fprintf(&cgo1, "package main\n\n/*\n") fmt.Fprintf(&cgo2, "package main\n\n/*\n") // C code for _, pt := range ptrTests { cgo := &cgo1 if strings.Contains(pt.support, "//export") { cgo = &cgo2 } fmt.Fprintf(cgo, "%s\n", pt.c) fmt.Fprintf(&cgo1, "%s\n", pt.c1) } fmt.Fprintf(&cgo1, "*/\nimport \"C\"\n\n") fmt.Fprintf(&cgo2, "*/\nimport \"C\"\n\n") // Imports did1 := make(map[string]bool) did2 := make(map[string]bool) did1["os"] = true // for ptrTestMain fmt.Fprintf(&cgo1, "import \"os\"\n") for _, pt := range ptrTests { did := did1 cgo := &cgo1 if strings.Contains(pt.support, "//export") { did = did2 cgo = &cgo2 } for _, imp := range pt.imports { if !did[imp] { did[imp] = true fmt.Fprintf(cgo, "import %q\n", imp) } } } // Func support and bodies. for _, pt := range ptrTests { cgo := &cgo1 if strings.Contains(pt.support, "//export") { cgo = &cgo2 } fmt.Fprintf(cgo, "%s\nfunc %s() {\n%s\n}\n", pt.support, pt.name, pt.body) } // Func list and main dispatch. fmt.Fprintf(&cgo1, "var funcs = map[string]func() {\n") for _, pt := range ptrTests { fmt.Fprintf(&cgo1, "\t%q: %s,\n", pt.name, pt.name) } fmt.Fprintf(&cgo1, "}\n\n") fmt.Fprintf(&cgo1, "%s\n", ptrTestMain) if err := os.WriteFile(filepath.Join(src, "cgo1.go"), cgo1.Bytes(), 0666); err != nil { t.Fatal(err) } if err := os.WriteFile(filepath.Join(src, "cgo2.go"), cgo2.Bytes(), 0666); err != nil { t.Fatal(err) } exeName := "ptrtest.exe" if cgocheck2 { exeName = "ptrtest2.exe" } cmd := exec.Command("go", "build", "-o", exeName) cmd.Dir = src cmd.Env = append(os.Environ(), "GOPATH="+gopath) // Set or remove cgocheck2 from the environment. goexperiment := strings.Split(os.Getenv("GOEXPERIMENT"), ",") if len(goexperiment) == 1 && goexperiment[0] == "" { goexperiment = nil } i := slices.Index(goexperiment, "cgocheck2") changed := false if cgocheck2 && i < 0 { goexperiment = append(goexperiment, "cgocheck2") changed = true } else if !cgocheck2 && i >= 0 { goexperiment = append(goexperiment[:i], goexperiment[i+1:]...) changed = true } if changed { cmd.Env = append(cmd.Env, "GOEXPERIMENT="+strings.Join(goexperiment, ",")) } out, err := cmd.CombinedOutput() if err != nil { t.Fatalf("go build: %v\n%s", err, out) } return filepath.Join(src, exeName) } const ptrTestMain = ` func main() { for _, arg := range os.Args[1:] { f := funcs[arg] if f == nil { panic("missing func "+arg) } f() } } ` var csem = make(chan bool, 16) func testOne(t *testing.T, pt ptrTest, exe, exe2 string) { t.Parallel() // Run the tests in parallel, but don't run too many // executions in parallel, to avoid overloading the system. runcmd := func(cgocheck string) ([]byte, error) { csem <- true defer func() { <-csem }() x := exe if cgocheck == "2" { x = exe2 cgocheck = "1" } cmd := exec.Command(x, pt.name) cmd.Env = append(os.Environ(), "GODEBUG=cgocheck="+cgocheck) return cmd.CombinedOutput() } if pt.expensive { buf, err := runcmd("1") if err != nil { t.Logf("%s", buf) if pt.fail { t.Fatalf("test marked expensive, but failed when not expensive: %v", err) } else { t.Errorf("failed unexpectedly with GODEBUG=cgocheck=1: %v", err) } } } cgocheck := "" if pt.expensive { cgocheck = "2" } buf, err := runcmd(cgocheck) if pt.fail { if err == nil { t.Logf("%s", buf) t.Fatalf("did not fail as expected") } else if !bytes.Contains(buf, []byte("Go pointer")) { t.Logf("%s", buf) t.Fatalf("did not print expected error (failed with %v)", err) } } else { if err != nil { t.Logf("%s", buf) t.Fatalf("failed unexpectedly: %v", err) } if !pt.expensive { // Make sure it passes with the expensive checks. buf, err := runcmd("2") if err != nil { t.Logf("%s", buf) t.Fatalf("failed unexpectedly with expensive checks: %v", err) } } } if pt.fail { buf, err := runcmd("0") if err != nil { t.Logf("%s", buf) t.Fatalf("failed unexpectedly with GODEBUG=cgocheck=0: %v", err) } } } PK ! ��Y Y testdata/issue42580.gonu �[��� // Copyright 2021 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Issue 42580: cmd/cgo: shifting identifier position in ast package cgotest // typedef int (*intFunc) (); // // char* strarg = ""; // // int func_with_char(char* arg, void* dummy) // {return 5;} // // int* get_arr(char* arg, void* dummy) // {return NULL;} import "C" import "unsafe" // Test variables var ( checkedPointer = []byte{1} doublePointerChecked = []byte{1} singleInnerPointerChecked = []byte{1} ) // This test checks the positions of variable identifiers. // Changing the positions of the test variables idents after this point will break the test. func TestSingleArgumentCast() C.int { retcode := C.func_with_char((*C.char)(unsafe.Pointer(&checkedPointer[0])), unsafe.Pointer(C.strarg)) return retcode } func TestSingleArgumentCastRecFuncAsSimpleArg() C.int { retcode := C.func_with_char((*C.char)(unsafe.Pointer(C.get_arr((*C.char)(unsafe.Pointer(&singleInnerPointerChecked[0])), unsafe.Pointer(C.strarg)))), nil) return retcode } func TestSingleArgumentCastRecFunc() C.int { retcode := C.func_with_char((*C.char)(unsafe.Pointer(C.get_arr((*C.char)(unsafe.Pointer(&doublePointerChecked[0])), unsafe.Pointer(C.strarg)))), unsafe.Pointer(C.strarg)) return retcode } PK ! H�&Pu u testdata/issue33061.gonu �[��� // Copyright 2019 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // cgo shouldn't crash if there is an extra argument with a C reference. package main // void F(void* p) {}; import "C" import "unsafe" func F() { var i int C.F(unsafe.Pointer(&i), C.int(0)) // ERROR HERE } PK ! �&' ' testdata/issue50710.gonu �[��� // Copyright 2022 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package main // size_t StrLen(_GoString_ s) { // return _GoStringLen(s); // } import "C" func main() { C.StrLen1() // ERROR HERE } PK ! ��gp p testdata/issue14669.gonu �[��� // Copyright 2016 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Issue 14669: test that fails when build with CGO_CFLAGS selecting // optimization. package p /* const int E = 1; typedef struct s { int c; } s; */ import "C" func F() { _ = C.s{ c: C.E, } } PK ! �1 testdata/issue11097a.gonu �[��� // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package main /* //enum test { foo, bar }; */ import "C" func main() { var a = C.enum_test(1) // ERROR HERE _ = a } PK ! �*&� � testdata/err1.gonu �[��� // Copyright 2013 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package main /* #cgo LDFLAGS: -L/nonexist void test() { xxx; // ERROR HERE } // Issue 8442. Cgo output unhelpful error messages for // invalid C preambles. void issue8442foo(UNDEF*); // ERROR HERE */ import "C" func main() { C.test() } PK ! 3-� testdata/issue11097b.gonu �[��� // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package main /* //enum test { foo, bar }; */ import "C" func main() { p := new(C.enum_test) // ERROR HERE _ = p } PK ! ��s testdata/err2.gonu �[��� // Copyright 2013 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package main /* #include <stdio.h> typedef struct foo foo_t; typedef struct bar bar_t; foo_t *foop; long double x = 0; static int transform(int x) { return x; } typedef void v; void F(v** p) {} void fvi(void *p, int x) {} void fppi(int** p) {} int i; void fi(int i) {} */ import "C" import ( "unsafe" ) func main() { s := "" _ = s C.malloc(s) // ERROR HERE x := (*C.bar_t)(nil) C.foop = x // ERROR HERE // issue 13129: used to output error about C.unsignedshort with CC=clang var x1 C.ushort x1 = int(0) // ERROR HERE: C\.ushort // issue 13423 _ = C.fopen() // ERROR HERE // issue 13467 var x2 rune = '✈' var _ rune = C.transform(x2) // ERROR HERE: C\.int // issue 13635: used to output error about C.unsignedchar. // This test tests all such types. var ( _ C.uchar = "uc" // ERROR HERE: C\.uchar _ C.schar = "sc" // ERROR HERE: C\.schar _ C.ushort = "us" // ERROR HERE: C\.ushort _ C.uint = "ui" // ERROR HERE: C\.uint _ C.ulong = "ul" // ERROR HERE: C\.ulong _ C.longlong = "ll" // ERROR HERE: C\.longlong _ C.ulonglong = "ull" // ERROR HERE: C\.ulonglong _ C.complexfloat = "cf" // ERROR HERE: C\.complexfloat _ C.complexdouble = "cd" // ERROR HERE: C\.complexdouble ) // issue 13830 // cgo converts C void* to Go unsafe.Pointer, so despite appearances C // void** is Go *unsafe.Pointer. This test verifies that we detect the // problem at build time. { type v [0]byte f := func(p **v) { C.F((**C.v)(unsafe.Pointer(p))) // ERROR HERE } var p *v f(&p) } // issue 16116 _ = C.fvi(1) // ERROR HERE // Issue 16591: Test that we detect an invalid call that was being // hidden by a type conversion inserted by cgo checking. { type x *C.int var p *x C.fppi(p) // ERROR HERE } // issue 26745 _ = func(i int) int { // typecheck reports at column 14 ('+'), but types2 reports at // column 10 ('C'). // TODO(mdempsky): Investigate why, and see if types2 can be // updated to match typecheck behavior. return C.i + 1 // ERROR HERE: \b(10|14)\b } _ = func(i int) { // typecheck reports at column 7 ('('), but types2 reports at // column 8 ('i'). The types2 position is more correct, but // updating typecheck here is fundamentally challenging because of // IR limitations. C.fi(i) // ERROR HERE: \b(7|8)\b } C.fi = C.fi // ERROR HERE } PK ! m.# testdata/err4.gonu �[��� // Copyright 2017 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package main /* long double x = 0; */ import "C" func main() { _ = C.x // ERROR HERE _ = C.x } PK ! ��}� � testdata/issue28721.gonu �[��� // Copyright 2018 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // cgo should reject the use of mangled C names. package main /* typedef struct a { int i; } a; void fn(void) {} */ import "C" type B _Ctype_struct_a // ERROR HERE var a _Ctype_struct_a // ERROR HERE type A struct { a *_Ctype_struct_a // ERROR HERE } var notExist _Ctype_NotExist // ERROR HERE func main() { _Cfunc_fn() // ERROR HERE } PK ! oqϔF F testdata/issue18889.gonu �[��� package main import "C" func main() { _ = C.malloc // ERROR HERE } PK ! g��1 1 testdata/long_double_size.gonu �[��� // Copyright 2017 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package main /* const int sizeofLongDouble = sizeof(long double); */ import "C" import "fmt" func main() { fmt.Println(C.sizeofLongDouble) } PK ! ���� � testdata/notmatchedcfunction.gonu �[��� // Copyright 2023 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package main /* // TODO(#56378): change back to "#cgo noescape noMatchedCFunction: no matched C function" in Go 1.23 // ERROR MESSAGE: #cgo noescape disabled until Go 1.23 #cgo noescape noMatchedCFunction */ import "C" func main() { } PK ! J�r+ + testdata/issue28069.gonu �[��� // Copyright 2018 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Test that the error message for an unrepresentable typedef in a // union appears on the right line. This test is only run if the size // of long double is larger than 64. package main /* typedef long double Float128; typedef struct SV { union { Float128 float128; } value; } SV; */ import "C" type ts struct { tv *C.SV // ERROR HERE } func main() {} PK ! ��� � testdata/malloc.gonu �[��� // Copyright 2016 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Test that C.malloc does not return nil. package main // #include <stdlib.h> import "C" import ( "fmt" "runtime" ) func main() { var size C.size_t size-- // The Dragonfly libc succeeds when asked to allocate // 0xffffffffffffffff bytes, so pass a different value that // causes it to fail. if runtime.GOOS == "dragonfly" { size = C.size_t(0x7fffffff << (32 * (^uintptr(0) >> 63))) } p := C.malloc(size) if p == nil { fmt.Println("malloc: C.malloc returned nil") // Just exit normally--the test script expects this // program to crash, so exiting normally indicates failure. } } PK ! ױ$0 0 testdata/err5.gonu �[��� // Copyright 2023 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package main //line /tmp/_cgo_.go:1 //go:cgo_dynamic_linker "/elf/interp" // ERROR MESSAGE: only allowed in cgo-generated code func main() {} PK ! �y�X� � testdata/issue18452.gonu �[��� // Copyright 2017 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Issue 18452: show pos info in undefined name errors package p import ( "C" "fmt" ) func a() { fmt.Println("Hello, world!") C.function_that_does_not_exist() // ERROR HERE C.pi // ERROR HERE } PK ! I�X�� � badsym_test.gonu �[��� PK ! �@� errors_test.gonu �[��� PK ! 0ݜ14 4 A'