x/sys/windows: use SyscallN in mkwinsyscall

The mkwinsyscall command has a hard limit of 15 on the
number of syscall arguments. Windows has several system
calls with more than 15 arguments, for example CreateFontPackage
has 18 arguments.

If the number of arguments is higher than 15 we use SyscallN.

Updates golang/go#57914
This commit is contained in:
Mauri de Souza Meneguzzo
2023-08-11 21:41:06 -03:00
parent 552c4e8192
commit 1f1e96fab7
2 changed files with 70 additions and 3 deletions

View File

@@ -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}}

View File

@@ -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())
}
})
}
}