Compare commits

...

3 Commits

Author SHA1 Message Date
Dag-Erling Smørgrav cc0d61260e Remove unnecessary log messages. 2021-10-22 17:21:48 +02:00
Dag-Erling Smørgrav f1871a7d9f Add unit tests for openpam_straddch(3). 2021-10-22 17:21:48 +02:00
Dag-Erling Smørgrav eed614622f Replace the coverage script with a Makefile target. 2021-10-22 17:21:48 +02:00
10 changed files with 230 additions and 53 deletions

View File

@ -17,3 +17,32 @@ EXTRA_DIST = \
RELNOTES \
autogen.sh \
misc/gendoc.pl
if WITH_CODE_COVERAGE
covdir = @abs_top_builddir@/cov
coverage: coverage-clean all coverage-prepare coverage-run coverage-report
coverage-clean:
-rm -rf "${covdir}"
coverage-prepare:
mkdir "${covdir}"
if CLANG_CODE_COVERAGE
profdata = ${covdir}/@PACKAGE@.profdata
# hardcoding libpam.so here is horrible, need to find a better solution
coverage-run:
LLVM_PROFILE_FILE="${covdir}/@PACKAGE@.%p.raw" \
${MAKE} -C "@abs_top_builddir@" check
coverage-report:
llvm-profdata@clang_ver@ merge \
--sparse "${covdir}/@PACKAGE@".*.raw -o "${profdata}"
llvm-cov@clang_ver@ show \
--format=html --tab-size=8 \
--output-dir="${covdir}" \
--instr-profile="${profdata}" \
--object "@abs_top_builddir@/lib/libpam/.libs/libpam.so"
@echo "coverage report: file://${covdir}/index.html"
endif
else
coverage:
echo "code coverage is not enabled." >&2
false
endif

View File

@ -127,17 +127,23 @@ AC_ARG_ENABLE([werror],
AC_ARG_ENABLE([code-coverage],
AS_HELP_STRING([--enable-code-coverage],
[enable code coverage]))
AM_CONDITIONAL([CODE_COVERAGE], [test x"$enable_code_coverage" = x"yes"])
AS_IF([test x"$enable_code_coverage" = x"yes"], [
AS_IF([test x"$ax_cv_c_compiler_vendor" = x"clang"], [
CFLAGS="${CFLAGS} -fprofile-instr-generate -fcoverage-mapping"
AM_COND_IF([WITH_TEST], [
AS_IF([test x"$ax_cv_c_compiler_vendor" = x"clang"], [
CFLAGS="${CFLAGS} -fprofile-instr-generate -fcoverage-mapping"
clang_code_coverage="yes"
AC_SUBST([clang_ver], [${CC#clang}])
], [
AC_MSG_ERROR([code coverage is only supported with clang])
])
AC_DEFINE([WITH_CODE_COVERAGE], [1], [Define to 1 if code coverage is enabled])
AC_MSG_NOTICE([code coverage enabled])
], [
AC_MSG_ERROR([code coverage is only supported with clang])
AC_MSG_ERROR([code coverage requires unit tests])
])
AC_DEFINE([CODE_COVERAGE], [1], [Define to 1 if code coverage is enabled])
AC_MSG_NOTICE([code coverage enabled])
])
AC_SUBST([enable_code_coverage], [$enable_code_coverage])
AM_CONDITIONAL([WITH_CODE_COVERAGE], [test x"$enable_code_coverage" = x"yes"])
AM_CONDITIONAL([CLANG_CODE_COVERAGE], [test x"$clang_code_coverage" = x"yes"])
AC_CONFIG_FILES([
Makefile
@ -160,6 +166,5 @@ AC_CONFIG_FILES([
modules/pam_unix/Makefile
t/Makefile
])
AC_CONFIG_FILES([misc/coverage.sh],[chmod +x misc/coverage.sh])
AC_CONFIG_FILES([misc/coverity.sh],[chmod +x misc/coverity.sh])
AC_OUTPUT

View File

@ -57,7 +57,6 @@ openpam_readlinev(FILE *f, int *lineno, int *lenp)
wordvsize = MIN_WORDV_SIZE;
wordvlen = 0;
if ((wordv = malloc(wordvsize * sizeof *wordv)) == NULL) {
openpam_log(PAM_LOG_ERROR, "malloc(): %m");
errno = ENOMEM;
return (NULL);
}
@ -68,7 +67,6 @@ openpam_readlinev(FILE *f, int *lineno, int *lenp)
wordvsize *= 2;
tmp = realloc(wordv, wordvsize * sizeof *wordv);
if (tmp == NULL) {
openpam_log(PAM_LOG_ERROR, "malloc(): %m");
errno = ENOMEM;
break;
}

View File

@ -132,7 +132,6 @@ openpam_readword(FILE *f, int *lineno, size_t *lenp)
}
if (ch == EOF && (escape || quote)) {
/* Missing escaped character or closing quote. */
openpam_log(PAM_LOG_DEBUG, "unexpected end of file");
free(word);
errno = EINVAL;
return (NULL);

View File

@ -56,7 +56,6 @@ openpam_straddch(char **str, size_t *size, size_t *len, int ch)
/* initial allocation */
tmpsize = MIN_STR_SIZE;
if ((tmpstr = malloc(tmpsize)) == NULL) {
openpam_log(PAM_LOG_ERROR, "malloc(): %m");
errno = ENOMEM;
return (-1);
}
@ -67,7 +66,6 @@ openpam_straddch(char **str, size_t *size, size_t *len, int ch)
/* additional space required */
tmpsize = *size * 2;
if ((tmpstr = realloc(*str, tmpsize)) == NULL) {
openpam_log(PAM_LOG_ERROR, "realloc(): %m");
errno = ENOMEM;
return (-1);
}

View File

@ -1 +1 @@
noinst_SCRIPTS = coverage.sh coverity.sh
noinst_SCRIPTS = coverity.sh

View File

@ -1,34 +0,0 @@
#!/bin/sh
usage() {
echo "usage: ${0##*/} [-jN]" >&2
exit 1
}
while getopts "j:" opt ; do
case $opt in
j)
j="-j$OPTARG"
;;
*)
usage
;;
esac
done
if ! [ "@enable_code_coverage@" = "yes" ] ; then
echo "Code coverage disabled." >&2
echo "Re-run ./configure with --enable-code-coverage and try again." >&2
exit 1
fi
srcdir="@abs_top_srcdir@"
profdir="@abs_top_builddir@/cov"
profraw="${profdir}/@PACKAGE@.%p.raw"
profdata="${profdir}/@PACKAGE@.profdata"
export LLVM_PROFILE_FILE="${profraw}"
[ -e "${profdir}" ] && rm -r "${profdir}"
gmake -C "${srcdir}" $j check
llvm-profdata merge -sparse "${profdir}/@PACKAGE@".*.raw -o "${profdata}"
llvm-cov show -instr-profile="${profdata}" -format=html -output-dir="${profdir}" \
--object "@abs_top_builddir@/lib/libpam/.libs/libpam.so"

7
t/.gitignore vendored
View File

@ -1,10 +1,7 @@
/t_*.trs
/t_openpam_ctype
/t_openpam_ctype.trs
/t_openpam_dispatch
/t_openpam_dispatch.trs
/t_openpam_readlinev
/t_openpam_readlinev.trs
/t_openpam_readword
/t_openpam_readword.trs
/t_openpam_straddch
/t_pam_env
/t_pam_env.trs

View File

@ -12,6 +12,7 @@ TESTS += t_openpam_ctype
TESTS += t_openpam_dispatch
TESTS += t_openpam_readword
TESTS += t_openpam_readlinev
TESTS += t_openpam_straddch
TESTS += t_pam_env
check_PROGRAMS = $(TESTS)

184
t/t_openpam_straddch.c Normal file
View File

@ -0,0 +1,184 @@
/*-
* Copyright (c) 2021 Dag-Erling Smørgrav
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <sys/types.h>
#include <errno.h>
#include <stdint.h>
#include <stdlib.h>
#include <cryb/test.h>
#include <security/pam_appl.h>
#include "openpam_impl.h"
static int
t_straddch_empty(char **desc CRYB_UNUSED, void *arg CRYB_UNUSED)
{
char *str;
size_t size, len;
int ret;
str = NULL;
size = len = SIZE_MAX;
ret = t_is_zero_i(openpam_straddch(&str, &size, &len, '\0'));
ret &= t_is_not_null(str);
ret &= t_is_not_zero_sz(size);
ret &= t_is_zero_sz(len);
free(str);
return ret;
}
static int
t_straddch_alloc_fail(char **desc CRYB_UNUSED, void *arg CRYB_UNUSED)
{
char *str;
size_t size, len;
int ret;
str = NULL;
size = len = SIZE_MAX;
errno = 0;
t_malloc_fail = 1;
ret = t_compare_i(-1, openpam_straddch(&str, &size, &len, '\0'));
t_malloc_fail = 0;
ret &= t_compare_i(ENOMEM, errno);
ret &= t_is_null(str);
ret &= t_compare_sz(SIZE_MAX, size);
ret &= t_compare_sz(SIZE_MAX, len);
free(str);
return ret;
}
static int
t_straddch_realloc_fail(char **desc CRYB_UNUSED, void *arg CRYB_UNUSED)
{
char *str, *_str;
size_t size, _size, len, _len;
int i, ret;
// start with an empty string
str = NULL;
size = len = SIZE_MAX;
ret = t_is_zero_i(openpam_straddch(&str, &size, &len, '\0'));
ret &= t_is_not_null(str);
ret &= t_is_not_zero_sz(size);
ret &= t_is_zero_sz(len);
if (!ret)
goto end;
// repeatedly append to it until allocation fails
errno = 0;
_str = str;
_size = size;
_len = len;
t_malloc_fail = 1;
for (i = 0; i < 4096; i++) {
if ((ret = openpam_straddch(&str, &size, &len, 'x')) != 0)
break;
_size = size;
_len = len;
}
t_malloc_fail = 0;
ret = t_compare_i(-1, ret);
ret &= t_compare_i(ENOMEM, errno);
ret &= t_compare_ptr(_str, str);
ret &= t_compare_sz(_size, size);
ret &= t_compare_sz(_len, len);
end:
free(str);
return ret;
}
static int
t_straddch_realloc_ok(char **desc CRYB_UNUSED, void *arg CRYB_UNUSED)
{
char *str, *_str;
size_t size, _size, len, _len;
int i, ret;
// start with an empty string
str = NULL;
size = len = SIZE_MAX;
ret = t_is_zero_i(openpam_straddch(&str, &size, &len, '\0'));
ret &= t_is_not_null(str);
ret &= t_is_not_zero_sz(size);
ret &= t_is_zero_sz(len);
if (!ret)
goto end;
// repeatedly append to it until size changes
_str = str;
_size = size;
_len = len;
for (i = ' '; i <= '~'; i++) { // assume ascii
if ((ret = openpam_straddch(&str, &size, &len, i)) != 0)
break;
if (size != _size)
break;
if (len != _len + 1)
break;
_len = len;
}
ret = t_is_zero_i(ret);
if (!ret)
goto end;
ret &= t_compare_sz(_len + 1, len);
ret &= t_compare_sz(_size * 2, size);
ret &= t_compare_i(i, str[_len]);
ret &= t_is_zero_i(str[len]);
end:
free(str);
return ret;
}
/***************************************************************************
* Boilerplate
*/
static int
t_prepare(int argc CRYB_UNUSED, char *argv[] CRYB_UNUSED)
{
t_add_test(t_straddch_empty, NULL, "empty string");
t_add_test(t_straddch_alloc_fail, NULL, "allocation failure");
t_add_test(t_straddch_realloc_fail, NULL, "reallocation failure");
t_add_test(t_straddch_realloc_ok, NULL, "reallocation success");
return (0);
}
int
main(int argc, char *argv[])
{
t_main(t_prepare, NULL, argc, argv);
}