Source file src/syscall/dll_windows.go

     1  // Copyright 2011 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package syscall
     6  
     7  import (
     8  	"internal/syscall/windows/sysdll"
     9  	"sync"
    10  	"sync/atomic"
    11  	"unsafe"
    12  )
    13  
    14  // DLLError describes reasons for DLL load failures.
    15  type DLLError struct {
    16  	Err     error
    17  	ObjName string
    18  	Msg     string
    19  }
    20  
    21  func (e *DLLError) Error() string { return e.Msg }
    22  
    23  func (e *DLLError) Unwrap() error { return e.Err }
    24  
    25  // Implemented in ../runtime/syscall_windows.go.
    26  
    27  // Deprecated: Use [SyscallN] instead.
    28  func Syscall(trap, nargs, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
    29  
    30  // Deprecated: Use [SyscallN] instead.
    31  func Syscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
    32  
    33  // Deprecated: Use [SyscallN] instead.
    34  func Syscall9(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno)
    35  
    36  // Deprecated: Use [SyscallN] instead.
    37  func Syscall12(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 uintptr) (r1, r2 uintptr, err Errno)
    38  
    39  // Deprecated: Use [SyscallN] instead.
    40  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)
    41  
    42  // Deprecated: Use [SyscallN] instead.
    43  func Syscall18(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18 uintptr) (r1, r2 uintptr, err Errno)
    44  
    45  func SyscallN(trap uintptr, args ...uintptr) (r1, r2 uintptr, err Errno)
    46  func loadlibrary(filename *uint16) (handle uintptr, err Errno)
    47  func loadsystemlibrary(filename *uint16) (handle uintptr, err Errno)
    48  func getprocaddress(handle uintptr, procname *uint8) (proc uintptr, err Errno)
    49  
    50  // A DLL implements access to a single DLL.
    51  type DLL struct {
    52  	Name   string
    53  	Handle Handle
    54  }
    55  
    56  // LoadDLL loads the named DLL file into memory.
    57  //
    58  // If name is not an absolute path and is not a known system DLL used by
    59  // Go, Windows will search for the named DLL in many locations, causing
    60  // potential DLL preloading attacks.
    61  //
    62  // Use [LazyDLL] in golang.org/x/sys/windows for a secure way to
    63  // load system DLLs.
    64  func LoadDLL(name string) (*DLL, error) {
    65  	namep, err := UTF16PtrFromString(name)
    66  	if err != nil {
    67  		return nil, err
    68  	}
    69  	var h uintptr
    70  	var e Errno
    71  	if sysdll.IsSystemDLL[name] {
    72  		h, e = loadsystemlibrary(namep)
    73  	} else {
    74  		h, e = loadlibrary(namep)
    75  	}
    76  	if e != 0 {
    77  		return nil, &DLLError{
    78  			Err:     e,
    79  			ObjName: name,
    80  			Msg:     "Failed to load " + name + ": " + e.Error(),
    81  		}
    82  	}
    83  	d := &DLL{
    84  		Name:   name,
    85  		Handle: Handle(h),
    86  	}
    87  	return d, nil
    88  }
    89  
    90  // MustLoadDLL is like [LoadDLL] but panics if load operation fails.
    91  func MustLoadDLL(name string) *DLL {
    92  	d, e := LoadDLL(name)
    93  	if e != nil {
    94  		panic(e)
    95  	}
    96  	return d
    97  }
    98  
    99  // FindProc searches [DLL] d for procedure named name and returns [*Proc]
   100  // if found. It returns an error if search fails.
   101  func (d *DLL) FindProc(name string) (proc *Proc, err error) {
   102  	namep, err := BytePtrFromString(name)
   103  	if err != nil {
   104  		return nil, err
   105  	}
   106  	a, e := getprocaddress(uintptr(d.Handle), namep)
   107  	if e != 0 {
   108  		return nil, &DLLError{
   109  			Err:     e,
   110  			ObjName: name,
   111  			Msg:     "Failed to find " + name + " procedure in " + d.Name + ": " + e.Error(),
   112  		}
   113  	}
   114  	p := &Proc{
   115  		Dll:  d,
   116  		Name: name,
   117  		addr: a,
   118  	}
   119  	return p, nil
   120  }
   121  
   122  // MustFindProc is like [DLL.FindProc] but panics if search fails.
   123  func (d *DLL) MustFindProc(name string) *Proc {
   124  	p, e := d.FindProc(name)
   125  	if e != nil {
   126  		panic(e)
   127  	}
   128  	return p
   129  }
   130  
   131  // Release unloads [DLL] d from memory.
   132  func (d *DLL) Release() (err error) {
   133  	return FreeLibrary(d.Handle)
   134  }
   135  
   136  // A Proc implements access to a procedure inside a [DLL].
   137  type Proc struct {
   138  	Dll  *DLL
   139  	Name string
   140  	addr uintptr
   141  }
   142  
   143  // Addr returns the address of the procedure represented by p.
   144  // The return value can be passed to Syscall to run the procedure.
   145  func (p *Proc) Addr() uintptr {
   146  	return p.addr
   147  }
   148  
   149  // Call executes procedure p with arguments a.
   150  //
   151  // The returned error is always non-nil, constructed from the result of GetLastError.
   152  // Callers must inspect the primary return value to decide whether an error occurred
   153  // (according to the semantics of the specific function being called) before consulting
   154  // the error. The error always has type [Errno].
   155  //
   156  // On amd64, Call can pass and return floating-point values. To pass
   157  // an argument x with C type "float", use
   158  // uintptr(math.Float32bits(x)). To pass an argument with C type
   159  // "double", use uintptr(math.Float64bits(x)). Floating-point return
   160  // values are returned in r2. The return value for C type "float" is
   161  // [math.Float32frombits](uint32(r2)). For C type "double", it is
   162  // [math.Float64frombits](uint64(r2)).
   163  //
   164  //go:uintptrescapes
   165  func (p *Proc) Call(a ...uintptr) (uintptr, uintptr, error) {
   166  	return SyscallN(p.Addr(), a...)
   167  }
   168  
   169  // A LazyDLL implements access to a single [DLL].
   170  // It will delay the load of the DLL until the first
   171  // call to its [LazyDLL.Handle] method or to one of its
   172  // [LazyProc]'s Addr method.
   173  //
   174  // LazyDLL is subject to the same DLL preloading attacks as documented
   175  // on [LoadDLL].
   176  //
   177  // Use LazyDLL in golang.org/x/sys/windows for a secure way to
   178  // load system DLLs.
   179  type LazyDLL struct {
   180  	mu   sync.Mutex
   181  	dll  *DLL // non nil once DLL is loaded
   182  	Name string
   183  }
   184  
   185  // Load loads DLL file d.Name into memory. It returns an error if fails.
   186  // Load will not try to load DLL, if it is already loaded into memory.
   187  func (d *LazyDLL) Load() error {
   188  	// Non-racy version of:
   189  	// if d.dll == nil {
   190  	if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&d.dll))) == nil {
   191  		d.mu.Lock()
   192  		defer d.mu.Unlock()
   193  		if d.dll == nil {
   194  			dll, e := LoadDLL(d.Name)
   195  			if e != nil {
   196  				return e
   197  			}
   198  			// Non-racy version of:
   199  			// d.dll = dll
   200  			atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&d.dll)), unsafe.Pointer(dll))
   201  		}
   202  	}
   203  	return nil
   204  }
   205  
   206  // mustLoad is like Load but panics if search fails.
   207  func (d *LazyDLL) mustLoad() {
   208  	e := d.Load()
   209  	if e != nil {
   210  		panic(e)
   211  	}
   212  }
   213  
   214  // Handle returns d's module handle.
   215  func (d *LazyDLL) Handle() uintptr {
   216  	d.mustLoad()
   217  	return uintptr(d.dll.Handle)
   218  }
   219  
   220  // NewProc returns a [LazyProc] for accessing the named procedure in the [DLL] d.
   221  func (d *LazyDLL) NewProc(name string) *LazyProc {
   222  	return &LazyProc{l: d, Name: name}
   223  }
   224  
   225  // NewLazyDLL creates new [LazyDLL] associated with [DLL] file.
   226  func NewLazyDLL(name string) *LazyDLL {
   227  	return &LazyDLL{Name: name}
   228  }
   229  
   230  // A LazyProc implements access to a procedure inside a [LazyDLL].
   231  // It delays the lookup until the [LazyProc.Addr], [LazyProc.Call], or [LazyProc.Find] method is called.
   232  type LazyProc struct {
   233  	mu   sync.Mutex
   234  	Name string
   235  	l    *LazyDLL
   236  	proc *Proc
   237  }
   238  
   239  // Find searches [DLL] for procedure named p.Name. It returns
   240  // an error if search fails. Find will not search procedure,
   241  // if it is already found and loaded into memory.
   242  func (p *LazyProc) Find() error {
   243  	// Non-racy version of:
   244  	// if p.proc == nil {
   245  	if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc))) == nil {
   246  		p.mu.Lock()
   247  		defer p.mu.Unlock()
   248  		if p.proc == nil {
   249  			e := p.l.Load()
   250  			if e != nil {
   251  				return e
   252  			}
   253  			proc, e := p.l.dll.FindProc(p.Name)
   254  			if e != nil {
   255  				return e
   256  			}
   257  			// Non-racy version of:
   258  			// p.proc = proc
   259  			atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc)), unsafe.Pointer(proc))
   260  		}
   261  	}
   262  	return nil
   263  }
   264  
   265  // mustFind is like Find but panics if search fails.
   266  func (p *LazyProc) mustFind() {
   267  	e := p.Find()
   268  	if e != nil {
   269  		panic(e)
   270  	}
   271  }
   272  
   273  // Addr returns the address of the procedure represented by p.
   274  // The return value can be passed to Syscall to run the procedure.
   275  func (p *LazyProc) Addr() uintptr {
   276  	p.mustFind()
   277  	return p.proc.Addr()
   278  }
   279  
   280  // Call executes procedure p with arguments a. See the documentation of
   281  // Proc.Call for more information.
   282  //
   283  //go:uintptrescapes
   284  func (p *LazyProc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
   285  	p.mustFind()
   286  	return p.proc.Call(a...)
   287  }
   288  

View as plain text