gpt4 book ai didi

Go `defer` 在卸载时没有按预期运行

转载 作者:IT王子 更新时间:2023-10-29 02:32:18 24 4
gpt4 key购买 nike

这是我的 main.go,我使用 go run main.go run sh 创建一个在其中运行 shell 的进程。

package main

import (
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"strconv"
"syscall"

"github.com/sirupsen/logrus"
)

func main() {
if len(os.Args) < 2 {
logrus.Errorf("missing commands")
return
}
switch os.Args[1] {
case "run":
run()
case "child":
child()
default:
logrus.Errorf("wrong command")
return
}
}

func run() {
logrus.Info("Setting up...")
cmd := exec.Command("/proc/self/exe", append([]string{"child"}, os.Args[2:]...)...)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.SysProcAttr = &syscall.SysProcAttr{
Cloneflags: syscall.CLONE_NEWUTS | syscall.CLONE_NEWPID | syscall.CLONE_NEWNS,
}
check(cmd.Run())
}

func child() {
logrus.Infof("Running %v", os.Args[2:])
cmd := exec.Command(os.Args[2], os.Args[3:]...)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
check(syscall.Sethostname([]byte("newhost")))
check(syscall.Chroot("/root/busybox"))
check(os.Chdir("/"))
check(syscall.Mount("proc", "proc", "proc", 0, ""))
check(syscall.Mount("tempdir", "temp", "tmpfs", 0, ""))
check(cmd.Run())
check(syscall.Unmount("proc", 0))
check(syscall.Unmount("temp", 0))
}

func check(err error) {
if err != nil {
logrus.Errorln(err)
}
}

当我在新 shell 中运行 mount 时,它返回

proc on /proc type proc (rw,relatime)
tempdir on /temp type tmpfs (rw,relatime)

这很好用。

但是当我把子函数改成

func child() {
...
check(os.Chdir("/"))
check(syscall.Mount("proc", "proc", "proc", 0, ""))
check(syscall.Mount("tempdir", "temp", "tmpfs", 0, ""))
defer check(syscall.Unmount("proc", 0))
defer check(syscall.Unmount("temp", 0))
check(cmd.Run())
}

然后再次运行mount,它返回mount: no/proc/mounts

defer 用于将其后的函数推迟到外部函数的末尾。但似乎 syscall.Umount() 是在 cmd.Run() 之前调用的。感谢您的帮助。

最佳答案

defer check(syscall.Unmount("proc", 0))
defer check(syscall.Unmount("temp", 0))

您正在推迟 check 调用,但它的参数会立即求值,这意味着 syscall.Unmount 不会被推迟。参见 https://golang.org/ref/spec#Defer_statements

Each time a "defer" statement executes, the function value and parameters to the call are evaluated as usual and saved anew but the actual function is not invoked. Instead, deferred functions are invoked immediately before the surrounding function returns, in the reverse order they were deferred. If a deferred function value evaluates to nil, execution panics when the function is invoked, not when the "defer" statement is executed.

如果您无法摆脱检查调用,请使用匿名函数:

defer func() { check(syscall.Unmount("proc", 0)) }()
defer func() { check(syscall.Unmount("temp", 0)) }()

关于Go `defer` 在卸载时没有按预期运行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46019892/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com