golang / go

The Go programming language
https://go.dev
BSD 3-Clause "New" or "Revised" License
121.66k stars 17.41k forks source link

runtime: poor error message for Goexit on C-created thread #68275

Open prattmic opened 4 weeks ago

prattmic commented 4 weeks ago

Go version

tip

Output of go env in your module/workspace:

N/A

What did you do?

// Copyright 2024 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

/*
#include <pthread.h>

void go_callback();

static void *thr(void *arg) {
    go_callback();
    return 0;
}

static void foo() {
    pthread_t th;
    pthread_attr_t attr;
    pthread_attr_init(&attr);
    pthread_attr_setstacksize(&attr, 256 << 10);
    pthread_create(&th, &attr, thr, 0);
    pthread_join(th, 0);
}
*/
import "C"

import (
        "runtime"
)

//export go_callback
func go_callback() {
        runtime.Goexit()
}

func main() {
        C.foo()
}

What did you see happen?

runtime: mp.lockedInt = 1               
fatal error: exited a goroutine internally locked to the OS thread
runtime stack:
runtime.throw({0x4851c4?, 0x600000000?})
        /usr/lib/google-golang/src/runtime/panic.go:1069 +0x48 fp=0x7fe3895c5dd0 sp=0x7fe3895c5da0 pc=0x460028
runtime.gdestroy(0xc000006700)
        /usr/lib/google-golang/src/runtime/proc.go:4324 +0x2a5 fp=0x7fe3895c5e10 sp=0x7fe3895c5dd0 pc=0x43bc85
runtime.goexit0(0xc000006700?)
        /usr/lib/google-golang/src/runtime/proc.go:4278 +0x13 fp=0x7fe3895c5e28 sp=0x7fe3895c5e10 pc=0x43b9b3
runtime.mcall()
        /usr/lib/google-golang/src/runtime/asm_amd64.s:459 +0x4e fp=0x7fe3895c5e40 sp=0x7fe3895c5e28 pc=0x46450e

goroutine 1 gp=0xc0000061c0 m=0 mp=0x4fcf20 [syscall]:
runtime.cgocall(0x46ab00, 0xc000058740)
        /usr/lib/google-golang/src/runtime/cgocall.go:167 +0x4b fp=0xc000058718 sp=0xc0000586e0 pc=0x45d60b
main._Cfunc_foo()
        _cgo_gotypes.go:43 +0x3f fp=0xc000058740 sp=0xc000058718 pc=0x46aa3f
main.main() 
        /tmp/c/main.go:38 +0xf fp=0xc000058750 sp=0xc000058740 pc=0x46aa6f
runtime.main()
        /usr/lib/google-golang/src/runtime/proc.go:272 +0x28b fp=0xc0000587e0 sp=0xc000058750 pc=0x4337eb
runtime.goexit({})
        /usr/lib/google-golang/src/runtime/asm_amd64.s:1700 +0x1 fp=0xc0000587e8 sp=0xc0000587e0 pc=0x4664e1

Note that this error was improved a bit recently in https://go.dev/cl/583675. In 1.22, the error is

invalid m->lockedInt = 1
fatal error: internal lockOSThread error

runtime stack:
...

What did you expect to see?

A more clear description of the problem.

The problem here is that it is not valid to call runtime.Goexit in a cgo callback from C to Go on a C-created thread. I think that restriction is fine (it is unclear what Goexit should do if we were to allow it), but the error message here should be more clear.

I think with an additional mp.isextra check in gdestroy we could be more explicit about what the user did wrong.

We should also update the runtime.Goexit docs to mention this case.

prattmic commented 4 weeks ago

cc @golang/runtime

gabyhelp commented 4 weeks ago

Related Issues

(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)