2011-10-15 00:29:25 -06:00
|
|
|
// Copyright 2011 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 syscall
|
|
|
|
|
|
|
|
import (
|
|
|
|
"sync"
|
2012-11-16 01:06:48 -07:00
|
|
|
"sync/atomic"
|
|
|
|
"unsafe"
|
2011-10-15 00:29:25 -06:00
|
|
|
)
|
|
|
|
|
|
|
|
// DLLError describes reasons for DLL load failures.
|
|
|
|
type DLLError struct {
|
2011-11-13 20:44:52 -07:00
|
|
|
Err error
|
2011-10-15 00:29:25 -06:00
|
|
|
ObjName string
|
|
|
|
Msg string
|
|
|
|
}
|
|
|
|
|
2011-11-01 20:05:34 -06:00
|
|
|
func (e *DLLError) Error() string { return e.Msg }
|
2011-10-15 00:29:25 -06:00
|
|
|
|
2014-09-14 19:25:44 -06:00
|
|
|
// Implemented in ../runtime/syscall_windows.go.
|
2011-11-13 20:44:52 -07:00
|
|
|
func Syscall(trap, nargs, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
|
|
|
|
func Syscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
|
|
|
|
func Syscall9(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno)
|
|
|
|
func Syscall12(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 uintptr) (r1, r2 uintptr, err Errno)
|
2011-11-28 16:24:19 -07:00
|
|
|
func Syscall15(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 uintptr) (r1, r2 uintptr, err Errno)
|
2012-06-27 17:21:48 -06:00
|
|
|
func loadlibrary(filename *uint16) (handle uintptr, err Errno)
|
2011-11-13 20:44:52 -07:00
|
|
|
func getprocaddress(handle uintptr, procname *uint8) (proc uintptr, err Errno)
|
2011-10-15 00:29:25 -06:00
|
|
|
|
|
|
|
// A DLL implements access to a single DLL.
|
|
|
|
type DLL struct {
|
|
|
|
Name string
|
|
|
|
Handle Handle
|
|
|
|
}
|
|
|
|
|
|
|
|
// LoadDLL loads DLL file into memory.
|
2011-11-01 20:12:41 -06:00
|
|
|
func LoadDLL(name string) (dll *DLL, err error) {
|
syscall: return EINVAL when string arguments have NUL characters
Since NUL usually terminates strings in underlying syscalls, allowing
it when converting string arguments is a security risk, especially
when dealing with filenames. For example, a program might reason that
filename like "/root/..\x00/" is a subdirectory or "/root/" and allow
access to it, while underlying syscall will treat "\x00" as an end of
that string and the actual filename will be "/root/..", which might
be unexpected. Returning EINVAL when string arguments have NUL in
them makes sure this attack vector is unusable.
R=golang-dev, r, bradfitz, fullung, rsc, minux.ma
CC=golang-dev
https://golang.org/cl/6458050
2012-08-05 15:24:32 -06:00
|
|
|
namep, err := UTF16PtrFromString(name)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
h, e := loadlibrary(namep)
|
2011-10-15 00:29:25 -06:00
|
|
|
if e != 0 {
|
|
|
|
return nil, &DLLError{
|
2011-11-13 20:44:52 -07:00
|
|
|
Err: e,
|
2011-10-15 00:29:25 -06:00
|
|
|
ObjName: name,
|
2011-11-13 20:44:52 -07:00
|
|
|
Msg: "Failed to load " + name + ": " + e.Error(),
|
2011-10-15 00:29:25 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
d := &DLL{
|
|
|
|
Name: name,
|
|
|
|
Handle: Handle(h),
|
|
|
|
}
|
|
|
|
return d, nil
|
|
|
|
}
|
|
|
|
|
2015-06-11 07:49:38 -06:00
|
|
|
// MustLoadDLL is like LoadDLL but panics if load operation fails.
|
2011-10-15 00:29:25 -06:00
|
|
|
func MustLoadDLL(name string) *DLL {
|
|
|
|
d, e := LoadDLL(name)
|
|
|
|
if e != nil {
|
|
|
|
panic(e)
|
|
|
|
}
|
|
|
|
return d
|
|
|
|
}
|
|
|
|
|
|
|
|
// FindProc searches DLL d for procedure named name and returns *Proc
|
|
|
|
// if found. It returns an error if search fails.
|
2011-11-01 20:12:41 -06:00
|
|
|
func (d *DLL) FindProc(name string) (proc *Proc, err error) {
|
syscall: return EINVAL when string arguments have NUL characters
Since NUL usually terminates strings in underlying syscalls, allowing
it when converting string arguments is a security risk, especially
when dealing with filenames. For example, a program might reason that
filename like "/root/..\x00/" is a subdirectory or "/root/" and allow
access to it, while underlying syscall will treat "\x00" as an end of
that string and the actual filename will be "/root/..", which might
be unexpected. Returning EINVAL when string arguments have NUL in
them makes sure this attack vector is unusable.
R=golang-dev, r, bradfitz, fullung, rsc, minux.ma
CC=golang-dev
https://golang.org/cl/6458050
2012-08-05 15:24:32 -06:00
|
|
|
namep, err := BytePtrFromString(name)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
a, e := getprocaddress(uintptr(d.Handle), namep)
|
syscall: keep allocated C string live across call to Syscall
Given:
p := alloc()
fn_taking_ptr(p)
p is NOT recorded as live at the call to fn_taking_ptr:
it's not needed by the code following the call.
p was passed to fn_taking_ptr, and fn_taking_ptr must keep
it alive as long as it needs it.
In practice, fn_taking_ptr will keep its own arguments live
for as long as the function is executing.
But if instead you have:
p := alloc()
i := uintptr(unsafe.Pointer(p))
fn_taking_int(i)
p is STILL NOT recorded as live at the call to fn_taking_int:
it's not needed by the code following the call.
fn_taking_int is responsible for keeping its own arguments
live, but fn_taking_int is written to take an integer, so even
though fn_taking_int does keep its argument live, that argument
does not keep the allocated memory live, because the garbage
collector does not dereference integers.
The shorter form:
p := alloc()
fn_taking_int(uintptr(unsafe.Pointer(p)))
and the even shorter form:
fn_taking_int(uintptr(unsafe.Pointer(alloc())))
are both the same as the 3-line form above.
syscall.Syscall is like fn_taking_int: it is written to take a list
of integers, and yet those integers are sometimes pointers.
If there is no other copy of those pointers being kept live,
the memory they point at may be garbage collected during
the call to syscall.Syscall.
This is happening on Solaris: for whatever reason, the timing
is such that the garbage collector manages to free the string
argument to the open(2) system call before the system call
has been invoked.
Change the system call wrappers to insert explicit references
that will keep the allocations alive in the original frame
(and therefore preserve the memory) until after syscall.Syscall
has returned.
Should fix Solaris flakiness.
This is not a problem for cgo, because cgo wrappers have
correctly typed arguments.
LGTM=iant, khr, aram, rlh
R=iant, khr, bradfitz, aram, rlh
CC=dvyukov, golang-codereviews, r
https://golang.org/cl/139360044
2014-09-08 14:59:59 -06:00
|
|
|
use(unsafe.Pointer(namep))
|
2011-10-15 00:29:25 -06:00
|
|
|
if e != 0 {
|
|
|
|
return nil, &DLLError{
|
2011-11-13 20:44:52 -07:00
|
|
|
Err: e,
|
2011-10-15 00:29:25 -06:00
|
|
|
ObjName: name,
|
2011-11-13 20:44:52 -07:00
|
|
|
Msg: "Failed to find " + name + " procedure in " + d.Name + ": " + e.Error(),
|
2011-10-15 00:29:25 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
p := &Proc{
|
|
|
|
Dll: d,
|
|
|
|
Name: name,
|
|
|
|
addr: a,
|
|
|
|
}
|
|
|
|
return p, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// MustFindProc is like FindProc but panics if search fails.
|
|
|
|
func (d *DLL) MustFindProc(name string) *Proc {
|
|
|
|
p, e := d.FindProc(name)
|
|
|
|
if e != nil {
|
|
|
|
panic(e)
|
|
|
|
}
|
|
|
|
return p
|
|
|
|
}
|
|
|
|
|
|
|
|
// Release unloads DLL d from memory.
|
2011-11-13 20:44:52 -07:00
|
|
|
func (d *DLL) Release() (err error) {
|
|
|
|
return FreeLibrary(d.Handle)
|
2011-10-15 00:29:25 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// A Proc implements access to a procedure inside a DLL.
|
|
|
|
type Proc struct {
|
|
|
|
Dll *DLL
|
|
|
|
Name string
|
|
|
|
addr uintptr
|
|
|
|
}
|
|
|
|
|
|
|
|
// Addr returns the address of the procedure represented by p.
|
|
|
|
// The return value can be passed to Syscall to run the procedure.
|
|
|
|
func (p *Proc) Addr() uintptr {
|
|
|
|
return p.addr
|
|
|
|
}
|
|
|
|
|
2013-02-02 10:42:17 -07:00
|
|
|
// Call executes procedure p with arguments a. It will panic, if more then 15 arguments
|
|
|
|
// are supplied.
|
|
|
|
//
|
|
|
|
// The returned error is always non-nil, constructed from the result of GetLastError.
|
|
|
|
// Callers must inspect the primary return value to decide whether an error occurred
|
|
|
|
// (according to the semantics of the specific function being called) before consulting
|
|
|
|
// the error. The error will be guaranteed to contain syscall.Errno.
|
|
|
|
func (p *Proc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
|
2011-10-15 00:29:25 -06:00
|
|
|
switch len(a) {
|
|
|
|
case 0:
|
|
|
|
return Syscall(p.Addr(), uintptr(len(a)), 0, 0, 0)
|
|
|
|
case 1:
|
|
|
|
return Syscall(p.Addr(), uintptr(len(a)), a[0], 0, 0)
|
|
|
|
case 2:
|
|
|
|
return Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], 0)
|
|
|
|
case 3:
|
|
|
|
return Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], a[2])
|
|
|
|
case 4:
|
|
|
|
return Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], 0, 0)
|
|
|
|
case 5:
|
|
|
|
return Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], 0)
|
|
|
|
case 6:
|
|
|
|
return Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5])
|
|
|
|
case 7:
|
|
|
|
return Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], 0, 0)
|
|
|
|
case 8:
|
|
|
|
return Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], 0)
|
|
|
|
case 9:
|
|
|
|
return Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8])
|
|
|
|
case 10:
|
|
|
|
return Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], 0, 0)
|
|
|
|
case 11:
|
|
|
|
return Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], 0)
|
|
|
|
case 12:
|
|
|
|
return Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11])
|
2011-11-28 16:24:19 -07:00
|
|
|
case 13:
|
|
|
|
return Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], 0, 0)
|
|
|
|
case 14:
|
|
|
|
return Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], 0)
|
|
|
|
case 15:
|
|
|
|
return Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14])
|
2011-10-15 00:29:25 -06:00
|
|
|
default:
|
|
|
|
panic("Call " + p.Name + " with too many arguments " + itoa(len(a)) + ".")
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// A LazyDLL implements access to a single DLL.
|
|
|
|
// It will delay the load of the DLL until the first
|
|
|
|
// call to its Handle method or to one of its
|
|
|
|
// LazyProc's Addr method.
|
|
|
|
type LazyDLL struct {
|
|
|
|
mu sync.Mutex
|
|
|
|
dll *DLL // non nil once DLL is loaded
|
|
|
|
Name string
|
|
|
|
}
|
|
|
|
|
|
|
|
// Load loads DLL file d.Name into memory. It returns an error if fails.
|
|
|
|
// Load will not try to load DLL, if it is already loaded into memory.
|
2011-11-01 20:12:41 -06:00
|
|
|
func (d *LazyDLL) Load() error {
|
2012-11-16 01:06:48 -07:00
|
|
|
// Non-racy version of:
|
|
|
|
// if d.dll == nil {
|
|
|
|
if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&d.dll))) == nil {
|
2011-10-15 00:29:25 -06:00
|
|
|
d.mu.Lock()
|
|
|
|
defer d.mu.Unlock()
|
|
|
|
if d.dll == nil {
|
|
|
|
dll, e := LoadDLL(d.Name)
|
|
|
|
if e != nil {
|
|
|
|
return e
|
|
|
|
}
|
2012-11-16 01:06:48 -07:00
|
|
|
// Non-racy version of:
|
|
|
|
// d.dll = dll
|
|
|
|
atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&d.dll)), unsafe.Pointer(dll))
|
2011-10-15 00:29:25 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// mustLoad is like Load but panics if search fails.
|
|
|
|
func (d *LazyDLL) mustLoad() {
|
|
|
|
e := d.Load()
|
|
|
|
if e != nil {
|
|
|
|
panic(e)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Handle returns d's module handle.
|
|
|
|
func (d *LazyDLL) Handle() uintptr {
|
|
|
|
d.mustLoad()
|
|
|
|
return uintptr(d.dll.Handle)
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewProc returns a LazyProc for accessing the named procedure in the DLL d.
|
|
|
|
func (d *LazyDLL) NewProc(name string) *LazyProc {
|
|
|
|
return &LazyProc{l: d, Name: name}
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewLazyDLL creates new LazyDLL associated with DLL file.
|
|
|
|
func NewLazyDLL(name string) *LazyDLL {
|
|
|
|
return &LazyDLL{Name: name}
|
|
|
|
}
|
|
|
|
|
|
|
|
// A LazyProc implements access to a procedure inside a LazyDLL.
|
|
|
|
// It delays the lookup until the Addr method is called.
|
|
|
|
type LazyProc struct {
|
|
|
|
mu sync.Mutex
|
|
|
|
Name string
|
|
|
|
l *LazyDLL
|
|
|
|
proc *Proc
|
|
|
|
}
|
|
|
|
|
|
|
|
// Find searches DLL for procedure named p.Name. It returns
|
|
|
|
// an error if search fails. Find will not search procedure,
|
|
|
|
// if it is already found and loaded into memory.
|
2011-11-01 20:12:41 -06:00
|
|
|
func (p *LazyProc) Find() error {
|
2012-11-16 01:06:48 -07:00
|
|
|
// Non-racy version of:
|
|
|
|
// if p.proc == nil {
|
|
|
|
if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc))) == nil {
|
2011-10-15 00:29:25 -06:00
|
|
|
p.mu.Lock()
|
|
|
|
defer p.mu.Unlock()
|
|
|
|
if p.proc == nil {
|
|
|
|
e := p.l.Load()
|
|
|
|
if e != nil {
|
|
|
|
return e
|
|
|
|
}
|
|
|
|
proc, e := p.l.dll.FindProc(p.Name)
|
|
|
|
if e != nil {
|
|
|
|
return e
|
|
|
|
}
|
2012-11-16 01:06:48 -07:00
|
|
|
// Non-racy version of:
|
|
|
|
// p.proc = proc
|
|
|
|
atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc)), unsafe.Pointer(proc))
|
2011-10-15 00:29:25 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// mustFind is like Find but panics if search fails.
|
|
|
|
func (p *LazyProc) mustFind() {
|
|
|
|
e := p.Find()
|
|
|
|
if e != nil {
|
|
|
|
panic(e)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Addr returns the address of the procedure represented by p.
|
|
|
|
// The return value can be passed to Syscall to run the procedure.
|
|
|
|
func (p *LazyProc) Addr() uintptr {
|
|
|
|
p.mustFind()
|
|
|
|
return p.proc.Addr()
|
|
|
|
}
|
|
|
|
|
2013-02-02 10:42:17 -07:00
|
|
|
// Call executes procedure p with arguments a. It will panic, if more then 15 arguments
|
|
|
|
// are supplied.
|
|
|
|
//
|
|
|
|
// The returned error is always non-nil, constructed from the result of GetLastError.
|
|
|
|
// Callers must inspect the primary return value to decide whether an error occurred
|
|
|
|
// (according to the semantics of the specific function being called) before consulting
|
|
|
|
// the error. The error will be guaranteed to contain syscall.Errno.
|
|
|
|
func (p *LazyProc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
|
2011-10-15 00:29:25 -06:00
|
|
|
p.mustFind()
|
|
|
|
return p.proc.Call(a...)
|
|
|
|
}
|