Home | History | Annotate | Download | only in testsanitizers
      1 #!/usr/bin/env bash
      2 # Copyright 2015 The Go Authors. All rights reserved.
      3 # Use of this source code is governed by a BSD-style
      4 # license that can be found in the LICENSE file.
      5 
      6 # This directory is intended to test the use of Go with sanitizers
      7 # like msan, asan, etc.  See https://github.com/google/sanitizers .
      8 
      9 set -e
     10 
     11 # The sanitizers were originally developed with clang, so prefer it.
     12 CC=cc
     13 if test -x "$(type -p clang)"; then
     14   CC=clang
     15 fi
     16 export CC
     17 
     18 if [ "$(sysctl -n vm.overcommit_memory)" = 2 ]; then
     19   echo "skipping msan/tsan tests: vm.overcommit_memory=2" >&2
     20   exit 0
     21 fi
     22 
     23 msan=yes
     24 
     25 TMPDIR=${TMPDIR:-/tmp}
     26 echo 'int main() { return 0; }' > ${TMPDIR}/testsanitizers$$.c
     27 if $CC -fsanitize=memory -o ${TMPDIR}/testsanitizers$$ ${TMPDIR}/testsanitizers$$.c 2>&1 | grep "unrecognized" >& /dev/null; then
     28   echo "skipping msan tests: $CC -fsanitize=memory not supported"
     29   msan=no
     30 elif ! test -x ${TMPDIR}/testsanitizers$$; then
     31   echo "skipping msan tests: $CC -fsanitize-memory did not generate an executable"
     32   msan=no
     33 elif ! ${TMPDIR}/testsanitizers$$ >/dev/null 2>&1; then
     34   echo "skipping msan tests: $CC -fsanitize-memory generates broken executable"
     35   msan=no
     36 fi
     37 rm -f ${TMPDIR}/testsanitizers$$.*
     38 
     39 tsan=yes
     40 
     41 # The memory and thread sanitizers in versions of clang before 3.6
     42 # don't work with Go.
     43 if test "$msan" = "yes" && $CC --version | grep clang >& /dev/null; then
     44   ver=$($CC --version | sed -e 's/.* version \([0-9.-]*\).*/\1/')
     45   major=$(echo $ver | sed -e 's/\([0-9]*\).*/\1/')
     46   minor=$(echo $ver | sed -e 's/[0-9]*\.\([0-9]*\).*/\1/')
     47   if test "$major" -lt 3 || test "$major" -eq 3 -a "$minor" -lt 6; then
     48     echo "skipping msan/tsan tests: clang version $major.$minor (older than 3.6)"
     49     msan=no
     50     tsan=no
     51   fi
     52 
     53   # Clang before 3.8 does not work with Linux at or after 4.1.
     54   # golang.org/issue/12898.
     55   if test "$msan" = "yes" -a "$major" -lt 3 || test "$major" -eq 3 -a "$minor" -lt 8; then
     56     if test "$(uname)" = Linux; then
     57       linuxver=$(uname -r)
     58       linuxmajor=$(echo $linuxver | sed -e 's/\([0-9]*\).*/\1/')
     59       linuxminor=$(echo $linuxver | sed -e 's/[0-9]*\.\([0-9]*\).*/\1/')
     60       if test "$linuxmajor" -gt 4 || test "$linuxmajor" -eq 4 -a "$linuxminor" -ge 1; then
     61         echo "skipping msan/tsan tests: clang version $major.$minor (older than 3.8) incompatible with linux version $linuxmajor.$linuxminor (4.1 or newer)"
     62 	msan=no
     63 	tsan=no
     64       fi
     65     fi
     66   fi
     67 fi
     68 
     69 status=0
     70 
     71 testmsanshared() {
     72   goos=$(go env GOOS)
     73   suffix="-installsuffix testsanitizers"
     74   libext="so"
     75   if [ "$goos" == "darwin" ]; then
     76 	  libext="dylib"
     77   fi
     78   go build -msan -buildmode=c-shared $suffix -o ${TMPDIR}/libmsanshared.$libext msan_shared.go
     79 
     80 	echo 'int main() { return 0; }' > ${TMPDIR}/testmsanshared.c
     81   $CC $(go env GOGCCFLAGS) -fsanitize=memory -o ${TMPDIR}/testmsanshared ${TMPDIR}/testmsanshared.c ${TMPDIR}/libmsanshared.$libext
     82 
     83   if ! LD_LIBRARY_PATH=. ${TMPDIR}/testmsanshared; then
     84     echo "FAIL: msan_shared"
     85     status=1
     86   fi
     87   rm -f ${TMPDIR}/{testmsanshared,testmsanshared.c,libmsanshared.$libext}
     88 }
     89 
     90 if test "$msan" = "yes"; then
     91     if ! go build -msan std; then
     92 	echo "FAIL: build -msan std"
     93 	status=1
     94     fi
     95 
     96     if ! go run -msan msan.go; then
     97 	echo "FAIL: msan"
     98 	status=1
     99     fi
    100 
    101     if ! CGO_LDFLAGS="-fsanitize=memory" CGO_CPPFLAGS="-fsanitize=memory" go run -msan -a msan2.go; then
    102 	echo "FAIL: msan2 with -fsanitize=memory"
    103 	status=1
    104     fi
    105 
    106     if ! go run -msan -a msan2.go; then
    107 	echo "FAIL: msan2"
    108 	status=1
    109     fi
    110 
    111     if ! go run -msan msan3.go; then
    112 	echo "FAIL: msan3"
    113 	status=1
    114     fi
    115 
    116     if ! go run -msan msan4.go; then
    117 	echo "FAIL: msan4"
    118 	status=1
    119     fi
    120 
    121     if ! go run -msan msan5.go; then
    122 	echo "FAIL: msan5"
    123 	status=1
    124     fi
    125 
    126     if go run -msan msan_fail.go 2>/dev/null; then
    127 	echo "FAIL: msan_fail"
    128 	status=1
    129     fi
    130 
    131     testmsanshared
    132 fi
    133 
    134 if test "$tsan" = "yes"; then
    135     echo 'int main() { return 0; }' > ${TMPDIR}/testsanitizers$$.c
    136     ok=yes
    137     if ! $CC -fsanitize=thread ${TMPDIR}/testsanitizers$$.c -o ${TMPDIR}/testsanitizers$$ &> ${TMPDIR}/testsanitizers$$.err; then
    138 	ok=no
    139     fi
    140      if grep "unrecognized" ${TMPDIR}/testsanitizers$$.err >& /dev/null; then
    141 	echo "skipping tsan tests: -fsanitize=thread not supported"
    142 	tsan=no
    143      elif test "$ok" != "yes"; then
    144 	 cat ${TMPDIR}/testsanitizers$$.err
    145 	 echo "skipping tsan tests: -fsanitizer=thread build failed"
    146 	 tsan=no
    147      fi
    148      rm -f ${TMPDIR}/testsanitizers$$*
    149 fi
    150 
    151 # Run a TSAN test.
    152 # $1 test name
    153 # $2 environment variables
    154 # $3 go run args
    155 testtsan() {
    156     err=${TMPDIR}/tsanerr$$.out
    157     if ! env $2 go run $3 $1 2>$err; then
    158 	cat $err
    159 	echo "FAIL: $1"
    160 	status=1
    161     elif grep -i warning $err >/dev/null 2>&1; then
    162 	cat $err
    163 	echo "FAIL: $1"
    164 	status=1
    165     fi
    166     rm -f $err
    167 }
    168 
    169 if test "$tsan" = "yes"; then
    170     testtsan tsan.go
    171     testtsan tsan2.go
    172     testtsan tsan3.go
    173     testtsan tsan4.go
    174     testtsan tsan8.go
    175     testtsan tsan9.go
    176 
    177     # These tests are only reliable using clang or GCC version 7 or later.
    178     # Otherwise runtime/cgo/libcgo.h can't tell whether TSAN is in use.
    179     ok=false
    180     if ${CC} --version | grep clang >/dev/null 2>&1; then
    181 	ok=true
    182     else
    183 	ver=$($CC -dumpversion)
    184 	major=$(echo $ver | sed -e 's/\([0-9]*\).*/\1/')
    185 	if test "$major" -lt 7; then
    186 	    echo "skipping remaining TSAN tests: GCC version $major (older than 7)"
    187 	else
    188 	    ok=true
    189 	fi
    190     fi
    191 
    192     if test "$ok" = "true"; then
    193 	# This test requires rebuilding os/user with -fsanitize=thread.
    194 	testtsan tsan5.go "CGO_CFLAGS=-fsanitize=thread CGO_LDFLAGS=-fsanitize=thread" "-installsuffix=tsan"
    195 
    196 	# This test requires rebuilding runtime/cgo with -fsanitize=thread.
    197 	testtsan tsan6.go "CGO_CFLAGS=-fsanitize=thread CGO_LDFLAGS=-fsanitize=thread" "-installsuffix=tsan"
    198 
    199 	# This test requires rebuilding runtime/cgo with -fsanitize=thread.
    200 	testtsan tsan7.go "CGO_CFLAGS=-fsanitize=thread CGO_LDFLAGS=-fsanitize=thread" "-installsuffix=tsan"
    201     fi
    202 fi
    203 
    204 exit $status
    205