| #!/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" && return 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 "</TABLE><BR>" |
| } |
| |
| ########################## run_ciphers_client ########################## |
| # local shell function to test client part of code (strsclnt) |
| ######################################################################## |
| run_ciphers_client() |
| { |
| html_head "Memory leak checking - client" |
| |
| stat_clear |
| |
| server_mode="NORMAL" |
| for client_mode in ${MODE_LIST}; do |
| set_test_mode |
| |
| for freebl in ${FREEBL_LIST}; do |
| set_freebl || continue |
| |
| LOGNAME=client-${BIT_NAME}-${freebl}-${client_mode} |
| LOGFILE=${LOGDIR}/${LOGNAME}.log |
| echo "Running ${LOGNAME}" |
| |
| ( |
| run_selfserv & |
| sleep 5 |
| run_strsclnt_dbg 2>> ${LOGFILE} |
| ) |
| |
| sleep 20 |
| clear_freebl |
| |
| log_parse |
| ret=$? |
| html_msg ${ret} 0 "${LOGNAME}" "produced a returncode of $ret, expected is 0" |
| done |
| done |
| |
| stat_print "Strsclnt" |
| |
| html "</TABLE><BR>" |
| } |
| |
| ########################## parse_logfile_dbx ########################### |
| # local shell function to parse and process logs from dbx |
| ######################################################################## |
| parse_logfile_dbx() |
| { |
| ${AWK} ' |
| BEGIN { |
| in_mel = 0 |
| mel_line = 0 |
| bytes = 0 |
| lbytes = 0 |
| minbytes = 9999999 |
| maxbytes = 0 |
| blocks = 0 |
| lblocks = 0 |
| minblocks = 9999999 |
| maxblocks = 0 |
| runs = 0 |
| stack_string = "" |
| bin_name = "" |
| } |
| /Memory Leak \(mel\):/ || |
| /Possible memory leak -- address in block \(aib\):/ || |
| /Block in use \(biu\):/ { |
| in_mel = 1 |
| stack_string = "" |
| next |
| } |
| in_mel == 1 && /^$/ { |
| print bin_name stack_string |
| in_mel = 0 |
| mel_line = 0 |
| next |
| } |
| in_mel == 1 { |
| mel_line += 1 |
| } |
| /Found leaked block of size/ { |
| bytes += $6 |
| blocks += 1 |
| next |
| } |
| /Found .* leaked blocks/ { |
| bytes += $8 |
| blocks += $2 |
| next |
| } |
| /Found block of size/ { |
| bytes += $5 |
| blocks += 1 |
| next |
| } |
| /Found .* blocks totaling/ { |
| bytes += $5 |
| blocks += $2 |
| next |
| } |
| mel_line > 2 { |
| gsub(/\(\)/, "") |
| new_line = $2 |
| stack_string = "/" new_line stack_string |
| next |
| } |
| /^Running: / { |
| bin_name = $2 |
| next |
| } |
| /execution completed/ { |
| runs += 1 |
| lbytes += bytes |
| minbytes = (minbytes < bytes) ? minbytes : bytes |
| maxbytes = (maxbytes > bytes) ? maxbytes : bytes |
| bytes = 0 |
| lblocks += blocks |
| minblocks = (minblocks < blocks) ? minblocks : blocks |
| maxblocks = (maxblocks > blocks) ? maxblocks : blocks |
| blocks = 0 |
| next |
| } |
| END { |
| print "# " lbytes " bytes " lblocks " blocks in " runs " runs " \ |
| minbytes " minbytes " maxbytes " maxbytes " minblocks " minblocks " \ |
| maxblocks " maxblocks " > "/dev/stderr" |
| }' 2> ${TMP_COUNT} |
| |
| stat_add |
| } |
| |
| ######################## parse_logfile_valgrind ######################## |
| # local shell function to parse and process logs from valgrind |
| ######################################################################## |
| parse_logfile_valgrind() |
| { |
| ${AWK} ' |
| BEGIN { |
| in_mel = 0 |
| in_sum = 0 |
| bytes = 0 |
| lbytes = 0 |
| minbytes = 9999999 |
| maxbytes = 0 |
| blocks = 0 |
| lblocks = 0 |
| minblocks = 9999999 |
| maxblocks = 0 |
| runs = 0 |
| stack_string = "" |
| bin_name = "" |
| } |
| !/==[0-9]*==/ { |
| if ( $1 == "Running:" ) |
| bin_name = $2 |
| bin_nf = split(bin_name, bin_fields, "/") |
| bin_name = bin_fields[bin_nf] |
| next |
| } |
| /blocks are/ { |
| in_mel = 1 |
| stack_string = "" |
| next |
| } |
| /LEAK SUMMARY/ { |
| in_sum = 1 |
| next |
| } |
| /^==[0-9]*== *$/ { |
| if (in_mel) |
| print bin_name stack_string |
| if (in_sum) { |
| runs += 1 |
| lbytes += bytes |
| minbytes = (minbytes < bytes) ? minbytes : bytes |
| maxbytes = (maxbytes > bytes) ? maxbytes : bytes |
| bytes = 0 |
| lblocks += blocks |
| minblocks = (minblocks < blocks) ? minblocks : blocks |
| maxblocks = (maxblocks > blocks) ? maxblocks : blocks |
| blocks = 0 |
| } |
| in_sum = 0 |
| in_mel = 0 |
| next |
| } |
| in_mel == 1 { |
| new_line = $4 |
| if ( new_line == "(within") |
| new_line = "*" |
| stack_string = "/" new_line stack_string |
| } |
| in_sum == 1 { |
| for (i = 2; i <= NF; i++) { |
| if ($i == "bytes") { |
| str = $(i - 1) |
| gsub(",", "", str) |
| bytes += str |
| } |
| if ($i == "blocks.") { |
| str = $(i - 1) |
| gsub(",", "", str) |
| blocks += str |
| } |
| } |
| } |
| END { |
| print "# " lbytes " bytes " lblocks " blocks in " runs " runs " \ |
| minbytes " minbytes " maxbytes " maxbytes " minblocks " minblocks " \ |
| maxblocks " maxblocks " > "/dev/stderr" |
| }' 2> ${TMP_COUNT} |
| |
| stat_add |
| } |
| |
| ############################# check_ignored ############################ |
| # local shell function to check all stacks if they are not ignored |
| ######################################################################## |
| check_ignored() |
| { |
| ${AWK} -F/ ' |
| BEGIN { |
| ignore = "'${IGNORED_STACKS}'" |
| # read in the ignore file |
| BUGNUM = "" |
| count = 0 |
| new = 0 |
| while ((getline line < ignore) > 0) { |
| if (line ~ "^#[0-9]+") { |
| BUGNUM = line |
| } else if (line ~ "^#") { |
| continue |
| } else if (line == "") { |
| continue |
| } else { |
| bugnum_array[count] = BUGNUM |
| # Create a regular expression for the ignored stack: |
| # replace * with % so we can later replace them with regular expressions |
| # without messing up everything (the regular expressions contain *) |
| gsub("\\*", "%", line) |
| # replace %% with .* |
| gsub("%%", ".*", line) |
| # replace % with [^/]* |
| gsub("%", "[^/]*", line) |
| # add ^ at the beginning |
| # add $ at the end |
| line_array[count] = "^" line "$" |
| count++ |
| } |
| } |
| } |
| { |
| match_found = 0 |
| # Look for matching ignored stack |
| for (i = 0; i < count; i++) { |
| if ($0 ~ line_array[i]) { |
| # found a match |
| match_found = 1 |
| bug_found = bugnum_array[i] |
| break |
| } |
| } |
| # Process result |
| if (match_found == 1 ) { |
| if (bug_found != "") { |
| print "IGNORED STACK (" bug_found "): " $0 |
| } else { |
| print "IGNORED STACK: " $0 |
| } |
| } else { |
| print "NEW STACK: " $0 |
| new = 1 |
| } |
| } |
| END { |
| exit new |
| }' |
| ret=$? |
| return $ret |
| } |
| |
| ############################### parse_log ############################## |
| # local shell function to parse log file |
| ######################################################################## |
| log_parse() |
| { |
| ${PARSE_LOGFILE} < ${LOGFILE} > ${TMP_STACKS} |
| echo "${SCRIPTNAME}: Processing log ${LOGNAME}:" > ${TMP_SORTED} |
| cat ${TMP_STACKS} | sort -u | check_ignored >> ${TMP_SORTED} |
| ret=$? |
| echo >> ${TMP_SORTED} |
| |
| cat ${TMP_SORTED} | tee -a ${FOUNDLEAKS} |
| rm ${TMP_STACKS} ${TMP_SORTED} |
| |
| return ${ret} |
| } |
| |
| ############################## cnt_total ############################### |
| # local shell function to count total leaked bytes |
| ######################################################################## |
| cnt_total() |
| { |
| echo "" |
| echo "TinderboxPrint:${OPT} Lk bytes: ${tbytes}" |
| echo "TinderboxPrint:${OPT} Lk blocks: ${tblocks}" |
| echo "TinderboxPrint:${OPT} # of runs: ${truns}" |
| echo "" |
| } |
| |
| ############################### run_ocsp ############################### |
| # local shell function to run ocsp tests |
| ######################################################################## |
| run_ocsp() |
| { |
| stat_clear |
| |
| cd ${QADIR}/iopr |
| . ./ocsp_iopr.sh |
| ocsp_iopr_run |
| |
| stat_print "Ocspclnt" |
| } |
| |
| ############################## run_chains ############################## |
| # local shell function to run PKIX certificate chains tests |
| ######################################################################## |
| run_chains() |
| { |
| stat_clear |
| |
| LOGNAME="chains" |
| LOGFILE=${LOGDIR}/chains.log |
| |
| . ${QADIR}/chains/chains.sh |
| |
| stat_print "Chains" |
| } |
| |
| ############################## run_chains ############################## |
| # local shell function to run memory leak tests |
| # |
| # NSS_MEMLEAK_TESTS - list of tests to run, if not defined before, |
| # then is redefined to default list |
| ######################################################################## |
| memleak_run_tests() |
| { |
| nss_memleak_tests="ssl_server ssl_client chains ocsp" |
| NSS_MEMLEAK_TESTS="${NSS_MEMLEAK_TESTS:-$nss_memleak_tests}" |
| |
| for MEMLEAK_TEST in ${NSS_MEMLEAK_TESTS} |
| do |
| case "${MEMLEAK_TEST}" in |
| "ssl_server") |
| run_ciphers_server |
| ;; |
| "ssl_client") |
| run_ciphers_client |
| ;; |
| "chains") |
| run_chains |
| ;; |
| "ocsp") |
| run_ocsp |
| ;; |
| esac |
| done |
| } |
| |
| ################################# main ################################# |
| |
| memleak_init |
| memleak_run_tests |
| cnt_total |
| memleak_cleanup |
| |