Почему в главной функции в src / runtime / proc.go есть, казалось бы, бесполезный бесконечный цикл for? - PullRequest
1 голос
/ 29 марта 2019

Сегодня я наткнулся на пост, спрашивающий об этом вопросе.В конце основной функции в src/runtime/proc.go есть, казалось бы, бесполезный бесконечный цикл for.Почему это там?

ссылка на исходный код

    if atomic.Load(&panicking) != 0 {
        gopark(nil, nil, waitReasonPanicWait, traceEvGoStop, 1)
    }

    exit(0)
    for {
        var x *int32
        *x = 0
    }

1 Ответ

1 голос
/ 29 марта 2019

Назначение 0 защищенной области памяти, например *(*int)(nil) = 0 и *x = 0 в системах с блок защиты памяти вызывает ошибка сегментации и останавливает программу,
А в системах без модуля защиты памяти просто записывает 0 по адресу памяти в ноль и ничего не происходит, поэтому они добавили цикл for для остановки программы (ЦП) там.

  1. Обычно это (должно быть) недоступный код .

  2. Файл: ~/go/src/runtime/proc.go в конце func main():

    exit(0)
    for {
        var x *int32
        *x = 0
    }

исх

Время выполнения - это особый случай во многих отношениях, и это один из специальные части. Этот цикл существует для обнаружения проблем при тестировании новых порты. Если этот цикл когда-либо достигнут, что-то пошло не так: вызов на выход должен был вызвать выход из программы. Мы не можем предположить эта паника работает. Мы не можем предположить, что что-то за работой. Что мы хотим сделать, это остановить программу. Так как выход не состоялся, Вполне возможно, что разыменование будет успешным. Если и это не поможет, нам еще нужно что-то делать, поэтому мы просто зацикливаемся. Мы не можем вернуться потому что это основная функция, которая запустила программу; есть нечего возвращаться


  1. Также звонит panic("err msg") здесь, внутри /usr/local/go/src/runtime/panic.go, в конце func fatalpanic(msgs *_panic) имеет недоступный код :
    systemstack(func() {
        exit(2)
    })

    *(*int)(nil) = 0 // not reached
}

  1. Здесь var x *int: x - указатель nil, поэтому *x = 0 - паника: ошибка времени выполнения: неверный адрес памяти или разыменование нулевого указателя и вызывает нарушение сегментации:
package main

func main() {
    var x *int
    *x = 0
}

Выход:

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x44f972]

  1. Здесь для теста предложите сгенерировать панику и восстановиться:
    Файл ~/go/src/internal/x/crypto/cryptobyte/cryptobyte_test.go
func TestGeneratedPanic(t *testing.T) {
    defer func() {
        recover()
    }()

    var b Builder
    b.AddUint8LengthPrefixed(func(b *Builder) {
        var p *byte
        *p = 0
    })

    t.Error("Builder did not panic")
}

  1. Файл ~/go/src/cmd/compile/internal/gc/subr.go:
func hcrash() {
    if Debug['h'] != 0 {
        flusherrors()
        if outfile != "" {
            os.Remove(outfile)
        }
        var x *int
        *x = 0
    }
}
  1. Файл ~/go/pkg/bootstrap/src/bootstrap/cmd/compile/internal/gc/subr.go:
func hcrash() {
    if Debug['h'] != 0 {
        flusherrors()
        if outfile != "" {
            os.Remove(outfile)
        }
        var x *int
        *x = 0
    }
}

Который называется здесь ~/go/src/cmd/compile/internal/gc/subr.go в конце:


func Fatalf(fmt_ string, args ...interface{}) {
    flusherrors()

    if Debug_panic != 0 || nsavederrors+nerrors == 0 {
        fmt.Printf("%v: internal compiler error: ", linestr(lineno))
        fmt.Printf(fmt_, args...)
        fmt.Printf("\n")

        // If this is a released compiler version, ask for a bug report.
        if strings.HasPrefix(objabi.Version, "go") {
            fmt.Printf("\n")
            fmt.Printf("Please file a bug report including a short program that triggers the error.\n")
            fmt.Printf("https://golang.org/issue/new\n")
        } else {
            // Not a release; dump a stack trace, too.
            fmt.Println()
            os.Stdout.Write(debug.Stack())
            fmt.Println()
        }
    }

    hcrash()
    errorexit()
}

  1. Следующий код паникует здесь, внутри /usr/local/go/src/runtime/panic.go в конце func fatalpanic(msgs *_panic):
    systemstack(func() {
        exit(2)
    })

    *(*int)(nil) = 0 // not reached
}

Код для паники! (похоже на Звонок panic("err msg"):

package main

import (
    "fmt"
    "math/rand"
)

func main() {
    r := rand.Rand{}
    i := r.Int()
    fmt.Println(i)
}

Выход:

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0xffffffff addr=0x0 pc=0xd8276]

goroutine 1 [running]:
math/rand.(*Rand).Int63(...)
    /usr/local/go/src/math/rand/rand.go:85
math/rand.(*Rand).Int(...)
    /usr/local/go/src/math/rand/rand.go:103
main.main()
    /tmp/sandbox449835614/main.go:10 +0x36
...