ocaml/tools/ci/inria/extra-checks

253 lines
7.8 KiB
Bash
Executable File

#!/bin/sh
#**************************************************************************
#* *
#* OCaml *
#* *
#* Damien Doligez, Xavier Leroy, projet Gallium, INRIA Paris *
#* *
#* Copyright 2018 Institut National de Recherche en Informatique et *
#* en Automatique. *
#* *
#* All rights reserved. This file is distributed under the terms of *
#* the GNU Lesser General Public License version 2.1, with the *
#* special exception on linking described in the file LICENSE. *
#* *
#**************************************************************************
# This script is run on Inria's continuous-integration servers to recompile
# from scratch, adding more run-time checks ("sanitizers") to the C code,
# and run the test suite.
# In this context, it is necessary to skip a few tests whose behaviour
# is modified by the instrumentation:
export OCAMLTEST_SKIP_TESTS="tests/afl-instrumentation/afltest.ml \
tests/runtime-errors/stackoverflow.ml"
# To know the slave's architecture, this script looks at the OCAML_ARCH
# environment variable. For a given node NODE, this variable can be defined
# in Jenkins at the following address:
# https://ci.inria.fr/ocaml/computer/NODE/configure
# Other environment variables that are honored:
# OCAML_JOBS number of jobs to run in parallel (make -j)
# Command-line arguments:
# -jNN pass "-jNN" option to make for parallel builds
error () {
echo "$1" >&2
exit 3
}
arch_error() {
configure_url="https://ci.inria.fr/ocaml/computer/${NODE_NAME}/configure"
msg="Unknown architecture. Make sure the OCAML_ARCH environment"
msg="$msg variable has been defined."
msg="$msg\nSee ${configure_url}"
error "$msg"
}
# Change a variable in Makefile.config
# Usage: set_config_var <variable name> <new value>
set_config_var() {
conffile=Makefile.config
mv ${conffile} ${conffile}.bak
(grep -v "^$1=" ${conffile}.bak; echo "$1=$2") > ${conffile}
}
#########################################################################
# stop on error
set -e
# be considerate towards other potential users of the test machine
case "${OCAML_ARCH}" in
bsd|macos|linux) renice 10 $$ ;;
esac
# set up variables
make=make
jobs=''
case "${OCAML_ARCH}" in
bsd) make=gmake ;;
macos) ;;
linux) ;;
cygwin|cygwin64|mingw|mingw64|msvc|msvc64)
error "Don't run this test under Windows";;
*) arch_error;;
esac
case "${OCAML_JOBS}" in
[1-9]|[1-9][0-9]) jobs="-j${OCAML_JOBS}" ;;
esac
# parse optional command-line arguments
while [ $# -gt 0 ]; do
case $1 in
-j[1-9]|-j[1-9][0-9]) jobs="$1";;
*) error "unknown option $1";;
esac
shift
done
# Tell gcc to use only ASCII in its diagnostic outputs.
export LC_ALL=C
# How to run the test suite
if test -n "$jobs" && test -x /usr/bin/parallel; then
export PARALLEL="$jobs $PARALLEL"
run_testsuite="$make -C testsuite parallel"
else
run_testsuite="$make -C testsuite all"
fi
# A tool that make error backtrace nicer
# Need to pick the one that matches clang-9 and is named "llvm-symbolizer"
# (/usr/bin/llvm-symbolizer-9 doesn't work, that would be too easy)
export ASAN_SYMBOLIZER_PATH=/usr/lib/llvm-9/bin/llvm-symbolizer
export TSAN_SYMBOLIZER_PATH="$ASAN_SYMBOLIZER_PATH"
#########################################################################
# Ensure that the repo still passes the check-typo script
if [ ! -x tools/check-typo ] ; then
error "tools/check-typo does not appear to be executable?"
fi
tools/check-typo
#########################################################################
echo "======== old school build =========="
git clean -q -f -d -x
instdir="$HOME/ocaml-tmp-install-$$"
./configure --prefix "$instdir" --disable-dependency-generation
# Build the system without using world.opt
make $jobs world
make $jobs opt
make $jobs opt.opt
make install
rm -rf "$instdir"
# It's a build system test only, so we don't bother testing the compiler
#########################################################################
echo "======== clang 9, address sanitizer, UB sanitizer =========="
git clean -q -f -d -x
# Use clang 9
# We cannot give the sanitizer options as part of -cc because
# then various autoconfiguration tests fail.
# Instead, we'll fix OC_CFLAGS a posteriori.
./configure CC=clang-9 --disable-stdlib-manpages --disable-dependency-generation
# These are the undefined behaviors we want to check
# Others occur on purpose e.g. signed arithmetic overflow
ubsan="\
bool,\
builtin,\
bounds,\
enum,\
nonnull-attribute,\
nullability,\
object-size,\
pointer-overflow,\
returns-nonnull-attribute,\
shift-exponent,\
unreachable"
# Select address sanitizer and UB sanitizer, with trap-on-error behavior
# Don't optimize too much to get better backtraces of errors
set_config_var OC_CFLAGS "-O1 \
-fno-strict-aliasing -fwrapv -fno-omit-frame-pointer \
-Wall -Werror \
-fsanitize=address \
-fsanitize-trap=$ubsan"
# Build the system. We want to check for memory leaks, hence
# 1- force ocamlrun to free memory before exiting
# 2- add an exception for ocamlyacc, which doesn't free memory
OCAMLRUNPARAM="c=1" \
LSAN_OPTIONS="suppressions=$(pwd)/tools/ci/inria/lsan-suppr.txt" \
make $jobs world.opt
# Run the testsuite.
# We deactivate leak detection for two reasons:
# - The suppressed leak detections related to ocamlyacc mess up the
# output of the tests and are reported as failures by ocamltest.
# - The Ocaml runtime does not free the memory when a fatal error
# occurs.
# We already use sigaltstack for stack overflow detection. Our use
# interacts with ASAN's. Hence, we tell ASAN not to use it.
ASAN_OPTIONS="detect_leaks=0,use_sigaltstack=0" $run_testsuite
#########################################################################
echo "======== clang 9, thread sanitizer =========="
git clean -q -f -d -x
./configure CC=clang-9 --disable-stdlib-manpages --disable-dependency-generation
# Select thread sanitizer
# Don't optimize too much to get better backtraces of errors
set_config_var OC_CFLAGS "-O1 \
-fno-strict-aliasing -fwrapv -fno-omit-frame-pointer \
-Wall -Werror \
-fsanitize=thread"
# Build the system
make $jobs world.opt
# Run the testsuite.
# ThreadSanitizer complains about fork() in threaded programs,
# we ask it to just continue in this case.
TSAN_OPTIONS="die_after_fork=0" $run_testsuite
#########################################################################
# This is a failed attempt at using the memory sanitizer
# (to detect reads from uninitialized memory).
# Some alarms are reported that look like false positive
# and are impossible to debug.
# echo "======== clang 6.0, memory sanitizer =========="
# git clean -q -f -d -x
# # Use clang 6.0
# # We cannot give the sanitizer options as part of -cc because
# # then various autoconfiguration tests fail.
# # Instead, we'll fix OC_CFLAGS a posteriori.
# # Memory sanitizer doesn't like the static data generated by ocamlopt,
# # hence build bytecode only
# ./configure CC=clang-9 --disable-native-compiler
# # Select memory sanitizer
# # Don't optimize at all to get better backtraces of errors
# set_config_var OC_CFLAGS "-O0 -g \
# -fno-strict-aliasing -fwrapv -fno-omit-frame-pointer \
# -Wall -Werror \
# -fsanitize=memory"
# # A tool that make error backtrace nicer
# # Need to pick the one that matches clang-6.0
# export MSAN_SYMBOLIZER_PATH=/usr/lib/llvm-6.0/bin/llvm-symbolizer
# # Build the system (bytecode only) and test
# make $jobs world
# $run_testsuite