pkujhd / goloader

load and run golang code at runtime.
Apache License 2.0
506 stars 58 forks source link

macos Lstat使用报index out of range #59

Closed yinhediyi closed 2 years ago

yinhediyi commented 2 years ago

同样的代码使用go直接编译的方式无错误,编译成o文件之后 大概率会报错(偶尔执行成功),WalkDir函数的作用为递归某个给定的目录

fatal error: index out of range

runtime stack: runtime.throw({0x1339ae2?, 0x154eb80?}) /usr/local/go/src/runtime/panic.go:992 +0x71 runtime.panicCheck1(0x2?, {0x1339ae2, 0x12}) /usr/local/go/src/runtime/panic.go:35 +0x87 runtime.goPanicIndex(0x108, 0x9) /usr/local/go/src/runtime/panic.go:88 +0x34 runtime.findfunc(0xc0000f4ea8?) /usr/local/go/src/runtime/symtab.go:845 +0x125 runtime.gentraceback(0x0?, 0x601?, 0x7ff81663da6f?, 0x70000af60c50?, 0x0, 0x0, 0x7fffffff, 0x70000af60d70, 0x0?, 0x0) /usr/local/go/src/runtime/traceback.go:235 +0x6f9 runtime.scanstack(0xc0000021a0, 0xc000030138) /usr/local/go/src/runtime/mgcmark.go:783 +0x1ba runtime.markroot.func1() /usr/local/go/src/runtime/mgcmark.go:241 +0xc5 runtime.markroot(0xc000030138, 0x15, 0x1) /usr/local/go/src/runtime/mgcmark.go:214 +0x1a5 runtime.gcDrain(0xc000030138, 0x7) /usr/local/go/src/runtime/mgcmark.go:1047 +0x39f runtime.gcBgMarkWorker.func2() /usr/local/go/src/runtime/mgc.go:1295 +0x6e runtime.systemstack() /usr/local/go/src/runtime/asm_amd64.s:469 +0x49

goroutine 35 [GC worker (idle)]: runtime.systemstack_switch() /usr/local/go/src/runtime/asm_amd64.s:436 fp=0xc00046ef58 sp=0xc00046ef50 pc=0x1060e20 runtime.gcBgMarkWorker() /usr/local/go/src/runtime/mgc.go:1263 +0x1b1 fp=0xc00046efe0 sp=0xc00046ef58 pc=0x101beb1 runtime.goexit() /usr/local/go/src/runtime/asm_amd64.s:1571 +0x1 fp=0xc00046efe8 sp=0xc00046efe0 pc=0x1063061 created by runtime.gcBgMarkStartWorkers /usr/local/go/src/runtime/mgc.go:1131 +0x25

goroutine 1 [GC assist marking (scan)]: syscall.ByteSliceFromString(...) /usr/local/go/src/syscall/syscall.go:53 syscall.BytePtrFromString(...) /usr/local/go/src/syscall/syscall.go:69 syscall.Lstat({0xc0004aec00?, 0xc0000c4b70?}, 0xc000680038?) /usr/local/go/src/syscall/zsyscall_darwin_amd64.go:1919 +0x6a os.lstatNolog.func1(...) /usr/local/go/src/os/stat_unix.go:45 os.ignoringEINTR(...) /usr/local/go/src/os/file_posix.go:245 os.lstatNolog({0xc0004aec00, 0x80}) /usr/local/go/src/os/stat_unix.go:44 +0x4f os.Lstat({0xc0004aec00, 0x80}) /usr/local/go/src/os/stat.go:22 +0x34 os.(File).readdir(0xc0000b9ae8, 0xffffffffffffffff, 0x2) /usr/local/go/src/os/dir_darwin.go:85 +0x692 os.(File).Readdir(0xc0004aeb00?, 0x77?) /usr/local/go/src/os/dir.go:41 +0x25 io/ioutil.ReadDir({0xc0004aeb00?, 0x1?}) /usr/local/go/src/io/ioutil/ioutil.go:63 +0x45 main.WalkDir({0xc0004aeb00, 0x77}, {0xc0003ea000, 0x953, 0xa00}) /Users/john/go/src/plugins/system/system_darwin.go:179 +0x53 main.WalkDir({0xc000497030, 0x6e}, {0xc0003ea000, 0x933, 0xa00}) /Users/john/go/src/plugins/system/system_darwin.go:186 +0x2a5 main.WalkDir({0xc000496a80, 0x67}, {0xc0003ea000, 0x923, 0xa00}) /Users/john/go/src/plugins/system/system_darwin.go:186 +0x2a5 main.WalkDir({0xc000424f60, 0x5e}, {0xc0003ea000, 0x923, 0xa00}) /Users/john/go/src/plugins/system/system_darwin.go:186 +0x2a5 main.WalkDir({0xc000424ba0, 0x5b}, {0xc0003ea000, 0x829, 0xa00}) /Users/john/go/src/plugins/system/system_darwin.go:186 +0x2a5 main.WalkDir({0xc0001c4c00, 0x32}, {0xc0003ea000, 0x829, 0xa00}) /Users/john/go/src/plugins/system/system_darwin.go:186 +0x2a5 main.WalkDir({0xc00019e0f0, 0x30}, {0xc0003ea000, 0x829, 0xa00}) /Users/john/go/src/plugins/system/system_darwin.go:186 +0x2a5 main.WalkDir({0xc0000b5f80, 0x25}, {0xc0003ea000, 0x7dd, 0xa00}) /Users/john/go/src/plugins/system/system_darwin.go:186 +0x2a5 main.WalkDir({0xc0000b5e60, 0x21}, {0xc0003ea000, 0x7dd, 0xa00}) /Users/john/go/src/plugins/system/system_darwin.go:186 +0x2a5 main.WalkDir({0xc00001ada0, 0x1d}, {0xc0003ea000, 0x7dc, 0xa00}) /Users/john/go/src/plugins/system/system_darwin.go:186 +0x2a5 main.WalkDir({0xc00001ace0, 0x1a}, {0xc0004fa580, 0x4, 0x4}) /Users/john/go/src/plugins/system/system_darwin.go:186 +0x2a5 fatal error: index out of range panic during panic

runtime stack: runtime.throw({0x1339ae2?, 0x154eb80?}) /usr/local/go/src/runtime/panic.go:992 +0x71 runtime.panicCheck1(0x0?, {0x1339ae2, 0x12}) /usr/local/go/src/runtime/panic.go:35 +0x87 runtime.goPanicIndex(0x108, 0x9) /usr/local/go/src/runtime/panic.go:88 +0x34 runtime.findfunc(0xc0000f4ea8?) /usr/local/go/src/runtime/symtab.go:845 +0x125 runtime.gentraceback(0x1064873?, 0x70000af60480?, 0x1062d81?, 0x1?, 0x0, 0x0, 0x64, 0x0, 0x70000af60458?, 0x0) /usr/local/go/src/runtime/traceback.go:235 +0x6f9 runtime.traceback1(0xc0000021a0?, 0x1035600?, 0x3?, 0xc0000021a0, 0x1059eca?) /usr/local/go/src/runtime/traceback.go:835 +0x1b1 runtime.traceback(...) /usr/local/go/src/runtime/traceback.go:782 runtime.tracebackothers.func1(0xc0000021a0) /usr/local/go/src/runtime/traceback.go:1051 +0xe5 runtime.forEachGRace(0x70000af60660) /usr/local/go/src/runtime/proc.go:590 +0x4d runtime.tracebackothers(0xc0005821a0?) /usr/local/go/src/runtime/traceback.go:1037 +0xdb runtime.dopanic_m(0xc0005821a0, 0x1?, 0x1?) /usr/local/go/src/runtime/panic.go:1192 +0x27c runtime.fatalthrow.func1() /usr/local/go/src/runtime/panic.go:1047 +0x48 runtime.fatalthrow() /usr/local/go/src/runtime/panic.go:1044 +0x50 runtime.throw({0x1339ae2?, 0x154eb80?}) /usr/local/go/src/runtime/panic.go:992 +0x71 runtime.panicCheck1(0x2?, {0x1339ae2, 0x12}) /usr/local/go/src/runtime/panic.go:35 +0x87 runtime.goPanicIndex(0x108, 0x9) /usr/local/go/src/runtime/panic.go:88 +0x34 runtime.findfunc(0xc0000f4ea8?) /usr/local/go/src/runtime/symtab.go:845 +0x125 runtime.gentraceback(0x0?, 0x601?, 0x7ff81663da6f?, 0x70000af60c50?, 0x0, 0x0, 0x7fffffff, 0x70000af60d70, 0x0?, 0x0) /usr/local/go/src/runtime/traceback.go:235 +0x6f9 runtime.scanstack(0xc0000021a0, 0xc000030138) /usr/local/go/src/runtime/mgcmark.go:783 +0x1ba runtime.markroot.func1() /usr/local/go/src/runtime/mgcmark.go:241 +0xc5 runtime.markroot(0xc000030138, 0x15, 0x1) /usr/local/go/src/runtime/mgcmark.go:214 +0x1a5 runtime.gcDrain(0xc000030138, 0x7) /usr/local/go/src/runtime/mgcmark.go:1047 +0x39f runtime.gcBgMarkWorker.func2() /usr/local/go/src/runtime/mgc.go:1295 +0x6e runtime.systemstack() /usr/local/go/src/runtime/asm_amd64.s:469 +0x49

目录结构无更改的情况下连续调用WalkDir函数 有几率panic

image

WalkDir函数代码

func WalkDir(pathname string, s []string) ([]string, error) {
    fromSlash := filepath.FromSlash(pathname)
    rd, err := ioutil.ReadDir(fromSlash)
    if err != nil {
        return s, err
    }
    for _, fi := range rd {
        if fi.IsDir() {
            fullDir := filepath.Join(fromSlash, fi.Name())
            s, err = WalkDir(fullDir, s)
            if err != nil {
                return s, err
            }
        } else {
            fullName := filepath.Join(fromSlash, fi.Name())
            s = append(s, fullName)
        }
    }
    return s, nil
}
pkujhd commented 2 years ago

@yinhediyi 给出你的运行环境 golang version, osx version and cpu arch

yinhediyi commented 2 years ago
$ go env
GO111MODULE="off"
GOARCH="amd64"
GOBIN=""
GOCACHE="/Users/john/Library/Caches/go-build"
GOENV="/Users/john/Library/Application Support/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOINSECURE=""
GOMODCACHE="/Users/john/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="darwin"
GOPATH="/Users/john/go"
GOPRIVATE=""
GOPROXY="https://goproxy.cn,direct"
GOROOT="/usr/local/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/darwin_amd64"
GOVCS=""
GOVERSION="go1.18"
GCCGO="gccgo"
GOAMD64="v1"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD=""
GOWORK=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -arch x86_64 -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/v8/637fvyq12fbcg3gyg9znmnkr0000gn/T/go-build2882249859=/tmp/go-build -gno-record-gcc-switches -fno-common"

# john @ johndeMacBook-Pro-5 in ~ [11:25:10]
$ sw_vers
ProductName:    macOS
ProductVersion: 12.5
BuildVersion:   21G72

CPU:x86_64

目前我测试下来觉得并不是macos的特有问题 windows也同样存在数组越界的问题 我估计可能是跟函数执行的时间或者返回的数据大小有关(是否有限制内存的使用)?

pkujhd commented 2 years ago

@yinhediyi 无法复现你的错误,麻烦给下完整的case,看你的调用栈可能是functab的问题. 和内存没关闭

yinhediyi commented 2 years ago

方便发一下您的邮箱地址吗?

pkujhd commented 2 years ago

@yinhediyi
你可以尝试修改下ld.go:377行,将 module.maxpc = uintptr(segment.dataBase) 修改为 module.maxpc = uintptr(segment.codeBase + segment.offset) 看是否还有问题?

yinhediyi commented 2 years ago

@pkujhd 大哥稍等一下 我刚刚把代码精简到只剩下一个函数的时候居然复现不了了 我尝试弄一个代码量最少 并且能复现问题的版本出来

pkujhd commented 2 years ago

@pkujhd 大哥稍等一下 我刚刚把代码精简到只剩下一个函数的时候居然复现不了了 我尝试弄一个代码量最少 并且能复现问题的版本出来

如果是我上面猜测的那个问题导致的话,改变代码会导致问题不出现,你可以还原到你之前到版本,修改下那个代码测试一下,看是否会修正问题

yinhediyi commented 2 years ago

按照您说的方法去修改ld.go 依然存在同样的问题

yinhediyi commented 2 years ago

@pkujhd 复现代码已经发送到您的邮箱了

pkujhd commented 2 years ago

@yinhediyi 使用你提供的case也无法复现你的错误

yinhediyi commented 2 years ago

@pkujhd 方便加个微信吗? 我邮箱发您

pkujhd commented 2 years ago

记录问题,当text段的长度>=4096(pcbucketsize)时,用pc查找函数时回出现问题,原因是之前版本的fillfuncbucket的填充错误