michael@0: #!/bin/bash
michael@0: #
michael@0: # This Source Code Form is subject to the terms of the Mozilla Public
michael@0: # License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0: # file, You can obtain one at http://mozilla.org/MPL/2.0/.
michael@0:
michael@0: ########################################################################
michael@0: #
michael@0: # mozilla/security/nss/tests/memleak/memleak.sh
michael@0: #
michael@0: # Script to test memory leaks in NSS
michael@0: #
michael@0: # needs to work on Solaris and Linux platforms, on others just print a message
michael@0: # that OS is not supported
michael@0: #
michael@0: # special strings
michael@0: # ---------------
michael@0: # FIXME ... known problems, search for this string
michael@0: # NOTE .... unexpected behavior
michael@0: #
michael@0: ########################################################################
michael@0:
michael@0: ############################# memleak_init #############################
michael@0: # local shell function to initialize this script
michael@0: ########################################################################
michael@0: memleak_init()
michael@0: {
michael@0: if [ -z "${INIT_SOURCED}" -o "${INIT_SOURCED}" != "TRUE" ]; then
michael@0: cd ../common
michael@0: . ./init.sh
michael@0: fi
michael@0:
michael@0: if [ ! -r ${CERT_LOG_FILE} ]; then
michael@0: cd ${QADIR}/cert
michael@0: . ./cert.sh
michael@0: fi
michael@0:
michael@0: SCRIPTNAME="memleak.sh"
michael@0: if [ -z "${CLEANUP}" ] ; then
michael@0: CLEANUP="${SCRIPTNAME}"
michael@0: fi
michael@0:
michael@0: OLD_LIBRARY_PATH=${LD_LIBRARY_PATH}
michael@0: TMP_LIBDIR="${HOSTDIR}/tmp"
michael@0: TMP_STACKS="${HOSTDIR}/stacks"
michael@0: TMP_SORTED="${HOSTDIR}/sorted"
michael@0: TMP_COUNT="${HOSTDIR}/count"
michael@0: DBXOUT="${HOSTDIR}/dbxout"
michael@0: DBXERR="${HOSTDIR}/dbxerr"
michael@0: DBXCMD="${HOSTDIR}/dbxcmd"
michael@0:
michael@0: PORT=${PORT:-8443}
michael@0:
michael@0: MODE_LIST="NORMAL BYPASS FIPS"
michael@0:
michael@0: SERVER_DB="${HOSTDIR}/server_memleak"
michael@0: CLIENT_DB="${HOSTDIR}/client_memleak"
michael@0: cp -r ${HOSTDIR}/server ${SERVER_DB}
michael@0: cp -r ${HOSTDIR}/client ${CLIENT_DB}
michael@0:
michael@0: LOGDIR="${HOSTDIR}/memleak_logs"
michael@0: mkdir -p ${LOGDIR}
michael@0:
michael@0: FOUNDLEAKS="${LOGDIR}/foundleaks"
michael@0:
michael@0: REQUEST_FILE="${QADIR}/memleak/sslreq.dat"
michael@0: IGNORED_STACKS="${QADIR}/memleak/ignored"
michael@0:
michael@0: gline=`echo ${OBJDIR} | grep "_64_"`
michael@0: if [ -n "${gline}" ] ; then
michael@0: BIT_NAME="64"
michael@0: else
michael@0: BIT_NAME="32"
michael@0: fi
michael@0:
michael@0: case "${OS_NAME}" in
michael@0: "SunOS")
michael@0: DBX=`which dbx`
michael@0: AWK=nawk
michael@0:
michael@0: if [ $? -eq 0 ] ; then
michael@0: echo "${SCRIPTNAME}: DBX found: ${DBX}"
michael@0: else
michael@0: echo "${SCRIPTNAME}: DBX not found, skipping memory leak checking."
michael@0: exit 0
michael@0: fi
michael@0:
michael@0: PROC_ARCH=`uname -p`
michael@0:
michael@0: if [ "${PROC_ARCH}" = "sparc" ] ; then
michael@0: if [ "${BIT_NAME}" = "64" ] ; then
michael@0: FREEBL_DEFAULT="libfreebl_64fpu_3"
michael@0: FREEBL_LIST="${FREEBL_DEFAULT} libfreebl_64int_3"
michael@0: else
michael@0: FREEBL_DEFAULT="libfreebl_32fpu_3"
michael@0: FREEBL_LIST="${FREEBL_DEFAULT} libfreebl_32int64_3"
michael@0: fi
michael@0: else
michael@0: if [ "${BIT_NAME}" = "64" ] ; then
michael@0: echo "${SCRIPTNAME}: OS not supported for memory leak checking."
michael@0: exit 0
michael@0: fi
michael@0:
michael@0: FREEBL_DEFAULT="libfreebl_3"
michael@0: FREEBL_LIST="${FREEBL_DEFAULT}"
michael@0: fi
michael@0:
michael@0: RUN_COMMAND_DBG="run_command_dbx"
michael@0: PARSE_LOGFILE="parse_logfile_dbx"
michael@0: ;;
michael@0: "Linux")
michael@0: VALGRIND=`which valgrind`
michael@0: AWK=awk
michael@0:
michael@0: if [ $? -eq 0 ] ; then
michael@0: echo "${SCRIPTNAME}: Valgrind found: ${VALGRIND}"
michael@0: else
michael@0: echo "${SCRIPTNAME}: Valgrind not found, skipping memory leak checking."
michael@0: exit 0
michael@0: fi
michael@0:
michael@0: FREEBL_DEFAULT="libfreebl_3"
michael@0: FREEBL_LIST="${FREEBL_DEFAULT}"
michael@0:
michael@0: RUN_COMMAND_DBG="run_command_valgrind"
michael@0: PARSE_LOGFILE="parse_logfile_valgrind"
michael@0: ;;
michael@0: *)
michael@0: echo "${SCRIPTNAME}: OS not supported for memory leak checking."
michael@0: exit 0
michael@0: ;;
michael@0: esac
michael@0:
michael@0: if [ "${BUILD_OPT}" = "1" ] ; then
michael@0: OPT="OPT"
michael@0: else
michael@0: OPT="DBG"
michael@0: fi
michael@0:
michael@0: NSS_DISABLE_UNLOAD="1"
michael@0: export NSS_DISABLE_UNLOAD
michael@0:
michael@0: SELFSERV_ATTR="-D -p ${PORT} -d ${SERVER_DB} -n ${HOSTADDR} -e ${HOSTADDR}-ec -w nss -c ABCDEF:C001:C002:C003:C004:C005:C006:C007:C008:C009:C00A:C00B:C00C:C00D:C00E:C00F:C010:C011:C012:C013:C014cdefgijklmnvyz -t 5"
michael@0: TSTCLNT_ATTR="-p ${PORT} -h ${HOSTADDR} -c j -f -d ${CLIENT_DB} -w nss -o"
michael@0: STRSCLNT_ATTR="-q -p ${PORT} -d ${CLIENT_DB} -w nss -c 1000 -n TestUser ${HOSTADDR}"
michael@0:
michael@0: tbytes=0
michael@0: tblocks=0
michael@0: truns=0
michael@0:
michael@0: MEMLEAK_DBG=1
michael@0: export MEMLEAK_DBG
michael@0: }
michael@0:
michael@0: ########################### memleak_cleanup ############################
michael@0: # local shell function to clean up after this script
michael@0: ########################################################################
michael@0: memleak_cleanup()
michael@0: {
michael@0: unset MEMLEAK_DBG
michael@0: unset NSS_DISABLE_UNLOAD
michael@0:
michael@0: . ${QADIR}/common/cleanup.sh
michael@0: }
michael@0:
michael@0: ############################ set_test_mode #############################
michael@0: # local shell function to set testing mode for server and for client
michael@0: ########################################################################
michael@0: set_test_mode()
michael@0: {
michael@0: if [ "${server_mode}" = "BYPASS" ] ; then
michael@0: echo "${SCRIPTNAME}: BYPASS is ON"
michael@0: SERVER_OPTION="-B -s"
michael@0: CLIENT_OPTION=""
michael@0: elif [ "${client_mode}" = "BYPASS" ] ; then
michael@0: echo "${SCRIPTNAME}: BYPASS is ON"
michael@0: SERVER_OPTION=""
michael@0: CLIENT_OPTION="-B -s"
michael@0: else
michael@0: echo "${SCRIPTNAME}: BYPASS is OFF"
michael@0: SERVER_OPTION=""
michael@0: CLIENT_OPTION=""
michael@0: fi
michael@0:
michael@0: if [ "${server_mode}" = "FIPS" ] ; then
michael@0: ${BINDIR}/modutil -dbdir ${SERVER_DB} -fips true -force
michael@0: ${BINDIR}/modutil -dbdir ${SERVER_DB} -list
michael@0: ${BINDIR}/modutil -dbdir ${CLIENT_DB} -fips false -force
michael@0: ${BINDIR}/modutil -dbdir ${CLIENT_DB} -list
michael@0:
michael@0: echo "${SCRIPTNAME}: FIPS is ON"
michael@0: cipher_list="c d e i j k n v y z"
michael@0: elif [ "${client_mode}" = "FIPS" ] ; then
michael@0:
michael@0: ${BINDIR}/modutil -dbdir ${SERVER_DB} -fips false -force
michael@0: ${BINDIR}/modutil -dbdir ${SERVER_DB} -list
michael@0: ${BINDIR}/modutil -dbdir ${CLIENT_DB} -fips true -force
michael@0: ${BINDIR}/modutil -dbdir ${CLIENT_DB} -list
michael@0:
michael@0: echo "${SCRIPTNAME}: FIPS is ON"
michael@0: cipher_list="c d e i j k n v y z"
michael@0: else
michael@0: ${BINDIR}/modutil -dbdir ${SERVER_DB} -fips false -force
michael@0: ${BINDIR}/modutil -dbdir ${SERVER_DB} -list
michael@0: ${BINDIR}/modutil -dbdir ${CLIENT_DB} -fips false -force
michael@0: ${BINDIR}/modutil -dbdir ${CLIENT_DB} -list
michael@0:
michael@0: echo "${SCRIPTNAME}: FIPS is OFF"
michael@0: cipher_list="A B C D E F :C001 :C002 :C003 :C004 :C005 :C006 :C007 :C008 :C009 :C00A :C010 :C011 :C012 :C013 :C014 c d e f g i j k l m n v y z"
michael@0: fi
michael@0: }
michael@0:
michael@0: ############################## set_freebl ##############################
michael@0: # local shell function to set freebl - sets temporary path for libraries
michael@0: ########################################################################
michael@0: set_freebl()
michael@0: {
michael@0: if [ "${freebl}" = "${FREEBL_DEFAULT}" ] ; then
michael@0: LD_LIBRARY_PATH="${OLD_LIBRARY_PATH}"
michael@0: export LD_LIBRARY_PATH
michael@0: else
michael@0: if [ -d "${TMP_LIBDIR}" ] ; then
michael@0: rm -rf ${TMP_LIBDIR}
michael@0: fi
michael@0:
michael@0: mkdir ${TMP_LIBDIR}
michael@0: [ $? -ne 0 ] && html_failed "Create temp directory" && return 1
michael@0:
michael@0: cp ${DIST}/${OBJDIR}/lib/*.so ${DIST}/${OBJDIR}/lib/*.chk ${TMP_LIBDIR}
michael@0: [ $? -ne 0 ] && html_failed "Copy libraries to temp directory" && return 1
michael@0:
michael@0: echo "${SCRIPTNAME}: Using ${freebl} instead of ${FREEBL_DEFAULT}"
michael@0:
michael@0: mv ${TMP_LIBDIR}/${FREEBL_DEFAULT}.so ${TMP_LIBDIR}/${FREEBL_DEFAULT}.so.orig
michael@0: [ $? -ne 0 ] && html_failed "Move ${FREEBL_DEFAULT}.so -> ${FREEBL_DEFAULT}.so.orig" && return 1
michael@0:
michael@0: cp ${TMP_LIBDIR}/${freebl}.so ${TMP_LIBDIR}/${FREEBL_DEFAULT}.so
michael@0: [ $? -ne 0 ] && html_failed "Copy ${freebl}.so -> ${FREEBL_DEFAULT}.so" && return 1
michael@0:
michael@0: mv ${TMP_LIBDIR}/${FREEBL_DEFAULT}.chk ${TMP_LIBDIR}/${FREEBL_DEFAULT}.chk.orig
michael@0: [ $? -ne 0 ] && html_failed "Move ${FREEBL_DEFAULT}.chk -> ${FREEBL_DEFAULT}.chk.orig" && return 1
michael@0:
michael@0: cp ${TMP_LIBDIR}/${freebl}.chk ${TMP_LIBDIR}/${FREEBL_DEFAULT}.chk
michael@0: [ $? -ne 0 ] && html_failed "Copy ${freebl}.chk to temp directory" && return 1
michael@0:
michael@0: echo "ls -l ${TMP_LIBDIR}"
michael@0: ls -l ${TMP_LIBDIR}
michael@0:
michael@0: LD_LIBRARY_PATH="${TMP_LIBDIR}"
michael@0: export LD_LIBRARY_PATH
michael@0: fi
michael@0:
michael@0: return 0
michael@0: }
michael@0:
michael@0: ############################# clear_freebl #############################
michael@0: # local shell function to set default library path and clear temporary
michael@0: # directory for libraries created by function set_freebl
michael@0: ########################################################################
michael@0: clear_freebl()
michael@0: {
michael@0: LD_LIBRARY_PATH="${OLD_LIBRARY_PATH}"
michael@0: export LD_LIBRARY_PATH
michael@0:
michael@0: if [ -d "${TMP_LIBDIR}" ] ; then
michael@0: rm -rf ${TMP_LIBDIR}
michael@0: fi
michael@0: }
michael@0:
michael@0: ############################ run_command_dbx ###########################
michael@0: # local shell function to run command under dbx tool
michael@0: ########################################################################
michael@0: run_command_dbx()
michael@0: {
michael@0: COMMAND=$1
michael@0: shift
michael@0: ATTR=$*
michael@0:
michael@0: COMMAND=`which ${COMMAND}`
michael@0:
michael@0: echo "dbxenv follow_fork_mode parent" > ${DBXCMD}
michael@0: echo "dbxenv rtc_mel_at_exit verbose" >> ${DBXCMD}
michael@0: echo "dbxenv rtc_biu_at_exit verbose" >> ${DBXCMD}
michael@0: echo "check -memuse -match 16 -frames 16" >> ${DBXCMD}
michael@0: echo "run ${ATTR}" >> ${DBXCMD}
michael@0:
michael@0: export NSS_DISABLE_ARENA_FREE_LIST=1
michael@0:
michael@0: echo "${SCRIPTNAME}: -------- Running ${COMMAND} under DBX:"
michael@0: echo "${DBX} ${COMMAND}"
michael@0: echo "${SCRIPTNAME}: -------- DBX commands:"
michael@0: cat ${DBXCMD}
michael@0:
michael@0: ( ${DBX} ${COMMAND} < ${DBXCMD} > ${DBXOUT} 2> ${DBXERR} )
michael@0: grep -v Reading ${DBXOUT} 1>&2
michael@0: cat ${DBXERR}
michael@0:
michael@0: unset NSS_DISABLE_ARENA_FREE_LIST
michael@0:
michael@0: grep "exit code is" ${DBXOUT}
michael@0: grep "exit code is 0" ${DBXOUT} > /dev/null
michael@0: return $?
michael@0: }
michael@0:
michael@0: ######################### run_command_valgrind #########################
michael@0: # local shell function to run command under valgrind tool
michael@0: ########################################################################
michael@0: run_command_valgrind()
michael@0: {
michael@0: COMMAND=$1
michael@0: shift
michael@0: ATTR=$*
michael@0:
michael@0: export NSS_DISABLE_ARENA_FREE_LIST=1
michael@0:
michael@0: echo "${SCRIPTNAME}: -------- Running ${COMMAND} under Valgrind:"
michael@0: echo "${VALGRIND} --tool=memcheck --leak-check=yes --show-reachable=yes --partial-loads-ok=yes --leak-resolution=high --num-callers=50 ${COMMAND} ${ATTR}"
michael@0: echo "Running: ${COMMAND} ${ATTR}" 1>&2
michael@0: ${VALGRIND} --tool=memcheck --leak-check=yes --show-reachable=yes --partial-loads-ok=yes --leak-resolution=high --num-callers=50 ${COMMAND} ${ATTR} 1>&2
michael@0: ret=$?
michael@0: echo "==0=="
michael@0:
michael@0: unset NSS_DISABLE_ARENA_FREE_LIST
michael@0:
michael@0: return $ret
michael@0: }
michael@0:
michael@0: ############################# run_selfserv #############################
michael@0: # local shell function to start selfserv
michael@0: ########################################################################
michael@0: run_selfserv()
michael@0: {
michael@0: echo "PATH=${PATH}"
michael@0: echo "LD_LIBRARY_PATH=${LD_LIBRARY_PATH}"
michael@0: echo "${SCRIPTNAME}: -------- Running selfserv:"
michael@0: echo "selfserv ${SELFSERV_ATTR}"
michael@0: ${BINDIR}/selfserv ${SELFSERV_ATTR}
michael@0: ret=$?
michael@0: if [ $ret -ne 0 ]; then
michael@0: html_failed "${LOGNAME}: Selfserv"
michael@0: echo "${SCRIPTNAME} ${LOGNAME}: " \
michael@0: "Selfserv produced a returncode of ${ret} - FAILED"
michael@0: fi
michael@0: }
michael@0:
michael@0: ########################### run_selfserv_dbg ###########################
michael@0: # local shell function to start selfserv under debug tool
michael@0: ########################################################################
michael@0: run_selfserv_dbg()
michael@0: {
michael@0: echo "PATH=${PATH}"
michael@0: echo "LD_LIBRARY_PATH=${LD_LIBRARY_PATH}"
michael@0: ${RUN_COMMAND_DBG} ${BINDIR}/selfserv ${SERVER_OPTION} ${SELFSERV_ATTR}
michael@0: ret=$?
michael@0: if [ $ret -ne 0 ]; then
michael@0: html_failed "${LOGNAME}: Selfserv"
michael@0: echo "${SCRIPTNAME} ${LOGNAME}: " \
michael@0: "Selfserv produced a returncode of ${ret} - FAILED"
michael@0: fi
michael@0: }
michael@0:
michael@0: ############################# run_strsclnt #############################
michael@0: # local shell function to run strsclnt for all ciphers and send stop
michael@0: # command to selfserv over tstclnt
michael@0: ########################################################################
michael@0: run_strsclnt()
michael@0: {
michael@0: for cipher in ${cipher_list}; do
michael@0: VMIN="ssl3"
michael@0: VMAX=
michael@0: case "${cipher}" in
michael@0: A|B|C|D|E|F)
michael@0: # Enable SSL 2 only for SSL 2 cipher suites.
michael@0: VMIN="ssl2"
michael@0: ;;
michael@0: f|g)
michael@0: # TLS 1.1 disallows export cipher suites.
michael@0: VMAX="tls1.0"
michael@0: ;;
michael@0: esac
michael@0: ATTR="${STRSCLNT_ATTR} -C ${cipher} -V ${VMIN}:${VMAX}"
michael@0: echo "${SCRIPTNAME}: -------- Trying cipher ${cipher}:"
michael@0: echo "strsclnt ${ATTR}"
michael@0: ${BINDIR}/strsclnt ${ATTR}
michael@0: ret=$?
michael@0: if [ $ret -ne 0 ]; then
michael@0: html_failed "${LOGNAME}: Strsclnt with cipher ${cipher}"
michael@0: echo "${SCRIPTNAME} ${LOGNAME}: " \
michael@0: "Strsclnt produced a returncode of ${ret} - FAILED"
michael@0: fi
michael@0: done
michael@0:
michael@0: echo "${SCRIPTNAME}: -------- Stopping server:"
michael@0: echo "tstclnt ${TSTCLNT_ATTR} < ${REQUEST_FILE}"
michael@0: ${BINDIR}/tstclnt ${TSTCLNT_ATTR} < ${REQUEST_FILE}
michael@0: ret=$?
michael@0: if [ $ret -ne 0 ]; then
michael@0: html_failed "${LOGNAME}: Tstclnt"
michael@0: echo "${SCRIPTNAME} ${LOGNAME}: " \
michael@0: "Tstclnt produced a returncode of ${ret} - FAILED"
michael@0: fi
michael@0:
michael@0: sleep 20
michael@0: kill $(jobs -p) 2> /dev/null
michael@0: }
michael@0:
michael@0: ########################### run_strsclnt_dbg ###########################
michael@0: # local shell function to run strsclnt under debug tool for all ciphers
michael@0: # and send stop command to selfserv over tstclnt
michael@0: ########################################################################
michael@0: run_strsclnt_dbg()
michael@0: {
michael@0: for cipher in ${cipher_list}; do
michael@0: VMIN="ssl3"
michael@0: VMAX=
michael@0: case "${cipher}" in
michael@0: A|B|C|D|E|F)
michael@0: # Enable SSL 2 only for SSL 2 cipher suites.
michael@0: VMIN="ssl2"
michael@0: ;;
michael@0: f|g)
michael@0: # TLS 1.1 disallows export cipher suites.
michael@0: VMAX="tls1.0"
michael@0: ;;
michael@0: esac
michael@0: ATTR="${STRSCLNT_ATTR} -C ${cipher} -V ${VMIN}:${VMAX}"
michael@0: ${RUN_COMMAND_DBG} ${BINDIR}/strsclnt ${CLIENT_OPTION} ${ATTR}
michael@0: ret=$?
michael@0: if [ $ret -ne 0 ]; then
michael@0: html_failed "${LOGNAME}: Strsclnt with cipher ${cipher}"
michael@0: echo "${SCRIPTNAME} ${LOGNAME}: " \
michael@0: "Strsclnt produced a returncode of ${ret} - FAILED"
michael@0: fi
michael@0: done
michael@0:
michael@0: echo "${SCRIPTNAME}: -------- Stopping server:"
michael@0: echo "tstclnt ${TSTCLNT_ATTR} < ${REQUEST_FILE}"
michael@0: ${BINDIR}/tstclnt ${TSTCLNT_ATTR} < ${REQUEST_FILE}
michael@0: ret=$?
michael@0: if [ $ret -ne 0 ]; then
michael@0: html_failed "${LOGNAME}: Tstclnt"
michael@0: echo "${SCRIPTNAME} ${LOGNAME}: " \
michael@0: "Tstclnt produced a returncode of ${ret} - FAILED"
michael@0: fi
michael@0:
michael@0: kill $(jobs -p) 2> /dev/null
michael@0: }
michael@0:
michael@0: stat_clear()
michael@0: {
michael@0: stat_minbytes=9999999
michael@0: stat_maxbytes=0
michael@0: stat_minblocks=9999999
michael@0: stat_maxblocks=0
michael@0: stat_bytes=0
michael@0: stat_blocks=0
michael@0: stat_runs=0
michael@0: }
michael@0:
michael@0: stat_add()
michael@0: {
michael@0: read hash lbytes bytes_str lblocks blocks_str in_str lruns runs_str \
michael@0: minbytes minbytes_str maxbytes maxbytes_str minblocks \
michael@0: minblocks_str maxblocks maxblocks_str rest < ${TMP_COUNT}
michael@0: rm ${TMP_COUNT}
michael@0:
michael@0: tbytes=`expr ${tbytes} + ${lbytes}`
michael@0: tblocks=`expr ${tblocks} + ${lblocks}`
michael@0: truns=`expr ${truns} + ${lruns}`
michael@0:
michael@0: if [ ${stat_minbytes} -gt ${minbytes} ]; then
michael@0: stat_minbytes=${minbytes}
michael@0: fi
michael@0:
michael@0: if [ ${stat_maxbytes} -lt ${maxbytes} ]; then
michael@0: stat_maxbytes=${maxbytes}
michael@0: fi
michael@0:
michael@0: if [ ${stat_minblocks} -gt ${minblocks} ]; then
michael@0: stat_minblocks=${minblocks}
michael@0: fi
michael@0:
michael@0: if [ ${stat_maxblocks} -lt ${maxblocks} ]; then
michael@0: stat_maxblocks=${maxblocks}
michael@0: fi
michael@0:
michael@0: stat_bytes=`expr ${stat_bytes} + ${lbytes}`
michael@0: stat_blocks=`expr ${stat_blocks} + ${lblocks}`
michael@0: stat_runs=`expr ${stat_runs} + ${lruns}`
michael@0: }
michael@0:
michael@0: stat_print()
michael@0: {
michael@0: if [ ${stat_runs} -gt 0 ]; then
michael@0: stat_avgbytes=`expr "${stat_bytes}" / "${stat_runs}"`
michael@0: stat_avgblocks=`expr "${stat_blocks}" / "${stat_runs}"`
michael@0:
michael@0: echo
michael@0: echo "$1 statistics:"
michael@0: echo "Leaked bytes: ${stat_minbytes} min, ${stat_avgbytes} avg, ${stat_maxbytes} max"
michael@0: echo "Leaked blocks: ${stat_minblocks} min, ${stat_avgblocks} avg, ${stat_maxblocks} max"
michael@0: echo "Total runs: ${stat_runs}"
michael@0: echo
michael@0: fi
michael@0: }
michael@0:
michael@0: ########################## run_ciphers_server ##########################
michael@0: # local shell function to test server part of code (selfserv)
michael@0: ########################################################################
michael@0: run_ciphers_server()
michael@0: {
michael@0: html_head "Memory leak checking - server"
michael@0:
michael@0: stat_clear
michael@0:
michael@0: client_mode="NORMAL"
michael@0: for server_mode in ${MODE_LIST}; do
michael@0: set_test_mode
michael@0:
michael@0: for freebl in ${FREEBL_LIST}; do
michael@0: set_freebl || continue
michael@0:
michael@0: LOGNAME=server-${BIT_NAME}-${freebl}-${server_mode}
michael@0: LOGFILE=${LOGDIR}/${LOGNAME}.log
michael@0: echo "Running ${LOGNAME}"
michael@0:
michael@0: (
michael@0: run_selfserv_dbg 2>> ${LOGFILE} &
michael@0: sleep 5
michael@0: run_strsclnt
michael@0: )
michael@0:
michael@0: sleep 20
michael@0: clear_freebl
michael@0:
michael@0: log_parse
michael@0: ret=$?
michael@0:
michael@0: html_msg ${ret} 0 "${LOGNAME}" "produced a returncode of $ret, expected is 0"
michael@0: done
michael@0: done
michael@0:
michael@0: stat_print "Selfserv"
michael@0:
michael@0: html "
"
michael@0: }
michael@0:
michael@0: ########################## run_ciphers_client ##########################
michael@0: # local shell function to test client part of code (strsclnt)
michael@0: ########################################################################
michael@0: run_ciphers_client()
michael@0: {
michael@0: html_head "Memory leak checking - client"
michael@0:
michael@0: stat_clear
michael@0:
michael@0: server_mode="NORMAL"
michael@0: for client_mode in ${MODE_LIST}; do
michael@0: set_test_mode
michael@0:
michael@0: for freebl in ${FREEBL_LIST}; do
michael@0: set_freebl || continue
michael@0:
michael@0: LOGNAME=client-${BIT_NAME}-${freebl}-${client_mode}
michael@0: LOGFILE=${LOGDIR}/${LOGNAME}.log
michael@0: echo "Running ${LOGNAME}"
michael@0:
michael@0: (
michael@0: run_selfserv &
michael@0: sleep 5
michael@0: run_strsclnt_dbg 2>> ${LOGFILE}
michael@0: )
michael@0:
michael@0: sleep 20
michael@0: clear_freebl
michael@0:
michael@0: log_parse
michael@0: ret=$?
michael@0: html_msg ${ret} 0 "${LOGNAME}" "produced a returncode of $ret, expected is 0"
michael@0: done
michael@0: done
michael@0:
michael@0: stat_print "Strsclnt"
michael@0:
michael@0: html "
"
michael@0: }
michael@0:
michael@0: ########################## parse_logfile_dbx ###########################
michael@0: # local shell function to parse and process logs from dbx
michael@0: ########################################################################
michael@0: parse_logfile_dbx()
michael@0: {
michael@0: ${AWK} '
michael@0: BEGIN {
michael@0: in_mel = 0
michael@0: mel_line = 0
michael@0: bytes = 0
michael@0: lbytes = 0
michael@0: minbytes = 9999999
michael@0: maxbytes = 0
michael@0: blocks = 0
michael@0: lblocks = 0
michael@0: minblocks = 9999999
michael@0: maxblocks = 0
michael@0: runs = 0
michael@0: stack_string = ""
michael@0: bin_name = ""
michael@0: }
michael@0: /Memory Leak \(mel\):/ ||
michael@0: /Possible memory leak -- address in block \(aib\):/ ||
michael@0: /Block in use \(biu\):/ {
michael@0: in_mel = 1
michael@0: stack_string = ""
michael@0: next
michael@0: }
michael@0: in_mel == 1 && /^$/ {
michael@0: print bin_name stack_string
michael@0: in_mel = 0
michael@0: mel_line = 0
michael@0: next
michael@0: }
michael@0: in_mel == 1 {
michael@0: mel_line += 1
michael@0: }
michael@0: /Found leaked block of size/ {
michael@0: bytes += $6
michael@0: blocks += 1
michael@0: next
michael@0: }
michael@0: /Found .* leaked blocks/ {
michael@0: bytes += $8
michael@0: blocks += $2
michael@0: next
michael@0: }
michael@0: /Found block of size/ {
michael@0: bytes += $5
michael@0: blocks += 1
michael@0: next
michael@0: }
michael@0: /Found .* blocks totaling/ {
michael@0: bytes += $5
michael@0: blocks += $2
michael@0: next
michael@0: }
michael@0: mel_line > 2 {
michael@0: gsub(/\(\)/, "")
michael@0: new_line = $2
michael@0: stack_string = "/" new_line stack_string
michael@0: next
michael@0: }
michael@0: /^Running: / {
michael@0: bin_name = $2
michael@0: next
michael@0: }
michael@0: /execution completed/ {
michael@0: runs += 1
michael@0: lbytes += bytes
michael@0: minbytes = (minbytes < bytes) ? minbytes : bytes
michael@0: maxbytes = (maxbytes > bytes) ? maxbytes : bytes
michael@0: bytes = 0
michael@0: lblocks += blocks
michael@0: minblocks = (minblocks < blocks) ? minblocks : blocks
michael@0: maxblocks = (maxblocks > blocks) ? maxblocks : blocks
michael@0: blocks = 0
michael@0: next
michael@0: }
michael@0: END {
michael@0: print "# " lbytes " bytes " lblocks " blocks in " runs " runs " \
michael@0: minbytes " minbytes " maxbytes " maxbytes " minblocks " minblocks " \
michael@0: maxblocks " maxblocks " > "/dev/stderr"
michael@0: }' 2> ${TMP_COUNT}
michael@0:
michael@0: stat_add
michael@0: }
michael@0:
michael@0: ######################## parse_logfile_valgrind ########################
michael@0: # local shell function to parse and process logs from valgrind
michael@0: ########################################################################
michael@0: parse_logfile_valgrind()
michael@0: {
michael@0: ${AWK} '
michael@0: BEGIN {
michael@0: in_mel = 0
michael@0: in_sum = 0
michael@0: bytes = 0
michael@0: lbytes = 0
michael@0: minbytes = 9999999
michael@0: maxbytes = 0
michael@0: blocks = 0
michael@0: lblocks = 0
michael@0: minblocks = 9999999
michael@0: maxblocks = 0
michael@0: runs = 0
michael@0: stack_string = ""
michael@0: bin_name = ""
michael@0: }
michael@0: !/==[0-9]*==/ {
michael@0: if ( $1 == "Running:" )
michael@0: bin_name = $2
michael@0: bin_nf = split(bin_name, bin_fields, "/")
michael@0: bin_name = bin_fields[bin_nf]
michael@0: next
michael@0: }
michael@0: /blocks are/ {
michael@0: in_mel = 1
michael@0: stack_string = ""
michael@0: next
michael@0: }
michael@0: /LEAK SUMMARY/ {
michael@0: in_sum = 1
michael@0: next
michael@0: }
michael@0: /^==[0-9]*== *$/ {
michael@0: if (in_mel)
michael@0: print bin_name stack_string
michael@0: if (in_sum) {
michael@0: runs += 1
michael@0: lbytes += bytes
michael@0: minbytes = (minbytes < bytes) ? minbytes : bytes
michael@0: maxbytes = (maxbytes > bytes) ? maxbytes : bytes
michael@0: bytes = 0
michael@0: lblocks += blocks
michael@0: minblocks = (minblocks < blocks) ? minblocks : blocks
michael@0: maxblocks = (maxblocks > blocks) ? maxblocks : blocks
michael@0: blocks = 0
michael@0: }
michael@0: in_sum = 0
michael@0: in_mel = 0
michael@0: next
michael@0: }
michael@0: in_mel == 1 {
michael@0: new_line = $4
michael@0: if ( new_line == "(within")
michael@0: new_line = "*"
michael@0: stack_string = "/" new_line stack_string
michael@0: }
michael@0: in_sum == 1 {
michael@0: for (i = 2; i <= NF; i++) {
michael@0: if ($i == "bytes") {
michael@0: str = $(i - 1)
michael@0: gsub(",", "", str)
michael@0: bytes += str
michael@0: }
michael@0: if ($i == "blocks.") {
michael@0: str = $(i - 1)
michael@0: gsub(",", "", str)
michael@0: blocks += str
michael@0: }
michael@0: }
michael@0: }
michael@0: END {
michael@0: print "# " lbytes " bytes " lblocks " blocks in " runs " runs " \
michael@0: minbytes " minbytes " maxbytes " maxbytes " minblocks " minblocks " \
michael@0: maxblocks " maxblocks " > "/dev/stderr"
michael@0: }' 2> ${TMP_COUNT}
michael@0:
michael@0: stat_add
michael@0: }
michael@0:
michael@0: ############################# check_ignored ############################
michael@0: # local shell function to check all stacks if they are not ignored
michael@0: ########################################################################
michael@0: check_ignored()
michael@0: {
michael@0: ${AWK} -F/ '
michael@0: BEGIN {
michael@0: ignore = "'${IGNORED_STACKS}'"
michael@0: # read in the ignore file
michael@0: BUGNUM = ""
michael@0: count = 0
michael@0: new = 0
michael@0: while ((getline line < ignore) > 0) {
michael@0: if (line ~ "^#[0-9]+") {
michael@0: BUGNUM = line
michael@0: } else if (line ~ "^#") {
michael@0: continue
michael@0: } else if (line == "") {
michael@0: continue
michael@0: } else {
michael@0: bugnum_array[count] = BUGNUM
michael@0: # Create a regular expression for the ignored stack:
michael@0: # replace * with % so we can later replace them with regular expressions
michael@0: # without messing up everything (the regular expressions contain *)
michael@0: gsub("\\*", "%", line)
michael@0: # replace %% with .*
michael@0: gsub("%%", ".*", line)
michael@0: # replace % with [^/]*
michael@0: gsub("%", "[^/]*", line)
michael@0: # add ^ at the beginning
michael@0: # add $ at the end
michael@0: line_array[count] = "^" line "$"
michael@0: count++
michael@0: }
michael@0: }
michael@0: }
michael@0: {
michael@0: match_found = 0
michael@0: # Look for matching ignored stack
michael@0: for (i = 0; i < count; i++) {
michael@0: if ($0 ~ line_array[i]) {
michael@0: # found a match
michael@0: match_found = 1
michael@0: bug_found = bugnum_array[i]
michael@0: break
michael@0: }
michael@0: }
michael@0: # Process result
michael@0: if (match_found == 1 ) {
michael@0: if (bug_found != "") {
michael@0: print "IGNORED STACK (" bug_found "): " $0
michael@0: } else {
michael@0: print "IGNORED STACK: " $0
michael@0: }
michael@0: } else {
michael@0: print "NEW STACK: " $0
michael@0: new = 1
michael@0: }
michael@0: }
michael@0: END {
michael@0: exit new
michael@0: }'
michael@0: ret=$?
michael@0: return $ret
michael@0: }
michael@0:
michael@0: ############################### parse_log ##############################
michael@0: # local shell function to parse log file
michael@0: ########################################################################
michael@0: log_parse()
michael@0: {
michael@0: ${PARSE_LOGFILE} < ${LOGFILE} > ${TMP_STACKS}
michael@0: echo "${SCRIPTNAME}: Processing log ${LOGNAME}:" > ${TMP_SORTED}
michael@0: cat ${TMP_STACKS} | sort -u | check_ignored >> ${TMP_SORTED}
michael@0: ret=$?
michael@0: echo >> ${TMP_SORTED}
michael@0:
michael@0: cat ${TMP_SORTED} | tee -a ${FOUNDLEAKS}
michael@0: rm ${TMP_STACKS} ${TMP_SORTED}
michael@0:
michael@0: return ${ret}
michael@0: }
michael@0:
michael@0: ############################## cnt_total ###############################
michael@0: # local shell function to count total leaked bytes
michael@0: ########################################################################
michael@0: cnt_total()
michael@0: {
michael@0: echo ""
michael@0: echo "TinderboxPrint:${OPT} Lk bytes: ${tbytes}"
michael@0: echo "TinderboxPrint:${OPT} Lk blocks: ${tblocks}"
michael@0: echo "TinderboxPrint:${OPT} # of runs: ${truns}"
michael@0: echo ""
michael@0: }
michael@0:
michael@0: ############################### run_ocsp ###############################
michael@0: # local shell function to run ocsp tests
michael@0: ########################################################################
michael@0: run_ocsp()
michael@0: {
michael@0: stat_clear
michael@0:
michael@0: cd ${QADIR}/iopr
michael@0: . ./ocsp_iopr.sh
michael@0: ocsp_iopr_run
michael@0:
michael@0: stat_print "Ocspclnt"
michael@0: }
michael@0:
michael@0: ############################## run_chains ##############################
michael@0: # local shell function to run PKIX certificate chains tests
michael@0: ########################################################################
michael@0: run_chains()
michael@0: {
michael@0: stat_clear
michael@0:
michael@0: LOGNAME="chains"
michael@0: LOGFILE=${LOGDIR}/chains.log
michael@0:
michael@0: . ${QADIR}/chains/chains.sh
michael@0:
michael@0: stat_print "Chains"
michael@0: }
michael@0:
michael@0: ############################## run_chains ##############################
michael@0: # local shell function to run memory leak tests
michael@0: #
michael@0: # NSS_MEMLEAK_TESTS - list of tests to run, if not defined before,
michael@0: # then is redefined to default list
michael@0: ########################################################################
michael@0: memleak_run_tests()
michael@0: {
michael@0: nss_memleak_tests="ssl_server ssl_client chains ocsp"
michael@0: NSS_MEMLEAK_TESTS="${NSS_MEMLEAK_TESTS:-$nss_memleak_tests}"
michael@0:
michael@0: for MEMLEAK_TEST in ${NSS_MEMLEAK_TESTS}
michael@0: do
michael@0: case "${MEMLEAK_TEST}" in
michael@0: "ssl_server")
michael@0: run_ciphers_server
michael@0: ;;
michael@0: "ssl_client")
michael@0: run_ciphers_client
michael@0: ;;
michael@0: "chains")
michael@0: run_chains
michael@0: ;;
michael@0: "ocsp")
michael@0: run_ocsp
michael@0: ;;
michael@0: esac
michael@0: done
michael@0: }
michael@0:
michael@0: ################################# main #################################
michael@0:
michael@0: memleak_init
michael@0: memleak_run_tests
michael@0: cnt_total
michael@0: memleak_cleanup
michael@0: