- libpopt-dev
- subversion
compiler: gcc
+ cache:
+ directories:
+ - $HOME/failmalloc
env:
- CONFIG=coverage
ln -s "$TRAVIS_BUILD_DIR" src/libexif
./build-config.sh
autoreconf -sivf
+ cd "$HOME"
+ # Failmalloc for improved test coverage
+ if [ ! -e "$HOME/failmalloc/lib/libfailmalloc.so.0" ] ; then
+ curl -fsSORL https://download.savannah.nongnu.org/releases/failmalloc/failmalloc-1.0.tar.gz
+ tar xaf failmalloc-1.0.tar.gz
+ cd failmalloc-1.0
+ sed -i -e 's/\(__malloc_initialize_hook\)/volatile \1/' failmalloc.c
+ ./configure --prefix="$HOME/failmalloc"
+ make
+ make install
+ fi
cd "$TRAVIS_BUILD_DIR"
fi
- if [ "$CONFIG" = "clang6" ] ; then CFLAGS='-Wall -Wextra -O3'; export CC=clang-6.0; fi
- if [ "$CONFIG" = "gcc8" ] ; then CFLAGS='-Wall -Wextra -O3'; export export CC=gcc-8; fi
- if [ "$CONFIG" = "sanitize" ] ; then CFLAGS='-g -Wall -Wextra -fsanitize=address -fsanitize=undefined'; export CC=clang-6.0; fi
- - if [ "$CONFIG" = "coverage" ] ; then cd "$HOME"/libexif-testsuite; CFLAGS=--coverage; LDFLAGS=--coverage; fi
- - ./configure --prefix="${HOME}"/install CFLAGS="$CFLAGS" ${LDFLAGS:+LDFLAGS=$LDFLAGS} || { tail -300 config.log; false; }
+ - if [ "$CONFIG" = "coverage" ] ; then cd "$HOME"/libexif-testsuite; CFLAGS=--coverage; CONFIGURE_OPTS="LDFLAGS=--coverage --with-failmalloc=$HOME/failmalloc/lib" ; fi
+ - ./configure --prefix="${HOME}"/install CFLAGS="$CFLAGS" $CONFIGURE_OPTS || { tail -300 config.log; false; }
- make V=1
- make V=1 check || { tail -300 test*/test-suite.log; false; }
- make V=1 install
])
])
+# Check whether libfailmalloc is available for tests
+CHECK_FAILMALLOC
+
# doc support
GP_CHECK_DOC_DIR
GP_CHECK_DOXYGEN
libexif.spec
libexif/Makefile
test/Makefile
+ test/check-vars.sh
test/nls/Makefile
m4m/Makefile
doc/Makefile
--- /dev/null
+dnl Search for libfailmalloc to use for testing
+AC_DEFUN([CHECK_FAILMALLOC],[dnl
+ dnl Libtool sets the default library paths
+ AM_PROG_LIBTOOL
+ path_provided=
+ AC_ARG_WITH(failmalloc, [ --with-failmalloc=PATH use Failmalloc for tests], [
+ if test x"$withval" = "x" -o x"$withval" = "xyes"; then
+ failmalloc_search_path="$sys_lib_search_path_spec"
+ elif test x"$withval" = "xno"; then
+ failmalloc_search_path=""
+ else
+ failmalloc_search_path="$withval"
+ path_provided=1
+ fi
+ ], [failmalloc_search_path="$sys_lib_search_path_spec"]
+ )
+ libfailmalloc_file=libfailmalloc.so.0
+ FAILMALLOC_PATH=
+ dnl Check if the argument is a directory
+ for d in $failmalloc_search_path; do
+ AC_CHECK_FILE([$d/$libfailmalloc_file], [
+ FAILMALLOC_PATH="$d/$libfailmalloc_file"
+ break
+ ], [])
+ done
+ if test -z "$FAILMALLOC_PATH" -a -n "$path_provided"; then
+ dnl Check if the argument is a file
+ AC_CHECK_FILE([$failmalloc_search_path], [FAILMALLOC_PATH="$failmalloc_search_path"], [])
+ fi
+ AC_MSG_CHECKING([for failmalloc])
+ dnl Make sure AC_CHECK_FILE didn't find a directory by mistake
+ if test -n "$FAILMALLOC_PATH" -a -f "$FAILMALLOC_PATH"; then
+ AC_MSG_RESULT([yes])
+ else
+ if test -n "$path_provided"; then
+ AC_MSG_ERROR([$libfailmalloc_file was not found at $failmalloc_search_path])
+ else
+ AC_MSG_RESULT([no])
+ fi
+ fi
+ AC_SUBST(FAILMALLOC_PATH)
+ AM_CONDITIONAL(USE_FAILMALLOC, [test "x$FAILMALLOC_PATH" != "x"])
+])
+
TESTS = test-mem test-value test-integers test-parse test-tagtable test-sorted \
test-fuzzer parse-regression.sh swap-byte-order.sh
+if USE_FAILMALLOC
+TESTS += check-failmalloc.sh
+endif
+
check_PROGRAMS = test-mem test-mnote test-value test-integers test-parse \
test-tagtable test-sorted test-fuzzer
LDADD = $(top_builddir)/libexif/libexif.la $(LTLIBINTL)
-EXTRA_DIST = parse-regression.sh swap-byte-order.sh \
+EXTRA_DIST = check-vars.sh.in parse-regression.sh swap-byte-order.sh \
+ check-failmalloc.sh \
testdata/canon_makernote_variant_1.jpg \
testdata/canon_makernote_variant_1.jpg.parsed \
testdata/fuji_makernote_variant_1.jpg \
--- /dev/null
+#!/bin/sh
+# Use Failmalloc to test behaviour in the face of out-of-memory conditions.
+# The test runs a binary multiple times while configuring Failmalloc to fail a
+# different malloc() call each time, while looking for abnormal program exits
+# due to segfaults. See https://www.nongnu.org/failmalloc/
+#
+# Ideally, it would ensure that the test binary returns an error code on each
+# failure, but this often doesn't happen. This is a problem that should be
+# rectified, but the API doesn't allow returning an error code in many
+# functions that could encounter a problem. The issue could be solve in more
+# cases with more judicious use of log calls with EXIF_LOG_CODE_NO_MEMORY
+# codes.
+. ./check-vars.sh
+
+VERBOSE=
+if [ "$1" = "-v" ] ; then
+ VERBOSE=1
+fi
+
+if [ x"$FAILMALLOC_PATH" = x ]; then
+ echo libfailmalloc is not available
+ echo SKIPPING
+ exit
+fi
+
+BINARY_PREFIX=./
+if [ -e .libs/lt-test-value ]; then
+ # If libtool is in use, the normal "binary" is actually a shell script which
+ # would be interfered with by libfailmalloc. Instead, use the special lt-
+ # binary which should work properly.
+ BINARY_PREFIX=".libs/lt-"
+fi
+
+# Usage: failmalloc_binary_test #iterations binary <optional arguments>
+# FIXME: auto-determine #iterations by comparing the output of each run
+# with the output of a normal run, and exiting when that happens.
+failmalloc_binary_test () {
+ binary="$BINARY_PREFIX$2"
+ iterations="$1"
+ shift
+ shift
+ echo Checking "$binary" for "$iterations" iterations
+ for n in $(seq "$iterations"); do
+ test "$VERBOSE" = 1 && { echo "$n"; set -x; }
+ FAILMALLOC_INTERVAL="$n" LD_PRELOAD="$FAILMALLOC_PATH" "$binary" "$@" >/dev/null
+ s=$?
+ test "$VERBOSE" = 1 && set +x;
+ if test "$s" -ge 128; then
+ # Such status codes only happen due to termination due to a signal
+ # like SIGSEGV.
+ echo "Abnormal binary exit status $s at malloc #$n on $binary"
+ echo FAILURE
+ exit 1
+ fi
+ done
+}
+
+# The number of iterations is determined empirically to be about twice as
+# high as the maximum number of mallocs performed by the test program in order
+# to avoid lowering code coverage in the case of future code changes that cause
+# more allocations.
+
+failmalloc_binary_test 500 test-value
+failmalloc_binary_test 300 test-mem
+for f in $SRCDIR/testdata/*jpg; do
+ echo "Testing `basename "$f"`"
+ failmalloc_binary_test 500 test-parse "$f"
+ # N.B., test-parse --swap-byte-order doesn't test any new paths
+done
+
+echo PASSED
--- /dev/null
+# Specifies autoconf variables for use by the test scripts
+
+SRCDIR=@srcdir@
+FAILMALLOC_PATH=@FAILMALLOC_PATH@