15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#!/bin/sh
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Copyright (c) 2005, Google Inc.
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# All rights reserved.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Redistribution and use in source and binary forms, with or without
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# modification, are permitted provided that the following conditions are
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# met:
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#     * Redistributions of source code must retain the above copyright
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# notice, this list of conditions and the following disclaimer.
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#     * Redistributions in binary form must reproduce the above
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# copyright notice, this list of conditions and the following disclaimer
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# in the documentation and/or other materials provided with the
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# distribution.
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#     * Neither the name of Google Inc. nor the names of its
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# contributors may be used to endorse or promote products derived from
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# this software without specific prior written permission.
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# ---
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Author: Maxim Lifantsev
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Run the heap checker unittest in a mode where it is supposed to crash and
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# return an error if it doesn't.
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# We expect BINDIR to be set in the environment.
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# If not, we set it to some reasonable value.
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BINDIR="${BINDIR:-.}"
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if [ "x$1" = "x-h" -o "x$1" = "x--help" ]; then
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  echo "USAGE: $0 [unittest dir]"
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  echo "       By default, unittest_dir=$BINDIR"
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  exit 1
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)fi
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)EXE="${1:-$BINDIR}/heap-checker_unittest"
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TMPDIR="/tmp/heap_check_death_info"
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ALARM() {
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # You need perl to run pprof, so I assume it's installed
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  perl -e '
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    $timeout=$ARGV[0]; shift;
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    $retval = 255;   # the default retval, for the case where we timed out
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    eval {           # need to run in an eval-block to trigger during system()
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      local $SIG{ALRM} = sub { die "alarm\n" };  # \n is required!
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      alarm $timeout;
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      $retval = system(@ARGV);
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Make retval bash-style: exit status, or 128+n if terminated by signal n
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      $retval = ($retval & 127) ? (128 + $retval) : ($retval >> 8);
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      alarm 0;
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    };
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    exit $retval;  # return system()-retval, or 255 if system() never returned
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)' "$@"
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# $1: timeout for alarm;
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# $2: regexp of expected exit code(s);
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# $3: regexp to match a line in the output;
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# $4: regexp to not match a line in the output;
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# $5+ args to pass to $EXE
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Test() {
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # Note: make sure these varnames don't conflict with any vars outside Test()!
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  timeout="$1"
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  shift
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected_ec="$1"
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  shift
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected_regexp="$1"
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  shift
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unexpected_regexp="$1"
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  shift
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  echo -n "Testing $EXE with $@ ... "
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  output="$TMPDIR/output"
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ALARM $timeout env "$@" $EXE > "$output" 2>&1
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  actual_ec=$?
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ec_ok=`expr "$actual_ec" : "$expected_ec$" >/dev/null || echo false`
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  matches_ok=`test -z "$expected_regexp" || \
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              grep "$expected_regexp" "$output" >/dev/null 2>&1 || echo false`
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  negmatches_ok=`test -z "$unexpected_regexp" || \
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 ! grep "$unexpected_regexp" "$output" >/dev/null 2>&1 || echo false`
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if $ec_ok && $matches_ok && $negmatches_ok; then
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    echo "PASS"
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0  # 0: success
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fi
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # If we get here, we failed.  Now we just need to report why
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  echo "FAIL"
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if [ $actual_ec -eq 255 ]; then  # 255 == SIGTERM due to $ALARM
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    echo "Test was taking unexpectedly long time to run and so we aborted it."
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    echo "Try the test case manually or raise the timeout from $timeout"
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    echo "to distinguish test slowness from a real problem."
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    $ec_ok || \
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      echo "Wrong exit code: expected: '$expected_ec'; actual: $actual_ec"
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    $matches_ok || \
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      echo "Output did not match '$expected_regexp'"
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    $negmatches_ok || \
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      echo "Output unexpectedly matched '$unexpected_regexp'"
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fi
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  echo "Output from failed run:"
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  echo "---"
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cat "$output"
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  echo "---"
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 1  # 1: failure
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TMPDIR=/tmp/heap_check_death_info
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)rm -rf $TMPDIR || exit 1
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)mkdir $TMPDIR || exit 2
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)export HEAPCHECK=strict       # default mode
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# These invocations should pass (0 == PASS):
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# This tests that turning leak-checker off dynamically works fine
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Test 120 0 "^PASS$" "" HEAPCHECK="" || exit 1
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# This disables threads so we can cause leaks reliably and test finding them
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Test 120 0 "^PASS$" "" HEAP_CHECKER_TEST_NO_THREADS=1 || exit 2
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Test that --test_cancel_global_check works
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Test 20 0 "Canceling .* whole-program .* leak check$" "" \
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HEAP_CHECKER_TEST_TEST_LEAK=1 HEAP_CHECKER_TEST_TEST_CANCEL_GLOBAL_CHECK=1 || exit 3
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Test 20 0 "Canceling .* whole-program .* leak check$" "" \
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HEAP_CHECKER_TEST_TEST_LOOP_LEAK=1 HEAP_CHECKER_TEST_TEST_CANCEL_GLOBAL_CHECK=1 || exit 4
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Test that very early log messages are present and controllable:
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)EARLY_MSG="Starting tracking the heap$"
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Test 60 0 "$EARLY_MSG" "" \
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HEAPCHECK="" HEAP_CHECKER_TEST_TEST_LEAK=1 HEAP_CHECKER_TEST_NO_THREADS=1 \
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PERFTOOLS_VERBOSE=10 || exit 5
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Test 60 0 "MemoryRegionMap Init$" "" \
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HEAPCHECK="" HEAP_CHECKER_TEST_TEST_LEAK=1 HEAP_CHECKER_TEST_NO_THREADS=1 \
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PERFTOOLS_VERBOSE=11 || exit 6
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Test 60 0 "" "$EARLY_MSG" \
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HEAPCHECK="" HEAP_CHECKER_TEST_TEST_LEAK=1 HEAP_CHECKER_TEST_NO_THREADS=1 \
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PERFTOOLS_VERBOSE=-11 || exit 7
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# These invocations should fail with very high probability,
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# rather than return 0 or hang (1 == exit(1), 134 == abort(), 139 = SIGSEGV):
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Test 60 1 "Exiting .* because of .* leaks$" "" \
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HEAP_CHECKER_TEST_TEST_LEAK=1 HEAP_CHECKER_TEST_NO_THREADS=1 || exit 8
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Test 60 1 "Exiting .* because of .* leaks$" "" \
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HEAP_CHECKER_TEST_TEST_LOOP_LEAK=1 HEAP_CHECKER_TEST_NO_THREADS=1 || exit 9
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Test that we produce a reasonable textual leak report.
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Test 60 1 "MakeALeak" "" \
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          HEAP_CHECKER_TEST_TEST_LEAK=1 HEAP_CHECK_TEST_NO_THREADS=1 \
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  || exit 10
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Test that very early log messages are present and controllable:
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Test 60 1 "Starting tracking the heap$" "" \
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HEAP_CHECKER_TEST_TEST_LEAK=1 HEAP_CHECKER_TEST_NO_THREADS=1 PERFTOOLS_VERBOSE=10 \
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  || exit 11
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Test 60 1 "" "Starting tracking the heap" \
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HEAP_CHECKER_TEST_TEST_LEAK=1 HEAP_CHECKER_TEST_NO_THREADS=1 PERFTOOLS_VERBOSE=-10 \
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  || exit 12
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)cd /    # so we're not in TMPDIR when we delete it
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)rm -rf $TMPDIR
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)echo "PASS"
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)exit 0
177