cch123 / supermonkey

Patch all Go functions for testing
MIT License
251 stars 17 forks source link

patch fun after how get origin fun #12

Open zeromake opened 3 years ago

zeromake commented 3 years ago

not use UnPatch

package main

import (
    "fmt"
    sm "github.com/cch123/supermonkey"
    "time"
)
//go:noinline
func Now() time.Time {
    return time.Time{}
}

func main() {
    sm.Patch(time.Now, Now)
    fmt.Println(time.Now())
    // how call origin Now fun
}
zeromake commented 3 years ago

@Mutated1994 What I want is not to use Unpatch

ioworker0 commented 3 years ago

@Mutated1994 What I want is not to use Unpatch

Unfortunately, you might not be able to call original function without Unpatch.

zeromake commented 3 years ago

a scenario main.go:

package main

import (
    sm "github.com/cch123/supermonkey"
    "log"
    "time"
    "unsafe"
)

//go:linkname runtimeNano runtime.nanotime
func runtimeNano() int64

//go:linkname now time.now
func now() (sec int64, nsec int32, mono int64)

var startNano = runtimeNano() - 1

type _time struct {
    wall uint64
    ext  int64
    loc  *time.Location
}

const (
    secondsPerMinute = 60
    secondsPerHour   = 60 * secondsPerMinute
    secondsPerDay    = 24 * secondsPerHour
)

const (
    unixToInternal int64 = (1969*365 + 1969/4 - 1969/100 + 1969/400) * secondsPerDay
    wallToInternal int64 = (1884*365 + 1884/4 - 1884/100 + 1884/400) * secondsPerDay
)

const (
    hasMonotonic = 1 << 63
    minWall      = wallToInternal // year 1885
    nsecShift    = 30
)

func _now() time.Time {
    sec, nsec, mono := now()
    mono -= startNano
    sec += unixToInternal - minWall
    var t *_time
    if uint64(sec)>>33 != 0 {
        t = &_time{uint64(nsec), sec + minWall, time.Local}
    } else {
        t = &_time{hasMonotonic | uint64(sec)<<nsecShift | uint64(nsec), mono, time.Local}
    }
    return *(*time.Time)(unsafe.Pointer(t))
}

func patchNow() time.Time {
    return time.Time{}
}

func main()  {
    log.Println("std:", time.Now())
    log.Println("customization:", _now())
    sm.Patch(time.Now, patchNow)
    log.Println("std:", time.Now())
    log.Println("customization:", _now())
}

output:

$ go run main.go
2021/09/22 19:08:03 std: 2021-09-22 19:08:03.4244406 +0800 CST m=+0.006212801
2021/09/22 19:08:03 customization: 2021-09-22 19:08:03.430072 +0800 CST m=+0.005631401
0001/01/01 00:00:00 std: 0001-01-01 00:00:00 +0000 UTC
0001/01/01 00:00:00 customization: 2021-09-22 19:08:03.430072 +0800 CST m=+0.005631401