diff --git a/windows/mkwinsyscall/mkwinsyscall.go b/windows/mkwinsyscall/mkwinsyscall.go index 11f4873bc..3947092c5 100644 --- a/windows/mkwinsyscall/mkwinsyscall.go +++ b/windows/mkwinsyscall/mkwinsyscall.go @@ -57,7 +57,6 @@ import ( "go/parser" "go/token" "io" - "io/ioutil" "log" "os" "path/filepath" @@ -568,6 +567,8 @@ func (f *Fn) SyscallParamCount() int { return 12 case n <= 15: return 15 + case n <= 42: // current SyscallN limit + return n default: panic("too many arguments to system call") } @@ -579,6 +580,9 @@ func (f *Fn) Syscall() string { if c == 3 { return syscalldot() + "Syscall" } + if c > 15 { + return syscalldot() + "SyscallN" + } return syscalldot() + "Syscall" + strconv.Itoa(c) } @@ -923,7 +927,7 @@ func main() { if *filename == "" { _, err = os.Stdout.Write(data) } else { - err = ioutil.WriteFile(*filename, data, 0644) + err = os.WriteFile(*filename, data, 0644) } if err != nil { log.Fatal(err) @@ -1011,7 +1015,7 @@ func {{.HelperName}}({{.HelperParamList}}) {{template "results" .}}{ {{define "results"}}{{if .Rets.List}}{{.Rets.List}} {{end}}{{end}} -{{define "syscall"}}{{.Rets.SetReturnValuesCode}}{{.Syscall}}(proc{{.DLLFuncName}}.Addr(), {{.ParamCount}}, {{.SyscallParamList}}){{end}} +{{define "syscall"}}{{.Rets.SetReturnValuesCode}}{{.Syscall}}(proc{{.DLLFuncName}}.Addr(),{{if le .ParamCount 15}} {{.ParamCount}},{{end}} {{.SyscallParamList}}){{end}} {{define "tmpvarsreadback"}}{{range .Params}}{{if .TmpVarReadbackCode}} {{.TmpVarReadbackCode}}{{end}}{{end}}{{end}} diff --git a/windows/mkwinsyscall/mkwinsyscall_test.go b/windows/mkwinsyscall/mkwinsyscall_test.go index cabbf4031..b000e6b5c 100644 --- a/windows/mkwinsyscall/mkwinsyscall_test.go +++ b/windows/mkwinsyscall/mkwinsyscall_test.go @@ -9,6 +9,7 @@ import ( "go/format" "os" "path/filepath" + "strings" "testing" ) @@ -48,3 +49,65 @@ func TestDLLFilenameEscaping(t *testing.T) { }) } } + +func TestSyscallXGeneration(t *testing.T) { + tests := []struct { + name string + wantsysfunc string + sig string + }{ + { + name: "syscall with 2 params", + wantsysfunc: "syscall.Syscall", + sig: "Example(a1 *uint16, a2 *uint16) = ", + }, + { + name: "syscall with 6 params", + wantsysfunc: "syscall.Syscall6", + sig: "Example(a1 *uint, a2 *uint, a3 *uint, a4 *uint, a5 *uint, a6 *uint) = ", + }, + { + name: "syscall with 15 params", + wantsysfunc: "syscall.Syscall15", + sig: strings.ReplaceAll(`Example(a1 *uint, a2 *uint, a3 *uint, a4 *uint, a5 *uint, a6 *uint, + a7 *uint, a8 *uint, a9 *uint, a10 *uint, a11 *uint, a12 *uint, + a13 *uint, a14 *uint, a15 *uint) = `, "\n", ""), + }, + { + name: "syscall with 18 params", + wantsysfunc: "syscall.SyscallN", + sig: strings.ReplaceAll(`Example(a1 *uint, a2 *uint, a3 *uint, a4 *uint, a5 *uint, a6 *uint, + a7 *uint, a8 *uint, a9 *uint, a10 *uint, a11 *uint, a12 *uint, + a13 *uint, a14 *uint, a15 *uint, a16 *uint, a17 *uint, a18 *uint) = `, "\n", ""), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Write the syscall into a temp file for testing. + prefix := "package windows\n//sys " + tt.sig + suffix := ".Example" + name := filepath.Join(t.TempDir(), "syscall.go") + if err := os.WriteFile(name, []byte(prefix+"example"+suffix), 0666); err != nil { + t.Fatal(err) + } + + // Ensure parsing, generating, and formatting run without errors. + // This is good enough to show that escaping is working. + src, err := ParseFiles([]string{name}) + if err != nil { + t.Fatal(err) + } + var buf bytes.Buffer + if err := src.Generate(&buf); err != nil { + t.Fatal(err) + } + if _, err := format.Source(buf.Bytes()); err != nil { + t.Fatal(err) + } + + if !strings.Contains(buf.String(), tt.wantsysfunc+"(") { + t.Fatalf("expected syscall func %q in buffer %s", tt.wantsysfunc, buf.String()) + } + }) + } +}