Go version
go version devel go1.22-78b42a5338a Fri Dec 8 03:28:17 2023 +0000 linux/amd64
What operating system and processor architecture are you using (go env
)?
GO111MODULE=''
GOARCH='amd64'
GOBIN=''
GOCACHE='/root/.cache/go-build'
GOENV='/root/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFLAGS=''
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOMODCACHE='/root/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPATH='/root/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/mnt/d/file/gofile/gogit/go1'
GOSUMDB='sum.golang.org'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/mnt/d/file/gofile/gogit/go1/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='devel go1.22-78b42a5338a Fri Dec 8 03:28:17 2023 +0000'
GCCGO='gccgo'
GOAMD64='v1'
AR='ar'
CC='clang'
CXX='g++'
CGO_ENABLED='1'
GOMOD='/mnt/d/file/gofile/gogit/go1/src/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 -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build9589947017406823330=/tmp/go-build -gno-record-gcc-switches'
GOROOT/bin/go version: go version devel go1.22-78b42a5338a Fri Dec 8 03:28:17 2023 +0000 linux/amd64
GOROOT/bin/go tool compile -V: compile version devel go1.22-78b42a5338a Fri Dec 8 03:28:17 2023 +0000
uname -sr: Linux 5.15.133.1-microsoft-standard-WSL2
Distributor ID: Kali
Description: Kali GNU/Linux Rolling
Release: 2023.4
Codename: kali-rolling
/lib/x86_64-linux-gnu/libc.so.6: GNU C Library (Debian GLIBC 2.37-12) stable release version 2.37.
What did you do?
In wsl2 export CC=clang clang --version Debian clang version 16.0.6 (16) Target: x86_64-pc-linux-gnu Thread model: posix InstalledDir: /usr/bin
go test cmd/cgo/internal/testsanitizers
What did you expect to see?
test pass.
What did you see instead?
--- FAIL: TestMSAN (9.40s)
--- FAIL: TestMSAN/msan8 (3.26s)
msan_test.go:81: /tmp/TestMSAN1734687677996663673/msan8 exited with exit status 1
==29491==WARNING: MemorySanitizer: use-of-uninitialized-value
#0 0x5062b8 in msanGoLoop (/tmp/TestMSAN1734687677996663673/msan8+0x5062b8) (BuildId: 519103c2e3c209c99d8a9bb8f9d7cf2065339178)
#1 0x5064c0 in _cgo_a322d3c7e754_Cfunc_msanGoLoop (/tmp/TestMSAN1734687677996663673/msan8+0x5064c0) (BuildId: 519103c2e3c209c99d8a9bb8f9d7cf2065339178)
#2 0x501143 in runtime.asmcgocall.abi0 /mnt/d/file/gofile/gogit/go1/src/runtime/asm_amd64.s:918
SUMMARY: MemorySanitizer: use-of-uninitialized-value (/tmp/TestMSAN1734687677996663673/msan8+0x5062b8) (BuildId: 519103c2e3c209c99d8a9bb8f9d7cf2065339178) in msanGoLoop
Exiting
FAIL
FAIL cmd/cgo/internal/testsanitizers 32.323s
FAIL
Comment From: mauri870
This appears to be a general clang 16 issue, not only to wsl2.
It is complaining about the use of uninit
that is uninitialized here:
https://go.googlesource.com/go/+/78b42a5338aa1fa293acc5bbb7ef9122a7acc2ba/src/cmd/cgo/internal/testsanitizers/testdata/msan8.go#65
Shorter repro:
package main
/*
#include <stdint.h>
#include <sanitizer/msan_interface.h>
__attribute__((noinline))
void funinit(unsigned long a1) {}
static unsigned long uninit;
void f() {
__msan_poison(&uninit, sizeof uninit);
funinit(uninit);
}
*/
import "C"
func main() {
C.f()
}
Strangely enough I can't seem to replicate it with a C version and clang-16.
Comment From: mauri870
Huh, something appear to have changed in clang-16 that makes it report memory as uninitialized in this case. From the test msan8 it reads:
// msanGoLoop loops calling msanGoWait, with the arguments passed
// such that msan thinks that they are undefined. msan permits
// undefined values to be used as long as they are not used to
// for conditionals or for memory access.
I tried clang 14, 15, 16, 17 and this only happens with clang >= 16. Looking at the release notes I can't spot anything that might've caused this change in msan behavior https://releases.llvm.org/16.0.0/docs/ReleaseNotes.html
I'm not sure if this comment above is actually a guarantee from the memory sanitizer, they might have changed it silently in clang-16 without mentioning it.
Here is a short C repro I put together that runs in clang 15 but not on clang 16:
// clang-16 -fsanitize=memory test.c && ./a.out
#include <stdint.h>
#include <sanitizer/msan_interface.h>
__attribute__((noinline))
void funinit(unsigned long a1) {}
static unsigned long uninit ;
void f() {
__msan_poison(&uninit, sizeof uninit);
funinit(uninit);
}
int main() {
f();
return 0;
}
Comment From: mauri870
Adjusting the labels as this appears to be a clang issue
Comment From: mauri870
cc @dvyukov
Comment From: dvyukov
This looks like -fsanitize-address-param-retval (detects passing uninits as arguments), but it should be disabled by default. Maybe it was accidentally enabled in clang 16 and then disabled. @kda @vitalybuka
Comment From: vitalybuka
It's enabled by default https://reviews.llvm.org/D134669
Comment From: vitalybuka
https://releases.llvm.org/16.0.0/tools/clang/docs/ReleaseNotes.html#sanitizers
Comment From: mauri870
Looks like that is the culprint, I was looking at the llvm release notes and not the tools, that is why I did not spot this change.
Thanks for the valuable insight @vitalybuka @dvyukov.
Comment From: mauri870
@bcmills Do you consider this as a breaking change? This new behavior seems to be beneficial for programs:
-fsanitize-memory-param-retval is turned on by default. With -fsanitize=memory, passing uninitialized variables to functions and returning uninitialized variables from functions is more aggressively reported. -fno-sanitize-memory-param-retval restores the previous behavior.
Should we retain the old behavior?
Comment From: dvyukov
I think end users can control this using CGO_CFLAGS. So the breakage is not that bad. And potentially we can go for the better/default behavior and gave users workaround via CGO_CFLAGS.
Comment From: vitalybuka
I think end users can control this using CGO_CFLAGS. So the breakage is not that bad. And potentially we can go for the better/default behavior and gave users workaround via CGO_CFLAGS.
The state of that flag for linked C/C++ code needs to be consistent with GO code. Mismatch either way will cause false positives.
Comment From: gopherbot
Change https://go.dev/cl/549297 mentions this issue: cmd/cgo/internal/testsanitizers: fix msan test failing with clang >= 16
Comment From: mauri870
So it appears that we cannot use #if
with #cgo
, so the fix I submitted was reverted. I'm glad to hear suggestions on how to handle this.
Comment From: bcmills
@mauri870, perhaps the test driver itself could first try building with CGO_CFLAGS=-fno-sanitize-memory-param-retval
, and try again without that flag if the build fails?
Comment From: gopherbot
Change https://go.dev/cl/601779 mentions this issue: cmd/cgo/internal/testsanitizers: avoid clang error in msan8.go