Hello,
I noticed that when importing the std "plugin" package then (some ?) 
unexported methods are kept in the binary.

Disclaimer it's something I only observed on a complex binary, I could not 
make a minimal reproducible example, so I'm probably misunderstanding 
something.

When using `-ldflags=-dumpdep` on my complex binary I was seeing something 
like `type:*text/template.Template -> text/template.(*Template).execute`, 
so just having the type `Template` makes the unexported method reachable. 
It disappeared when removing the "plugin" import.

I believe the associated code in the linker is 
https://github.com/golang/go/blob/go1.23.6/src/cmd/link/internal/ld/deadcode.go#L455.
We can see that if we have reflect and the binary is dynamically linked 
(with plugin or shared build modes), then unexported methods are also kept. 
Note that when `dynlink` is true then `reflectSeen` is also set to true, so 
I think you actually don't even need to use reflect for that to happen.

I'm curious why ? The documentation of `Plugin.Lookup` says the symbol must 
be exported https://pkg.go.dev/plugin#Plugin.Lookup .
I would have expected the first part of the condition to be `m.isExported() 
&& (d.reflectSeen || d.dynlink)` instead.

This makes binaries importing "plugin" (and probably plugins and shared 
builds too) significantly bigger, in my case removing the "plugin" import 
reduced the size of various binaries by around 30%.
See https://github.com/containerd/containerd/issues/11202 
and https://github.com/DataDog/datadog-agent/pull/32538 for details.

Thanks !
Pierre.

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion visit 
https://groups.google.com/d/msgid/golang-nuts/3254f0fd-7fe0-4ddd-aab4-918b5f8ae1a2n%40googlegroups.com.

Reply via email to