github.com/HACKERALERT/Picocrypt/src/external/sys@v0.0.0-20210609020157-e519952f829f/windows/syscall_windows_test.go (about)

     1  // Copyright 2012 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 windows_test
     6  
     7  import (
     8  	"bytes"
     9  	"debug/pe"
    10  	"errors"
    11  	"fmt"
    12  	"io/ioutil"
    13  	"math/rand"
    14  	"os"
    15  	"path/filepath"
    16  	"runtime"
    17  	"strconv"
    18  	"strings"
    19  	"syscall"
    20  	"testing"
    21  	"unsafe"
    22  
    23  	"golang.org/x/sys/windows"
    24  )
    25  
    26  func TestWin32finddata(t *testing.T) {
    27  	dir, err := ioutil.TempDir("", "go-build")
    28  	if err != nil {
    29  		t.Fatalf("failed to create temp directory: %v", err)
    30  	}
    31  	defer os.RemoveAll(dir)
    32  
    33  	path := filepath.Join(dir, "long_name.and_extension")
    34  	f, err := os.Create(path)
    35  	if err != nil {
    36  		t.Fatalf("failed to create %v: %v", path, err)
    37  	}
    38  	f.Close()
    39  
    40  	type X struct {
    41  		fd  windows.Win32finddata
    42  		got byte
    43  		pad [10]byte // to protect ourselves
    44  
    45  	}
    46  	var want byte = 2 // it is unlikely to have this character in the filename
    47  	x := X{got: want}
    48  
    49  	pathp, _ := windows.UTF16PtrFromString(path)
    50  	h, err := windows.FindFirstFile(pathp, &(x.fd))
    51  	if err != nil {
    52  		t.Fatalf("FindFirstFile failed: %v", err)
    53  	}
    54  	err = windows.FindClose(h)
    55  	if err != nil {
    56  		t.Fatalf("FindClose failed: %v", err)
    57  	}
    58  
    59  	if x.got != want {
    60  		t.Fatalf("memory corruption: want=%d got=%d", want, x.got)
    61  	}
    62  }
    63  
    64  func TestFormatMessage(t *testing.T) {
    65  	dll := windows.MustLoadDLL("netevent.dll")
    66  
    67  	const TITLE_SC_MESSAGE_BOX uint32 = 0xC0001B75
    68  	const flags uint32 = syscall.FORMAT_MESSAGE_FROM_HMODULE | syscall.FORMAT_MESSAGE_ARGUMENT_ARRAY | syscall.FORMAT_MESSAGE_IGNORE_INSERTS
    69  	buf := make([]uint16, 300)
    70  	_, err := windows.FormatMessage(flags, uintptr(dll.Handle), TITLE_SC_MESSAGE_BOX, 0, buf, nil)
    71  	if err != nil {
    72  		t.Fatalf("FormatMessage for handle=%x and errno=%x failed: %v", dll.Handle, TITLE_SC_MESSAGE_BOX, err)
    73  	}
    74  }
    75  
    76  func abort(funcname string, err error) {
    77  	panic(funcname + " failed: " + err.Error())
    78  }
    79  
    80  func ExampleLoadLibrary() {
    81  	h, err := windows.LoadLibrary("kernel32.dll")
    82  	if err != nil {
    83  		abort("LoadLibrary", err)
    84  	}
    85  	defer windows.FreeLibrary(h)
    86  	proc, err := windows.GetProcAddress(h, "GetVersion")
    87  	if err != nil {
    88  		abort("GetProcAddress", err)
    89  	}
    90  	r, _, _ := syscall.Syscall(uintptr(proc), 0, 0, 0, 0)
    91  	major := byte(r)
    92  	minor := uint8(r >> 8)
    93  	build := uint16(r >> 16)
    94  	print("windows version ", major, ".", minor, " (Build ", build, ")\n")
    95  }
    96  
    97  func TestTOKEN_ALL_ACCESS(t *testing.T) {
    98  	if windows.TOKEN_ALL_ACCESS != 0xF01FF {
    99  		t.Errorf("TOKEN_ALL_ACCESS = %x, want 0xF01FF", windows.TOKEN_ALL_ACCESS)
   100  	}
   101  }
   102  
   103  func TestCreateWellKnownSid(t *testing.T) {
   104  	sid, err := windows.CreateWellKnownSid(windows.WinBuiltinAdministratorsSid)
   105  	if err != nil {
   106  		t.Fatalf("Unable to create well known sid for administrators: %v", err)
   107  	}
   108  	if got, want := sid.String(), "S-1-5-32-544"; got != want {
   109  		t.Fatalf("Builtin Administrators SID = %s, want %s", got, want)
   110  	}
   111  }
   112  
   113  func TestPseudoTokens(t *testing.T) {
   114  	version, err := windows.GetVersion()
   115  	if err != nil {
   116  		t.Fatal(err)
   117  	}
   118  	if ((version&0xffff)>>8)|((version&0xff)<<8) < 0x0602 {
   119  		return
   120  	}
   121  
   122  	realProcessToken, err := windows.OpenCurrentProcessToken()
   123  	if err != nil {
   124  		t.Fatal(err)
   125  	}
   126  	defer realProcessToken.Close()
   127  	realProcessUser, err := realProcessToken.GetTokenUser()
   128  	if err != nil {
   129  		t.Fatal(err)
   130  	}
   131  
   132  	pseudoProcessToken := windows.GetCurrentProcessToken()
   133  	pseudoProcessUser, err := pseudoProcessToken.GetTokenUser()
   134  	if err != nil {
   135  		t.Fatal(err)
   136  	}
   137  	if !windows.EqualSid(realProcessUser.User.Sid, pseudoProcessUser.User.Sid) {
   138  		t.Fatal("The real process token does not have the same as the pseudo process token")
   139  	}
   140  
   141  	runtime.LockOSThread()
   142  	defer runtime.UnlockOSThread()
   143  
   144  	err = windows.RevertToSelf()
   145  	if err != nil {
   146  		t.Fatal(err)
   147  	}
   148  
   149  	pseudoThreadToken := windows.GetCurrentThreadToken()
   150  	_, err = pseudoThreadToken.GetTokenUser()
   151  	if err != windows.ERROR_NO_TOKEN {
   152  		t.Fatal("Expected an empty thread token")
   153  	}
   154  	pseudoThreadEffectiveToken := windows.GetCurrentThreadEffectiveToken()
   155  	pseudoThreadEffectiveUser, err := pseudoThreadEffectiveToken.GetTokenUser()
   156  	if err != nil {
   157  		t.Fatal(nil)
   158  	}
   159  	if !windows.EqualSid(realProcessUser.User.Sid, pseudoThreadEffectiveUser.User.Sid) {
   160  		t.Fatal("The real process token does not have the same as the pseudo thread effective token, even though we aren't impersonating")
   161  	}
   162  
   163  	err = windows.ImpersonateSelf(windows.SecurityImpersonation)
   164  	if err != nil {
   165  		t.Fatal(err)
   166  	}
   167  	defer windows.RevertToSelf()
   168  	pseudoThreadUser, err := pseudoThreadToken.GetTokenUser()
   169  	if err != nil {
   170  		t.Fatal(err)
   171  	}
   172  	if !windows.EqualSid(realProcessUser.User.Sid, pseudoThreadUser.User.Sid) {
   173  		t.Fatal("The real process token does not have the same as the pseudo thread token after impersonating self")
   174  	}
   175  }
   176  
   177  func TestGUID(t *testing.T) {
   178  	guid, err := windows.GenerateGUID()
   179  	if err != nil {
   180  		t.Fatal(err)
   181  	}
   182  	if guid.Data1 == 0 && guid.Data2 == 0 && guid.Data3 == 0 && guid.Data4 == [8]byte{} {
   183  		t.Fatal("Got an all zero GUID, which is overwhelmingly unlikely")
   184  	}
   185  	want := fmt.Sprintf("{%08X-%04X-%04X-%04X-%012X}", guid.Data1, guid.Data2, guid.Data3, guid.Data4[:2], guid.Data4[2:])
   186  	got := guid.String()
   187  	if got != want {
   188  		t.Fatalf("String = %q; want %q", got, want)
   189  	}
   190  	guid2, err := windows.GUIDFromString(got)
   191  	if err != nil {
   192  		t.Fatal(err)
   193  	}
   194  	if guid2 != guid {
   195  		t.Fatalf("Did not parse string back to original GUID = %q; want %q", guid2, guid)
   196  	}
   197  	_, err = windows.GUIDFromString("not-a-real-guid")
   198  	if err != syscall.Errno(windows.CO_E_CLASSSTRING) {
   199  		t.Fatalf("Bad GUID string error = %v; want CO_E_CLASSSTRING", err)
   200  	}
   201  }
   202  
   203  func TestKnownFolderPath(t *testing.T) {
   204  	token, err := windows.OpenCurrentProcessToken()
   205  	if err != nil {
   206  		t.Fatal(err)
   207  	}
   208  	defer token.Close()
   209  	profileDir, err := token.GetUserProfileDirectory()
   210  	if err != nil {
   211  		t.Fatal(err)
   212  	}
   213  	want := filepath.Join(profileDir, "Desktop")
   214  	got, err := windows.KnownFolderPath(windows.FOLDERID_Desktop, windows.KF_FLAG_DEFAULT)
   215  	if err != nil {
   216  		t.Fatal(err)
   217  	}
   218  	if want != got {
   219  		t.Fatalf("Path = %q; want %q", got, want)
   220  	}
   221  }
   222  
   223  func TestRtlGetVersion(t *testing.T) {
   224  	version := windows.RtlGetVersion()
   225  	major, minor, build := windows.RtlGetNtVersionNumbers()
   226  	// Go is not explictly added to the application compatibility database, so
   227  	// these two functions should return the same thing.
   228  	if version.MajorVersion != major || version.MinorVersion != minor || version.BuildNumber != build {
   229  		t.Fatalf("%d.%d.%d != %d.%d.%d", version.MajorVersion, version.MinorVersion, version.BuildNumber, major, minor, build)
   230  	}
   231  }
   232  
   233  func TestGetNamedSecurityInfo(t *testing.T) {
   234  	path, err := windows.GetSystemDirectory()
   235  	if err != nil {
   236  		t.Fatal(err)
   237  	}
   238  	sd, err := windows.GetNamedSecurityInfo(path, windows.SE_FILE_OBJECT, windows.OWNER_SECURITY_INFORMATION)
   239  	if err != nil {
   240  		t.Fatal(err)
   241  	}
   242  	if !sd.IsValid() {
   243  		t.Fatal("Invalid security descriptor")
   244  	}
   245  	sdOwner, _, err := sd.Owner()
   246  	if err != nil {
   247  		t.Fatal(err)
   248  	}
   249  	if !sdOwner.IsValid() {
   250  		t.Fatal("Invalid security descriptor owner")
   251  	}
   252  }
   253  
   254  func TestGetSecurityInfo(t *testing.T) {
   255  	sd, err := windows.GetSecurityInfo(windows.CurrentProcess(), windows.SE_KERNEL_OBJECT, windows.DACL_SECURITY_INFORMATION)
   256  	if err != nil {
   257  		t.Fatal(err)
   258  	}
   259  	if !sd.IsValid() {
   260  		t.Fatal("Invalid security descriptor")
   261  	}
   262  	sdStr := sd.String()
   263  	if !strings.HasPrefix(sdStr, "D:(A;") {
   264  		t.Fatalf("DACL = %q; want D:(A;...", sdStr)
   265  	}
   266  }
   267  
   268  func TestSddlConversion(t *testing.T) {
   269  	sd, err := windows.SecurityDescriptorFromString("O:BA")
   270  	if err != nil {
   271  		t.Fatal(err)
   272  	}
   273  	if !sd.IsValid() {
   274  		t.Fatal("Invalid security descriptor")
   275  	}
   276  	sdOwner, _, err := sd.Owner()
   277  	if err != nil {
   278  		t.Fatal(err)
   279  	}
   280  	if !sdOwner.IsValid() {
   281  		t.Fatal("Invalid security descriptor owner")
   282  	}
   283  	if !sdOwner.IsWellKnown(windows.WinBuiltinAdministratorsSid) {
   284  		t.Fatalf("Owner = %q; want S-1-5-32-544", sdOwner)
   285  	}
   286  }
   287  
   288  func TestBuildSecurityDescriptor(t *testing.T) {
   289  	const want = "O:SYD:(A;;GA;;;BA)"
   290  
   291  	adminSid, err := windows.CreateWellKnownSid(windows.WinBuiltinAdministratorsSid)
   292  	if err != nil {
   293  		t.Fatal(err)
   294  	}
   295  	systemSid, err := windows.CreateWellKnownSid(windows.WinLocalSystemSid)
   296  	if err != nil {
   297  		t.Fatal(err)
   298  	}
   299  
   300  	access := []windows.EXPLICIT_ACCESS{{
   301  		AccessPermissions: windows.GENERIC_ALL,
   302  		AccessMode:        windows.GRANT_ACCESS,
   303  		Trustee: windows.TRUSTEE{
   304  			TrusteeForm:  windows.TRUSTEE_IS_SID,
   305  			TrusteeType:  windows.TRUSTEE_IS_GROUP,
   306  			TrusteeValue: windows.TrusteeValueFromSID(adminSid),
   307  		},
   308  	}}
   309  	owner := &windows.TRUSTEE{
   310  		TrusteeForm:  windows.TRUSTEE_IS_SID,
   311  		TrusteeType:  windows.TRUSTEE_IS_USER,
   312  		TrusteeValue: windows.TrusteeValueFromSID(systemSid),
   313  	}
   314  
   315  	sd, err := windows.BuildSecurityDescriptor(owner, nil, access, nil, nil)
   316  	if err != nil {
   317  		t.Fatal(err)
   318  	}
   319  	sd, err = sd.ToAbsolute()
   320  	if err != nil {
   321  		t.Fatal(err)
   322  	}
   323  	err = sd.SetSACL(nil, false, false)
   324  	if err != nil {
   325  		t.Fatal(err)
   326  	}
   327  	if got := sd.String(); got != want {
   328  		t.Fatalf("SD = %q; want %q", got, want)
   329  	}
   330  	sd, err = sd.ToSelfRelative()
   331  	if err != nil {
   332  		t.Fatal(err)
   333  	}
   334  	if got := sd.String(); got != want {
   335  		t.Fatalf("SD = %q; want %q", got, want)
   336  	}
   337  
   338  	sd, err = windows.NewSecurityDescriptor()
   339  	if err != nil {
   340  		t.Fatal(err)
   341  	}
   342  	acl, err := windows.ACLFromEntries(access, nil)
   343  	if err != nil {
   344  		t.Fatal(err)
   345  	}
   346  	err = sd.SetDACL(acl, true, false)
   347  	if err != nil {
   348  		t.Fatal(err)
   349  	}
   350  	err = sd.SetOwner(systemSid, false)
   351  	if err != nil {
   352  		t.Fatal(err)
   353  	}
   354  	if got := sd.String(); got != want {
   355  		t.Fatalf("SD = %q; want %q", got, want)
   356  	}
   357  	sd, err = sd.ToSelfRelative()
   358  	if err != nil {
   359  		t.Fatal(err)
   360  	}
   361  	if got := sd.String(); got != want {
   362  		t.Fatalf("SD = %q; want %q", got, want)
   363  	}
   364  }
   365  
   366  func TestGetDiskFreeSpaceEx(t *testing.T) {
   367  	cwd, err := windows.UTF16PtrFromString(".")
   368  	if err != nil {
   369  		t.Fatalf(`failed to call UTF16PtrFromString("."): %v`, err)
   370  	}
   371  	var freeBytesAvailableToCaller, totalNumberOfBytes, totalNumberOfFreeBytes uint64
   372  	if err := windows.GetDiskFreeSpaceEx(cwd, &freeBytesAvailableToCaller, &totalNumberOfBytes, &totalNumberOfFreeBytes); err != nil {
   373  		t.Fatalf("failed to call GetDiskFreeSpaceEx: %v", err)
   374  	}
   375  
   376  	if freeBytesAvailableToCaller == 0 {
   377  		t.Errorf("freeBytesAvailableToCaller: got 0; want > 0")
   378  	}
   379  	if totalNumberOfBytes == 0 {
   380  		t.Errorf("totalNumberOfBytes: got 0; want > 0")
   381  	}
   382  	if totalNumberOfFreeBytes == 0 {
   383  		t.Errorf("totalNumberOfFreeBytes: got 0; want > 0")
   384  	}
   385  }
   386  
   387  func TestGetPreferredUILanguages(t *testing.T) {
   388  	tab := map[string]func(flags uint32) ([]string, error){
   389  		"GetProcessPreferredUILanguages": windows.GetProcessPreferredUILanguages,
   390  		"GetThreadPreferredUILanguages":  windows.GetThreadPreferredUILanguages,
   391  		"GetUserPreferredUILanguages":    windows.GetUserPreferredUILanguages,
   392  		"GetSystemPreferredUILanguages":  windows.GetSystemPreferredUILanguages,
   393  	}
   394  	for fName, f := range tab {
   395  		lang, err := f(windows.MUI_LANGUAGE_ID)
   396  		if err != nil {
   397  			t.Errorf(`failed to call %v(MUI_LANGUAGE_ID): %v`, fName, err)
   398  		}
   399  		for _, l := range lang {
   400  			_, err := strconv.ParseUint(l, 16, 16)
   401  			if err != nil {
   402  				t.Errorf(`%v(MUI_LANGUAGE_ID) returned unexpected LANGID: %v`, fName, l)
   403  			}
   404  		}
   405  
   406  		lang, err = f(windows.MUI_LANGUAGE_NAME)
   407  		if err != nil {
   408  			t.Errorf(`failed to call %v(MUI_LANGUAGE_NAME): %v`, fName, err)
   409  		}
   410  	}
   411  }
   412  
   413  func TestProcessWorkingSetSizeEx(t *testing.T) {
   414  	// Grab a handle to the current process
   415  	hProcess := windows.CurrentProcess()
   416  
   417  	// Allocate memory to store the result of the query
   418  	var minimumWorkingSetSize, maximumWorkingSetSize uintptr
   419  
   420  	// Make the system-call
   421  	var flag uint32
   422  	windows.GetProcessWorkingSetSizeEx(hProcess, &minimumWorkingSetSize, &maximumWorkingSetSize, &flag)
   423  
   424  	// Set the new limits to the current ones
   425  	if err := windows.SetProcessWorkingSetSizeEx(hProcess, minimumWorkingSetSize, maximumWorkingSetSize, flag); err != nil {
   426  		t.Error(err)
   427  	}
   428  }
   429  
   430  func TestJobObjectInfo(t *testing.T) {
   431  	jo, err := windows.CreateJobObject(nil, nil)
   432  	if err != nil {
   433  		t.Fatalf("CreateJobObject failed: %v", err)
   434  	}
   435  	defer windows.CloseHandle(jo)
   436  
   437  	var info windows.JOBOBJECT_EXTENDED_LIMIT_INFORMATION
   438  
   439  	err = windows.QueryInformationJobObject(jo, windows.JobObjectExtendedLimitInformation,
   440  		uintptr(unsafe.Pointer(&info)), uint32(unsafe.Sizeof(info)), nil)
   441  	if err != nil {
   442  		t.Fatalf("QueryInformationJobObject failed: %v", err)
   443  	}
   444  
   445  	const wantMemLimit = 4 * 1024
   446  
   447  	info.BasicLimitInformation.LimitFlags |= windows.JOB_OBJECT_LIMIT_PROCESS_MEMORY
   448  	info.ProcessMemoryLimit = wantMemLimit
   449  	_, err = windows.SetInformationJobObject(jo, windows.JobObjectExtendedLimitInformation,
   450  		uintptr(unsafe.Pointer(&info)), uint32(unsafe.Sizeof(info)))
   451  	if err != nil {
   452  		t.Fatalf("SetInformationJobObject failed: %v", err)
   453  	}
   454  
   455  	err = windows.QueryInformationJobObject(jo, windows.JobObjectExtendedLimitInformation,
   456  		uintptr(unsafe.Pointer(&info)), uint32(unsafe.Sizeof(info)), nil)
   457  	if err != nil {
   458  		t.Fatalf("QueryInformationJobObject failed: %v", err)
   459  	}
   460  
   461  	if have := info.ProcessMemoryLimit; wantMemLimit != have {
   462  		t.Errorf("ProcessMemoryLimit is wrong: want %v have %v", wantMemLimit, have)
   463  	}
   464  }
   465  
   466  func TestIsWow64Process2(t *testing.T) {
   467  	var processMachine, nativeMachine uint16
   468  	err := windows.IsWow64Process2(windows.CurrentProcess(), &processMachine, &nativeMachine)
   469  	if errors.Is(err, windows.ERROR_PROC_NOT_FOUND) {
   470  		maj, min, build := windows.RtlGetNtVersionNumbers()
   471  		if maj < 10 || (maj == 10 && min == 0 && build < 17763) {
   472  			t.Skip("not available on older versions of Windows")
   473  			return
   474  		}
   475  	}
   476  	if err != nil {
   477  		t.Fatalf("IsWow64Process2 failed: %v", err)
   478  	}
   479  	if processMachine == pe.IMAGE_FILE_MACHINE_UNKNOWN {
   480  		processMachine = nativeMachine
   481  	}
   482  	switch {
   483  	case processMachine == pe.IMAGE_FILE_MACHINE_AMD64 && runtime.GOARCH == "amd64":
   484  	case processMachine == pe.IMAGE_FILE_MACHINE_I386 && runtime.GOARCH == "386":
   485  	case processMachine == pe.IMAGE_FILE_MACHINE_ARMNT && runtime.GOARCH == "arm":
   486  	case processMachine == pe.IMAGE_FILE_MACHINE_ARM64 && runtime.GOARCH == "arm64":
   487  	default:
   488  		t.Errorf("IsWow64Process2 is wrong: want %v have %v", runtime.GOARCH, processMachine)
   489  	}
   490  }
   491  
   492  func TestNTStatusString(t *testing.T) {
   493  	want := "The name limit for the local computer network adapter card was exceeded."
   494  	got := windows.STATUS_TOO_MANY_NAMES.Error()
   495  	if want != got {
   496  		t.Errorf("NTStatus.Error did not return an expected error string - want %q; got %q", want, got)
   497  	}
   498  }
   499  
   500  func TestNTStatusConversion(t *testing.T) {
   501  	want := windows.ERROR_TOO_MANY_NAMES
   502  	got := windows.STATUS_TOO_MANY_NAMES.Errno()
   503  	if want != got {
   504  		t.Errorf("NTStatus.Errno = %q (0x%x); want %q (0x%x)", got.Error(), got, want.Error(), want)
   505  	}
   506  }
   507  
   508  func TestPEBFilePath(t *testing.T) {
   509  	peb := windows.RtlGetCurrentPeb()
   510  	if peb == nil || peb.Ldr == nil {
   511  		t.Error("unable to retrieve PEB with valid Ldr")
   512  	}
   513  	var entry *windows.LDR_DATA_TABLE_ENTRY
   514  	for cur := peb.Ldr.InMemoryOrderModuleList.Flink; cur != &peb.Ldr.InMemoryOrderModuleList; cur = cur.Flink {
   515  		e := (*windows.LDR_DATA_TABLE_ENTRY)(unsafe.Pointer(uintptr(unsafe.Pointer(cur)) - unsafe.Offsetof(windows.LDR_DATA_TABLE_ENTRY{}.InMemoryOrderLinks)))
   516  		if e.DllBase == peb.ImageBaseAddress {
   517  			entry = e
   518  			break
   519  		}
   520  	}
   521  	if entry == nil {
   522  		t.Error("unable to find Ldr entry for current process")
   523  	}
   524  	osPath, err := os.Executable()
   525  	if err != nil {
   526  		t.Errorf("unable to get path to current executable: %v", err)
   527  	}
   528  	pebPath := entry.FullDllName.String()
   529  	if osPath != pebPath {
   530  		t.Errorf("peb.Ldr.{entry}.FullDllName = %#q; want %#q", pebPath, osPath)
   531  	}
   532  	paramPath := peb.ProcessParameters.ImagePathName.String()
   533  	if osPath != paramPath {
   534  		t.Errorf("peb.ProcessParameters.ImagePathName.{entry}.ImagePathName = %#q; want %#q", paramPath, osPath)
   535  	}
   536  	osCwd, err := os.Getwd()
   537  	if err != nil {
   538  		t.Errorf("unable to get working directory: %v", err)
   539  	}
   540  	osCwd = filepath.Clean(osCwd)
   541  	paramCwd := filepath.Clean(peb.ProcessParameters.CurrentDirectory.DosPath.String())
   542  	if paramCwd != osCwd {
   543  		t.Errorf("peb.ProcessParameters.CurrentDirectory.DosPath = %#q; want %#q", paramCwd, osCwd)
   544  	}
   545  }
   546  
   547  func TestResourceExtraction(t *testing.T) {
   548  	system32, err := windows.GetSystemDirectory()
   549  	if err != nil {
   550  		t.Errorf("unable to find system32 directory: %v", err)
   551  	}
   552  	cmd, err := windows.LoadLibrary(filepath.Join(system32, "cmd.exe"))
   553  	if err != nil {
   554  		t.Errorf("unable to load cmd.exe: %v", err)
   555  	}
   556  	defer windows.FreeLibrary(cmd)
   557  	rsrc, err := windows.FindResource(cmd, windows.CREATEPROCESS_MANIFEST_RESOURCE_ID, windows.RT_MANIFEST)
   558  	if err != nil {
   559  		t.Errorf("unable to find cmd.exe manifest resource: %v", err)
   560  	}
   561  	manifest, err := windows.LoadResourceData(cmd, rsrc)
   562  	if err != nil {
   563  		t.Errorf("unable to load cmd.exe manifest resource data: %v", err)
   564  	}
   565  	if !bytes.Contains(manifest, []byte("</assembly>")) {
   566  		t.Errorf("did not find </assembly> in manifest")
   567  	}
   568  }
   569  
   570  func TestCommandLineRecomposition(t *testing.T) {
   571  	const (
   572  		maxCharsPerArg  = 35
   573  		maxArgsPerTrial = 80
   574  		doubleQuoteProb = 4
   575  		singleQuoteProb = 1
   576  		backSlashProb   = 3
   577  		spaceProb       = 1
   578  		trials          = 1000
   579  	)
   580  	randString := func(l int) []rune {
   581  		s := make([]rune, l)
   582  		for i := range s {
   583  			s[i] = rand.Int31()
   584  		}
   585  		return s
   586  	}
   587  	mungeString := func(s []rune, char rune, timesInTen int) {
   588  		if timesInTen < rand.Intn(10)+1 || len(s) == 0 {
   589  			return
   590  		}
   591  		s[rand.Intn(len(s))] = char
   592  	}
   593  	argStorage := make([]string, maxArgsPerTrial+1)
   594  	for i := 0; i < trials; i++ {
   595  		args := argStorage[:rand.Intn(maxArgsPerTrial)+2]
   596  		args[0] = "valid-filename-for-arg0"
   597  		for j := 1; j < len(args); j++ {
   598  			arg := randString(rand.Intn(maxCharsPerArg + 1))
   599  			mungeString(arg, '"', doubleQuoteProb)
   600  			mungeString(arg, '\'', singleQuoteProb)
   601  			mungeString(arg, '\\', backSlashProb)
   602  			mungeString(arg, ' ', spaceProb)
   603  			args[j] = string(arg)
   604  		}
   605  		commandLine := windows.ComposeCommandLine(args)
   606  		decomposedArgs, err := windows.DecomposeCommandLine(commandLine)
   607  		if err != nil {
   608  			t.Errorf("Unable to decompose %#q made from %v: %v", commandLine, args, err)
   609  			continue
   610  		}
   611  		if len(decomposedArgs) != len(args) {
   612  			t.Errorf("Incorrect decomposition length from %v to %#q to %v", args, commandLine, decomposedArgs)
   613  			continue
   614  		}
   615  		badMatches := make([]int, 0, len(args))
   616  		for i := range args {
   617  			if args[i] != decomposedArgs[i] {
   618  				badMatches = append(badMatches, i)
   619  			}
   620  		}
   621  		if len(badMatches) != 0 {
   622  			t.Errorf("Incorrect decomposition at indices %v from %v to %#q to %v", badMatches, args, commandLine, decomposedArgs)
   623  			continue
   624  		}
   625  	}
   626  }