• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/bin/sh
2# Use Failmalloc to test behaviour in the face of out-of-memory conditions.
3# The test runs a binary multiple times while configuring Failmalloc to fail a
4# different malloc() call each time, while looking for abnormal program exits
5# due to segfaults. See https://www.nongnu.org/failmalloc/
6#
7# Ideally, it would ensure that the test binary returns an error code on each
8# failure, but this often doesn't happen. This is a problem that should be
9# rectified, but the API doesn't allow returning an error code in many
10# functions that could encounter a problem. The issue could be solved in more
11# cases with more judicious use of log calls with EXIF_LOG_CODE_NO_MEMORY
12# codes.
13#
14# Copyright (C) 2018-2021 Dan Fandrich <dan@coneharvesters.com>, et. al.
15# SPDX-License-Identifier: LGPL-2.0-or-later
16
17srcdir="${srcdir:-.}"
18
19VERBOSE=
20if [ "$1" = "-v" ] ; then
21    VERBOSE=1
22fi
23
24if [ x"$FAILMALLOC_PATH" = x ]; then
25    echo "libfailmalloc is not available"
26    exit 77
27fi
28
29BINARY_PREFIX=./
30if [ -e .libs/lt-test-value ]; then
31    # If libtool is in use, the normal "binary" is actually a shell script which
32    # would be interfered with by libfailmalloc. Instead, use the special lt-
33    # binary which should work properly.
34    BINARY_PREFIX=".libs/lt-"
35fi
36
37# Usage: failmalloc_binary_test #iterations binary <optional arguments>
38# FIXME: auto-determine #iterations by comparing the output of each run
39# with the output of a normal run, and exiting when that happens.
40failmalloc_binary_test () {
41  binary="$BINARY_PREFIX$2"
42  iterations="$1"
43  shift
44  shift
45  echo Checking "$binary" for "$iterations" iterations
46  for n in $(seq "$iterations"); do
47      test "$VERBOSE" = 1 && { echo "$n"; set -x; }
48      FAILMALLOC_INTERVAL="$n" LD_PRELOAD="${LD_PRELOAD:+$LD_PRELOAD:}$FAILMALLOC_PATH" "$binary" "$@" >/dev/null
49      s=$?
50      test "$VERBOSE" = 1 && set +x;
51      if test "$s" -ge 125; then
52          # Such status codes only happen due to termination due to a signal
53          # like SIGSEGV or ASAN errors (ignoring a couple that the shell
54          # itself produces).
55          echo "Abnormal binary exit status $s at malloc #$n on $binary"
56          echo FAILURE
57          exit 1
58      fi
59  done
60}
61
62# Make ASAN errors return a high number to differentiate them from regular test
63# errors (which are ignored). This only does something if ASAN was configured
64# in the build.
65export ASAN_OPTIONS="exitcode=125${ASAN_OPTIONS:+:$ASAN_OPTIONS}"
66
67# The number of iterations is determined empirically to be about twice as
68# high as the maximum number of mallocs performed by the test program in order
69# to avoid lowering code coverage in the case of future code changes that cause
70# more allocations.
71
72failmalloc_binary_test 700 test-mem
73failmalloc_binary_test 500 test-value
74
75for f in ${srcdir}/testdata/*jpg; do
76    echo "Testing `basename "$f"`"
77    failmalloc_binary_test 600 test-parse$EXEEXT "$f"
78done
79# N.B. adding the following binaries doesn't actually increase code coverage:
80#  test-extract -o /dev/null
81#  test-gps
82#  test-mnote
83#  test-parse --swap-byte-order
84
85echo PASSED
86