Skip to content

Commit

Permalink
fix on all unsafe.Pointer rules (#8)
Browse files Browse the repository at this point in the history
  • Loading branch information
KnicKnic authored Dec 13, 2019
1 parent 8e4b87b commit 7fa72aa
Show file tree
Hide file tree
Showing 8 changed files with 101 additions and 50 deletions.
2 changes: 1 addition & 1 deletion native-powershell
65 changes: 40 additions & 25 deletions pkg/powershell/chelpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ package powershell

import (
"unsafe"

"golang.org/x/sys/windows"
)

func makeUint64FromPtr(v uintptr) uint64 {
Expand All @@ -13,18 +11,50 @@ func makeUintptrFromUint64(v uint64) uintptr {
return *((*uintptr)(unsafe.Pointer(&v)))
}

func allocWrapper(size uint64) uintptr {
func allocWrapper(size uint64) (uintptr, error) {
return nativePowerShell_DefaultAlloc(size)
}
func freeWrapper(v uintptr) {
nativePowerShell_DefaultFree(v)
}

func mallocCopy(input uintptr, size uintptr) uintptr {
func mallocCopyLogStringHolder(input nativePowerShell_LogString_Holder) uintptr {

size := uint64(unsafe.Sizeof(input))

data, err := allocWrapper(size)
if err != nil {
panic("Couldn't allocate memory")
}

_ = memcpyLogStringHolder(data, input)

return data
}

func mallocCopyGenericPowerShellObject(input *nativePowerShell_GenericPowerShellObject, inputCount uint64) uintptr {

size := inputCount * uint64(unsafe.Sizeof(*input))

data, err := allocWrapper(size)
if err != nil {
panic("Couldn't allocate memory")
}

u64Size := makeUint64FromPtr(size)
data := allocWrapper(u64Size)
_ = memcpy(data, uintptr(unsafe.Pointer(input)), u64Size)
_ = memcpyGenericPowerShellObject(data, input, size)

return data
}

func mallocCopyStr(str string) uintptr {

size := 2 * uint64((len(str) + 1))
data, err := allocWrapper(size)
if err != nil {
panic("Couldn't allocate memory")
}
// safe usage due to data being c pointer
_ = memcpyStr(data, str)

return data
}
Expand All @@ -33,30 +63,15 @@ func wsclen(str uintptr) uint64 {
var charCode uint16 = 1
var i uint64 = 0
for ; charCode != 0; i++ {
charCode = *(*uint16)(unsafe.Pointer(str + (makeUintptrFromUint64(i) * unsafe.Sizeof(charCode))))
charCode = *((*uint16)(unsafe.Pointer(str + (makeUintptrFromUint64(i) * unsafe.Sizeof(charCode)))))
}
return i
}

func makeString(str uintptr) string {
count := wsclen(str) + 1
arr := make([]uint16, count)
ptrwchar := unsafe.Pointer(&arr[0])

memcpy(uintptr(ptrwchar), str, count*2)

s := windows.UTF16ToString(arr)
return s
}

func uintptrMakeString(ptr uintptr) string {
return makeString(ptr)
return cstrToStr(ptr)
}

func makeCStringUintptr(str string) uintptr {
cs, _ := windows.UTF16PtrFromString(str)
ptrwchar := unsafe.Pointer(cs)
size := 2 * (wsclen(uintptr(ptrwchar)) + 1)

return mallocCopy(uintptr(ptrwchar), makeUintptrFromUint64(size))
return mallocCopyStr(str)
}
15 changes: 3 additions & 12 deletions pkg/powershell/hostcommand.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package powershell

import "unsafe"

// CallbackResultsWriter allows you to write values to powershell when inside Send-HostCommand
type CallbackResultsWriter interface {
WriteString(string)
Expand Down Expand Up @@ -57,20 +55,13 @@ func (writer *callbackResultsWriter) Write(handle Object, needsClose bool) {
writer.objects = append(writer.objects, obj)
}

func mallocCopyGenericPowerShellObject(input *nativePowerShell_GenericPowerShellObject, inputCount uint64) *nativePowerShell_GenericPowerShellObject {

size := uintptr(inputCount) * unsafe.Sizeof(*input)

return (*nativePowerShell_GenericPowerShellObject)(unsafe.Pointer(mallocCopy(uintptr(unsafe.Pointer(input)), size)))
}

// filloutResults takes accumulated objects from Write calls and prepares them to cross the C boundary
func (writer *callbackResultsWriter) filloutResults(res uintptr) {
results := (*nativePowerShell_JsonReturnValues)(unsafe.Pointer(res))
results.objects = nil
results.count = 0
var results nativePowerShell_JsonReturnValues

if writer.objects != nil && len(writer.objects) > 0 {
results.count = uint32(len(writer.objects))
results.objects = mallocCopyGenericPowerShellObject(&writer.objects[0], uint64(len(writer.objects)))
}
_ = memcpyJsonReturnValues(res, results)
}
3 changes: 1 addition & 2 deletions pkg/powershell/powershell.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,9 +118,8 @@ func makePowerShellObjectIndexed(objects uintptr, index uint32) Object {
// I don't get why I have to use unsafe.Pointer on C memory
var handle nativePowerShell_PowerShellObject

ptr := unsafe.Pointer(objects)
offset := (uintptr(index) * unsafe.Sizeof(handle))
handle = *(*nativePowerShell_PowerShellObject)(unsafe.Pointer(uintptr(ptr) + offset))
handle = *(*nativePowerShell_PowerShellObject)(unsafe.Pointer(objects + offset))
return makePowerShellObject(handle)
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/powershell/psh_host.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ type (
}

nativePowerShell_JsonReturnValues struct {
objects *nativePowerShell_GenericPowerShellObject
objects uintptr // *nativePowerShell_GenericPowerShellObject
count uint32
}
nativePowerShell_ReceiveJsonCommand func(context uintptr, command nativePowerShell_StringPtr, inputrs *nativePowerShell_PowerShellObject, inputCount uint64, returnValues *nativePowerShell_JsonReturnValues) uintptr
Expand Down
2 changes: 1 addition & 1 deletion pkg/powershell/runspace_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ func ExampleCallbackHolder() {

func ExampleRunspace_customSimpleLogger() {
// create a custom logger object
customLogger := logger.SimpleFuncPtr{func(str string) {
customLogger := logger.SimpleFuncPtr{FuncPtr: func(str string) {
fmt.Print("Custom: " + str)
}}
// create a runspace (where you run your powershell statements in)
Expand Down
13 changes: 8 additions & 5 deletions pkg/powershell/runspacehelpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package powershell

import (
"syscall"
"unsafe"
)

func loggerCallback(context uint64, str uintptr) uintptr {
Expand Down Expand Up @@ -133,15 +132,19 @@ var (
LogVerboseLine: syscall.NewCallbackCDecl(loggerCallbackVerboseln),
LogDebugLine: syscall.NewCallbackCDecl(loggerCallbackDebugln),
}
loggerCallbackPointer unsafe.Pointer = unsafe.Pointer(&loggerCallbackHolder)
commandCallbackPointer uintptr = syscall.NewCallbackCDecl(commandCallback)

// intentionally leak loggerCallbackPointer (once per process)
// doing this so the callback object will be around for lifetime of process
// If it was golang object just marshalled for duration of call, golang garbage collection could move things and we would crash
loggerCallbackPointer uintptr = mallocCopyLogStringHolder(loggerCallbackHolder)
commandCallbackPointer uintptr = syscall.NewCallbackCDecl(commandCallback)
)

func createRunspaceHelper(context uint64, useLogger byte, useCommand byte) nativePowerShell_RunspaceHandle {
var commandPtr uintptr = 0
var loggerPtr uintptr = 0
if useLogger != 0 {
loggerPtr = uintptr(loggerCallbackPointer)
loggerPtr = loggerCallbackPointer
}
if useCommand != 0 {
commandPtr = commandCallbackPointer
Expand All @@ -152,7 +155,7 @@ func createRunspaceHelper(context uint64, useLogger byte, useCommand byte) nativ
func createRemoteRunspaceHelper(context uint64, useLogger byte, remoteMachine *uint16, userName *uint16, password *uint16) nativePowerShell_RunspaceHandle {
var loggerPtr uintptr = 0
if useLogger != 0 {
loggerPtr = uintptr(loggerCallbackPointer)
loggerPtr = loggerCallbackPointer
}
return nativePowerShell_CreateRemoteRunspace(makeUintptrFromUint64(context), loggerPtr, remoteMachine, userName, password)
}
49 changes: 46 additions & 3 deletions pkg/powershell/zpsh_host.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 7fa72aa

Please sign in to comment.