#! /bin/bash

LEAKCHECKFILE="$1"
TMPFILE="${TMPDIR:-/tmp}/malloc-free-check-$$${RANDOM}${RANDOM}${RANDOM}.tmp"
export LEAKCHECKFILE TMPFILE

if [ -z "${LEAKCHECKFILE}" ]; then
	echo "Usage: leakcheck <filename>" >&2
	echo "         filename       Name of file containing debugging output" >&2

	exit 1
fi

egrep '(MALLOC|FREE|REALLOC)' "${LEAKCHECKFILE}" | sed 's@^.*FREE(\([x0-9a-fA-F]*\)).*$@free \1@;s@^.*MALLOC() = @malloc @;s@^.*REALLOC(\([x0-9a-fA-F]*\)) = @realloc \1 @' > "${TMPFILE}"

cat "${TMPFILE}" | while read op addr newaddr; do
	case "${op}" in
		malloc)
			if [ -z "${alloclist}" ]; then
				alloclist="${addr}"
			else
				alloclist="${alloclist} ${addr}"
			fi
			;;
		free)
			if ! echo " ${alloclist} " | grep " ${addr} " >/dev/null; then
				if [ -z "${alloclist}" ]; then
					alloclist="!${addr}"
				else
					alloclist="${alloclist} !${addr}"
				fi
			else
				alloclist="$(echo " ${alloclist} " | sed "s@ ${addr} @ @;s@^  *@@;s@  *\$@@")"
			fi
			;;
		realloc)
			alloclist="$(echo " ${alloclist} " | sed "s@ ${addr} @ ${newaddr} @;s@^  *@@;s@  *\$@@")"
			;;
	esac

	echo "${alloclist}"
done | tail -1 | while read leftovers; do
	for leftover in ${leftovers}; do
		case "${leftover}" in
			!*)
				leftover="$(echo "${leftover}" | cut -c 2-)"

				echo "Double freed or never allocated ${leftover}:"
				grep "${leftover}" "${LEAKCHECKFILE}" | sed 's@^@    @'
				echo ''
				;;
			*)
				echo "Unfreed memory ${leftover}:"
				grep "${leftover}" "${LEAKCHECKFILE}" | sed 's@^@    @'
				echo ''
				;;
		esac
	done
done

rm -f "${TMPFILE}"
