diff options
author | Alex Brainman <alex.brainman@gmail.com> | 2015-05-22 10:58:57 +1000 |
---|---|---|
committer | Alex Brainman <alex.brainman@gmail.com> | 2015-06-29 02:45:45 +0000 |
commit | 85d4d46f3cefceb87924ad1b0acec9f753413736 (patch) | |
tree | 30455427e19e41a0b87893ebbdd6cf0f05252dd1 /src/runtime/syscall_windows_test.go | |
parent | 3b7841b3aff9204f054ffabbe4dd39d3e3dd3e91 (diff) | |
download | go-85d4d46f3cefceb87924ad1b0acec9f753413736.tar.gz go-85d4d46f3cefceb87924ad1b0acec9f753413736.zip |
runtime: store syscall parameters in m not on stack
Stack can move during callback, so libcall struct cannot be stored on stack.
asmstdcall updates return values and errno in libcall struct parameter, but
these could be at different location when callback returns.
Store these in m, so they are not affected by GC.
Fixes #10406
Change-Id: Id01c9d2b4b44530494e6d9e9e1c875261ce477cd
Reviewed-on: https://go-review.googlesource.com/10370
Reviewed-by: Russ Cox <rsc@golang.org>
Diffstat (limited to 'src/runtime/syscall_windows_test.go')
-rw-r--r-- | src/runtime/syscall_windows_test.go | 83 |
1 files changed, 83 insertions, 0 deletions
diff --git a/src/runtime/syscall_windows_test.go b/src/runtime/syscall_windows_test.go index 720f70bdfc..cb9dfcde9d 100644 --- a/src/runtime/syscall_windows_test.go +++ b/src/runtime/syscall_windows_test.go @@ -554,3 +554,86 @@ func TestWERDialogue(t *testing.T) { // Child process should not open WER dialogue, but return immediately instead. cmd.CombinedOutput() } + +var used byte + +func use(buf []byte) { + for _, c := range buf { + used += c + } +} + +func forceStackCopy() (r int) { + var f func(int) int + f = func(i int) int { + var buf [256]byte + use(buf[:]) + if i == 0 { + return 0 + } + return i + f(i-1) + } + r = f(128) + return +} + +func TestReturnAfterStackGrowInCallback(t *testing.T) { + + const src = ` +#include <stdint.h> +#include <windows.h> + +typedef uintptr_t __stdcall (*callback)(uintptr_t); + +uintptr_t cfunc(callback f, uintptr_t n) { + uintptr_t r; + r = f(n); + SetLastError(333); + return r; +} +` + tmpdir, err := ioutil.TempDir("", "TestReturnAfterStackGrowInCallback") + if err != nil { + t.Fatal("TempDir failed: ", err) + } + defer os.RemoveAll(tmpdir) + + srcname := "mydll.c" + err = ioutil.WriteFile(filepath.Join(tmpdir, srcname), []byte(src), 0) + if err != nil { + t.Fatal(err) + } + outname := "mydll.dll" + cmd := exec.Command("gcc", "-shared", "-s", "-Werror", "-o", outname, srcname) + cmd.Dir = tmpdir + out, err := cmd.CombinedOutput() + if err != nil { + t.Fatalf("failed to build dll: %v - %v", err, string(out)) + } + dllpath := filepath.Join(tmpdir, outname) + + dll := syscall.MustLoadDLL(dllpath) + defer dll.Release() + + proc := dll.MustFindProc("cfunc") + + cb := syscall.NewCallback(func(n uintptr) uintptr { + forceStackCopy() + return n + }) + + // Use a new goroutine so that we get a small stack. + type result struct { + r uintptr + err syscall.Errno + } + c := make(chan result) + go func() { + r, _, err := proc.Call(cb, 100) + c <- result{r, err.(syscall.Errno)} + }() + want := result{r: 100, err: 333} + if got := <-c; got != want { + t.Errorf("got %d want %d", got, want) + } +} |