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/coverage: covcounters not written in -buildmode=c-shared #64371

Open
1 task done
spacewander opened this issue Nov 24, 2023 · 10 comments
Open
1 task done

runtime/coverage: covcounters not written in -buildmode=c-shared #64371

spacewander opened this issue Nov 24, 2023 · 10 comments
Assignees
Labels
compiler/runtime Issues related to the Go compiler and/or runtime. NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Milestone

Comments

@spacewander
Copy link
Contributor

Go version

go version go1.21.4 linux/arm64

Reproducibility

  • Does this issue reproduce with the latest release?

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

GO111MODULE=''
GOARCH='arm64'
GOBIN=''
GOCACHE='/root/.cache/go-build'
GOENV='/root/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFLAGS=''
GOHOSTARCH='arm64'
GOHOSTOS='linux'
GOINSECURE=''
GOMODCACHE='/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPATH='/go'
GOPRIVATE=''
GOPROXY='https://goproxy.cn'
GOROOT='/usr/local/go'
GOSUMDB='sum.golang.org'
GOTMPDIR=''
GOTOOLCHAIN='local'
GOTOOLDIR='/usr/local/go/pkg/tool/linux_arm64'
GOVCS=''
GOVERSION='go1.21.4'
GCCGO='gccgo'
AR='ar'
CC='gcc'
CXX='g++'
CGO_ENABLED='1'
GOMOD='/go/src/mosn.io/moe/go.mod'
GOWORK=''
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
PKG_CONFIG='pkg-config'
GOGCCFLAGS='-fPIC -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build681226605=/tmp/go-build -gno-record-gcc-switches'

What did you do?

  1. built Go program into a shared library by using CGO_ENABLED=1 go build -cover --buildmode=c-shared -o libgolang.so.
  2. Run a process with env variable GOCOVERDIR set, the process will load the libgolang.so.
  3. The process exited.
  4. I checked the GOCOVERDIR, only covmeta file is generated.

What did you expect to see?

Both covmeta and covcounters file should be generated.

What did you see instead?

Only covmeta file is generated.
Look like when Go code runs as a shared library, the covcounters file is not flushed when the host process exits.

Currently, I work around this by calling coverage.WriteCounters manually.

@seankhliao seankhliao changed the title go build -cover: doesn't work when --buildmode=c-shared runtime/coverage: covcounters not written in -buildmode=c-shared Nov 24, 2023
@dmitshur
Copy link
Contributor

CC @thanm.

@dmitshur dmitshur added NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. compiler/runtime Issues related to the Go compiler and/or runtime. labels Nov 27, 2023
@dmitshur dmitshur added this to the Backlog milestone Nov 27, 2023
@thanm thanm self-assigned this Nov 27, 2023
@thanm thanm added the WaitingForInfo Issue is not actionable because of missing required information, which needs to be provided. label Nov 27, 2023
@thanm
Copy link
Contributor

thanm commented Nov 27, 2023

Thanks for the report.

If you could please post a complete example, that would be helpful. In particular, does your example program invoke os.Exit() when it terminates?

@spacewander
Copy link
Contributor Author

does your example program invoke os.Exit() when it terminates?

No, it can't. The program loads the Go shared library is a C++ program, so it won't invoke os.Exit() when it terminates.

If you could please post a complete example, that would be helpful.

It is a Go plugin running inside Envoy: https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/golang_filter.html#golang.

It would require knowledge about Envoy (a network proxy) to run the example. I am glad to give you help if you need.

@thanm
Copy link
Contributor

thanm commented Nov 28, 2023

No, it can't. The program loads the Go shared library is a C++ program, so it won't invoke os.Exit() when it terminates.

Thanks for that.

Given that the Go code is running as a plugin of some sort and is only invoked at the behest of the main process, and isn't being notified when the program terminates, how exactly would you imagine it would be possible to write out coverage counters?

Unless the Go runtime within the plugin has some idea that the program is complete, it doesn't seem as though there's much the runtime can do. I think this is a case where it needs a bit of help from the main program, would you not agree?

@spacewander
Copy link
Contributor Author

No, it can't. The program loads the Go shared library is a C++ program, so it won't invoke os.Exit() when it terminates.

Thanks for that.

Given that the Go code is running as a plugin of some sort and is only invoked at the behest of the main process, and isn't being notified when the program terminates, how exactly would you imagine it would be possible to write out coverage counters?

Unless the Go runtime within the plugin has some idea that the program is complete, it doesn't seem as though there's much the runtime can do. I think this is a case where it needs a bit of help from the main program, would you not agree?

Thanks for your reply.
Is it possible that Go can register something like atexit or add hook to dlclose, so that when the program is gone, the Go code can be noticed and flush the counter?

@seankhliao seankhliao removed the WaitingForInfo Issue is not actionable because of missing required information, which needs to be provided. label Jan 13, 2024
@sotirisk
Copy link

sotirisk commented Nov 12, 2024

@spacewander I have the same problem but in my case it does not work properly even with your work around.

in Makefile

instrumented:
GO111MODULE=off go build -cover -covermode=atomic -o lib_um.so -buildmode=c-shared -ldflags="-s -w" ../src/auth.go
gcc -ftest-coverage -fprofile-arcs -shared -o pam.so -I . -DPAM -fPIC ../src/go_auth.c -lcrypt -lcurl -lpthread -ldl -lpam -L. -lum
install:
sudo cp pam.so /usr/lib64/security/
sudo install -m 0755 libzts_um.so /lib64 ; sudo ldconfig

and in the code i have added

    import (
            "runtime/coverage"
    )

and before the main function returns

    writeCoverageData()
    return pamSuccess
	
    func writeCoverageData() {
        coverageFile := "/tmp/auth.go_coverage.out"
        file, err := os.Create(coverageFile)
        if err != nil {
	        panic(err)
        }
        defer file.Close()
        if err := coverage.WriteCounters(file); err != nil {
	        panic(err)
        }
    }		

after successful ssh login (this is a PAM module) I get this file which cannot be read

bash-4.4# go tool cover -func=/tmp/auth.go_coverage.out
cover: bad mode line: cwm����tQ�-��f
bash-4.4#
bash-4.4#
bash-4.4# cat /tmp/auth.go_coverage.out
cwm����tQ�-��f
��@
argc2argv0sshd: user5 [priv]argv1GOOSlinuxGOARCHamd64Rcwmbash-4.4#

@spacewander
Copy link
Contributor Author

This workaround is done by flushing the coverage manually at the proper time. I know nothing about PAM, maybe because it doesn't flush the coverage at the right moment.

@wangpeilin
Copy link

@spacewander Hello, I want to manually export coverage data during program execution instead of waiting the program terminates. I also called the coverage.WriteCounters method to output a binary file, but the file cannot be parsed correctly. So I want to know how you manually output coverage and read coverage files. Can you share the code? Thank you very much

@spacewander
Copy link
Contributor Author

I call https://github.com/mosn/htnn/blob/855823f2e50e6c2cc53568fe43be1a17dcd904df/api/plugins/tests/integration/dataplane/plugins.go#L55 at the end of each TestXXX.

@wangpeilin
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compiler/runtime Issues related to the Go compiler and/or runtime. NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Projects
Development

No branches or pull requests

6 participants