'Go programs won't run after MacOS Catalina upgrade

This might be a weird question, but some programs written in Go won't run on my MacBook Pro after MacOS Catalina upgrade.

However a basic "Hello World" program runs, but then I am using the writing a program using net/http package I get the following error:

Note: The programs are correct, they run fine inside a Docker container

Output (IntelliJ):


# runtime/cgo
In file included from gcc_darwin_amd64.c:6:
/usr/local/include/pthread.h:331:6: error: macro expansion producing 'defined' has undefined behavior [-Werror,-Wexpansion-to-defined]
/usr/local/include/pthread.h:200:2: note: expanded from macro '_PTHREAD_SWIFT_IMPORTER_NULLABILITY_COMPAT'
/usr/local/include/pthread.h:331:6: error: macro expansion producing 'defined' has undefined behavior [-Werror,-Wexpansion-to-defined]
/usr/local/include/pthread.h:200:34: note: expanded from macro '_PTHREAD_SWIFT_IMPORTER_NULLABILITY_COMPAT'
/usr/local/include/pthread.h:540:6: error: macro expansion producing 'defined' has undefined behavior [-Werror,-Wexpansion-to-defined]
/usr/local/include/pthread.h:200:2: note: expanded from macro '_PTHREAD_SWIFT_IMPORTER_NULLABILITY_COMPAT'
/usr/local/include/pthread.h:540:6: error: macro expansion producing 'defined' has undefined behavior [-Werror,-Wexpansion-to-defined]
/usr/local/include/pthread.h:200:34: note: expanded from macro '_PTHREAD_SWIFT_IMPORTER_NULLABILITY_COMPAT'

Things that I have already tried:

  1. Reinstall go
  2. Reinstall xcode
  3. Check if GOPATH & GOROOT are properly set

Used:

MacOS version - Catalina 10.15.6
Go version - go1.15.2 darwin/amd64


Solution 1:[1]

Sadly, none of the tryouts worked.

I have been using IntelliJ IDEA Ultimate for sometime now.. so I tried to setup Go SDK, GOROOT and GOPATH using the IDE (just a thought came to my mind).

I uninstalled/deleted everything related to Go on my MacBook.

Then I installed the Go plugin on IntelliJ IDEA and as expected it prompted that Go SDK is not available, neither GOROOT and GOPATH are set.

I followed the instructions and IntelliJ IDEA took care of the rest!

It downloaded and installed Go SDK, asked me to select GOPATH, it indexed stuff and now every thing is working like a charm!

Solution 2:[2]

Type xcode-select -print-path in terminal window and check your installed directory. In my case the output was: /Applications/Xcode.app/Contents/Developer

If it's the same case then using the following command on your terminal can fix things:

sudo xcode-select --switch /Library/Developer/CommandLineTools

Another option is to use CGO_CPPFLAGS as mentioned in this issue, but it would work within the session:

export CGO_CPPFLAGS="-Wno-error -Wno-nullability-completeness -Wno-expansion-to-defined -Wno-builtin-requires-header"

Solution 3:[3]

This is a bug in the <pthread.h> that ships with macOS tools:

This macro is even bogus for more than one reason! The definition in <pthread.h> is this:

#define _PTHREAD_SWIFT_IMPORTER_NULLABILITY_COMPAT \
    defined(SWIFT_CLASS_EXTRA) && (!defined(SWIFT_SDK_OVERLAY_PTHREAD_EPOCH) || (SWIFT_SDK_OVERLAY_PTHREAD_EPOCH < 1))

The macro expansion is not properly parenthesized. The macro is used this way in the same file:

#if !_PTHREAD_SWIFT_IMPORTER_NULLABILITY_COMPAT

Which expands to:

#if !defined(SWIFT_CLASS_EXTRA) && (!defined(SWIFT_SDK_OVERLAY_PTHREAD_EPOCH) || (SWIFT_SDK_OVERLAY_PTHREAD_EPOCH < 1))

The ! only applies to the first test defined(SWIFT_CLASS_EXTRA) not to the whole boolean expression.

The compiler does not detect this problem, it just complains about the defined preprocessor operator coming from a macro expansion, which has undefined behavior as specified in the C Standard:

6.10.1 Conditional inclusion

[...]

Constraints

1 The expression that controls conditional inclusion shall be an integer constant expression except that: identifiers (including those lexically identical to keywords) are interpreted as described below; and it may contain unary operator expressions of the form

defined identifier

or

defined ( identifier )

which evaluate to 1 if the identifier is currently defined as a macro name (that is, if it is predefined or if it has been the subject of a #define preprocessing directive without an intervening #undef directive with the same subject identifier), 0 if it is not.

2 Each preprocessing token that remains (in the list of preprocessing tokens that will become the controlling expression) after all macro replacements have occurred shall be in the lexical form of a token (6.4).

Semantics

3 Preprocessing directives of the forms

# if constant-expression new-line groupopt

# elif constant-expression new-line groupopt

check whether the controlling constant expression evaluates to nonzero.

4 Prior to evaluation, macro invocations in the list of preprocessing tokens that will become the controlling constant expression are replaced (except for those macro names modified by the defined unary operator), just as in normal text. If the token defined is generated as a result of this replacement process or use of the defined unary operator does not match one of the two specified forms prior to macro replacement, the behavior is undefined. After all replacements due to macro expansion and the defined unary operator have been performed, all remaining identifiers (including those lexically identical to keywords) are replaced with the pp-number 0, and then each preprocessing token is converted into a token. The resulting tokens compose the controlling constant expression which is evaluated according to the rules of 6.6. For the purposes of this token conversion and evaluation, all signed integer types and all unsigned integer types act as if they have the same representation as, respectively, the types intmax_t and uintmax_t defined in the header <stdint.h>. This includes interpreting character constants, which may involve converting escape sequences into execution character set members. Whether the numeric value for these character constants matches the value obtained when an identical character constant occurs in an expression (other than within a #if or #elif directive) is implementation-defined. Also, whether a single-character character constant may have a negative value is implementation-defined.

This relevant phrase is If the token defined is generated as a result of this replacement process or use of the defined unary operator does not match one of the two specified forms prior to macro replacement, the behavior is undefined.

It is unclear if generated just means produced as part of the macro expansion or more specifically produced by token pasting. clang seems to consider that any defined token produced coming from a macro expansion has undefined behavior in a #if controlling expression.

For both reasons, this seems to be a bug in <pthread.h> for Apple to fix.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 rav
Solution 2 srgyrn
Solution 3 chqrlie