Description
Someone on my team uses the GoLand IDE on MacOS, which uses github.com/google/gops
to list processes to attach a debugger to, which in turn uses goversion
to identify which processes are go programs. They recently ran into an issue where GoLand no longer shows our own builds as a process to attach to, and determined that it was due to an incompatibility with goversion
.
The incompatibility only exists with some of our builds. On these files we get errors like this:
implausible string size 13669722811215734528 for runtime.buildVersion
I stepped through this issue with a debugger, and it turns out some (but not all) of our builds include a "symbolic debugging entry" for _runtime.buildVersion
, which happens to be found earlier in the file than the symbol entry which actually points to its value.
I don't know much about Mach-O, but I was looking at this include file:
https://opensource.apple.com/source/xnu/xnu-201/EXTERNAL_HEADERS/mach-o/nlist.h
The entry that confuses goversion
has a type of 0x20 and a value of 0. According to nlist.h:
/*
* The n_type field really contains three fields:
* unsigned char N_STAB:3,
* N_PEXT:1,
* N_TYPE:3,
* N_EXT:1;
* which are used via the following masks.
*/
#define N_STAB 0xe0 /* if any of these bits set, a symbolic debugging entry */
#define N_PEXT 0x10 /* private external symbol bit */
#define N_TYPE 0x0e /* mask for the type bits */
#define N_EXT 0x01 /* external symbol bit, set for external symbols */
/*
* Only symbolic debugging entries have some of the N_STAB bits set and if any
* of these bits are set then it is a symbolic debugging entry (a stab). In
* which case then the values of the n_type field (the entire field) are given
* in <mach-o/stab.h>
*/
Note that the value of 32 is one of those N_STAB bits.
If I modify goversion
to ignore symbols where (type & 0xe0) != 0
, then goversion
can read the version of our builds again (I will follow up with a PR for this shortly).
Unfortunately I have not been able to come up with a way to reproduce these builds (without sharing code that I do not have permission to share). The only hints I have are that it only started happening after we migrated our code to a go module and/or after we upgraded from go 1.13 to 1.14 (1.14.1, to be precise). I've built a few targets from our repo, and it seems like only the relatively larger builds have these symbols, but I have too few data points so far to conclude that it has anything to do with size or complexity.