#!/bin/bash
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
########################################################################
#
# mozilla/security/nss/tests/memleak/memleak.sh
#
# Script to test memory leaks in NSS
#
# needs to work on Solaris and Linux platforms, on others just print a message
# that OS is not supported
#
# special strings
# ---------------
# FIXME ... known problems, search for this string
# NOTE .... unexpected behavior
#
########################################################################
############################# memleak_init #############################
# local shell function to initialize this script
########################################################################
memleak_init()
{
if [ -z
"${INIT_SOURCED}" -o
"${INIT_SOURCED}" !=
"TRUE" ];
then
cd ../common
. ./init.sh
fi
if [ ! -r ${CERT_LOG_FILE} ];
then
cd ${QADIR}/cert
. ./cert.sh
fi
SCRIPTNAME=
"memleak.sh"
if [ -z
"${CLEANUP}" ] ;
then
CLEANUP=
"${SCRIPTNAME}"
fi
OLD_LIBRARY_PATH=${LD_LIBRARY_PATH}
TMP_LIBDIR=
"${HOSTDIR}/tmp"
TMP_STACKS=
"${HOSTDIR}/stacks"
TMP_SORTED=
"${HOSTDIR}/sorted"
TMP_COUNT=
"${HOSTDIR}/count"
DBXOUT=
"${HOSTDIR}/dbxout"
DBXERR=
"${HOSTDIR}/dbxerr"
DBXCMD=
"${HOSTDIR}/dbxcmd"
PORT=${PORT:-8443}
MODE_LIST=
"NORMAL BYPASS FIPS"
SERVER_DB=
"${HOSTDIR}/server_memleak"
CLIENT_DB=
"${HOSTDIR}/client_memleak"
cp -r ${HOSTDIR}/server ${SERVER_DB}
cp -r ${HOSTDIR}/client ${CLIENT_DB}
LOGDIR=
"${HOSTDIR}/memleak_logs"
mkdir -p ${LOGDIR}
FOUNDLEAKS=
"${LOGDIR}/foundleaks"
REQUEST_FILE=
"${QADIR}/memleak/sslreq.dat"
IGNORED_STACKS=
"${QADIR}/memleak/ignored"
gline=`
echo ${OBJDIR} | grep
"_64_"`
if [ -n
"${gline}" ] ;
then
BIT_NAME=
"64"
else
BIT_NAME=
"32"
fi
case
"${OS_NAME}" in
"SunOS")
DBX=`which dbx`
AWK=nawk
if [ $? -eq 0 ] ;
then
echo "${SCRIPTNAME}: DBX found: ${DBX}"
else
echo "${SCRIPTNAME}: DBX not found, skipping memory leak checking."
exit 0
fi
PROC_ARCH=`uname -p`
if [
"${PROC_ARCH}" =
"sparc" ] ;
then
if [
"${BIT_NAME}" =
"64" ] ;
then
FREEBL_DEFAULT=
"libfreebl_64fpu_3"
FREEBL_LIST=
"${FREEBL_DEFAULT} libfreebl_64int_3"
else
FREEBL_DEFAULT=
"libfreebl_32fpu_3"
FREEBL_LIST=
"${FREEBL_DEFAULT} libfreebl_32int64_3"
fi
else
if [
"${BIT_NAME}" =
"64" ] ;
then
echo "${SCRIPTNAME}: OS not supported for memory leak checking."
exit 0
fi
FREEBL_DEFAULT=
"libfreebl_3"
FREEBL_LIST=
"${FREEBL_DEFAULT}"
fi
RUN_COMMAND_DBG=
"run_command_dbx"
PARSE_LOGFILE=
"parse_logfile_dbx"
;;
"Linux")
VALGRIND=`which valgrind`
AWK=awk
if [ $? -eq 0 ] ;
then
echo "${SCRIPTNAME}: Valgrind found: ${VALGRIND}"
else
echo "${SCRIPTNAME}: Valgrind not found, skipping memory leak checking."
exit 0
fi
FREEBL_DEFAULT=
"libfreebl_3"
FREEBL_LIST=
"${FREEBL_DEFAULT}"
RUN_COMMAND_DBG=
"run_command_valgrind"
PARSE_LOGFILE=
"parse_logfile_valgrind"
;;
*)
echo "${SCRIPTNAME}: OS not supported for memory leak checking."
exit 0
;;
esac
if [
"${BUILD_OPT}" =
"1" ] ;
then
OPT=
"OPT"
else
OPT=
"DBG"
fi
NSS_DISABLE_UNLOAD=
"1"
export NSS_DISABLE_UNLOAD
SELFSERV_ATTR=
"-D -p ${PORT} -d ${SERVER_DB} -n ${HOSTADDR} -e ${HOSTADDR}-ec -w nss -c :C001:C002:C003:C004:C005:C006:C007:C008:C009:C00A:C00B:C00C:C00D:C00E:C00F:C010:C011:C012:C013:C014cdefgijklmnvyz -t 5 -V ssl3:tls1.2"
TSTCLNT_ATTR=
"-p ${PORT} -h ${HOSTADDR} -c j -f -d ${CLIENT_DB} -w nss -o"
STRSCLNT_ATTR=
"-q -p ${PORT} -d ${CLIENT_DB} -w nss -c 1000 -n TestUser ${HOSTADDR}"
tbytes=0
tblocks=0
truns=0
MEMLEAK_DBG=1
export MEMLEAK_DBG
}
########################### memleak_cleanup ############################
# local shell function to clean up after this script
########################################################################
memleak_cleanup()
{
unset MEMLEAK_DBG
unset NSS_DISABLE_UNLOAD
. ${QADIR}/common/cleanup.sh
}
############################ set_test_mode #############################
# local shell function to set testing mode for server and for client
########################################################################
set_test_mode()
{
if [
"${server_mode}" =
"BYPASS" ] ;
then
echo "${SCRIPTNAME}: BYPASS is ON"
SERVER_OPTION=
"-B -s"
CLIENT_OPTION=
""
elif [
"${client_mode}" =
"BYPASS" ] ;
then
echo "${SCRIPTNAME}: BYPASS is ON"
SERVER_OPTION=
""
CLIENT_OPTION=
"-B -s"
else
echo "${SCRIPTNAME}: BYPASS is OFF"
SERVER_OPTION=
""
CLIENT_OPTION=
""
fi
if [
"${server_mode}" =
"FIPS" ] ;
then
${BINDIR}/modutil -dbdir ${SERVER_DB} -fips true -force
${BINDIR}/modutil -dbdir ${SERVER_DB} -list
${BINDIR}/modutil -dbdir ${CLIENT_DB} -fips false -force
${BINDIR}/modutil -dbdir ${CLIENT_DB} -list
echo "${SCRIPTNAME}: FIPS is ON"
cipher_list=
"c d e i j k n v y z"
elif [
"${client_mode}" =
"FIPS" ] ;
then
${BINDIR}/modutil -dbdir ${SERVER_DB} -fips false -force
${BINDIR}/modutil -dbdir ${SERVER_DB} -list
${BINDIR}/modutil -dbdir ${CLIENT_DB} -fips true -force
${BINDIR}/modutil -dbdir ${CLIENT_DB} -list
echo "${SCRIPTNAME}: FIPS is ON"
cipher_list=
"c d e i j k n v y z"
else
${BINDIR}/modutil -dbdir ${SERVER_DB} -fips false -force
${BINDIR}/modutil -dbdir ${SERVER_DB} -list
${BINDIR}/modutil -dbdir ${CLIENT_DB} -fips false -force
${BINDIR}/modutil -dbdir ${CLIENT_DB} -list
echo "${SCRIPTNAME}: FIPS is OFF"
# ciphers l and m removed, see bug 1136095
cipher_list=
":C001 :C002 :C003 :C004 :C005 :C006 :C007 :C008 :C009 :C00A :C010 :C011 :C012 :C013 :C014 c d e f g i j k n v y z"
fi
}
############################## set_freebl ##############################
# local shell function to set freebl - sets temporary path for libraries
########################################################################
set_freebl()
{
if [
"${freebl}" =
"${FREEBL_DEFAULT}" ] ;
then
LD_LIBRARY_PATH=
"${OLD_LIBRARY_PATH}"
export LD_LIBRARY_PATH
else
if [ -d
"${TMP_LIBDIR}" ] ;
then
rm -rf ${TMP_LIBDIR}
fi
mkdir ${TMP_LIBDIR}
[ $? -ne 0 ] && html_failed
"Create temp directory" && return 1
cp ${DIST}/${OBJDIR}/lib/*.so ${DIST}/${OBJDIR}/lib/*.chk ${TMP_LIBDIR}
[ $? -ne 0 ] && html_failed
"Copy libraries to temp directory" && return 1
echo "${SCRIPTNAME}: Using ${freebl} instead of ${FREEBL_DEFAULT}"
mv ${TMP_LIBDIR}/${FREEBL_DEFAULT}.so ${TMP_LIBDIR}/${FREEBL_DEFAULT}.so.orig
[ $? -ne 0 ] && html_failed
"Move ${FREEBL_DEFAULT}.so -> ${FREEBL_DEFAULT}.so.orig" && retur
n 1
cp ${TMP_LIBDIR}/${freebl}.so ${TMP_LIBDIR}/${FREEBL_DEFAULT}.so
[ $? -ne 0 ] && html_failed "Copy ${freebl}.so -> ${FREEBL_DEFAULT}.so" && return 1
mv ${TMP_LIBDIR}/${FREEBL_DEFAULT}.chk ${TMP_LIBDIR}/${FREEBL_DEFAULT}.chk.orig
[ $? -ne 0 ] && html_failed "Move ${FREEBL_DEFAULT}.chk -> ${FREEBL_DEFAULT}.chk.orig" && return 1
cp ${TMP_LIBDIR}/${freebl}.chk ${TMP_LIBDIR}/${FREEBL_DEFAULT}.chk
[ $? -ne 0 ] && html_failed "Copy ${freebl}.chk to temp directory" && return 1
echo "ls -l ${TMP_LIBDIR}"
ls -l ${TMP_LIBDIR}
LD_LIBRARY_PATH="${TMP_LIBDIR}"
export LD_LIBRARY_PATH
fi
return 0
}
############################# clear_freebl #############################
# local shell function to set default library path and clear temporary
# directory for libraries created by function set_freebl
########################################################################
clear_freebl()
{
LD_LIBRARY_PATH="${OLD_LIBRARY_PATH}"
export LD_LIBRARY_PATH
if [ -d "${TMP_LIBDIR}" ] ; then
rm -rf ${TMP_LIBDIR}
fi
}
############################ run_command_dbx ###########################
# local shell function to run command under dbx tool
########################################################################
run_command_dbx()
{
COMMAND=$1
shift
ATTR=$*
COMMAND=`which ${COMMAND}`
echo "dbxenv follow_fork_mode parent" > ${DBXCMD}
echo "dbxenv rtc_mel_at_exit verbose" >> ${DBXCMD}
echo "dbxenv rtc_biu_at_exit verbose" >> ${DBXCMD}
echo "check -memuse -match 16 -frames 16" >> ${DBXCMD}
echo "run ${ATTR}" >> ${DBXCMD}
export NSS_DISABLE_ARENA_FREE_LIST=1
echo "${SCRIPTNAME}: -------- Running ${COMMAND} under DBX:"
echo "${DBX} ${COMMAND}"
echo "${SCRIPTNAME}: -------- DBX commands:"
cat ${DBXCMD}
( ${DBX} ${COMMAND} < ${DBXCMD} > ${DBXOUT} 2> ${DBXERR} )
grep -v Reading ${DBXOUT} 1>&2
cat ${DBXERR}
unset NSS_DISABLE_ARENA_FREE_LIST
grep "exit code is" ${DBXOUT}
grep "exit code is 0" ${DBXOUT} > /dev/null
return $?
}
######################### run_command_valgrind #########################
# local shell function to run command under valgrind tool
########################################################################
run_command_valgrind()
{
COMMAND=$1
shift
ATTR=$*
export NSS_DISABLE_ARENA_FREE_LIST=1
echo "${SCRIPTNAME}: -------- Running ${COMMAND} under Valgrind:"
echo "${VALGRIND} --tool=memcheck --leak-check=yes --show-reachable=yes --partial-loads-ok=yes --leak-resolution=high --num-callers=50 ${COMMAND} ${ATTR}"
echo "Running: ${COMMAND} ${ATTR}" 1>&2
${VALGRIND} --tool=memcheck --leak-check=yes --show-reachable=yes --partial-loads-ok=yes --leak-resolution=high --num-callers=50 ${COMMAND} ${ATTR} 1>&2
ret=$?
echo "==0=="
unset NSS_DISABLE_ARENA_FREE_LIST
return $ret
}
############################# run_selfserv #############################
# local shell function to start selfserv
########################################################################
run_selfserv()
{
echo "PATH=${PATH}"
echo "LD_LIBRARY_PATH=${LD_LIBRARY_PATH}"
echo "${SCRIPTNAME}: -------- Running selfserv:"
echo "selfserv ${SELFSERV_ATTR}"
${BINDIR}/selfserv ${SELFSERV_ATTR}
ret=$?
if [ $ret -ne 0 ]; then
html_failed "${LOGNAME}: Selfserv"
echo "${SCRIPTNAME} ${LOGNAME}: " \
"Selfserv produced a returncode of ${ret} - FAILED"
fi
}
########################### run_selfserv_dbg ###########################
# local shell function to start selfserv under debug tool
########################################################################
run_selfserv_dbg()
{
echo "PATH=${PATH}"
echo "LD_LIBRARY_PATH=${LD_LIBRARY_PATH}"
${RUN_COMMAND_DBG} ${BINDIR}/selfserv ${SERVER_OPTION} ${SELFSERV_ATTR}
ret=$?
if [ $ret -ne 0 ]; then
html_failed "${LOGNAME}: Selfserv"
echo "${SCRIPTNAME} ${LOGNAME}: " \
"Selfserv produced a returncode of ${ret} - FAILED"
fi
}
############################# run_strsclnt #############################
# local shell function to run strsclnt for all ciphers and send stop
# command to selfserv over tstclnt
########################################################################
run_strsclnt()
{
for cipher in ${cipher_list}; do
VMIN="ssl3"
VMAX="tls1.2"
case "${cipher}" in
f|g)
# TLS 1.1 disallows export cipher suites.
VMAX="tls1.0"
;;
esac
ATTR="${STRSCLNT_ATTR} -C ${cipher} -V ${VMIN}:${VMAX}"
echo "${SCRIPTNAME}: -------- Trying cipher ${cipher}:"
echo "strsclnt ${ATTR}"
${BINDIR}/strsclnt ${ATTR}
ret=$?
if [ $ret -ne 0 ]; then
html_failed "${LOGNAME}: Strsclnt with cipher ${cipher}"
echo "${SCRIPTNAME} ${LOGNAME}: " \
"Strsclnt produced a returncode of ${ret} - FAILED"
fi
done
ATTR="${TSTCLNT_ATTR} -V ssl3:tls1.2"
echo "${SCRIPTNAME}: -------- Stopping server:"
echo "tstclnt ${ATTR} < ${REQUEST_FILE}"
${BINDIR}/tstclnt ${ATTR} < ${REQUEST_FILE}
ret=$?
if [ $ret -ne 0 ]; then
html_failed "${LOGNAME}: Tstclnt"
echo "${SCRIPTNAME} ${LOGNAME}: " \
"Tstclnt produced a returncode of ${ret} - FAILED"
fi
sleep 20
kill $(jobs -p) 2> /dev/null
}
########################### run_strsclnt_dbg ###########################
# local shell function to run strsclnt under debug tool for all ciphers
# and send stop command to selfserv over tstclnt
########################################################################
run_strsclnt_dbg()
{
for cipher in ${cipher_list}; do
VMIN="ssl3"
VMAX="tls1.2"
case "${cipher}" in
f|g)
# TLS 1.1 disallows export cipher suites.
VMAX="tls1.0"
;;
esac
ATTR="${STRSCLNT_ATTR} -C ${cipher} -V ${VMIN}:${VMAX}"
${RUN_COMMAND_DBG} ${BINDIR}/strsclnt ${CLIENT_OPTION} ${ATTR}
ret=$?
if [ $ret -ne 0 ]; then
html_failed "${LOGNAME}: Strsclnt with cipher ${cipher}"
echo "${SCRIPTNAME} ${LOGNAME}: " \
"Strsclnt produced a returncode of ${ret} - FAILED"
fi
done
ATTR="${TSTCLNT_ATTR} -V ssl3:tls1.2"
echo "${SCRIPTNAME}: -------- Stopping server:"
echo "tstclnt ${ATTR} < ${REQUEST_FILE}"
${BINDIR}/tstclnt ${ATTR} < ${REQUEST_FILE}
ret=$?
if [ $ret -ne 0 ]; then
html_failed "${LOGNAME}: Tstclnt"
echo "${SCRIPTNAME} ${LOGNAME}: " \
"Tstclnt produced a returncode of ${ret} - FAILED"
fi
kill $(jobs -p) 2> /dev/null
}
stat_clear()
{
stat_minbytes=9999999
stat_maxbytes=0
stat_minblocks=9999999
stat_maxblocks=0
stat_bytes=0
stat_blocks=0
stat_runs=0
}
stat_add()
{
read hash lbytes bytes_str lblocks blocks_str in_str lruns runs_str \
minbytes minbytes_str maxbytes maxbytes_str minblocks \
minblocks_str maxblocks maxblocks_str rest < ${TMP_COUNT}
rm ${TMP_COUNT}
tbytes=`expr ${tbytes} + ${lbytes}`
tblocks=`expr ${tblocks} + ${lblocks}`
truns=`expr ${truns} + ${lruns}`
if [ ${stat_minbytes} -gt ${minbytes} ]; then
stat_minbytes=${minbytes}
fi
if [ ${stat_maxbytes} -lt ${maxbytes} ]; then
stat_maxbytes=${maxbytes}
fi
if [ ${stat_minblocks} -gt ${minblocks} ]; then
stat_minblocks=${minblocks}
fi
if [ ${stat_maxblocks} -lt ${maxblocks} ]; then
stat_maxblocks=${maxblocks}
fi
stat_bytes=`expr ${stat_bytes} + ${lbytes}`
stat_blocks=`expr ${stat_blocks} + ${lblocks}`
stat_runs=`expr ${stat_runs} + ${lruns}`
}
stat_print()
{
if [ ${stat_runs} -gt 0 ]; then
stat_avgbytes=`expr "${stat_bytes}" / "${stat_runs}"`
stat_avgblocks=`expr "${stat_blocks}" / "${stat_runs}"`
echo
echo "$1 statistics:"
echo "Leaked bytes: ${stat_minbytes} min, ${stat_avgbytes} avg, ${stat_maxbytes} max"
echo "Leaked blocks: ${stat_minblocks} min, ${stat_avgblocks} avg, ${stat_maxblocks} max"
echo "Total runs: ${stat_runs}"
echo
fi
}
########################## run_ciphers_server ##########################
# local shell function to test server part of code (selfserv)
########################################################################
run_ciphers_server()
{
html_head "Memory leak checking - server"
stat_clear
client_mode="NORMAL"
for server_mode in ${MODE_LIST}; do
set_test_mode
for freebl in ${FREEBL_LIST}; do
set_freebl || continue
LOGNAME=server-${BIT_NAME}-${freebl}-${server_mode}
LOGFILE=${LOGDIR}/${LOGNAME}.log
echo "Running ${LOGNAME}"
(
run_selfserv_dbg 2>> ${LOGFILE} &
sleep 5
run_strsclnt
)
sleep 20
clear_freebl
log_parse
ret=$?
html_msg ${ret} 0 "${LOGNAME}" "produced a returncode of $ret, expected is 0"
done
done
stat_print "Selfserv"
html "