Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

runtime/cgo: call C exit to allow global destructors/atexit to run #20713

Open
h1467792822 opened this issue Jun 17, 2017 · 7 comments

Comments

Projects
None yet
7 participants
@h1467792822
Copy link

commented Jun 17, 2017

Please answer these questions before submitting your issue. Thanks!

What version of Go are you using (go version)?

go version go1.8 linux/amd64

What operating system and processor architecture are you using (go env)?

GOARCH="amd64"
GOBIN=""
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/home/go"
GORACE=""
GOROOT="/usr/local/go"
GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
GCCGO="gccgo"
CC="gcc"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build855140157=/tmp/go-build -gno-record-gcc-switches"
CXX="g++"
CGO_ENABLED="1"
PKG_CONFIG="pkg-config"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"

What did you do?

I want to do something in the destructor of a global variable defined in c++ library which is linked into a go program via cgo. but the destructor can't be invoked when the go program exited.

//c++ library
class AutoInit
{
public:
AutoInit() { printf("+++++ auto init\n"); }
~AutoInit() { printf("---- auto fini\n"); }
};

What did you expect to see?

two lines should be printed:
+++++ auto init
---- auto fini

What did you see instead?

only one line was be printed:
+++++ auto init

@Konstantin8105

This comment has been minimized.

Copy link
Contributor

commented Jun 18, 2017

Could you clarify your CPP and Go code.

@h1467792822

This comment has been minimized.

Copy link
Author

commented Jun 19, 2017

//library files:
//tmp_log.h
#ifndef TMP_LOG_H
#define TMP_LOG_H

#ifdef __cplusplus
extern "C"
{
#endif

void tmp_log(const char* msg);

#ifdef __cplusplus
}
#endif

#endif

//tmp_log.cpp
#include "tmp_log.h"
#include <stdio.h>

extern "C"
{

void tmp_log(const char* msg)
{
printf("%s",msg);
}

}

struct Auto_Init
{
Auto_Init() {
tmp_log("++++ auto_init\n");
}
~Auto_Init() {
tmp_log("--- auto_fini\n");
}
};
static Auto_Init auto_init;

//compile
g++ -shared -fPIC -g -o libtmp_log.so tmp_log.cpp

//go files: go/src/tmp/log.go
package log

import(
"unsafe"
)

/*
#cgo CPPFLAGS: -I./tool -I.
#cgo LDFLAGS: -L./tool -L. -ltmp_log
#include "tmp_log.h"
#include <malloc.h>
*/
import "C"

func Log(msg string) {
cmsg := C.CString(msg)
C.tmp_log(cmsg)
C.free(unsafe.Pointer(cmsg))
}

//tool.go
package main

import (
"tmp/log"
)

func main() {
log.Log("go is running\n")
}

//run tool:
$ LD_LIBRARY_PATH=. ./tool
++++ auto_init
go is running

//c test, tool.c
#include "tmp_log.h"

int main(int argc,char* argv[])
{
tmp_log("*** tmp_log running\n");
return 0;
}
//compile
gcc -g -o c_tool tool.c -L. -ltmp_log
//run c tool
$ LD_LIBRARY_PATH=. ./c_tool
++++ auto_init
*** tmp_log running
--- auto_fini

@bradfitz

This comment has been minimized.

Copy link
Member

commented Jun 19, 2017

@bradfitz bradfitz changed the title cgo don't invoke the destructor of global variant defined in c++ library runtime/cgo: destructor of global variant defined in c++ library are not invoked Jun 19, 2017

@bradfitz bradfitz added this to the Go1.10 milestone Jun 19, 2017

@ianlancetaylor

This comment has been minimized.

Copy link
Contributor

commented Jun 19, 2017

It's true that Go programs don't currently run the C++ static destructors of any code linked in via cgo.

I guess the way to fix this would be for cgo programs to call the C library exit function rather than the exit system call.

@rsc rsc changed the title runtime/cgo: destructor of global variant defined in c++ library are not invoked runtime/cgo: call C exit to allow global destructors/atexit to run Jun 26, 2017

@ianlancetaylor ianlancetaylor self-assigned this Jun 26, 2017

@rsc rsc modified the milestones: Go1.10, Go1.11 Nov 29, 2017

@rsc

This comment has been minimized.

Copy link
Contributor

commented Nov 29, 2017

I agree we need to do this, although I am very sad about it. It didn't happen for Go 1.10, though, so at least there's that to be happy about.

@bcmills

This comment has been minimized.

Copy link
Member

commented Jan 8, 2018

It occurs to me that this will have an unfortunate interaction with log.Fatal: log.Fatal is defined to call os.Exit(1), which (after this is addressed) will invoke atexit hooks.

However, atexit hooks are not normally invoked if a program terminates abnormally, and I would argue that most uses of log.Fatal indicate abnormal termination. (I would argue that ideally log.Fatal should instead exit by raising SIGABRT.)

I don't think that interaction is fixable for Go 1, since the os.Exit behavior is clearly documented in the log API, but we should at least consider the interaction and perhaps revisit it for Go 2.

@ryanp76

This comment has been minimized.

Copy link

commented Jun 6, 2018

Just wanted to comment on other issues we have encountered due to this issue. When attempting to extract GCOV or mem track data for the C code, these tools require a C exit. Currently we have to explicitly call the exit() function in our test framework which prevents the go test code from finishing up. Please consider this when deciding the priority for the fix. We are looking forward to removing these workarounds once you have a fix. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.