Refactor travis build to use clang's sanitizers

- Valgrind configuration removed
- Fix errors reported by the undefined behavior sanitizer
- Travis will now run two build steps:
  - A normal build of a shared library for unit testing(in parallel with gcc)
  - A clang build with some sanitizers enabled for integration testing.

After these changes travis will run much faster, while providing valgrind-like
error detection.
This commit is contained in:
Thiago de Arruda 2014-03-13 12:11:03 -03:00
parent 3cac32e49c
commit f6ace9962d
9 changed files with 122 additions and 51 deletions

2
.gitignore vendored
View File

@ -1,6 +1,8 @@
# Build/deps dir
/build/
/dist/
/.deps/
/tmp/
*.rej
*.orig

View File

@ -1,7 +1,8 @@
language: c
script: ./scripts/travis.sh
before_install:
- sudo apt-get install valgrind
compiler:
- clang
- gcc
before_install:
- sudo ./scripts/travis-setup.sh
script:
- ./scripts/travis.sh

View File

@ -1,7 +0,0 @@
{
nss_parse_service_list
Memcheck:Leak
fun:malloc
fun:nss_parse_service_list
fun:__nss_database_lookup
}

View File

@ -10,12 +10,7 @@ set(NEOVIM_VERSION_PATCH 0)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# If the C compiler is some GNU-alike, use the gnu99 standard and enable all warnings.
if(CMAKE_COMPILER_IS_GNUCC)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror -Wall -Wextra -pedantic -Wno-unused-parameter -std=gnu99")
elseif(CMAKE_C_COMPILER_ID MATCHES "Clang")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror -Wall -Wextra -pedantic -Wno-unused-parameter -std=gnu99")
endif(CMAKE_COMPILER_IS_GNUCC)
add_definitions(-Werror -Wall -Wextra -pedantic -Wno-unused-parameter -std=gnu99)
add_definitions(-DHAVE_CONFIG_H)
if(CMAKE_BUILD_TYPE MATCHES Debug)
@ -25,11 +20,6 @@ else()
set(DEBUG 0)
endif()
if(DEFINED ENV{VALGRIND_CHECK})
message(STATUS "Defining EXITFREE for valgrind checks")
add_definitions(-DEXITFREE)
endif()
# Modules used by platform auto-detection
include(CheckLibraryExists)

19
scripts/travis-setup.sh Executable file
View File

@ -0,0 +1,19 @@
#!/bin/sh -e
# [ "$CC" != "clang" ] && exit
add-apt-repository -y ppa:ubuntu-toolchain-r/ppa
wget -O - http://llvm.org/apt/llvm-snapshot.gpg.key | apt-key add -
cat > /etc/apt/sources.list.d/clang.list << "EOF"
deb http://llvm.org/apt/precise/ llvm-toolchain-precise main
deb-src http://llvm.org/apt/precise/ llvm-toolchain-precise main
# 3.4
deb http://llvm.org/apt/precise/ llvm-toolchain-precise-3.4 main
deb-src http://llvm.org/apt/precise/ llvm-toolchain-precise-3.4 main
# Common
deb http://ppa.launchpad.net/ubuntu-toolchain-r/test/ubuntu precise main
EOF
apt-get -qq update
apt-get -qq -y --no-install-recommends install clang-3.4 lldb-3.4

View File

@ -1,21 +1,49 @@
#!/bin/sh -e
export VALGRIND_CHECK=1
export BUSTED_OUTPUT_TYPE="TAP"
make cmake CMAKE_EXTRA_FLAGS="-DCMAKE_INSTALL_PREFIX=$PWD/dist"
make
make unittest
echo "Running tests with valgrind..."
if ! make test; then
if ls src/testdir/valgrind.* > /dev/null 2>&1; then
echo "Memory leak detected" >&2
cat src/testdir/valgrind.*
else
echo "Failed tests:" >&2
for t in src/testdir/*.failed; do
echo ${t%%.*}
done
check_and_report() {
reset
(
cd $tmpdir
if [ -f asan.* ] || [ -f tsan.* ] || [ -f ubsan.* ]; then
cat $tmpdir/asan.* 2> /dev/null || true
cat $tmpdir/tsan.* 2> /dev/null || true
cat $tmpdir/ubsan.* 2> /dev/null || true
exit 1
fi
exit 1
)
}
if [ "$CC" = "clang" ]; then
# force using the version installed by 'travis-setup.sh'
export CC=/usr/bin/clang
install_dir="$(pwd)/dist"
# temporary directory for writing sanitizer logs
tmpdir="$(pwd)/tmp"
rm -rf "$tmpdir"
mkdir -p "$tmpdir"
# need the symbolizer path for stack traces with source information
symbolizer=/usr/bin/llvm-symbolizer-3.4
export SKIP_UNITTEST=1
export SANITIZE=1
export ASAN_SYMBOLIZER_PATH=$symbolizer
export ASAN_OPTIONS="detect_leaks=1:log_path=$tmpdir/asan"
export TSAN_OPTIONS="external_symbolizer_path=$symbolizer:log_path=$tmpdir/tsan"
export UBSAN_OPTIONS="log_path=$tmpdir/ubsan" # not sure if this works
make cmake CMAKE_EXTRA_FLAGS="-DCMAKE_INSTALL_PREFIX=$install_dir"
make
if ! make test; then
check_and_report
fi
check_and_report
make install
else
export BUSTED_OUTPUT_TYPE="TAP"
export SKIP_EXEC=1
make cmake
make unittest
fi
make install

View File

@ -12,8 +12,25 @@ list(APPEND NEOVIM_SOURCES "${PROJECT_BINARY_DIR}/config/auto/pathdef.c")
file( GLOB OS_SOURCES os/*.c )
add_executable (nvim ${NEOVIM_SOURCES} ${OS_SOURCES})
add_library (nvim-test MODULE ${NEOVIM_SOURCES} ${OS_SOURCES})
if(CMAKE_C_COMPILER_ID MATCHES "Clang")
if(DEFINED ENV{SANITIZE})
message(STATUS "Enabling the sanitizers")
add_definitions(-DEXITFREE) # is this necessary for LeakSanitizer?
add_definitions(-fno-sanitize-recover -fno-omit-frame-pointer
-fno-optimize-sibling-calls -fsanitize=address -fsanitize=undefined)
set(CMAKE_EXE_LINKER_FLAGS
"-fsanitize=address -fsanitize=undefined ${CMAKE_EXE_LINKER_FLAGS}")
set(CMAKE_SHARED_LINKER_FLAGS
"-fsanitize=address -fsanitize=undefined ${CMAKE_SHARED_LINKER_FLAGS}")
endif()
endif()
if(NOT DEFINED ENV{SKIP_EXEC})
add_executable (nvim ${NEOVIM_SOURCES} ${OS_SOURCES})
endif()
if(NOT DEFINED ENV{SKIP_UNITTEST})
add_library (nvim-test MODULE ${NEOVIM_SOURCES} ${OS_SOURCES})
endif()
# The libraries we link against for nvim
set(NVIM_LINK_LIBRARIES m ${LibUV_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
@ -28,27 +45,46 @@ if (LibIntl_FOUND)
list(APPEND NVIM_LINK_LIBRARIES ${LibIntl_LIBRARY})
endif()
target_link_libraries (nvim ${NVIM_LINK_LIBRARIES})
target_link_libraries (nvim-test ${NVIM_LINK_LIBRARIES})
if(NOT DEFINED ENV{SKIP_EXEC})
target_link_libraries (nvim ${NVIM_LINK_LIBRARIES})
endif()
if(NOT DEFINED ENV{SKIP_UNITTEST})
target_link_libraries (nvim-test ${NVIM_LINK_LIBRARIES})
endif()
include(CheckLibraryExists)
check_library_exists(termcap tgetent "" HAVE_LIBTERMCAP)
if (HAVE_LIBTERMCAP)
target_link_libraries(nvim termcap)
target_link_libraries(nvim-test termcap)
if(NOT DEFINED ENV{SKIP_EXEC})
target_link_libraries(nvim termcap)
endif()
if(NOT DEFINED ENV{SKIP_UNITTEST})
target_link_libraries(nvim-test termcap)
endif()
else()
check_library_exists(curses tgetent "" HAVE_LIBCURSES)
if (HAVE_LIBCURSES)
target_link_libraries(nvim curses)
target_link_libraries(nvim-test curses)
if(NOT DEFINED ENV{SKIP_EXEC})
target_link_libraries(nvim curses)
endif()
if(NOT DEFINED ENV{SKIP_UNITTEST})
target_link_libraries(nvim-test curses)
endif()
else()
find_package(Curses REQUIRED)
target_link_libraries(nvim ${CURSES_LIBRARIES})
target_link_libraries(nvim-test ${CURSES_LIBRARIES})
if(NOT DEFINED ENV{SKIP_EXEC})
target_link_libraries(nvim ${CURSES_LIBRARIES})
endif()
if(DEFINED ENV{SKIP_UNITTEST})
target_link_libraries(nvim-test ${CURSES_LIBRARIES})
endif()
endif()
endif()
include_directories ("${PROJECT_SOURCE_DIR}/src/proto")
install(TARGETS nvim RUNTIME DESTINATION bin)
if(NOT DEFINED ENV{SKIP_EXEC})
install(TARGETS nvim RUNTIME DESTINATION bin)
endif()

View File

@ -4275,7 +4275,7 @@ eval6 (
else if (op == '/') {
/* We rely on the floating point library to handle divide
* by zero to result in "inf" and not a crash. */
f1 = f1 / f2;
f1 = f2 != 0 ? f1 / f2 : INFINITY;
} else {
EMSG(_("E804: Cannot use '%' with Float"));
return FAIL;

View File

@ -2834,8 +2834,10 @@ do_ecmd (
* <VN> We could instead free the synblock
* and re-attach to buffer, perhaps.
*/
if (curwin->w_s == &(curwin->w_buffer->b_s))
if (curwin->w_buffer != NULL &&
curwin->w_s == &(curwin->w_buffer->b_s))
curwin->w_s = &(buf->b_s);
curwin->w_buffer = buf;
curbuf = buf;
++curbuf->b_nwindows;