]> eyrie.org Git - kerberos/krb5-strength.git/commitdiff
Update to rra-c-util 5.7 and C TAP Harness 4.1
authorRuss Allbery <eagle@eyrie.org>
Mon, 7 Nov 2016 02:27:57 +0000 (18:27 -0800)
committerRuss Allbery <eagle@eyrie.org>
Mon, 7 Nov 2016 02:27:57 +0000 (18:27 -0800)
Update to rra-c-util 6.2:

* Use calloc in preference to malloc wherever appropriate.
* Use reallocarray in preference to realloc wherever appropriate.
* Suppress warnings from Kerberos headers under make warnings.
* Support the embedded Kerberos in Solaris 10 in library probes.
* Add missing va_end in xasprintf implementation.
* Fix logic in Test::RRA::Automake for new Automake dist checking.
* Fix all return-value checks for snprintf to avoid off-by-one error.
* Update warning flags for make warnings to GCC 6.1.0.
* Fix Test::RRA::Config for new "do" semantics in Perl 5.22.2.
* Add a new test for obsolete eyrie.org URLs.
* Require Test::Strict 0.25 or newer for Perl strictness checks.

Update to C TAP Harness 4.1:

* Replace all remaining uses of sprintf.
* Test lists may now have comments and blank lines.
* runtests -v will show the complete output from a test.
* Fix segfault in runtests when given an empty test list.
* Tests use C_TAP_SOURCE and C_TAP_BUILD instead of SOURCE and BUILD.

79 files changed:
.gitignore
Makefile.am
NEWS
README
configure.ac
cracklib/HISTORY
cracklib/fascist.c
cracklib/packlib.c
cracklib/rules.c
cracklib/stringlib.c
m4/cc-flags.m4 [new file with mode: 0644]
m4/clang.m4 [new file with mode: 0644]
m4/krb5-config.m4
m4/krb5.m4
m4/lib-depends.m4
m4/lib-helper.m4
m4/lib-pathname.m4
m4/snprintf.m4
m4/sqlite.m4
m4/tinycdb.m4
m4/vamacros.m4
plugin/error.c
plugin/sqlite.c
portable/asprintf.c
portable/dummy.c
portable/kadmin.h
portable/krb5-extra.c
portable/krb5.h
portable/macros.h
portable/mkstemp.c
portable/reallocarray.c [new file with mode: 0644]
portable/snprintf.c
portable/stdbool.h
portable/strndup.c
portable/system.h
tests/README [moved from tests/HOWTO with 90% similarity]
tests/TESTS
tests/data/perlcriticrc
tests/data/perltidyrc
tests/data/valgrind.supp
tests/docs/pod-spelling-t
tests/docs/pod-t
tests/docs/urls-t [new file with mode: 0755]
tests/perl/critic-t
tests/perl/minimum-version-t
tests/perl/strict-t
tests/portable/asprintf-t.c
tests/portable/mkstemp-t.c
tests/portable/reallocarray-t.c [new file with mode: 0644]
tests/portable/reallocarray.c [new file with mode: 0644]
tests/portable/snprintf-t.c
tests/portable/strndup-t.c
tests/runtests.c
tests/tap/basic.c
tests/tap/basic.h
tests/tap/kerberos.c
tests/tap/kerberos.h
tests/tap/libtap.sh
tests/tap/macros.h
tests/tap/perl/Test/RRA.pm
tests/tap/perl/Test/RRA/Automake.pm
tests/tap/perl/Test/RRA/Config.pm
tests/tap/process.c
tests/tap/process.h
tests/tap/string.c
tests/tap/string.h
tests/util/messages-krb5-t.c
tests/util/messages-t.c
tests/util/xmalloc-t
tests/util/xmalloc.c
tools/heimdal-strength.pod
tools/krb5-strength-wordlist
util/macros.h
util/messages-krb5.c
util/messages-krb5.h
util/messages.c
util/messages.h
util/xmalloc.c
util/xmalloc.h

index d723ddf3986358fad715f11235c1fde07753964e..cfbaa38780a87828d2e45f4c1353ebd4f8ea7299 100644 (file)
@@ -26,6 +26,7 @@
 /tests/plugin/mit-t
 /tests/portable/asprintf-t
 /tests/portable/mkstemp-t
+/tests/portable/reallocarray-t
 /tests/portable/snprintf-t
 /tests/portable/strndup-t
 /tests/runtests
index 7d8c5c9301d23fe4201f9c7e2e7a250661b1993a..51006993efe64470546ac8d7378dd076ebe95a8e 100644 (file)
@@ -1,25 +1,26 @@
 # Automake makefile for krb5-strength.
 #
 # Written by Russ Allbery <eagle@eyrie.org>
+# Copyright 2016 Russ Allbery <eagle@eyrie.org>
 # Copyright 2007, 2009, 2010, 2012, 2013, 2014
 #     The Board of Trustees of the Leland Stanford Junior University
 #
 # See LICENSE for licensing terms.
 
 ACLOCAL_AMFLAGS = -I m4
-EXTRA_DIST = .gitignore LICENSE autogen cracklib/HISTORY cracklib/LICENCE  \
-       cracklib/README cracklib/genrules.pl cracklib/mkdict tests/HOWTO   \
-       tests/TESTS tests/data/krb5.conf tests/data/make-krb5-conf         \
-       tests/data/passwords tests/data/perl.conf tests/data/perlcriticrc  \
-       tests/data/perltidyrc tests/data/valgrind.supp tests/data/wordlist \
-       tests/data/wordlist.cdb tests/data/wordlist.sqlite                 \
-       tests/docs/pod-spelling-t tests/docs/pod-t tests/perl/critic-t     \
-       tests/perl/minimum-version-t tests/perl/strict-t                   \
-       tests/tap/libtap.sh tests/tap/perl/Test/RRA.pm                     \
-       tests/tap/perl/Test/RRA/Config.pm                                  \
-       tests/tap/perl/Test/RRA/Automake.pm tests/tools/heimdal-history-t  \
-       tests/tools/heimdal-strength-t tests/tools/wordlist-cdb-t          \
-       tests/tools/wordlist-sqlite-t tests/tools/wordlist-t               \
+EXTRA_DIST = .gitignore LICENSE bootstrap cracklib/HISTORY cracklib/LICENCE \
+       cracklib/README cracklib/genrules.pl cracklib/mkdict tests/HOWTO    \
+       tests/TESTS tests/data/krb5.conf tests/data/make-krb5-conf          \
+       tests/data/passwords tests/data/perl.conf tests/data/perlcriticrc   \
+       tests/data/perltidyrc tests/data/valgrind.supp tests/data/wordlist  \
+       tests/data/wordlist.cdb tests/data/wordlist.sqlite                  \
+       tests/docs/pod-spelling-t tests/docs/pod-t tests/perl/critic-t      \
+       tests/perl/minimum-version-t tests/perl/strict-t                    \
+       tests/tap/libtap.sh tests/tap/perl/Test/RRA.pm                      \
+       tests/tap/perl/Test/RRA/Config.pm                                   \
+       tests/tap/perl/Test/RRA/Automake.pm tests/tools/heimdal-history-t   \
+       tests/tools/heimdal-strength-t tests/tools/wordlist-cdb-t           \
+       tests/tools/wordlist-sqlite-t tests/tools/wordlist-t                \
        tests/util/xmalloc-t tools/heimdal-strength.pod
 
 # Do this globally.  Everything needs to find the Kerberos headers and
@@ -114,37 +115,23 @@ MAINTAINERCLEANFILES = Makefile.in aclocal.m4 build-aux/compile            \
 maintainer-clean-local:
        rm -f tests/data/passwords/*.c
 
-# A set of flags for warnings.  Add -O because gcc won't find some warnings
-# without optimization turned on.  Desirable warnings that can't be turned
-# on due to other problems:
-#
-#     -Wconversion      http://bugs.debian.org/488884 (htons warnings)
-#
-# Last checked against gcc 4.7.2 (2013-04-22).  -D_FORTIFY_SOURCE=2 enables
-# warn_unused_result attribute markings on glibc functions on Linux, which
-# catches a few more issues.
-WARNINGS = -g -O -D_FORTIFY_SOURCE=2 -Wall -Wextra -Wendif-labels         \
-       -Wformat=2 -Winit-self -Wswitch-enum -Wuninitialized -Wfloat-equal \
-       -Wdeclaration-after-statement -Wshadow -Wpointer-arith             \
-       -Wbad-function-cast -Wcast-align -Wwrite-strings                   \
-       -Wjump-misses-init -Wlogical-op -Wstrict-prototypes                \
-       -Wold-style-definition -Wmissing-prototypes -Wnormalized=nfc       \
-       -Wpacked -Wredundant-decls -Wnested-externs -Winline -Wvla -Werror
-
 warnings:
-       $(MAKE) V=0 CFLAGS='$(WARNINGS)'
-       $(MAKE) V=0 CFLAGS='$(WARNINGS)' $(check_PROGRAMS)
+       $(MAKE) V=0 CFLAGS='$(WARNINGS_CFLAGS) $(AM_CFLAGS)' \
+           KRB5_CPPFLAGS='$(KRB5_CPPFLAGS_GCC)'
+       $(MAKE) V=0 CFLAGS='$(WARNINGS_CFLAGS) $(AM_CFLAGS)' \
+           KRB5_CPPFLAGS='$(KRB5_CPPFLAGS_GCC)' $(check_PROGRAMS)
 
 # The bits below are for the test suite, not for the main package.
-check_PROGRAMS = tests/runtests tests/plugin/heimdal-t tests/plugin/mit-t   \
-       tests/portable/asprintf-t tests/portable/mkstemp-t                  \
-       tests/portable/snprintf-t tests/portable/strndup-t                  \
-       tests/util/messages-krb5-t tests/util/messages-t tests/util/xmalloc
+check_PROGRAMS = tests/runtests tests/plugin/heimdal-t tests/plugin/mit-t \
+       tests/portable/asprintf-t tests/portable/mkstemp-t                \
+       tests/portable/reallocarray-t tests/portable/snprintf-t           \
+       tests/portable/strndup-t tests/util/messages-krb5-t               \
+       tests/util/messages-t tests/util/xmalloc
 if EMBEDDED_CRACKLIB
     check_PROGRAMS += cracklib/packer
 endif
-tests_runtests_CPPFLAGS = -DSOURCE='"$(abs_top_srcdir)/tests"' \
-       -DBUILD='"$(abs_top_builddir)/tests"'
+tests_runtests_CPPFLAGS = -DC_TAP_SOURCE='"$(abs_top_srcdir)/tests"' \
+       -DC_TAP_BUILD='"$(abs_top_builddir)/tests"'
 check_LIBRARIES = tests/tap/libtap.a
 tests_tap_libtap_a_CPPFLAGS = -I$(abs_top_srcdir)/tests $(KRB5_CPPFLAGS)
 tests_tap_libtap_a_SOURCES = tests/tap/basic.c tests/tap/basic.h       \
@@ -165,6 +152,10 @@ tests_portable_asprintf_t_LDADD = tests/tap/libtap.a portable/libportable.la
 tests_portable_mkstemp_t_SOURCES = tests/portable/mkstemp-t.c \
        tests/portable/mkstemp.c
 tests_portable_mkstemp_t_LDADD = tests/tap/libtap.a portable/libportable.la
+tests_portable_reallocarray_t_SOURCES = tests/portable/reallocarray-t.c \
+       tests/portable/reallocarray.c
+tests_portable_reallocarray_t_LDADD = tests/tap/libtap.a \
+       portable/libportable.la
 tests_portable_snprintf_t_SOURCES = tests/portable/snprintf-t.c \
        tests/portable/snprintf.c
 tests_portable_snprintf_t_LDADD = tests/tap/libtap.a portable/libportable.la
diff --git a/NEWS b/NEWS
index e9242ccb82e59071f92030f86576dee0e35efa67..fca40de7aa01efb189dca2d3ccadf9b240909665 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -26,6 +26,28 @@ krb5-strength 3.1 (unreleased)
     doesn't apply since all the GECOS manipulation code was removed from
     the embedded CrackLib in this package.)
 
+    Update to rra-c-util 6.2:
+
+    * Use calloc in preference to malloc wherever appropriate.
+    * Use reallocarray in preference to realloc wherever appropriate.
+    * Suppress warnings from Kerberos headers under make warnings.
+    * Support the embedded Kerberos in Solaris 10 in library probes.
+    * Add missing va_end in xasprintf implementation.
+    * Fix logic in Test::RRA::Automake for new Automake dist checking.
+    * Fix all return-value checks for snprintf to avoid off-by-one error.
+    * Update warning flags for make warnings to GCC 6.1.0.
+    * Fix Test::RRA::Config for new "do" semantics in Perl 5.22.2.
+    * Add a new test for obsolete eyrie.org URLs.
+    * Require Test::Strict 0.25 or newer for Perl strictness checks.
+
+    Update to C TAP Harness 4.1:
+
+    * Replace all remaining uses of sprintf.
+    * Test lists may now have comments and blank lines.
+    * runtests -v will show the complete output from a test.
+    * Fix segfault in runtests when given an empty test list.
+    * Tests use C_TAP_SOURCE and C_TAP_BUILD instead of SOURCE and BUILD.
+
 krb5-strength 3.0 (2014-03-25)
 
     The krb5-strength plugin and heimdal-strength program now support a
diff --git a/README b/README
index 508d21cd257b3bd59133e5ede7e62bbfe6a4b0ed..756ffcc195182adfca92f9b6164362e76307a80e 100644 (file)
--- a/README
+++ b/README
@@ -505,7 +505,7 @@ SUPPORT
 
   The krb5-strength web page at:
 
-      http://www.eyrie.org/~eagle/software/krb5-strength/
+      https://www.eyrie.org/~eagle/software/krb5-strength/
 
   will always have the current version of this package, the current
   documentation, and pointers to any additional resources.
@@ -524,7 +524,7 @@ SOURCE REPOSITORY
 
   or view the repository via the web at:
 
-      http://git.eyrie.org/?p=kerberos/krb5-strength.git
+      https://git.eyrie.org/?p=kerberos/krb5-strength.git
 
   When contributing modifications, either patches (possibly generated by
   git format-patch) or Git pull requests are welcome.
index 1e0760c5de6ab05cca360b88ac627d9492500891..9e2aa18e30fbf448637ac9d22446c7090edd8447 100644 (file)
@@ -1,6 +1,7 @@
 dnl Process this file with autoconf to produce a configure script.
 dnl
 dnl Written by Russ Allbery <eagle@eyrie.org>
+dnl Copyright 2016 Russ Allbery <eagle@eyrie.org>
 dnl Copyright 2006, 2007, 2009, 2010, 2012, 2013, 2014
 dnl     The Board of Trustees of the Leland Stanford Junior University
 dnl
@@ -16,13 +17,18 @@ AM_INIT_AUTOMAKE([1.11 check-news dist-xz foreign silent-rules subdir-objects
     -Wall -Werror])
 AM_MAINTAINER_MODE
 
+dnl Detect unexpanded macros.
+m4_pattern_forbid([^PKG_])
+m4_pattern_forbid([^_?RRA_])
+
 dnl Probe for basic build system tools.
 AC_PROG_CC
 AC_USE_SYSTEM_EXTENSIONS
+RRA_PROG_CC_WARNINGS_FLAGS
 AC_SYS_LARGEFILE
 AM_PROG_CC_C_O
-AC_PROG_INSTALL
 m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
+AC_PROG_INSTALL
 AM_DISABLE_STATIC
 LT_INIT
 
@@ -35,8 +41,6 @@ AS_IF([test x"$rra_system_cracklib" = xyes],
      RRA_LIB_CRACKLIB_RESTORE])
 RRA_LIB_KRB5
 RRA_LIB_KRB5_SWITCH
-AC_CHECK_HEADERS([kadm5/kadm5-pwcheck.h kadm5/kadm5_err.h], [], [],
-    [RRA_INCLUDES_KRB5])
 AC_CHECK_HEADERS([krb5/pwqual_plugin.h], [], [], [RRA_INCLUDES_KRB5])
 AC_CHECK_TYPES([krb5_realm], [], [], [RRA_INCLUDES_KRB5])
 AC_CHECK_FUNCS([krb5_free_default_realm \
@@ -49,6 +53,8 @@ AC_CHECK_FUNCS([krb5_get_init_creds_opt_free],
     [RRA_FUNC_KRB5_GET_INIT_CREDS_OPT_FREE_ARGS])
 AC_CHECK_DECLS([krb5_kt_free_entry], [], [], [RRA_INCLUDES_KRB5])
 AC_LIBOBJ([krb5-extra])
+AC_CHECK_HEADERS([kadm5/kadm5-pwcheck.h kadm5/kadm5_err.h], [], [],
+    [RRA_INCLUDES_KRB5])
 RRA_LIB_KRB5_RESTORE
 RRA_LIB_SQLITE_OPTIONAL
 
@@ -60,7 +66,7 @@ AC_SUBST([DL_LIBS])
 
 dnl Checks for basic C functionality.
 AC_HEADER_STDBOOL
-AC_CHECK_HEADERS([sys/bittypes.h sys/select.h syslog.h])
+AC_CHECK_HEADERS([sys/bittypes.h sys/select.h sys/time.h syslog.h])
 AC_CHECK_DECLS([snprintf, vsnprintf])
 RRA_C_C99_VAMACROS
 RRA_C_GNU_VAMACROS
@@ -72,7 +78,7 @@ AC_CHECK_TYPES([ssize_t], [], [],
     [#include <sys/types.h>])
 RRA_FUNC_SNPRINTF
 AC_CHECK_FUNCS([setrlimit])
-AC_REPLACE_FUNCS([asprintf mkstemp strndup])
+AC_REPLACE_FUNCS([asprintf mkstemp reallocarray strndup])
 
 dnl Write out the results.
 AC_CONFIG_FILES([Makefile])
index b82f94096169d8d6e4049b58f099c2bbcdab32f7..3a9621914f64873a10c5ab888058ce92df8537ab 100644 (file)
@@ -22,6 +22,7 @@ following modifications have been made:
  * Set hidden visibility on all CrackLib symbols.
  * Close the wfp file handle on PWClose if it's open.
  * Applied various patches from distributions for security vulnerabilities.
+ * Changed the type of some variables to size_t to avoid truncation.
 
 See the leading comments in each source file for a more detailed timeline
 and list of changes.
index cde8eb29cec167917ffb974e61d0054b282fdf18..c5f3a655827ede8aab9755a0eb155aecff6d74b2 100644 (file)
  *   - Replaced MAXSTEP with allowing one increment per four characters.
  *   - Changed error for very short passwords to match current CrackLib.
  *   - Close the dictionary after each password lookup.
+ * 2016-11-06  Russ Allbery <eagle@eyrie.org>
+ *   - Remove unused vers_id to silence GCC warnings
+ *   - Changed some variables from int or unsigned int to size_t
  */
 
-static const char vers_id[] = "fascist.c : v2.3p3 Alec Muffett 14 dec 1997";
-
 #include "packer.h"
 #include <sys/types.h>
 #include <pwd.h>
@@ -435,8 +436,8 @@ static const char *r_destructors[] = {
 static const char *
 FascistLook(PWDICT *pwp, const char *instring)
 {
-    int i, pw_len;
-    unsigned int mindiff;
+    int i;
+    size_t pw_len, mindiff;
     char *ptr;
     char *jptr;
     char junk[STRINGSIZE];
index 74e75fd3f0a944780062e7ba57351c076349a587..94964de02461b0b002ca7629630e10d1774c0c5e 100644 (file)
@@ -26,6 +26,8 @@
  *   - Remove last block optimization in GetPW and start fresh each time.
  * 2013-12-13  Russ Allbery <eagle@eyrie.org>
  *   - Close the wfp file handle on PWClose if it's open.
+ * 2016-11-06  Russ Allbery <eagle@eyrie.org>
+ *   - Remove unused vers_id to silence GCC warnings.
  */
 
 #include <stdio.h>
@@ -33,8 +35,6 @@
 
 #include "packer.h"
 
-static const char vers_id[] = "packlib.c : v2.3p2 Alec Muffett 18 May 1993";
-
 PWDICT *
 PWOpen(const char *prefix, const char *mode)
 {
index a3e439bcf1453f2ffa994bf170b4b3455e514981..8f958458b9671d54f2063ca5595c0743bccb3410 100644 (file)
  *   - Make internal functions static.
  *   - Remove unused variables.
  *   - Changed a variable to unsigned to avoid gcc warnings.
+ * 2016-11-06  Russ Allbery <eagle@eyrie.org>
+ *   - Remove unused vers_id to silence GCC warnings.
+ *   - Added GCC __attribute__ marker on Debug() function.
  */
 
-static const char vers_id[] = "rules.c : v5.0p3 Alec Muffett 20 May 1993";
-
 #include <stdarg.h>
 
 #ifndef IN_CRACKLIB
@@ -39,7 +40,7 @@ static const char vers_id[] = "rules.c : v5.0p3 Alec Muffett 20 May 1993";
 
 #include "packer.h"
 
-static void
+static void __attribute__((__format__(printf, 2, 3)))
 Debug(int val, const char *fmt, ...)
 {
     if (val < 2) {
index 3a38164537dce1fe31e198c2cea465d219a7179e..efd795bff788bc149c5242299745558bc1a2c699 100644 (file)
@@ -14,6 +14,8 @@
  * 2009-10-14  Russ Allbery <eagle@eyrie.org>
  *   - Add ANSI C protototypes for all functions.
  *   - Remove unused Clone function.
+ * 2016-11-06  Russ Allbery <eagle@eyrie.org>
+ *   - Remove unused vers_id to silence GCC warnings.
  */
 
 #include <string.h>
@@ -21,8 +23,6 @@
 
 #include "packer.h"
 
-static const char vers_id[] = "stringlib.c : v2.3p2 Alec Muffett 18 May 1993";
-
 char
 Chop(char *string)
 {
diff --git a/m4/cc-flags.m4 b/m4/cc-flags.m4
new file mode 100644 (file)
index 0000000..9bbdccb
--- /dev/null
@@ -0,0 +1,94 @@
+dnl Check whether the compiler supports particular flags.
+dnl
+dnl Provides RRA_PROG_CC_FLAG, which checks whether a compiler supports a
+dnl given flag.  If it does, the commands in the second argument are run.  If
+dnl not, the commands in the third argument are run.
+dnl
+dnl Provides RRA_PROG_CC_WARNINGS_FLAGS, which checks whether a compiler
+dnl supports a large set of warning flags and sets the WARNINGS_CFLAGS
+dnl substitution variable to all of the supported warning flags.  (Note that
+dnl this may be too aggressive for some people.)
+dnl
+dnl Depends on RRA_PROG_CC_CLANG.
+dnl
+dnl The canonical version of this file is maintained in the rra-c-util
+dnl package, available at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
+dnl
+dnl Copyright 2016 Russ Allbery <eagle@eyrie.org>
+dnl Copyright 2006, 2009, 2016
+dnl     by Internet Systems Consortium, Inc. ("ISC")
+dnl
+dnl Permission to use, copy, modify, and distribute this software for any
+dnl purpose with or without fee is hereby granted, provided that the above
+dnl copyright notice and this permission notice appear in all copies.
+dnl
+dnl THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+dnl REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+dnl MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY
+dnl SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+dnl WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+dnl ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+dnl IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+dnl Used to build the result cache name.
+AC_DEFUN([_RRA_PROG_CC_FLAG_CACHE],
+[translit([rra_cv_compiler_c_$1], [-=], [__])])
+
+dnl Check whether a given flag is supported by the complier.
+AC_DEFUN([RRA_PROG_CC_FLAG],
+[AC_REQUIRE([AC_PROG_CC])
+ AC_MSG_CHECKING([if $CC supports $1])
+ AC_CACHE_VAL([_RRA_PROG_CC_FLAG_CACHE([$1])],
+    [save_CFLAGS=$CFLAGS
+     AS_CASE([$1],
+        [-Wno-*], [CFLAGS="$CFLAGS `echo "$1" | sed 's/-Wno-/-W/'`"],
+        [*],      [CFLAGS="$CFLAGS $1"])
+     AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [int foo = 0;])],
+        [_RRA_PROG_CC_FLAG_CACHE([$1])=yes],
+        [_RRA_PROG_CC_FLAG_CACHE([$1])=no])
+     CFLAGS=$save_CFLAGS])
+ AC_MSG_RESULT([$_RRA_PROG_CC_FLAG_CACHE([$1])])
+ AS_IF([test x"$_RRA_PROG_CC_FLAG_CACHE([$1])" = xyes], [$2], [$3])])
+
+dnl Determine the full set of viable warning flags for the current compiler.
+dnl
+dnl This is based partly on personal preference and is a fairly aggressive set
+dnl of warnings.  Desirable warnings that can't be turned on due to other
+dnl problems:
+dnl
+dnl   -Wconversion       http://bugs.debian.org/488884 (htons warnings)
+dnl   -Wsign-conversion  Too much noise from ssize_t and flag variables
+dnl   -Wstack-protector  Too many false positives from small buffers
+dnl
+dnl Last checked against gcc 6.1.0 (2016-09-25).  -D_FORTIFY_SOURCE=2 enables
+dnl warn_unused_result attribute markings on glibc functions on Linux, which
+dnl catches a few more issues.  Add -O2 because gcc won't find some warnings
+dnl without optimization turned on.
+dnl
+dnl The warnings here are listed in the same order they're listed in the
+dnl "Preprocessor Options" and "Warning Options" chapters of the GCC manual.
+dnl
+dnl Sets WARNINGS_CFLAGS as a substitution variable.
+AC_DEFUN([RRA_PROG_CC_WARNINGS_FLAGS],
+[AC_REQUIRE([RRA_PROG_CC_CLANG])
+ AS_IF([test x"$CLANG" = xyes],
+    [WARNINGS_CFLAGS="-Werror"
+     m4_foreach_w([flag],
+        [-Weverything -Wno-padded],
+        [RRA_PROG_CC_FLAG(flag,
+            [WARNINGS_CFLAGS="${WARNINGS_CFLAGS} flag"])])],
+    [WARNINGS_CFLAGS="-g -O2 -D_FORTIFY_SOURCE=2 -Werror"
+     m4_foreach_w([flag],
+        [-fstrict-overflow -fstrict-aliasing -Wcomments -Wendif-labels -Wall
+         -Wextra -Wformat=2 -Wformat-signedness -Wnull-dereference -Winit-self
+         -Wswitch-enum -Wuninitialized -Wstrict-overflow=5
+         -Wmissing-format-attribute -Wduplicated-cond -Wtrampolines
+         -Wfloat-equal -Wdeclaration-after-statement -Wshadow -Wpointer-arith
+         -Wbad-function-cast -Wcast-align -Wwrite-strings -Wdate-time
+         -Wjump-misses-init -Wfloat-conversion -Wlogical-op
+         -Wstrict-prototypes -Wold-style-definition -Wmissing-prototypes
+         -Wnormalized=nfc -Wpacked -Wredundant-decls -Wnested-externs -Winline
+         -Wvla],
+        [RRA_PROG_CC_FLAG(flag,
+            [WARNINGS_CFLAGS="${WARNINGS_CFLAGS} flag"])])])
+ AC_SUBST([WARNINGS_CFLAGS])])
diff --git a/m4/clang.m4 b/m4/clang.m4
new file mode 100644 (file)
index 0000000..b9ceefe
--- /dev/null
@@ -0,0 +1,26 @@
+dnl Determine whether the current compiler is Clang.
+dnl
+dnl If the current compiler is Clang, set the shell variable CLANG to yes.
+dnl
+dnl The canonical version of this file is maintained in the rra-c-util
+dnl package, available at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
+dnl
+dnl Copyright 2015 Russ Allbery <eagle@eyrie.org>
+dnl
+dnl This file is free software; the authors give unlimited permission to copy
+dnl and/or distribute it, with or without modifications, as long as this
+dnl notice is preserved.
+
+dnl Source used by RRA_PROG_CC_CLANG.
+AC_DEFUN([_RRA_PROG_CC_CLANG_SOURCE], [[
+#if ! __clang__
+#error
+#endif
+]])
+
+AC_DEFUN([RRA_PROG_CC_CLANG],
+[AC_CACHE_CHECK([if the compiler is Clang], [rra_cv_prog_cc_clang],
+    [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_RRA_PROG_CC_CLANG_SOURCE])],
+        [rra_cv_prog_cc_clang=yes],
+        [rra_cv_prog_cc_clang=no])])
+ AS_IF([test x"$rra_cv_prog_cc_clang" = xyes], [CLANG=yes])])
index c69c4f337fdff2971a02ec5274d5245c239334a0..738b30b826eceffcb76e139e914c5451786d722a 100644 (file)
@@ -8,7 +8,7 @@ dnl
 dnl Depends on RRA_ENABLE_REDUCED_DEPENDS.
 dnl
 dnl The canonical version of this file is maintained in the rra-c-util
-dnl package, available at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+dnl package, available at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
 dnl
 dnl Written by Russ Allbery <eagle@eyrie.org>
 dnl Copyright 2011, 2012
index 950524f4069f28c62c51ecaaae8e68966f93a7bb..236f0b09261c716e49f5fb04b0957cfcacb00bc9 100644 (file)
@@ -17,6 +17,12 @@ dnl
 dnl If KRB5_CPPFLAGS, KRB5_LDFLAGS, or KRB5_LIBS are set before calling these
 dnl macros, their values will be added to whatever the macros discover.
 dnl
+dnl KRB5_CPPFLAGS_GCC will be set to the same value as KRB5_CPPFLAGS but with
+dnl any occurrences of -I changed to -isystem.  This may be useful to suppress
+dnl warnings from the Kerberos header files when building with GCC and
+dnl aggressive warning flags.  Be aware that this change will change the
+dnl compiler header file search order as well.
+dnl
 dnl Provides the RRA_LIB_KRB5_OPTIONAL macro, which should be used if Kerberos
 dnl support is optional.  In this case, Kerberos libraries are mandatory if
 dnl --with-krb5 is given, and will not be probed for if --without-krb5 is
@@ -41,10 +47,10 @@ dnl Also provides RRA_INCLUDES_KRB5, which are the headers to include when
 dnl probing the Kerberos library properties.
 dnl
 dnl The canonical version of this file is maintained in the rra-c-util
-dnl package, available at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+dnl package, available at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
 dnl
 dnl Written by Russ Allbery <eagle@eyrie.org>
-dnl Copyright 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2013
+dnl Copyright 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2013, 2014
 dnl     The Board of Trustees of the Leland Stanford Junior University
 dnl
 dnl This file is free software; the authors give unlimited permission to copy
@@ -58,6 +64,8 @@ dnl Headers to include when probing for Kerberos library properties.
 AC_DEFUN([RRA_INCLUDES_KRB5], [[
 #if HAVE_KRB5_H
 # include <krb5.h>
+#elif HAVE_KERBEROSV5_KRB5_H
+# include <kerberosv5/krb5.h>
 #else
 # include <krb5/krb5.h>
 #endif
@@ -107,6 +115,23 @@ AC_DEFUN([_RRA_LIB_KRB5_CHECK_HEADER],
      AC_MSG_RESULT([yes])],
     [AC_MSG_RESULT([no])])])
 
+dnl Check for the com_err header.  Internal helper macro since we need
+dnl to do the same checks in multiple places.
+AC_DEFUN([_RRA_LIB_KRB5_CHECK_HEADER_COM_ERR],
+[AS_IF([test x"$rra_krb5_incroot" = x],
+    [AC_CHECK_HEADERS([et/com_err.h kerberosv5/com_err.h])],
+        [_RRA_LIB_KRB5_CHECK_HEADER([et/com_err.h])
+         _RRA_LIB_KRB5_CHECK_HEADER([kerberosv5/com_err.h])])])
+
+dnl Check for the main Kerberos header.  Internal helper macro since we need
+dnl to do the same checks in multiple places.
+AC_DEFUN([_RRA_LIB_KRB5_CHECK_HEADER_KRB5],
+[AS_IF([test x"$rra_krb5_incroot" = x],
+     [AC_CHECK_HEADERS([krb5.h kerberosv5/krb5.h krb5/krb5.h])],
+     [_RRA_LIB_KRB5_CHECK_HEADER([krb5.h])
+      _RRA_LIB_KRB5_CHECK_HEADER([kerberosv5/krb5.h])
+      _RRA_LIB_KRB5_CHECK_HEADER([krb5/krb5.h])])])
+
 dnl Does the appropriate library checks for reduced-dependency Kerberos
 dnl linkage.  The single argument, if true, says to fail if Kerberos could not
 dnl be found.
@@ -116,10 +141,7 @@ AC_DEFUN([_RRA_LIB_KRB5_REDUCED],
      [AS_IF([test x"$1" = xtrue],
          [AC_MSG_ERROR([cannot find usable Kerberos library])])])
  LIBS="$KRB5_LIBS $LIBS"
- AS_IF([test x"$rra_krb5_incroot" = x],
-     [AC_CHECK_HEADERS([krb5.h krb5/krb5.h])],
-     [_RRA_LIB_KRB5_CHECK_HEADER([krb5.h])
-      _RRA_LIB_KRB5_CHECK_HEADER([krb5/krb5.h])])
+ _RRA_LIB_KRB5_CHECK_HEADER_KRB5
  AC_CHECK_FUNCS([krb5_get_error_message],
      [AC_CHECK_FUNCS([krb5_free_error_message])],
      [AC_CHECK_FUNCS([krb5_get_error_string], [],
@@ -134,7 +156,7 @@ AC_DEFUN([_RRA_LIB_KRB5_REDUCED],
                      [AS_IF([test x"$1" = xtrue],
                          [AC_MSG_ERROR([cannot find usable com_err library])],
                          [KRB5_LIBS=""])])
-                  AC_CHECK_HEADERS([et/com_err.h])])])])])
+                  _RRA_LIB_KRB5_CHECK_HEADER_COM_ERR])])])])
  RRA_LIB_KRB5_RESTORE])
 
 dnl Does the appropriate library checks for Kerberos linkage when we don't
@@ -181,10 +203,7 @@ AC_DEFUN([_RRA_LIB_KRB5_MANUAL],
         [$rra_krb5_extra])],
     [-lasn1 -lcom_err -lcrypto $rra_krb5_extra])
  LIBS="$KRB5_LIBS $LIBS"
- AS_IF([test x"$rra_krb5_incroot" = x],
-     [AC_CHECK_HEADERS([krb5.h krb5/krb5.h])],
-     [_RRA_LIB_KRB5_CHECK_HEADER([krb5.h])
-      _RRA_LIB_KRB5_CHECK_HEADER([krb5/krb5.h])])
+ _RRA_LIB_KRB5_CHECK_HEADER_KRB5
  AC_CHECK_FUNCS([krb5_get_error_message],
      [AC_CHECK_FUNCS([krb5_free_error_message])],
      [AC_CHECK_FUNCS([krb5_get_error_string], [],
@@ -192,7 +211,7 @@ AC_DEFUN([_RRA_LIB_KRB5_MANUAL],
              [AC_CHECK_FUNCS([krb5_svc_get_msg],
                  [AC_CHECK_HEADERS([ibm_svc/krb5_svc.h], [], [],
                      [RRA_INCLUDES_KRB5])],
-                 [AC_CHECK_HEADERS([et/com_err.h])])])])])
+                 [_RRA_LIB_KRB5_CHECK_HEADER_COM_ERR])])])])
  RRA_LIB_KRB5_RESTORE])
 
 dnl Sanity-check the results of krb5-config and be sure we can really link a
@@ -216,10 +235,7 @@ AC_DEFUN([_RRA_LIB_KRB5_CONFIG],
 [RRA_KRB5_CONFIG([${rra_krb5_root}], [krb5], [KRB5],
     [_RRA_LIB_KRB5_CHECK([$1])
      RRA_LIB_KRB5_SWITCH
-     AS_IF([test x"$rra_krb5_incroot" = x],
-         [AC_CHECK_HEADERS([krb5.h krb5/krb5.h])],
-         [_RRA_LIB_KRB5_CHECK_HEADER([krb5.h])
-          _RRA_LIB_KRB5_CHECK_HEADER([krb5/krb5.h])])
+     _RRA_LIB_KRB5_CHECK_HEADER_KRB5
      AC_CHECK_FUNCS([krb5_get_error_message],
          [AC_CHECK_FUNCS([krb5_free_error_message])],
          [AC_CHECK_FUNCS([krb5_get_error_string], [],
@@ -227,7 +243,7 @@ AC_DEFUN([_RRA_LIB_KRB5_CONFIG],
                  [AC_CHECK_FUNCS([krb5_svc_get_msg],
                      [AC_CHECK_HEADERS([ibm_svc/krb5_svc.h], [], [],
                          [RRA_INCLUDES_KRB5])],
-                     [AC_CHECK_HEADERS([et/com_err.h])])])])])
+                     [_RRA_LIB_KRB5_CHECK_HEADER_COM_ERR])])])])
      RRA_LIB_KRB5_RESTORE],
     [_RRA_LIB_KRB5_PATHS
      _RRA_LIB_KRB5_MANUAL([$1])])])
@@ -239,6 +255,10 @@ dnl checking.
 AC_DEFUN([_RRA_LIB_KRB5_INTERNAL],
 [AC_REQUIRE([RRA_ENABLE_REDUCED_DEPENDS])
  rra_krb5_incroot=
+ AC_SUBST([KRB5_CPPFLAGS])
+ AC_SUBST([KRB5_CPPFLAGS_GCC])
+ AC_SUBST([KRB5_LDFLAGS])
+ AC_SUBST([KRB5_LIBS])
  AS_IF([test x"$rra_krb5_includedir" != x],
     [rra_krb5_incroot="$rra_krb5_includedir"],
     [AS_IF([test x"$rra_krb5_root" != x],
@@ -253,7 +273,8 @@ AC_DEFUN([_RRA_LIB_KRB5_INTERNAL],
  rra_krb5_uses_com_err=false
  AS_CASE([$KRB5_LIBS], [*-lcom_err*], [rra_krb5_uses_com_err=true])
  AM_CONDITIONAL([KRB5_USES_COM_ERR],
-    [test x"$rra_krb5_uses_com_err" = xtrue])])
+    [test x"$rra_krb5_uses_com_err" = xtrue])
+ KRB5_CPPFLAGS_GCC=`echo "$KRB5_CPPFLAGS" | sed -e 's/-I/-isystem /g'`])
 
 dnl The main macro for packages with mandatory Kerberos support.
 AC_DEFUN([RRA_LIB_KRB5],
@@ -261,9 +282,6 @@ AC_DEFUN([RRA_LIB_KRB5],
  rra_krb5_libdir=
  rra_krb5_includedir=
  rra_use_KRB5=true
- AC_SUBST([KRB5_CPPFLAGS])
- AC_SUBST([KRB5_LDFLAGS])
- AC_SUBST([KRB5_LIBS])
 
  AC_ARG_WITH([krb5],
     [AS_HELP_STRING([--with-krb5=DIR],
@@ -289,9 +307,6 @@ AC_DEFUN([RRA_LIB_KRB5_OPTIONAL],
  rra_krb5_libdir=
  rra_krb5_includedir=
  rra_use_KRB5=
- AC_SUBST([KRB5_CPPFLAGS])
- AC_SUBST([KRB5_LDFLAGS])
- AC_SUBST([KRB5_LIBS])
 
  AC_ARG_WITH([krb5],
     [AS_HELP_STRING([--with-krb5@<:@=DIR@:>@],
index 22d38ee8164f8874502e908daee28f4f2a45fa1a..4b32ef55527ad799ca2c6e81afd4d3f77ae708ff 100644 (file)
@@ -10,7 +10,7 @@ dnl This macro doesn't do much but is defined separately so that other macros
 dnl can require it with AC_REQUIRE.
 dnl
 dnl The canonical version of this file is maintained in the rra-c-util
-dnl package, available at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+dnl package, available at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
 dnl
 dnl Written by Russ Allbery <eagle@eyrie.org>
 dnl Copyright 2005, 2006, 2007
index 0b2e85ca99e650a27ba844563b751003e082566c..4e0c751c44e21ec2cef2718c5a8952c3091b6acf 100644 (file)
@@ -9,7 +9,7 @@ dnl
 dnl Depends on RRA_SET_LDFLAGS.
 dnl
 dnl The canonical version of this file is maintained in the rra-c-util
-dnl package, available at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+dnl package, available at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
 dnl
 dnl Written by Russ Allbery <eagle@eyrie.org>
 dnl Copyright 2011, 2013
index 828270f7671e34d1f52ea6ba3994c27f0d26347b..858bed5fcfd1c19af7777a64650a54ba4b869a48 100644 (file)
@@ -13,7 +13,7 @@ dnl This file also provides the Autoconf macro RRA_SET_LIBDIR, which sets the
 dnl libdir variable to PREFIX/lib{,32,64} as appropriate.
 dnl
 dnl The canonical version of this file is maintained in the rra-c-util
-dnl package, available at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+dnl package, available at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
 dnl
 dnl Written by Russ Allbery <eagle@eyrie.org>
 dnl Copyright 2008, 2009
index f134ab975b167126c0d4f3481eaa09aa1ed71b84..3d9c8517e407009173f66c352faf2ef71101b4bd 100644 (file)
@@ -10,7 +10,7 @@ dnl Provides RRA_FUNC_SNPRINTF, which adds snprintf.o to LIBOBJS unless a
 dnl fully working snprintf is found.
 dnl
 dnl The canonical version of this file is maintained in the rra-c-util
-dnl package, available at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+dnl package, available at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
 dnl
 dnl Written by Russ Allbery <eagle@eyrie.org>
 dnl Copyright 2006, 2008, 2009
index d17ca9b21e3be6ad79ddeca5e867487594f2b14e..edc68908fc3a04722ea564d25246cd3cb8f50c78 100644 (file)
@@ -17,7 +17,7 @@ dnl
 dnl Depends on the lib-helper.m4 framework.
 dnl
 dnl The canonical version of this file is maintained in the rra-c-util
-dnl package, available at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+dnl package, available at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
 dnl
 dnl Written by Russ Allbery <eagle@eyrie.org>
 dnl Copyright 2014
index 1b28bcad9d597c9b09350842f2301d0cdffc0170..53176706a2c873097df2a5aadb3b436335050d60 100644 (file)
@@ -14,7 +14,7 @@ dnl
 dnl Depends on the lib-helper.m4 framework.
 dnl
 dnl The canonical version of this file is maintained in the rra-c-util
-dnl package, available at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+dnl package, available at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
 dnl
 dnl Written by Russ Allbery <eagle@eyrie.org>
 dnl Copyright 2013
index 62fb82d521ad3c82f1d7bb12533ba81789986502..3ed5496f211f1c53f0561e492950d166e169771c 100644 (file)
@@ -14,7 +14,7 @@ dnl
 dnl They set HAVE_C99_VAMACROS or HAVE_GNU_VAMACROS as appropriate.
 dnl
 dnl The canonical version of this file is maintained in the rra-c-util
-dnl package, available at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+dnl package, available at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
 dnl
 dnl Written by Russ Allbery <eagle@eyrie.org>
 dnl Copyright 2006, 2008, 2009
index 9fc0422d14d2a95a1222526e6ead71bd03b775cc..ba51366736bc16adc0f8f56418a09895ef74e4ce 100644 (file)
@@ -5,6 +5,7 @@
  * message in the Kerberos context.
  *
  * Written by Russ Allbery <eagle@eyrie.org>
+ * Copyright 2016 Russ Allbery <eagle@eyrie.org>
  * Copyright 2013
  *     The Board of Trustees of the Leland Stanford Junior University
  *
@@ -25,7 +26,7 @@
  * Internal helper function to set the Kerberos error message given a format,
  * an error code, and a variable argument structure.
  */
-static void
+static void __attribute__((__format__(printf, 3, 0)))
 set_error(krb5_context ctx, krb5_error_code code, const char *format,
           va_list args)
 {
index 83ec900f7a00b3131d9a6877727deec22568c10f..30bc9a5ab7b8a349c672717a4c167b627b41a6ef 100644 (file)
@@ -29,6 +29,7 @@
  *
  * Written by Russ Allbery <eagle@eyrie.org>
  * Based on work by David Mazières
+ * Copyright 2016 Russ Allbery <eagle@eyrie.org>
  * Copyright 2014
  *     The Board of Trustees of the Leland Stanford Junior University
  *
@@ -91,7 +92,7 @@ strength_init_sqlite(krb5_context ctx, krb5_pwqual_moddata data UNUSED)
  * context, and returns the generic KADM5_FAILURE code, since there doesn't
  * appear to be anything better.
  */
-static krb5_error_code
+static krb5_error_code __attribute__((__format__(printf, 3, 4)))
 error_sqlite(krb5_context ctx, krb5_pwqual_moddata data, const char *format,
              ...)
 {
index eb2b713e55b3fd5f023f07c870aed588e813288f..83fdaa78c33e36aeb9ebcc876baa2e3f1782a321 100644 (file)
@@ -5,7 +5,7 @@
  * asprintf and vasprintf for those platforms that don't have them.
  *
  * The canonical version of this file is maintained in the rra-c-util package,
- * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+ * which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
  *
  * Written by Russ Allbery <eagle@eyrie.org>
  *
@@ -19,6 +19,7 @@
  */
 
 #include <config.h>
+#include <portable/macros.h>
 #include <portable/system.h>
 
 #include <errno.h>
  * with the system versions.
  */
 #if TESTING
+# undef asprintf
+# undef vasprintf
 # define asprintf test_asprintf
 # define vasprintf test_vasprintf
 int test_asprintf(char **, const char *, ...)
     __attribute__((__format__(printf, 2, 3)));
-int test_vasprintf(char **, const char *, va_list);
+int test_vasprintf(char **, const char *, va_list)
+    __attribute__((__format__(printf, 2, 0)));
 #endif
 
 
index 890bc0cc3ea8332bd1184d1765992071730fff57..953e16d569e9365be988eb08671eda2b319f6094 100644 (file)
@@ -6,7 +6,7 @@
  * arguments.  Ensure that libportable always contains at least one symbol.
  *
  * The canonical version of this file is maintained in the rra-c-util package,
- * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+ * which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
  *
  * Written by Russ Allbery <eagle@eyrie.org>
  *
index f4104814f2d96193e23e9796c8a04cd24ddc041f..6acb3a8e3add68a749d441f98e07ee6044612e76 100644 (file)
@@ -6,7 +6,7 @@
  * (favoring the Heimdal API as the exposed one).
  *
  * The canonical version of this file is maintained in the rra-c-util package,
- * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+ * which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
  *
  * Written by Russ Allbery <eagle@eyrie.org>
  *
 # define KADM5_MISSING_KRB5_CONF_PARAMS KADM5_MISSING_CONF_PARAMS
 #endif
 
-/*
- * Heimdal provides _ctx functions that take an existing context.  MIT always
- * requires the context be passed in.  Code should use the _ctx variant, and
- * the below will fix it up if built against MIT.
- *
- * MIT also doesn't have a const prototype for the server argument, so cast it
- * so that we can use the KADM5_ADMIN_SERVICE define.
- */
-#ifndef HAVE_KADM5_INIT_WITH_SKEY_CTX
-# define kadm5_init_with_skey_ctx(c, u, k, s, p, sv, av, h) \
-    kadm5_init_with_skey((c), (u), (k), (char *) (s), (p), (sv), (av), NULL, \
-                         (h))
-#endif
-
 #endif /* !PORTABLE_KADMIN_H */
index b1c8b8d1f5b0aa2d05b26a6ee306513145c0b45b..01993711e142033a1c67b21378dca0a335bb50b6 100644 (file)
@@ -7,7 +7,7 @@
  * Kerberos libraries are fully capable, this file will be skipped.
  *
  * The canonical version of this file is maintained in the rra-c-util package,
- * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+ * which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
  *
  * Written by Russ Allbery <eagle@eyrie.org>
  *
@@ -22,6 +22,7 @@
 
 #include <config.h>
 #include <portable/krb5.h>
+#include <portable/macros.h>
 #include <portable/system.h>
 
 #include <errno.h>
@@ -33,6 +34,8 @@
 #   include <ibm_svc/krb5_svc.h>
 #  elif defined(HAVE_ET_COM_ERR_H)
 #   include <et/com_err.h>
+#  elif defined(HAVE_KERBEROSV5_COM_ERR_H)
+#   include <kerberosv5/com_err.h>
 #  else
 #   include <com_err.h>
 #  endif
  * This string is returned for unknown error messages.  We use a static
  * variable so that we can be sure not to free it.
  */
+#if !defined(HAVE_KRB5_GET_ERROR_MESSAGE) \
+    || !defined(HAVE_KRB5_FREE_ERROR_MESSAGE)
 static const char error_unknown[] = "unknown error";
+#endif
 
 
 #ifndef HAVE_KRB5_GET_ERROR_MESSAGE
index b50d75d1b8783d21227bd95cb3aeac3b2e9057e1..59562721651cbab78315665540f4edb14485d69e 100644 (file)
@@ -17,7 +17,7 @@
  * krb5_free_unparsed_name() for both APIs since it's the most specific call.
  *
  * The canonical version of this file is maintained in the rra-c-util package,
- * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+ * which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
  *
  * Written by Russ Allbery <eagle@eyrie.org>
  *
 #endif
 #include <portable/macros.h>
 
-#ifdef HAVE_KRB5_H
+#if defined(HAVE_KRB5_H)
 # include <krb5.h>
+#elif defined(HAVE_KERBEROSV5_KRB5_H)
+# include <kerberosv5/krb5.h>
 #else
 # include <krb5/krb5.h>
 #endif
index b5093f53bdd004843af5c0cb12523a32d9315596..810a1f8b10fe961b456d0df2f65a50f3713e2a48 100644 (file)
@@ -2,7 +2,7 @@
  * Portability macros used in include files.
  *
  * The canonical version of this file is maintained in the rra-c-util package,
- * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+ * which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
  *
  * Written by Russ Allbery <eagle@eyrie.org>
  *
@@ -37,7 +37,8 @@
  * variadic macro support.
  */
 #if !defined(__attribute__) && !defined(__alloc_size__)
-# if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 3)
+# if (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 3)) \
+    && !defined(__clang__)
 #  define __alloc_size__(spec, args...) /* empty */
 # endif
 #endif
index 2cbfe081249ff735e7dd890f6492ca7d862179ac..2d4268180815a5d144a31d1f2320ba37fc40980b 100644 (file)
@@ -5,7 +5,7 @@
  * systems that don't have it.
  *
  * The canonical version of this file is maintained in the rra-c-util package,
- * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+ * which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
  *
  * Written by Russ Allbery <eagle@eyrie.org>
  *
 
 #include <errno.h>
 #include <fcntl.h>
-#include <sys/time.h>
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+#endif
+#include <time.h>
 
 /*
  * If we're running the test suite, rename mkstemp to avoid conflicts with the
diff --git a/portable/reallocarray.c b/portable/reallocarray.c
new file mode 100644 (file)
index 0000000..bfa85e7
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Replacement for a missing reallocarray.
+ *
+ * Provides the same functionality as the OpenBSD library function
+ * reallocarray for those systems that don't have it.  This function is the
+ * same as realloc, but takes the size arguments in the same form as calloc
+ * and checks for overflow so that the caller doesn't need to.
+ *
+ * The canonical version of this file is maintained in the rra-c-util package,
+ * which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
+ *
+ * Written by Russ Allbery <eagle@eyrie.org>
+ *
+ * The authors hereby relinquish any claim to any copyright that they may have
+ * in this work, whether granted under contract or by operation of law or
+ * international treaty, and hereby commit to the public, at large, that they
+ * shall not, at any time in the future, seek to enforce any copyright in this
+ * work against any person or entity, or prevent any person or entity from
+ * copying, publishing, distributing or creating derivative works of this
+ * work.
+ */
+
+#include <config.h>
+#include <portable/system.h>
+
+#include <errno.h>
+
+/*
+ * If we're running the test suite, rename reallocarray to avoid conflicts
+ * with the system version.  #undef it first because some systems may define
+ * it to another name.
+ */
+#if TESTING
+# undef reallocarray
+# define reallocarray test_reallocarray
+void *test_reallocarray(void *, size_t, size_t);
+#endif
+
+/*
+ * nmemb * size cannot overflow if both are smaller than sqrt(SIZE_MAX).  We
+ * can calculate that value statically by using 2^(sizeof(size_t) * 8) as the
+ * value of SIZE_MAX and then taking the square root, which gives
+ * 2^(sizeof(size_t) * 4).  Compute the exponentiation with shift.
+ */
+#define CHECK_THRESHOLD (1UL << (sizeof(size_t) * 4))
+
+void *
+reallocarray(void *ptr, size_t nmemb, size_t size)
+{
+    if (nmemb >= CHECK_THRESHOLD || size >= CHECK_THRESHOLD)
+        if (nmemb > 0 && SIZE_MAX / nmemb <= size) {
+            errno = ENOMEM;
+            return NULL;
+        }
+    return realloc(ptr, nmemb * size);
+}
index c35ad807671286144845be9cb9c4570bdbe86801..3aaf3fd224714f78d820ac337fc2482467db4c10 100644 (file)
@@ -11,7 +11,7 @@
  * improvements should be sent back to the original author.
  *
  * The canonical version of this file is maintained in the rra-c-util package,
- * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+ * which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
  */
 
 /*
@@ -19,6 +19,8 @@
  * conflicts with the system version.
  */
 #if TESTING
+# undef snprintf
+# undef vsnprintf
 # define snprintf test_snprintf
 # define vsnprintf test_vsnprintf
 #endif
@@ -77,6 +79,7 @@
  *  Russ Allbery <eagle@eyrie.org> 2000-08-26
  *    fixed return value to comply with C99
  *    fixed handling of snprintf(NULL, ...)
+ *    added explicit casts for double to long long int conversion
  *
  *  Hrvoje Niksic <hniksic@arsdigita.com> 2000-11-04
  *    include <stdio.h> for NULL.
@@ -178,7 +181,7 @@ static int dopr (char *buffer, size_t maxlen, const char *format, va_list args)
   char *strvalue;
   int min;
   int max;
-  int state;
+  unsigned int state;
   int flags;
   int cflags;
   int total;
@@ -610,7 +613,7 @@ static LDOUBLE abs_val (LDOUBLE value)
   return result;
 }
 
-static LDOUBLE pow10_int (int exp)
+static LLONG pow10_int (int exp)
 {
   LDOUBLE result = 1;
 
@@ -620,14 +623,14 @@ static LDOUBLE pow10_int (int exp)
     exp--;
   }
   
-  return result;
+  return (LLONG) result;
 }
 
 static LLONG round_int (LDOUBLE value)
 {
   LLONG intpart;
 
-  intpart = value;
+  intpart = (LLONG) value;
   value = value - intpart;
   if (value >= 0.5)
     intpart++;
@@ -676,7 +679,7 @@ static int fmtfp (char *buffer, size_t *currlen, size_t maxlen,
   if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
 #endif
 
-  intpart = ufvalue;
+  intpart = (LLONG) ufvalue;
 
   /* With %g precision is the number of significant digits, which
      includes the digits in intpart. */
index 14d011b804272d84e046659a517c42b3502cb5d1..fb317a90d8c8c9752b25b963e50bb3e7bf734ed8 100644 (file)
@@ -6,7 +6,7 @@
  * logic is based heavily on the example in the Autoconf manual.
  *
  * The canonical version of this file is maintained in the rra-c-util package,
- * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+ * which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
  *
  * Written by Russ Allbery <eagle@eyrie.org>
  *
index e94d944a65d05d4f1391c5fab842ee14d60d86e8..1a0c8166130b614e1ccd5cff7f26ed3f88e0e7a0 100644 (file)
@@ -2,7 +2,7 @@
  * Replacement for a missing strndup.
  *
  * The canonical version of this file is maintained in the rra-c-util package,
- * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+ * which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
  *
  * Written by Russ Allbery <eagle@eyrie.org>
  *
index 5345da360c4a6f921bd7e15b624d119542d1dd2e..a35df767d26381e21cfbb89c28488a946130726c 100644 (file)
@@ -5,7 +5,8 @@
  * file is the equivalent of including all of the following headers,
  * portably:
  *
- *     #include <sys/types.h>
+ *     #include <inttypes.h>
+ *     #include <limits.h>
  *     #include <stdarg.h>
  *     #include <stdbool.h>
  *     #include <stddef.h>
  *     #include <stdint.h>
  *     #include <string.h>
  *     #include <strings.h>
+ *     #include <sys/types.h>
  *     #include <unistd.h>
  *
  * Missing functions are provided via #define or prototyped if available from
  * the portable helper library.  Also provides some standard #defines.
  *
  * The canonical version of this file is maintained in the rra-c-util package,
- * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+ * which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
  *
  * Written by Russ Allbery <eagle@eyrie.org>
  *
@@ -46,6 +48,7 @@
 #if HAVE_INTTYPES_H
 # include <inttypes.h>
 #endif
+#include <limits.h>
 #include <stdarg.h>
 #include <stddef.h>
 #if HAVE_STDINT_H
@@ -124,6 +127,12 @@ extern int snprintf(char *, size_t, const char *, ...)
 #if !HAVE_DECL_VSNPRINTF
 extern int vsnprintf(char *, size_t, const char *, va_list);
 #endif
+#if !HAVE_MKSTEMP
+extern int mkstemp(char *);
+#endif
+#if !HAVE_REALLOCARRAY
+extern void *reallocarray(void *, size_t, size_t);
+#endif
 #if !HAVE_STRNDUP
 extern char *strndup(const char *, size_t);
 #endif
similarity index 90%
rename from tests/HOWTO
rename to tests/README
index b94985def87eeff3cf5140c58bbc58f1da19cd61..e31a47d80d14a592f1943fc686dd5f99f5a2db59 100644 (file)
@@ -70,18 +70,20 @@ Writing TAP Tests
 
     One of the special features of C TAP Harness is the environment that
     it sets up for your test cases.  If your test program is called under
-    the runtests driver, the environment variables SOURCE and BUILD will
-    be set to the top of the test directory in the source tree and the top
-    of the build tree, respectively.  You can use those environment
-    variables to locate additional test data, programs and libraries built
-    as part of your software build, and other supporting information
-    needed by tests.
+    the runtests driver, the environment variables C_TAP_SOURCE and
+    C_TAP_BUILD will be set to the top of the test directory in the source
+    tree and the top of the build tree, respectively.  You can use those
+    environment variables to locate additional test data, programs and
+    libraries built as part of your software build, and other supporting
+    information needed by tests.
 
     The C and shell TAP libraries support a test_file_path() function,
     which looks for a file under the build tree and then under the source
-    tree, using the BUILD and SOURCE environment variables, and return the
-    full path to the file.  This can be used to locate supporting data
-    files.
+    tree, using the C_TAP_BUILD and C_TAP_SOURCE environment variables,
+    and return the full path to the file.  This can be used to locate
+    supporting data files.  They also support a test_tmpdir() function
+    that returns a directory that can be used for temporary files during
+    tests.
 
   Perl
 
@@ -151,7 +153,7 @@ Writing TAP Tests
     Complete API documentation for the basic C TAP library that comes with
     C TAP Harness is available at:
 
-        <http://www.eyrie.org/~eagle/software/c-tap-harness/>
+        <https://www.eyrie.org/~eagle/software/c-tap-harness/>
 
     It's common to need additional test functions and utility functions
     for your C tests, particularly if you have to set up and tear down a
@@ -168,7 +170,7 @@ Writing TAP Tests
     Libraries of additional useful TAP test functions are available in
     rra-c-util at:
 
-        <http://www.eyrie.org/~eagle/software/rra-c-util/>
+        <https://www.eyrie.org/~eagle/software/rra-c-util/>
 
     Some of the code there is particularly useful when testing programs
     that require Kerberos keys.
@@ -190,15 +192,15 @@ Writing TAP Tests
     your test suite area.  It can then be loaded by tests written in shell
     using the environment set up by runtests with:
 
-        . "$SOURCE"/tap/libtap.sh
+        . "$C_TAP_SOURCE"/tap/libtap.sh
 
     Here is a complete test case written in shell which produces the same
     output as the TAP sample above:
 
         #!/bin/sh
 
-        . "$SOURCE"/tap/libtap.sh
-        cd "$BUILD"
+        . "$C_TAP_SOURCE"/tap/libtap.sh
+        cd "$C_TAP_BUILD"
 
         plan 4
         ok 'the first test' true
@@ -238,9 +240,9 @@ Writing TAP Tests
 License
 
     This file is part of the documentation of C TAP Harness, which can be
-    found at <http://www.eyrie.org/~eagle/software/c-tap-harness/>.
+    found at <https://www.eyrie.org/~eagle/software/c-tap-harness/>.
 
-    Copyright 2010 Russ Allbery <eagle@eyrie.org>
+    Copyright 2010, 2016 Russ Allbery <eagle@eyrie.org>
 
     Copying and distribution of this file, with or without modification,
     are permitted in any medium without royalty provided the copyright
index 58a834c142184dc95a9b790ca8af7cbc8258b86b..b2ff5f621c5ebc6b26ea84684fb957d8efbeaca2 100644 (file)
@@ -1,5 +1,6 @@
 docs/pod
 docs/pod-spelling
+docs/urls
 plugin/heimdal
 plugin/mit
 perl/critic
index b05bb38c0d068a70dfa93dfa8b0f649ce6371bd9..cf333762e49e79301565bf7637d60bf37f021cbe 100644 (file)
@@ -7,7 +7,7 @@
 # This file has been updated to match perlcritic 1.118.
 #
 # The canonical version of this file is maintained in the rra-c-util package,
-# which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+# which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
 #
 # Written by Russ Allbery <eagle@eyrie.org>
 # Copyright 2011, 2012, 2013
index 64d7da11f88509fa0fb5d140ced1593e9417bb29..e35e8a8fe2144a7bab20cab26f52b94c008f19e7 100644 (file)
@@ -3,7 +3,7 @@
 # Default options for perltidy for proper Perl code reformatting.
 #
 # The canonical version of this file is maintained in the rra-c-util package,
-# which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+# which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
 
 -bbao           # put line breaks before any operator
 -nbbc           # don't force blank lines before comments (bad for else blocks)
index 8be538f95a04710c5007b988287b4a0ea387d8a0..c5a2e5dbef43dde1ac2ef332d61bdca9f9915650 100644 (file)
@@ -8,7 +8,7 @@
 # and related software.
 #
 # The canonical version of this file is maintained in the rra-c-util package,
-# which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+# which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
 #
 # Written by Russ Allbery <eagle@eyrie.org>
 # Copyright 2011, 2012, 2013, 2014
index 7b61c86382b70f22fb7e3c7cff75e8aac6e31230..729d96e757abfd78e9d3741d64e7eee4151c83a6 100755 (executable)
@@ -3,9 +3,10 @@
 # Checks all POD files in the tree for spelling errors using Test::Spelling.
 #
 # The canonical version of this file is maintained in the rra-c-util package,
-# which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+# which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
 #
 # Written by Russ Allbery <eagle@eyrie.org>
+# Copyright 2016 Russ Allbery <eagle@eyrie.org>
 # Copyright 2012, 2013, 2014
 #     The Board of Trustees of the Leland Stanford Junior University
 #
@@ -31,7 +32,7 @@ use 5.006;
 use strict;
 use warnings;
 
-use lib "$ENV{SOURCE}/tap/perl";
+use lib "$ENV{C_TAP_SOURCE}/tap/perl";
 
 use Test::More;
 use Test::RRA qw(skip_unless_author use_prereq);
index 53f9925cbf4496c00b6b015a48215bec2cdef89d..0bd5b430e7eeed997c10504ce14406725415ad06 100755 (executable)
@@ -4,9 +4,10 @@
 # distribution, for POD formatting errors.
 #
 # The canonical version of this file is maintained in the rra-c-util package,
-# which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+# which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
 #
 # Written by Russ Allbery <eagle@eyrie.org>
+# Copyright 2016 Russ Allbery <eagle@eyrie.org>
 # Copyright 2012, 2013, 2014
 #     The Board of Trustees of the Leland Stanford Junior University
 #
@@ -32,7 +33,7 @@ use 5.006;
 use strict;
 use warnings;
 
-use lib "$ENV{SOURCE}/tap/perl";
+use lib "$ENV{C_TAP_SOURCE}/tap/perl";
 
 use Test::More;
 use Test::RRA qw(skip_unless_automated use_prereq);
diff --git a/tests/docs/urls-t b/tests/docs/urls-t
new file mode 100755 (executable)
index 0000000..cad76d8
--- /dev/null
@@ -0,0 +1,97 @@
+#!/usr/bin/perl
+#
+# Check URLs in source files.
+#
+# Examine all source files in a distribution for bad URL patterns and report
+# on files that fail this check.  Currently, this just checks that all the
+# links to www.eyrie.org are https.
+#
+# The canonical version of this file is maintained in the rra-c-util package,
+# which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
+#
+# Copyright 2016 Russ Allbery <eagle@eyrie.org>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+# DEALINGS IN THE SOFTWARE.
+
+use 5.006;
+use strict;
+use warnings;
+
+use lib "$ENV{C_TAP_SOURCE}/tap/perl";
+
+use File::Basename qw(basename);
+use Test::More;
+use Test::RRA qw(skip_unless_author);
+use Test::RRA::Automake qw(all_files automake_setup);
+
+# Bad patterns to search for.
+my @BAD_REGEXES = (qr{ http:// \S+ [.]eyrie[.]org }xms);
+my @BAD_STRINGS = qw(rra@stanford.edu);
+
+# Only run this test for the package author, since it doesn't indicate any
+# user-noticable flaw in the package itself.
+skip_unless_author('Documentation URL tests');
+
+# Set up Automake testing.
+automake_setup();
+
+# Check a single file for one of the bad patterns.
+#
+# $path - Path to the file
+#
+# Returns: undef
+sub check_file {
+    my ($path) = @_;
+    my $filename = basename($path);
+
+    # Ignore this check itself (or the Perl version of it) and binary files.
+    return if ($filename eq 'urls.t' || $filename eq 'urls-t');
+    return if !-T $path;
+
+    # Scan the file.
+    open(my $fh, '<', $path) or BAIL_OUT("Cannot open $path");
+    while (defined(my $line = <$fh>)) {
+        for my $regex (@BAD_REGEXES) {
+            if ($line =~ $regex) {
+                ok(0, "$path contains $regex");
+                close($fh) or BAIL_OUT("Cannot close $path");
+                return;
+            }
+        }
+        for my $string (@BAD_STRINGS) {
+            if (index($line, $string) != -1) {
+                ok(0, "$path contains $string");
+                close($fh) or BAIL_OUT("Cannot close $path");
+                return;
+            }
+        }
+    }
+    close($fh) or BAIL_OUT("Cannot close $path");
+    ok(1, $path);
+    return;
+}
+
+# Scan every file for any of the bad patterns or strings.  We don't declare a
+# plan since we skip a lot of files and don't want to precalculate the file
+# list.
+my @paths = all_files();
+for my $path (@paths) {
+    check_file($path);
+}
+done_testing();
index c66227c39e7c5a25bf7ac691aa3035c9570c3ba7..b5593e4caf591b24fc62609496a75dff3e4b105b 100755 (executable)
@@ -3,9 +3,10 @@
 # Check for perlcritic errors in included Perl scripts.
 #
 # The canonical version of this file is maintained in the rra-c-util package,
-# which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+# which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
 #
 # Written by Russ Allbery <eagle@eyrie.org>
+# Copyright 2016 Russ Allbery <eagle@eyrie.org>
 # Copyright 2012, 2013, 2014
 #     The Board of Trustees of the Leland Stanford Junior University
 #
@@ -31,7 +32,7 @@ use 5.006;
 use strict;
 use warnings;
 
-use lib "$ENV{SOURCE}/tap/perl";
+use lib "$ENV{C_TAP_SOURCE}/tap/perl";
 
 use File::Spec;
 use Test::More;
index 8c493279289b83a8e607de166af06e7396639f70..acdb13116783f42ec364f3a881089a697fa85f9c 100755 (executable)
@@ -7,9 +7,10 @@
 # required for internal tools than for public code.
 #
 # The canonical version of this file is maintained in the rra-c-util package,
-# which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+# which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
 #
 # Written by Russ Allbery <eagle@eyrie.org>
+# Copyright 2016 Russ Allbery <eagle@eyrie.org>
 # Copyright 2012, 2013, 2014
 #     The Board of Trustees of the Leland Stanford Junior University
 #
@@ -35,7 +36,7 @@ use 5.006;
 use strict;
 use warnings;
 
-use lib "$ENV{SOURCE}/tap/perl";
+use lib "$ENV{C_TAP_SOURCE}/tap/perl";
 
 use Test::More;
 use Test::RRA qw(skip_unless_automated use_prereq);
index 2df6d58c7fdc5b287ed46e80ceb523fed3db9af1..58a7cf7db5ac04035e9e3e38e5009c5f87ce6dea 100755 (executable)
@@ -7,9 +7,10 @@
 # all pass a syntax check.  Currently, test suite coverage is not checked.
 #
 # The canonical version of this file is maintained in the rra-c-util package,
-# which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+# which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
 #
 # Written by Russ Allbery <eagle@eyrie.org>
+# Copyright 2016 Russ Allbery <eagle@eyrie.org>
 # Copyright 2012, 2013, 2014
 #     The Board of Trustees of the Leland Stanford Junior University
 #
@@ -35,7 +36,7 @@ use 5.006;
 use strict;
 use warnings;
 
-use lib "$ENV{SOURCE}/tap/perl";
+use lib "$ENV{C_TAP_SOURCE}/tap/perl";
 
 use Test::More;
 use Test::RRA qw(skip_unless_automated use_prereq);
@@ -46,7 +47,7 @@ use Test::RRA::Config qw(@STRICT_IGNORE @STRICT_PREREQ);
 skip_unless_automated('Strictness tests');
 
 # Load prerequisite modules.
-use_prereq('Test::Strict');
+use_prereq('Test::Strict', '0.25');
 
 # Check whether all prerequisites are available, and skip the test if any of
 # them are not.
index c61c14aef1415c8b42892cb87568bc73080cc3dd..4f7a6f617ae3262ba1ee5c6e56f361fa56bfefb8 100644 (file)
@@ -2,7 +2,7 @@
  * asprintf and vasprintf test suite.
  *
  * The canonical version of this file is maintained in the rra-c-util package,
- * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+ * which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
  *
  * Written by Russ Allbery <eagle@eyrie.org>
  *
@@ -16,6 +16,7 @@
  */
 
 #include <config.h>
+#include <portable/macros.h>
 #include <portable/system.h>
 
 #include <tests/tap/basic.h>
index 20a83fc578febb992d4368dd7da003bd82f0769d..5899a388c3d87ad9f2db41284c8346c0b69c32ac 100644 (file)
@@ -2,7 +2,7 @@
  * mkstemp test suite.
  *
  * The canonical version of this file is maintained in the rra-c-util package,
- * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+ * which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
  *
  * Written by Russ Allbery <eagle@eyrie.org>
  *
diff --git a/tests/portable/reallocarray-t.c b/tests/portable/reallocarray-t.c
new file mode 100644 (file)
index 0000000..26db70a
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * reallocarray test suite.
+ *
+ * This does some simple sanity checks and checks some of the overflow
+ * detection, but isn't particularly thorough.
+ *
+ * The canonical version of this file is maintained in the rra-c-util package,
+ * which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
+ *
+ * Written by Russ Allbery <eagle@eyrie.org>
+ *
+ * The authors hereby relinquish any claim to any copyright that they may have
+ * in this work, whether granted under contract or by operation of law or
+ * international treaty, and hereby commit to the public, at large, that they
+ * shall not, at any time in the future, seek to enforce any copyright in this
+ * work against any person or entity, or prevent any person or entity from
+ * copying, publishing, distributing or creating derivative works of this
+ * work.
+ */
+
+#include <config.h>
+#include <portable/system.h>
+
+#include <errno.h>
+
+#include <tests/tap/basic.h>
+
+void *test_reallocarray(void *, size_t, size_t);
+
+
+int
+main(void)
+{
+    char *p, *base;
+    size_t sqrt_max;
+    int oerrno;
+
+    plan(15);
+
+    /* Test success cases and write to the memory for valgrind checks. */
+    p = test_reallocarray(NULL, 2, 5);
+    memcpy(p, "123456789", 10);
+    is_string("123456789", p, "reallocarray of NULL");
+    p = test_reallocarray(p, 4, 5);
+    is_string("123456789", p, "reallocarray after resize");
+    memcpy(p + 9, "0123456789", 11);
+    is_string("1234567890123456789", p, "write to larger memory segment");
+    free(p);
+
+    /*
+     * If nmemb or size are 0, we should either get NULL or a pointer we can
+     * free.  Make sure we don't get something weird, like division by zero.
+     */
+    p = test_reallocarray(NULL, 0, 100);
+    if (p != NULL)
+        free(p);
+    p = test_reallocarray(NULL, 100, 0);
+    if (p != NULL)
+        free(p);
+
+    /* Test the range-checking error cases. */
+    p = test_reallocarray(NULL, 2, SIZE_MAX / 2);
+    oerrno = errno;
+    ok(p == NULL, "reallocarray fails for 2, SIZE_MAX / 2");
+    is_int(ENOMEM, oerrno, "...with correct errno");
+    base = malloc(10);
+    p = test_reallocarray(base, 3, SIZE_MAX / 3);
+    oerrno = errno;
+    ok(p == NULL, "reallocarray fails for 3, SIZE_MAX / 3");
+    is_int(ENOMEM, oerrno, "...with correct errno");
+    sqrt_max = (1UL << (sizeof(size_t) * 4));
+    p = test_reallocarray(base, sqrt_max, sqrt_max);
+    oerrno = errno;
+    ok(p == NULL, "reallocarray fails for sqrt(SIZE_MAX), sqrt(SIZE_MAX)");
+    is_int(ENOMEM, oerrno, "...with correct errno");
+    p = test_reallocarray(base, 1, SIZE_MAX);
+    oerrno = errno;
+    ok(p == NULL, "reallocarray fails for 1, SIZE_MAX");
+    is_int(ENOMEM, oerrno, "...with correct errno");
+    p = test_reallocarray(base, SIZE_MAX, 1);
+    oerrno = errno;
+    ok(p == NULL, "reallocarray fails for SIZE_MAX, 1");
+    is_int(ENOMEM, oerrno, "...with correct errno");
+    p = test_reallocarray(base, 2, SIZE_MAX);
+    oerrno = errno;
+    ok(p == NULL, "reallocarray fails for 2, SIZE_MAX");
+    is_int(ENOMEM, oerrno, "...with correct errno");
+
+    /* Clean up and exit. */
+    free(base);
+    return 0;
+}
diff --git a/tests/portable/reallocarray.c b/tests/portable/reallocarray.c
new file mode 100644 (file)
index 0000000..7cd29e2
--- /dev/null
@@ -0,0 +1,2 @@
+#define TESTING 1
+#include <portable/reallocarray.c>
index 270d2e1831743b5366c66cf318ca7a38b317dddd..601579bc3d4cc768eed7ceb4afc27d87f7e9576b 100644 (file)
@@ -2,7 +2,7 @@
  * snprintf test suite.
  *
  * The canonical version of this file is maintained in the rra-c-util package,
- * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+ * which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
  *
  * Written by Russ Allbery <eagle@eyrie.org>
  * Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006
@@ -26,7 +26,9 @@
  * Disable the requirement that format strings be literals.  We need variable
  * formats for easy testing.
  */
-#pragma GCC diagnostic ignored "-Wformat-nonliteral"
+#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 2) || defined(__clang__)
+# pragma GCC diagnostic ignored "-Wformat-nonliteral"
+#endif
 
 /*
  * Intentionally don't add the printf attribute here since we pass a
index 0f923b795e00d0c8ccfa6326757b27e5e252fcd2..c08786f9974a9e925417d4a927eee9f6a4d5f807 100644 (file)
@@ -2,7 +2,7 @@
  * strndup test suite.
  *
  * The canonical version of this file is maintained in the rra-c-util package,
- * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+ * which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
  *
  * Written by Russ Allbery <eagle@eyrie.org>
  *
index 047c031205eb30e5446f481b4d8ec2eae50aeef7..ab9a4cb6bfa2ee0c9d9426bbcad70d8565a5ad71 100644 (file)
@@ -3,15 +3,19 @@
  *
  * Usage:
  *
- *      runtests [-b <build-dir>] [-s <source-dir>] <test-list>
- *      runtests -o [-b <build-dir>] [-s <source-dir>] <test>
+ *      runtests [-hv] [-b <build-dir>] [-s <source-dir>] -l <test-list>
+ *      runtests [-hv] [-b <build-dir>] [-s <source-dir>] <test> [<test> ...]
+ *      runtests -o [-h] [-b <build-dir>] [-s <source-dir>] <test>
  *
  * In the first case, expects a list of executables located in the given file,
  * one line per executable.  For each one, runs it as part of a test suite,
- * reporting results.  Test output should start with a line containing the
- * number of tests (numbered from 1 to this number), optionally preceded by
- * "1..", although that line may be given anywhere in the output.  Each
- * additional line should be in the following format:
+ * reporting results.  In the second case, use the same infrastructure, but
+ * run only the tests listed on the command line.
+ *
+ * Test output should start with a line containing the number of tests
+ * (numbered from 1 to this number), optionally preceded by "1..", although
+ * that line may be given anywhere in the output.  Each additional line should
+ * be in the following format:
  *
  *      ok <number>
  *      not ok <number>
  * output.  This is intended for use with failing tests so that the person
  * running the test suite can get more details about what failed.
  *
- * If built with the C preprocessor symbols SOURCE and BUILD defined, C TAP
- * Harness will export those values in the environment so that tests can find
- * the source and build directory and will look for tests under both
- * directories.  These paths can also be set with the -b and -s command-line
- * options, which will override anything set at build time.
+ * If built with the C preprocessor symbols C_TAP_SOURCE and C_TAP_BUILD
+ * defined, C TAP Harness will export those values in the environment so that
+ * tests can find the source and build directory and will look for tests under
+ * both directories.  These paths can also be set with the -b and -s
+ * command-line options, which will override anything set at build time.
+ *
+ * If the -v option is given, or the C_TAP_VERBOSE environment variable is set,
+ * display the full output of each test as it runs rather than showing a
+ * summary of the results of each test.
  *
  * Any bug reports, bug fixes, and improvements are very much welcome and
  * should be sent to the e-mail address below.  This program is part of C TAP
- * Harness <http://www.eyrie.org/~eagle/software/c-tap-harness/>.
+ * Harness <https://www.eyrie.org/~eagle/software/c-tap-harness/>.
  *
  * Copyright 2000, 2001, 2004, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013,
- *     2014 Russ Allbery <eagle@eyrie.org>
+ *     2014, 2015, 2016 Russ Allbery <eagle@eyrie.org>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -86,6 +94,7 @@
 #include <ctype.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <limits.h>
 #include <stdarg.h>
 #include <stddef.h>
 #include <stdio.h>
 
 /*
  * The source and build versions of the tests directory.  This is used to set
- * the SOURCE and BUILD environment variables and find test programs, if set.
- * Normally, this should be set as part of the build process to the test
- * subdirectories of $(abs_top_srcdir) and $(abs_top_builddir) respectively.
+ * the C_TAP_SOURCE and C_TAP_BUILD environment variables (and the SOURCE and
+ * BUILD environment variables set for backward compatibility) and find test
+ * programs, if set.  Normally, this should be set as part of the build
+ * process to the test subdirectories of $(abs_top_srcdir) and
+ * $(abs_top_builddir) respectively.
  */
-#ifndef SOURCE
-# define SOURCE NULL
+#ifndef C_TAP_SOURCE
+# define C_TAP_SOURCE NULL
 #endif
-#ifndef BUILD
-# define BUILD NULL
+#ifndef C_TAP_BUILD
+# define C_TAP_BUILD NULL
 #endif
 
 /* Test status codes. */
@@ -145,6 +156,12 @@ enum test_status {
     TEST_INVALID
 };
 
+/* Really, just a boolean, but this is more self-documenting. */
+enum test_verbose {
+    CONCISE = 0,
+    VERBOSE = 1
+};
+
 /* Indicates the state of our plan. */
 enum plan_status {
     PLAN_INIT,                  /* Nothing seen yet. */
@@ -191,16 +208,18 @@ struct testlist {
  * split into variables to satisfy the pedantic ISO C90 limit on strings.
  */
 static const char usage_message[] = "\
-Usage: %s [-b <build-dir>] [-s <source-dir>] <test> ...\n\
-       %s [-b <build-dir>] [-s <source-dir>] -l <test-list>\n\
-       %s -o [-b <build-dir>] [-s <source-dir>] <test>\n\
-\n%s";
-static const char usage_extra[] = "\
+Usage: %s [-hv] [-b <build-dir>] [-s <source-dir>] <test> ...\n\
+       %s [-hv] [-b <build-dir>] [-s <source-dir>] -l <test-list>\n\
+       %s -o [-h] [-b <build-dir>] [-s <source-dir>] <test>\n\
+\n\
 Options:\n\
     -b <build-dir>      Set the build directory to <build-dir>\n\
+%s";
+static const char usage_extra[] = "\
     -l <list>           Take the list of tests to run from <test-list>\n\
     -o                  Run a single test rather than a list of tests\n\
     -s <source-dir>     Set the source directory to <source-dir>\n\
+    -v                  Show the full output of each test\n\
 \n\
 runtests normally runs each test listed on the command line.  With the -l\n\
 option, it instead runs every test listed in a file.  With the -o option,\n\
@@ -220,10 +239,11 @@ Failed Set                 Fail/Total (%) Skip Stat  Failing Tests\n\
 -------------------------- -------------- ---- ----  ------------------------";
 
 /* Include the file name and line number in malloc failures. */
-#define xcalloc(n, size)  x_calloc((n), (size), __FILE__, __LINE__)
-#define xmalloc(size)     x_malloc((size), __FILE__, __LINE__)
-#define xrealloc(p, size) x_realloc((p), (size), __FILE__, __LINE__)
-#define xstrdup(p)        x_strdup((p), __FILE__, __LINE__)
+#define xcalloc(n, size)      x_calloc((n), (size), __FILE__, __LINE__)
+#define xmalloc(size)         x_malloc((size), __FILE__, __LINE__)
+#define xstrdup(p)            x_strdup((p), __FILE__, __LINE__)
+#define xreallocarray(p, n, size) \
+    x_reallocarray((p), (n), (size), __FILE__, __LINE__)
 
 /*
  * __attribute__ is available in gcc 2.5 and later, but only with gcc 2.7
@@ -244,8 +264,10 @@ Failed Set                 Fail/Total (%) Skip Stat  Failing Tests\n\
  * variadic macro support.
  */
 #if !defined(__attribute__) && !defined(__alloc_size__)
-# if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 3)
-#  define __alloc_size__(spec, args...) /* empty */
+# if defined(__GNUC__) && !defined(__clang__)
+#  if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 3)
+#   define __alloc_size__(spec, args...) /* empty */
+#  endif
 # endif
 #endif
 
@@ -266,8 +288,8 @@ static void *x_calloc(size_t, size_t, const char *, int)
     __attribute__((__alloc_size__(1, 2), __malloc__, __nonnull__));
 static void *x_malloc(size_t, const char *, int)
     __attribute__((__alloc_size__(1), __malloc__, __nonnull__));
-static void *x_realloc(void *, size_t, const char *, int)
-    __attribute__((__alloc_size__(2), __malloc__, __nonnull__(3)));
+static void *x_reallocarray(void *, size_t, size_t, const char *, int)
+    __attribute__((__alloc_size__(2, 3), __malloc__, __nonnull__(4)));
 static char *x_strdup(const char *, const char *, int)
     __attribute__((__malloc__, __nonnull__));
 
@@ -328,14 +350,26 @@ x_malloc(size_t size, const char *file, int line)
 
 /*
  * Reallocate memory, reporting a fatal error and exiting on failure.
+ *
+ * We should technically use SIZE_MAX here for the overflow check, but
+ * SIZE_MAX is C99 and we're only assuming C89 + SUSv3, which does not
+ * guarantee that it exists.  They do guarantee that UINT_MAX exists, and we
+ * can assume that UINT_MAX <= SIZE_MAX.  And we should not be allocating
+ * anything anywhere near that large.
+ *
+ * (In theory, C89 and C99 permit size_t to be smaller than unsigned int, but
+ * I disbelieve in the existence of such systems and they will have to cope
+ * without overflow checks.)
  */
 static void *
-x_realloc(void *p, size_t size, const char *file, int line)
+x_reallocarray(void *p, size_t n, size_t size, const char *file, int line)
 {
-    p = realloc(p, size);
+    if (n > 0 && UINT_MAX / n <= size)
+        sysdie("realloc too large at %s line %d", file, line);
+    p = realloc(p, n * size);
     if (p == NULL)
         sysdie("failed to realloc %lu bytes at %s line %d",
-               (unsigned long) size, file, line);
+               (unsigned long) (n * size), file, line);
     return p;
 }
 
@@ -359,6 +393,55 @@ x_strdup(const char *s, const char *file, int line)
 }
 
 
+/*
+ * Form a new string by concatenating multiple strings.  The arguments must be
+ * terminated by (const char *) 0.
+ *
+ * This function only exists because we can't assume asprintf.  We can't
+ * simulate asprintf with snprintf because we're only assuming SUSv3, which
+ * does not require that snprintf with a NULL buffer return the required
+ * length.  When those constraints are relaxed, this should be ripped out and
+ * replaced with asprintf or a more trivial replacement with snprintf.
+ */
+static char *
+concat(const char *first, ...)
+{
+    va_list args;
+    char *result;
+    const char *string;
+    size_t offset;
+    size_t length = 0;
+
+    /*
+     * Find the total memory required.  Ensure we don't overflow length.  We
+     * aren't guaranteed to have SIZE_MAX, so use UINT_MAX as an acceptable
+     * substitute (see the x_nrealloc comments).
+     */
+    va_start(args, first);
+    for (string = first; string != NULL; string = va_arg(args, const char *)) {
+        if (length >= UINT_MAX - strlen(string)) {
+            errno = EINVAL;
+            sysdie("strings too long in concat");
+        }
+        length += strlen(string);
+    }
+    va_end(args);
+    length++;
+
+    /* Create the string. */
+    result = xmalloc(length);
+    va_start(args, first);
+    offset = 0;
+    for (string = first; string != NULL; string = va_arg(args, const char *)) {
+        memcpy(result + offset, string, strlen(string));
+        offset += strlen(string);
+    }
+    va_end(args);
+    result[offset] = '\0';
+    return result;
+}
+
+
 /*
  * Given a struct timeval, return the number of seconds it represents as a
  * double.  Use difftime() to convert a time_t to a double.
@@ -493,6 +576,55 @@ test_backspace(struct testset *ts)
 }
 
 
+/*
+ * Allocate or resize the array of test results to be large enough to contain
+ * the test number in.
+ */
+static void
+resize_results(struct testset *ts, unsigned long n)
+{
+    unsigned long i;
+    size_t s;
+
+    /* If there's already enough space, return quickly. */
+    if (n <= ts->allocated)
+        return;
+
+    /*
+     * If no space has been allocated, do the initial allocation.  Otherwise,
+     * resize.  Start with 32 test cases and then add 1024 with each resize to
+     * try to reduce the number of reallocations.
+     */
+    if (ts->allocated == 0) {
+        s = (n > 32) ? n : 32;
+        ts->results = xcalloc(s, sizeof(enum test_status));
+    } else {
+        s = (n > ts->allocated + 1024) ? n : ts->allocated + 1024;
+        ts->results = xreallocarray(ts->results, s, sizeof(enum test_status));
+    }
+
+    /* Set the results for the newly-allocated test array. */
+    for (i = ts->allocated; i < s; i++)
+        ts->results[i] = TEST_INVALID;
+    ts->allocated = s;
+}
+
+
+/*
+ * Report an invalid test number and set the appropriate flags.  Pulled into a
+ * separate function since we do this in several places.
+ */
+static void
+invalid_test_number(struct testset *ts, long n, enum test_verbose verbose)
+{
+    if (!verbose)
+        test_backspace(ts);
+    printf("ABORTED (invalid test number %ld)\n", n);
+    ts->aborted = 1;
+    ts->reported = 1;
+}
+
+
 /*
  * Read the plan line of test output, which should contain the range of test
  * numbers.  We may initialize the testset structure here if we haven't yet
@@ -500,9 +632,8 @@ test_backspace(struct testset *ts)
  * continue, false otherwise.
  */
 static int
-test_plan(const char *line, struct testset *ts)
+test_plan(const char *line, struct testset *ts, enum test_verbose verbose)
 {
-    unsigned long i;
     long n;
 
     /*
@@ -515,12 +646,14 @@ test_plan(const char *line, struct testset *ts)
         line += 3;
 
     /*
-     * Get the count, check it for validity, and initialize the struct.  If we
-     * have something of the form "1..0 # skip foo", the whole file was
+     * Get the count and check it for validity.
+     *
+     * If we have something of the form "1..0 # skip foo", the whole file was
      * skipped; record that.  If we do skip the whole file, zero out all of
-     * our statistics, since they're no longer relevant.  strtol is called
-     * with a second argument to advance the line pointer past the count to
-     * make it simpler to detect the # skip case.
+     * our statistics, since they're no longer relevant.
+     *
+     * strtol is called with a second argument to advance the line pointer
+     * past the count to make it simpler to detect the # skip case.
      */
     n = strtol(line, (char **) &line, 10);
     if (n == 0) {
@@ -549,30 +682,27 @@ test_plan(const char *line, struct testset *ts)
         ts->reported = 1;
         return 0;
     }
-    if (ts->plan == PLAN_INIT && ts->allocated == 0) {
-        ts->count = n;
-        ts->allocated = n;
+
+    /*
+     * If we are doing lazy planning, check the plan against the largest test
+     * number that we saw and fail now if we saw a check outside the plan
+     * range.
+     */
+    if (ts->plan == PLAN_PENDING && (unsigned long) n < ts->count) {
+        invalid_test_number(ts, (long) ts->count, verbose);
+        return 0;
+    }
+
+    /*
+     * Otherwise, allocated or resize the results if needed and update count,
+     * and then record that we've seen a plan.
+     */
+    resize_results(ts, (unsigned long) n);
+    ts->count = (unsigned long) n;
+    if (ts->plan == PLAN_INIT)
         ts->plan = PLAN_FIRST;
-        ts->results = xmalloc(ts->count * sizeof(enum test_status));
-        for (i = 0; i < ts->count; i++)
-            ts->results[i] = TEST_INVALID;
-    } else if (ts->plan == PLAN_PENDING) {
-        if ((unsigned long) n < ts->count) {
-            test_backspace(ts);
-            printf("ABORTED (invalid test number %lu)\n", ts->count);
-            ts->aborted = 1;
-            ts->reported = 1;
-            return 0;
-        }
-        ts->count = n;
-        if ((unsigned long) n > ts->allocated) {
-            ts->results = xrealloc(ts->results, n * sizeof(enum test_status));
-            for (i = ts->allocated; i < ts->count; i++)
-                ts->results[i] = TEST_INVALID;
-            ts->allocated = n;
-        }
+    else if (ts->plan == PLAN_PENDING)
         ts->plan = PLAN_FINAL;
-    }
     return 1;
 }
 
@@ -584,13 +714,14 @@ test_plan(const char *line, struct testset *ts)
  * reported status.
  */
 static void
-test_checkline(const char *line, struct testset *ts)
+test_checkline(const char *line, struct testset *ts,
+               enum test_verbose verbose)
 {
     enum test_status status = TEST_PASS;
     const char *bail;
     char *end;
     long number;
-    unsigned long i, current;
+    unsigned long current;
     int outlen;
 
     /* Before anything, check for a test abort. */
@@ -603,7 +734,8 @@ test_checkline(const char *line, struct testset *ts)
             length = strlen(bail);
             if (bail[length - 1] == '\n')
                 length--;
-            test_backspace(ts);
+            if (!verbose)
+                test_backspace(ts);
             printf("ABORTED (%.*s)\n", (int) length, bail);
             ts->reported = 1;
         }
@@ -624,14 +756,15 @@ test_checkline(const char *line, struct testset *ts)
 
     /* If we haven't yet seen a plan, look for one. */
     if (ts->plan == PLAN_INIT && isdigit((unsigned char)(*line))) {
-        if (!test_plan(line, ts))
+        if (!test_plan(line, ts, verbose))
             return;
     } else if (strncmp(line, "1..", 3) == 0) {
         if (ts->plan == PLAN_PENDING) {
-            if (!test_plan(line, ts))
+            if (!test_plan(line, ts, verbose))
                 return;
         } else {
-            test_backspace(ts);
+            if (!verbose)
+                test_backspace(ts);
             puts("ABORTED (multiple plans)");
             ts->aborted = 1;
             ts->reported = 1;
@@ -650,32 +783,23 @@ test_checkline(const char *line, struct testset *ts)
     errno = 0;
     number = strtol(line, &end, 10);
     if (errno != 0 || end == line)
-        number = ts->current + 1;
-    current = number;
-    if (number <= 0 || (current > ts->count && ts->plan == PLAN_FIRST)) {
-        test_backspace(ts);
-        printf("ABORTED (invalid test number %lu)\n", current);
-        ts->aborted = 1;
-        ts->reported = 1;
+        current = ts->current + 1;
+    else if (number <= 0) {
+        invalid_test_number(ts, number, verbose);
+        return;
+    } else
+        current = (unsigned long) number;
+    if (current > ts->count && ts->plan == PLAN_FIRST) {
+        invalid_test_number(ts, (long) current, verbose);
         return;
     }
 
     /* We have a valid test result.  Tweak the results array if needed. */
     if (ts->plan == PLAN_INIT || ts->plan == PLAN_PENDING) {
         ts->plan = PLAN_PENDING;
+        resize_results(ts, current);
         if (current > ts->count)
             ts->count = current;
-        if (current > ts->allocated) {
-            unsigned long n;
-
-            n = (ts->allocated == 0) ? 32 : ts->allocated * 2;
-            if (n < current)
-                n = current;
-            ts->results = xrealloc(ts->results, n * sizeof(enum test_status));
-            for (i = ts->allocated; i < n; i++)
-                ts->results[i] = TEST_INVALID;
-            ts->allocated = n;
-        }
     }
 
     /*
@@ -695,7 +819,8 @@ test_checkline(const char *line, struct testset *ts)
 
     /* Make sure that the test number is in range and not a duplicate. */
     if (ts->results[current - 1] != TEST_INVALID) {
-        test_backspace(ts);
+        if (!verbose)
+            test_backspace(ts);
         printf("ABORTED (duplicate test number %lu)\n", current);
         ts->aborted = 1;
         ts->reported = 1;
@@ -711,13 +836,13 @@ test_checkline(const char *line, struct testset *ts)
     }
     ts->current = current;
     ts->results[current - 1] = status;
-    if (isatty(STDOUT_FILENO)) {
+    if (!verbose && isatty(STDOUT_FILENO)) {
         test_backspace(ts);
         if (ts->plan == PLAN_PENDING)
             outlen = printf("%lu/?", current);
         else
             outlen = printf("%lu/%lu", current, ts->count);
-        ts->length = (outlen >= 0) ? outlen : 0;
+        ts->length = (outlen >= 0) ? (unsigned int) outlen : 0;
         fflush(stdout);
     }
 }
@@ -733,7 +858,7 @@ test_checkline(const char *line, struct testset *ts)
  * disable this).
  */
 static unsigned int
-test_print_range(unsigned long first, unsigned long last, unsigned int chars,
+test_print_range(unsigned long first, unsigned long last, unsigned long chars,
                  unsigned int limit)
 {
     unsigned int needed = 0;
@@ -903,7 +1028,7 @@ test_analyze(struct testset *ts)
  * false otherwise.
  */
 static int
-test_run(struct testset *ts)
+test_run(struct testset *ts, enum test_verbose verbose)
 {
     pid_t testpid, child;
     int outfd, status;
@@ -920,12 +1045,19 @@ test_run(struct testset *ts)
         sysdie("fdopen failed");
     }
 
-    /* Pass each line of output to test_checkline(). */
-    while (!ts->aborted && fgets(buffer, sizeof(buffer), output))
-        test_checkline(buffer, ts);
+    /*
+     * Pass each line of output to test_checkline(), and print the line if
+     * verbosity is requested.
+     */
+    while (!ts->aborted && fgets(buffer, sizeof(buffer), output)) {
+        if (verbose)
+            printf("%s", buffer);
+        test_checkline(buffer, ts, verbose);
+    }
     if (ferror(output) || ts->plan == PLAN_INIT)
         ts->aborted = 1;
-    test_backspace(ts);
+    if (!verbose)
+        test_backspace(ts);
 
     /*
      * Consume the rest of the test output, close the output descriptor,
@@ -933,7 +1065,8 @@ test_run(struct testset *ts)
      * for eventual output.
      */
     while (fgets(buffer, sizeof(buffer), output))
-        ;
+        if (verbose)
+            printf("%s", buffer);
     fclose(output);
     child = waitpid(testpid, &ts->status, 0);
     if (child == (pid_t) -1) {
@@ -1041,7 +1174,7 @@ is_valid_test(const char *path)
 static char *
 find_test(const char *name, const char *source, const char *build)
 {
-    char *path;
+    char *path = NULL;
     const char *bases[3], *suffix, *base;
     unsigned int i, j;
     const char *suffixes[3] = { "-t", ".t", "" };
@@ -1058,8 +1191,7 @@ find_test(const char *name, const char *source, const char *build)
             base = bases[j];
             if (base == NULL)
                 continue;
-            path = xmalloc(strlen(base) + strlen(name) + strlen(suffix) + 2);
-            sprintf(path, "%s/%s%s", base, name, suffix);
+            path = concat(base, "/", name, suffix, (const char *) 0);
             if (is_valid_test(path))
                 return path;
             free(path);
@@ -1074,7 +1206,8 @@ find_test(const char *name, const char *source, const char *build)
 
 /*
  * Read a list of tests from a file, returning the list of tests as a struct
- * testlist.  Reports an error to standard error and exits if the list of
+ * testlist, or NULL if there were no tests (such as a file containing only
+ * comments).  Reports an error to standard error and exits if the list of
  * tests cannot be read.
  */
 static struct testlist *
@@ -1084,12 +1217,11 @@ read_test_list(const char *filename)
     unsigned int line;
     size_t length;
     char buffer[BUFSIZ];
+    const char *testname;
     struct testlist *listhead, *current;
 
     /* Create the initial container list that will hold our results. */
-    listhead = xmalloc(sizeof(struct testlist));
-    listhead->ts = NULL;
-    listhead->next = NULL;
+    listhead = xcalloc(1, sizeof(struct testlist));
     current = NULL;
 
     /*
@@ -1108,20 +1240,33 @@ read_test_list(const char *filename)
             exit(1);
         }
         buffer[length] = '\0';
+
+        /* Skip comments, leading spaces, and blank lines. */
+        testname = skip_whitespace(buffer);
+        if (strlen(testname) == 0)
+            continue;
+        if (testname[0] == '#')
+            continue;
+
+        /* Allocate the new testset structure. */
         if (current == NULL)
             current = listhead;
         else {
-            current->next = xmalloc(sizeof(struct testlist));
+            current->next = xcalloc(1, sizeof(struct testlist));
             current = current->next;
-            current->next = NULL;
         }
         current->ts = xcalloc(1, sizeof(struct testset));
         current->ts->plan = PLAN_INIT;
-        current->ts->file = xstrdup(buffer);
-        current->ts->reason = NULL;
+        current->ts->file = xstrdup(testname);
     }
     fclose(file);
 
+    /* If there were no tests, current is still NULL. */
+    if (current == NULL) {
+        free(listhead);
+        return NULL;
+    }
+
     /* Return the results. */
     return listhead;
 }
@@ -1130,7 +1275,8 @@ read_test_list(const char *filename)
 /*
  * Build a list of tests from command line arguments.  Takes the argv and argc
  * representing the command line arguments and returns a newly allocated test
- * list.  The caller is responsible for freeing.
+ * list, or NULL if there were no tests.  The caller is responsible for
+ * freeing.
  */
 static struct testlist *
 build_test_list(char *argv[], int argc)
@@ -1139,9 +1285,7 @@ build_test_list(char *argv[], int argc)
     struct testlist *listhead, *current;
 
     /* Create the initial container list that will hold our results. */
-    listhead = xmalloc(sizeof(struct testlist));
-    listhead->ts = NULL;
-    listhead->next = NULL;
+    listhead = xcalloc(1, sizeof(struct testlist));
     current = NULL;
 
     /* Walk the list of arguments and create test sets for them. */
@@ -1149,14 +1293,18 @@ build_test_list(char *argv[], int argc)
         if (current == NULL)
             current = listhead;
         else {
-            current->next = xmalloc(sizeof(struct testlist));
+            current->next = xcalloc(1, sizeof(struct testlist));
             current = current->next;
-            current->next = NULL;
         }
         current->ts = xcalloc(1, sizeof(struct testset));
         current->ts->plan = PLAN_INIT;
         current->ts->file = xstrdup(argv[i]);
-        current->ts->reason = NULL;
+    }
+
+    /* If there were no tests, current is still NULL. */
+    if (current == NULL) {
+        free(listhead);
+        return NULL;
     }
 
     /* Return the results. */
@@ -1184,11 +1332,11 @@ free_testset(struct testset *ts)
  * frees the test list that's passed in.
  */
 static int
-test_batch(struct testlist *tests, const char *source, const char *build)
+test_batch(struct testlist *tests, const char *source, const char *build,
+           enum test_verbose verbose)
 {
-    size_t length;
-    unsigned int i;
-    unsigned int longest = 0;
+    size_t length, i;
+    size_t longest = 0;
     unsigned int count = 0;
     struct testset *ts;
     struct timeval start, end;
@@ -1227,15 +1375,20 @@ test_batch(struct testlist *tests, const char *source, const char *build)
 
         /* Print out the name of the test file. */
         fputs(ts->file, stdout);
-        for (i = strlen(ts->file); i < longest; i++)
-            putchar('.');
+        if (verbose)
+            fputs("\n\n", stdout);
+        else
+            for (i = strlen(ts->file); i < longest; i++)
+                putchar('.');
         if (isatty(STDOUT_FILENO))
             fflush(stdout);
 
         /* Run the test. */
         ts->path = find_test(ts->file, source, build);
-        succeeded = test_run(ts);
+        succeeded = test_run(ts, verbose);
         fflush(stdout);
+        if (verbose)
+            putchar('\n');
 
         /* Record cumulative statistics. */
         aborted += ts->aborted;
@@ -1328,8 +1481,9 @@ test_single(const char *program, const char *source, const char *build)
 
 
 /*
- * Main routine.  Set the SOURCE and BUILD environment variables and then,
- * given a file listing tests, run each test listed.
+ * Main routine.  Set the C_TAP_SOURCE, C_TAP_BUILD, SOURCE, and BUILD
+ * environment variables and then, given a file listing tests, run each test
+ * listed.
  */
 int
 main(int argc, char *argv[])
@@ -1337,23 +1491,27 @@ main(int argc, char *argv[])
     int option;
     int status = 0;
     int single = 0;
+    enum test_verbose verbose = CONCISE;
+    char *c_tap_source_env = NULL;
+    char *c_tap_build_env = NULL;
     char *source_env = NULL;
     char *build_env = NULL;
+    const char *program;
     const char *shortlist;
     const char *list = NULL;
-    const char *source = SOURCE;
-    const char *build = BUILD;
+    const char *source = C_TAP_SOURCE;
+    const char *build = C_TAP_BUILD;
     struct testlist *tests;
 
-    while ((option = getopt(argc, argv, "b:hl:os:")) != EOF) {
+    program = argv[0];
+    while ((option = getopt(argc, argv, "b:hl:os:v")) != EOF) {
         switch (option) {
         case 'b':
             build = optarg;
             break;
         case 'h':
-            printf(usage_message, argv[0], argv[0], argv[0], usage_extra);
+            printf(usage_message, program, program, program, usage_extra);
             exit(0);
-            break;
         case 'l':
             list = optarg;
             break;
@@ -1363,6 +1521,9 @@ main(int argc, char *argv[])
         case 's':
             source = optarg;
             break;
+        case 'v':
+            verbose = VERBOSE;
+            break;
         default:
             exit(1);
         }
@@ -1370,20 +1531,35 @@ main(int argc, char *argv[])
     argv += optind;
     argc -= optind;
     if ((list == NULL && argc < 1) || (list != NULL && argc > 0)) {
-        fprintf(stderr, usage_message, argv[0], argv[0], argv[0], usage_extra);
+        fprintf(stderr, usage_message, program, program, program, usage_extra);
         exit(1);
     }
 
-    /* Set SOURCE and BUILD environment variables. */
+    /*
+     * If C_TAP_VERBOSE is set in the environment, that also turns on verbose
+     * mode.
+     */
+    if (getenv("C_TAP_VERBOSE") != NULL)
+        verbose = VERBOSE;
+
+    /*
+     * Set C_TAP_SOURCE and C_TAP_BUILD environment variables.  Also set
+     * SOURCE and BUILD for backward compatibility, although we're trying to
+     * migrate to the ones with a C_TAP_* prefix.
+     */
     if (source != NULL) {
-        source_env = xmalloc(strlen("SOURCE=") + strlen(source) + 1);
-        sprintf(source_env, "SOURCE=%s", source);
+        c_tap_source_env = concat("C_TAP_SOURCE=", source, (const char *) 0);
+        if (putenv(c_tap_source_env) != 0)
+            sysdie("cannot set C_TAP_SOURCE in the environment");
+        source_env = concat("SOURCE=", source, (const char *) 0);
         if (putenv(source_env) != 0)
             sysdie("cannot set SOURCE in the environment");
     }
     if (build != NULL) {
-        build_env = xmalloc(strlen("BUILD=") + strlen(build) + 1);
-        sprintf(build_env, "BUILD=%s", build);
+        c_tap_build_env = concat("C_TAP_BUILD=", build, (const char *) 0);
+        if (putenv(c_tap_build_env) != 0)
+            sysdie("cannot set C_TAP_BUILD in the environment");
+        build_env = concat("BUILD=", build, (const char *) 0);
         if (putenv(build_env) != 0)
             sysdie("cannot set BUILD in the environment");
     }
@@ -1399,19 +1575,23 @@ main(int argc, char *argv[])
             shortlist++;
         printf(banner, shortlist);
         tests = read_test_list(list);
-        status = test_batch(tests, source, build) ? 0 : 1;
+        status = test_batch(tests, source, build, verbose) ? 0 : 1;
     } else {
         tests = build_test_list(argv, argc);
-        status = test_batch(tests, source, build) ? 0 : 1;
+        status = test_batch(tests, source, build, verbose) ? 0 : 1;
     }
 
     /* For valgrind cleanliness, free all our memory. */
     if (source_env != NULL) {
+        putenv((char *) "C_TAP_SOURCE=");
         putenv((char *) "SOURCE=");
+        free(c_tap_source_env);
         free(source_env);
     }
     if (build_env != NULL) {
+        putenv((char *) "C_TAP_BUILD=");
         putenv((char *) "BUILD=");
+        free(c_tap_build_env);
         free(build_env);
     }
     exit(status);
index bedcc35daaeb1f17b54cf607cb618fd77810a3a1..c244e05b197751024e0ef2f56419a1e3753e79f3 100644 (file)
  * up the TAP output format, or finding things in the test environment.
  *
  * This file is part of C TAP Harness.  The current version plus supporting
- * documentation is at <http://www.eyrie.org/~eagle/software/c-tap-harness/>.
+ * documentation is at <https://www.eyrie.org/~eagle/software/c-tap-harness/>.
  *
- * Copyright 2009, 2010, 2011, 2012, 2013 Russ Allbery <eagle@eyrie.org>
+ * Copyright 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016
+ *     Russ Allbery <eagle@eyrie.org>
  * Copyright 2001, 2002, 2004, 2005, 2006, 2007, 2008, 2011, 2012, 2013, 2014
  *     The Board of Trustees of the Leland Stanford Junior University
  *
@@ -36,6 +37,7 @@
  */
 
 #include <errno.h>
+#include <limits.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -104,7 +106,7 @@ static struct cleanup_func *cleanup_funcs = NULL;
 /*
  * Registered diag files.  Any output found in these files will be printed out
  * as if it were passed to diag() before any other output we do.  This allows
- * background processes to log to a file and have that output interleved with
+ * background processes to log to a file and have that output interleaved with
  * the test output.
  */
 struct diag_file {
@@ -135,6 +137,52 @@ static struct diag_file *diag_files = NULL;
     } while (0)
 
 
+/*
+ * Form a new string by concatenating multiple strings.  The arguments must be
+ * terminated by (const char *) 0.
+ *
+ * This function only exists because we can't assume asprintf.  We can't
+ * simulate asprintf with snprintf because we're only assuming SUSv3, which
+ * does not require that snprintf with a NULL buffer return the required
+ * length.  When those constraints are relaxed, this should be ripped out and
+ * replaced with asprintf or a more trivial replacement with snprintf.
+ */
+static char *
+concat(const char *first, ...)
+{
+    va_list args;
+    char *result;
+    const char *string;
+    size_t offset;
+    size_t length = 0;
+
+    /*
+     * Find the total memory required.  Ensure we don't overflow length.  See
+     * the comment for breallocarray for why we're using UINT_MAX here.
+     */
+    va_start(args, first);
+    for (string = first; string != NULL; string = va_arg(args, const char *)) {
+        if (length >= UINT_MAX - strlen(string))
+            bail("strings too long in concat");
+        length += strlen(string);
+    }
+    va_end(args);
+    length++;
+
+    /* Create the string. */
+    result = bmalloc(length);
+    va_start(args, first);
+    offset = 0;
+    for (string = first; string != NULL; string = va_arg(args, const char *)) {
+        memcpy(result + offset, string, strlen(string));
+        offset += strlen(string);
+    }
+    va_end(args);
+    result[offset] = '\0';
+    return result;
+}
+
+
 /*
  * Check all registered diag_files for any output.  We only print out the
  * output if we see a complete line; otherwise, we wait for the next newline.
@@ -145,7 +193,7 @@ check_diag_files(void)
     struct diag_file *file;
     fpos_t where;
     size_t length;
-    int incomplete;
+    int size, incomplete;
 
     /*
      * Walk through each file and read each line of output available.  The
@@ -169,7 +217,8 @@ check_diag_files(void)
         /* Continue until we get EOF or an incomplete line of data. */
         incomplete = 0;
         while (!feof(file->file) && !incomplete) {
-            if (fgets(file->buffer, file->bufsize, file->file) == NULL) {
+            size = file->bufsize > INT_MAX ? INT_MAX : (int) file->bufsize;
+            if (fgets(file->buffer, size, file->file) == NULL) {
                 if (ferror(file->file))
                     sysbail("cannot read from %s", file->name);
                 continue;
@@ -177,13 +226,16 @@ check_diag_files(void)
 
             /*
              * See if the line ends in a newline.  If not, see which error
-             * case we have.
+             * case we have.  Use UINT_MAX as a substitute for SIZE_MAX (see
+             * the comment for breallocarray).
              */
             length = strlen(file->buffer);
             if (file->buffer[length - 1] != '\n') {
                 if (length < file->bufsize - 1)
                     incomplete = 1;
                 else {
+                    if (file->bufsize >= UINT_MAX - BUFSIZ)
+                        sysbail("line too long in %s", file->name);
                     file->bufsize += BUFSIZ;
                     file->buffer = brealloc(file->buffer, file->bufsize);
                 }
@@ -349,7 +401,7 @@ skip_all(const char *format, ...)
  * Takes a boolean success value and assumes the test passes if that value
  * is true and fails if that value is false.
  */
-void
+int
 ok(int success, const char *format, ...)
 {
     fflush(stderr);
@@ -359,13 +411,14 @@ ok(int success, const char *format, ...)
         _failed++;
     PRINT_DESC(" - ", format);
     putchar('\n');
+    return success;
 }
 
 
 /*
  * Same as ok(), but takes the format arguments as a va_list.
  */
-void
+int
 okv(int success, const char *format, va_list args)
 {
     fflush(stderr);
@@ -378,6 +431,7 @@ okv(int success, const char *format, va_list args)
         vprintf(format, args);
     }
     putchar('\n');
+    return success;
 }
 
 
@@ -398,20 +452,21 @@ skip(const char *reason, ...)
 /*
  * Report the same status on the next count tests.
  */
-void
-ok_block(unsigned long count, int status, const char *format, ...)
+int
+ok_block(unsigned long count, int success, const char *format, ...)
 {
     unsigned long i;
 
     fflush(stderr);
     check_diag_files();
     for (i = 0; i < count; i++) {
-        printf("%sok %lu", status ? "" : "not ", testnum++);
-        if (!status)
+        printf("%sok %lu", success ? "" : "not ", testnum++);
+        if (!success)
             _failed++;
         PRINT_DESC(" - ", format);
         putchar('\n');
     }
+    return success;
 }
 
 
@@ -437,12 +492,15 @@ skip_block(unsigned long count, const char *reason, ...)
  * Takes an expected integer and a seen integer and assumes the test passes
  * if those two numbers match.
  */
-void
+int
 is_int(long wanted, long seen, const char *format, ...)
 {
+    int success;
+
     fflush(stderr);
     check_diag_files();
-    if (wanted == seen)
+    success = (wanted == seen);
+    if (success)
         printf("ok %lu", testnum++);
     else {
         diag("wanted: %ld", wanted);
@@ -452,6 +510,7 @@ is_int(long wanted, long seen, const char *format, ...)
     }
     PRINT_DESC(" - ", format);
     putchar('\n');
+    return success;
 }
 
 
@@ -459,16 +518,19 @@ is_int(long wanted, long seen, const char *format, ...)
  * Takes a string and what the string should be, and assumes the test passes
  * if those strings match (using strcmp).
  */
-void
+int
 is_string(const char *wanted, const char *seen, const char *format, ...)
 {
+    int success;
+
     if (wanted == NULL)
         wanted = "(null)";
     if (seen == NULL)
         seen = "(null)";
     fflush(stderr);
     check_diag_files();
-    if (strcmp(wanted, seen) == 0)
+    success = (strcmp(wanted, seen) == 0);
+    if (success)
         printf("ok %lu", testnum++);
     else {
         diag("wanted: %s", wanted);
@@ -478,6 +540,7 @@ is_string(const char *wanted, const char *seen, const char *format, ...)
     }
     PRINT_DESC(" - ", format);
     putchar('\n');
+    return success;
 }
 
 
@@ -485,12 +548,15 @@ is_string(const char *wanted, const char *seen, const char *format, ...)
  * Takes an expected unsigned long and a seen unsigned long and assumes the
  * test passes if the two numbers match.  Otherwise, reports them in hex.
  */
-void
+int
 is_hex(unsigned long wanted, unsigned long seen, const char *format, ...)
 {
+    int success;
+
     fflush(stderr);
     check_diag_files();
-    if (wanted == seen)
+    success = (wanted == seen);
+    if (success)
         printf("ok %lu", testnum++);
     else {
         diag("wanted: %lx", (unsigned long) wanted);
@@ -500,6 +566,7 @@ is_hex(unsigned long wanted, unsigned long seen, const char *format, ...)
     }
     PRINT_DESC(" - ", format);
     putchar('\n');
+    return success;
 }
 
 
@@ -547,9 +614,10 @@ sysbail(const char *format, ...)
 
 
 /*
- * Report a diagnostic to stderr.
+ * Report a diagnostic to stderr.  Always returns 1 to allow embedding in
+ * compound statements.
  */
-void
+int
 diag(const char *format, ...)
 {
     va_list args;
@@ -562,13 +630,15 @@ diag(const char *format, ...)
     vprintf(format, args);
     va_end(args);
     printf("\n");
+    return 1;
 }
 
 
 /*
- * Report a diagnostic to stderr, appending strerror(errno).
+ * Report a diagnostic to stderr, appending strerror(errno).  Always returns 1
+ * to allow embedding in compound statements.
  */
-void
+int
 sysdiag(const char *format, ...)
 {
     va_list args;
@@ -582,6 +652,7 @@ sysdiag(const char *format, ...)
     vprintf(format, args);
     va_end(args);
     printf(": %s\n", strerror(oerrno));
+    return 1;
 }
 
 
@@ -679,6 +750,32 @@ brealloc(void *p, size_t size)
 }
 
 
+/*
+ * The same as brealloc, but determine the size by multiplying an element
+ * count by a size, similar to calloc.  The multiplication is checked for
+ * integer overflow.
+ *
+ * We should technically use SIZE_MAX here for the overflow check, but
+ * SIZE_MAX is C99 and we're only assuming C89 + SUSv3, which does not
+ * guarantee that it exists.  They do guarantee that UINT_MAX exists, and we
+ * can assume that UINT_MAX <= SIZE_MAX.
+ *
+ * (In theory, C89 and C99 permit size_t to be smaller than unsigned int, but
+ * I disbelieve in the existence of such systems and they will have to cope
+ * without overflow checks.)
+ */
+void *
+breallocarray(void *p, size_t n, size_t size)
+{
+    if (n > 0 && UINT_MAX / n <= size)
+        bail("reallocarray too large");
+    p = realloc(p, n * size);
+    if (p == NULL)
+        sysbail("failed to realloc %lu bytes", (unsigned long) (n * size));
+    return p;
+}
+
+
 /*
  * Copy a string, reporting a fatal error with bail on failure.
  */
@@ -712,7 +809,7 @@ bstrndup(const char *s, size_t n)
     /* Don't assume that the source string is nul-terminated. */
     for (p = s; (size_t) (p - s) < n && *p != '\0'; p++)
         ;
-    length = p - s;
+    length = (size_t) (p - s);
     copy = malloc(length + 1);
     if (p == NULL)
         sysbail("failed to strndup %lu bytes", (unsigned long) length);
@@ -723,31 +820,24 @@ bstrndup(const char *s, size_t n)
 
 
 /*
- * Locate a test file.  Given the partial path to a file, look under BUILD and
- * then SOURCE for the file and return the full path to the file.  Returns
- * NULL if the file doesn't exist.  A non-NULL return should be freed with
- * test_file_path_free().
- *
- * This function uses sprintf because it attempts to be independent of all
- * other portability layers.  The use immediately after a memory allocation
- * should be safe without using snprintf or strlcpy/strlcat.
+ * Locate a test file.  Given the partial path to a file, look under
+ * C_TAP_BUILD and then C_TAP_SOURCE for the file and return the full path to
+ * the file.  Returns NULL if the file doesn't exist.  A non-NULL return
+ * should be freed with test_file_path_free().
  */
 char *
 test_file_path(const char *file)
 {
     char *base;
     char *path = NULL;
-    size_t length;
-    const char *envs[] = { "BUILD", "SOURCE", NULL };
+    const char *envs[] = { "C_TAP_BUILD", "C_TAP_SOURCE", NULL };
     int i;
 
     for (i = 0; envs[i] != NULL; i++) {
         base = getenv(envs[i]);
         if (base == NULL)
             continue;
-        length = strlen(base) + 1 + strlen(file) + 1;
-        path = bmalloc(length);
-        sprintf(path, "%s/%s", base, file);
+        path = concat(base, "/", file, (const char *) 0);
         if (access(path, R_OK) == 0)
             break;
         free(path);
@@ -770,7 +860,7 @@ test_file_path_free(char *path)
 
 
 /*
- * Create a temporary directory, tmp, under BUILD if set and the current
+ * Create a temporary directory, tmp, under C_TAP_BUILD if set and the current
  * directory if it does not.  Returns the path to the temporary directory in
  * newly allocated memory, and calls bail on any failure.  The return value
  * should be freed with test_tmpdir_free.
@@ -784,14 +874,11 @@ test_tmpdir(void)
 {
     const char *build;
     char *path = NULL;
-    size_t length;
 
-    build = getenv("BUILD");
+    build = getenv("C_TAP_BUILD");
     if (build == NULL)
         build = ".";
-    length = strlen(build) + strlen("/tmp") + 1;
-    path = bmalloc(length);
-    sprintf(path, "%s/tmp", build);
+    path = concat(build, "/tmp", (const char *) 0);
     if (access(path, X_OK) < 0)
         if (mkdir(path, 0777) < 0)
             sysbail("error creating temporary directory %s", path);
index 166804b40cc400257d1c0ea687ee828b1ed86405..a4b1a61dd88a1880e950a42e9b2db4f747ca61be 100644 (file)
@@ -2,9 +2,10 @@
  * Basic utility routines for the TAP protocol.
  *
  * This file is part of C TAP Harness.  The current version plus supporting
- * documentation is at <http://www.eyrie.org/~eagle/software/c-tap-harness/>.
+ * documentation is at <https://www.eyrie.org/~eagle/software/c-tap-harness/>.
  *
- * Copyright 2009, 2010, 2011, 2012, 2013 Russ Allbery <eagle@eyrie.org>
+ * Copyright 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016
+ *     Russ Allbery <eagle@eyrie.org>
  * Copyright 2001, 2002, 2004, 2005, 2006, 2007, 2008, 2011, 2012, 2014
  *     The Board of Trustees of the Leland Stanford Junior University
  *
@@ -67,26 +68,34 @@ void skip_all(const char *format, ...)
 /*
  * Basic reporting functions.  The okv() function is the same as ok() but
  * takes the test description as a va_list to make it easier to reuse the
- * reporting infrastructure when writing new tests.
+ * reporting infrastructure when writing new tests.  ok() and okv() return the
+ * value of the success argument.
  */
-void ok(int success, const char *format, ...)
+int ok(int success, const char *format, ...)
     __attribute__((__format__(printf, 2, 3)));
-void okv(int success, const char *format, va_list args);
+int okv(int success, const char *format, va_list args)
+    __attribute__((__format__(printf, 2, 0)));
 void skip(const char *reason, ...)
     __attribute__((__format__(printf, 1, 2)));
 
-/* Report the same status on, or skip, the next count tests. */
-void ok_block(unsigned long count, int success, const char *format, ...)
+/*
+ * Report the same status on, or skip, the next count tests.  ok_block()
+ * returns the value of the success argument.
+ */
+int ok_block(unsigned long count, int success, const char *format, ...)
     __attribute__((__format__(printf, 3, 4)));
 void skip_block(unsigned long count, const char *reason, ...)
     __attribute__((__format__(printf, 2, 3)));
 
-/* Check an expected value against a seen value. */
-void is_int(long wanted, long seen, const char *format, ...)
+/*
+ * Check an expected value against a seen value.  Returns true if the test
+ * passes and false if it fails.
+ */
+int is_int(long wanted, long seen, const char *format, ...)
     __attribute__((__format__(printf, 3, 4)));
-void is_string(const char *wanted, const char *seen, const char *format, ...)
+int is_string(const char *wanted, const char *seen, const char *format, ...)
     __attribute__((__format__(printf, 3, 4)));
-void is_hex(unsigned long wanted, unsigned long seen, const char *format, ...)
+int is_hex(unsigned long wanted, unsigned long seen, const char *format, ...)
     __attribute__((__format__(printf, 3, 4)));
 
 /* Bail out with an error.  sysbail appends strerror(errno). */
@@ -96,9 +105,9 @@ void sysbail(const char *format, ...)
     __attribute__((__noreturn__, __nonnull__, __format__(printf, 1, 2)));
 
 /* Report a diagnostic to stderr prefixed with #. */
-void diag(const char *format, ...)
+int diag(const char *format, ...)
     __attribute__((__nonnull__, __format__(printf, 1, 2)));
-void sysdiag(const char *format, ...)
+int sysdiag(const char *format, ...)
     __attribute__((__nonnull__, __format__(printf, 1, 2)));
 
 /*
@@ -118,6 +127,8 @@ void *bcalloc(size_t, size_t)
     __attribute__((__alloc_size__(1, 2), __malloc__, __warn_unused_result__));
 void *bmalloc(size_t)
     __attribute__((__alloc_size__(1), __malloc__, __warn_unused_result__));
+void *breallocarray(void *, size_t, size_t)
+    __attribute__((__alloc_size__(2, 3), __malloc__, __warn_unused_result__));
 void *brealloc(void *, size_t)
     __attribute__((__alloc_size__(2), __malloc__, __warn_unused_result__));
 char *bstrdup(const char *)
@@ -126,16 +137,16 @@ char *bstrndup(const char *, size_t)
     __attribute__((__malloc__, __nonnull__, __warn_unused_result__));
 
 /*
- * Find a test file under BUILD or SOURCE, returning the full path.  The
- * returned path should be freed with test_file_path_free().
+ * Find a test file under C_TAP_BUILD or C_TAP_SOURCE, returning the full
+ * path.  The returned path should be freed with test_file_path_free().
  */
 char *test_file_path(const char *file)
     __attribute__((__malloc__, __nonnull__, __warn_unused_result__));
 void test_file_path_free(char *path);
 
 /*
- * Create a temporary directory relative to BUILD and return the path.  The
- * returned path should be freed with test_tmpdir_free.
+ * Create a temporary directory relative to C_TAP_BUILD and return the path.
+ * The returned path should be freed with test_tmpdir_free().
  */
 char *test_tmpdir(void)
     __attribute__((__malloc__, __warn_unused_result__));
@@ -146,7 +157,7 @@ void test_tmpdir_free(char *path);
  * registered functions will be run during atexit handling (and are therefore
  * subject to all the same constraints and caveats as atexit functions).
  *
- * The function must return void and will be passed two argument, an int that
+ * The function must return void and will be passed two arguments: an int that
  * will be true if the test completed successfully and false otherwise, and an
  * int that will be true if the cleanup function is run in the primary process
  * (the one that called plan or plan_lazy) and false otherwise.
index 578a8583cb50518310462fd228706a106973e956..5551fbc8d35776e1b640440054e8adeadff438e6 100644 (file)
@@ -12,7 +12,7 @@
  * are available.
  *
  * The canonical version of this file is maintained in the rra-c-util package,
- * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+ * which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
  *
  * Written by Russ Allbery <eagle@eyrie.org>
  * Copyright 2006, 2007, 2009, 2010, 2011, 2012, 2013, 2014
@@ -55,7 +55,9 @@
  * Disable the requirement that format strings be literals, since it's easier
  * to handle the possible patterns for kinit commands as an array.
  */
-#pragma GCC diagnostic ignored "-Wformat-nonliteral"
+#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 2) || defined(__clang__)
+# pragma GCC diagnostic ignored "-Wformat-nonliteral"
+#endif
 
 
 /*
@@ -219,6 +221,8 @@ kerberos_free(void)
         free(config->userprinc);
         free(config->username);
         free(config->password);
+        free(config->pkinit_principal);
+        free(config->pkinit_cert);
         free(config);
         config = NULL;
     }
@@ -350,6 +354,31 @@ kerberos_setup(enum kerberos_needs needs)
     }
     test_file_path_free(path);
 
+    /*
+     * If we have PKINIT configuration, read it and fill out the relevant
+     * members of our config struct.
+     */
+    path = test_file_path("config/pkinit-principal");
+    if (path != NULL)
+        file = fopen(path, "r");
+    if (file != NULL) {
+        if (fgets(buffer, sizeof(buffer), file) == NULL)
+            bail("cannot read %s", path);
+        if (buffer[strlen(buffer) - 1] != '\n')
+            bail("no newline in %s", path);
+        buffer[strlen(buffer) - 1] = '\0';
+        fclose(file);
+        test_file_path_free(path);
+        path = test_file_path("config/pkinit-cert");
+        if (path != NULL) {
+            config->pkinit_principal = bstrdup(buffer);
+            config->pkinit_cert = bstrdup(path);
+        }
+    }
+    test_file_path_free(path);
+    if (config->pkinit_cert == NULL && (needs & TAP_KRB_NEEDS_PKINIT) != 0)
+        skip_all("PKINIT tests not configured");
+
     /*
      * Register the cleanup function so that the caller doesn't have to do
      * explicit cleanup.
index 8be0add4c10cef80bcf2a99d7a02843b0623bc50..c0e7a1bd363edf41b9052bb385145a4482965cc1 100644 (file)
@@ -2,7 +2,7 @@
  * Utility functions for tests that use Kerberos.
  *
  * The canonical version of this file is maintained in the rra-c-util package,
- * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+ * which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
  *
  * Written by Russ Allbery <eagle@eyrie.org>
  * Copyright 2006, 2007, 2009, 2011, 2012, 2013, 2014
@@ -46,17 +46,21 @@ struct kerberos_config {
     char *username;             /* The local (non-realm) part of principal. */
     char *realm;                /* The realm part of the principal. */
     char *password;             /* The password. */
+    char *pkinit_principal;     /* Principal for PKINIT authentication. */
+    char *pkinit_cert;          /* Path to certificates for PKINIT. */
 };
 
 /*
  * Whether to skip all tests (by calling skip_all) in kerberos_setup if
- * certain configuration information isn't available.
+ * certain configuration information isn't available.  "_BOTH" means that the
+ * tests require both keytab and password, but PKINIT is not required.
  */
 enum kerberos_needs {
     TAP_KRB_NEEDS_NONE     = 0x00,
     TAP_KRB_NEEDS_KEYTAB   = 0x01,
     TAP_KRB_NEEDS_PASSWORD = 0x02,
-    TAP_KRB_NEEDS_BOTH     = 0x01 | 0x02
+    TAP_KRB_NEEDS_BOTH     = 0x01 | 0x02,
+    TAP_KRB_NEEDS_PKINIT   = 0x04
 };
 
 BEGIN_DECLS
@@ -104,11 +108,11 @@ void kerberos_cleanup_conf(void);
 
 /* Bail out with an error, appending the Kerberos error message. */
 void bail_krb5(krb5_context, krb5_error_code, const char *format, ...)
-    __attribute__((__noreturn__, __nonnull__, __format__(printf, 3, 4)));
+    __attribute__((__noreturn__, __nonnull__(3), __format__(printf, 3, 4)));
 
 /* Report a diagnostic with Kerberos error to stderr prefixed with #. */
 void diag_krb5(krb5_context, krb5_error_code, const char *format, ...)
-    __attribute__((__nonnull__, __format__(printf, 3, 4)));
+    __attribute__((__nonnull__(3), __format__(printf, 3, 4)));
 
 /*
  * Given a Kerberos context and the path to a keytab, retrieve the principal
index 9731032addeb85b2770248d7725ca07a0d6cdeeb..a7aee0fef31293cb1695de32c83e72be0b6185b6 100644 (file)
@@ -7,10 +7,10 @@
 #
 # This file provides a TAP-compatible shell function library useful for
 # writing test cases.  It is part of C TAP Harness, which can be found at
-# <http://www.eyrie.org/~eagle/software/c-tap-harness/>.
+# <https://www.eyrie.org/~eagle/software/c-tap-harness/>.
 #
 # Written by Russ Allbery <eagle@eyrie.org>
-# Copyright 2009, 2010, 2011, 2012 Russ Allbery <eagle@eyrie.org>
+# Copyright 2009, 2010, 2011, 2012, 2016 Russ Allbery <eagle@eyrie.org>
 # Copyright 2006, 2007, 2008, 2013
 #     The Board of Trustees of the Leland Stanford Junior University
 #
@@ -212,32 +212,32 @@ diag () {
     echo '#' "$@"
 }
 
-# Search for the given file first in $BUILD and then in $SOURCE and echo the
-# path where the file was found, or the empty string if the file wasn't
-# found.
+# Search for the given file first in $C_TAP_BUILD and then in $C_TAP_SOURCE
+# and echo the path where the file was found, or the empty string if the file
+# wasn't found.
 #
 # This macro uses puts, so don't run it using backticks inside double quotes
 # or bizarre quoting behavior will happen with Solaris sh.
 test_file_path () {
-    if [ -n "$BUILD" ] && [ -f "$BUILD/$1" ] ; then
-        puts "$BUILD/$1"
-    elif [ -n "$SOURCE" ] && [ -f "$SOURCE/$1" ] ; then
-        puts "$SOURCE/$1"
+    if [ -n "$C_TAP_BUILD" ] && [ -f "$C_TAP_BUILD/$1" ] ; then
+        puts "$C_TAP_BUILD/$1"
+    elif [ -n "$C_TAP_SOURCE" ] && [ -f "$C_TAP_SOURCE/$1" ] ; then
+        puts "$C_TAP_SOURCE/$1"
     else
         echo ''
     fi
 }
 
-# Create $BUILD/tmp for use by tests for storing temporary files and return
-# the path (via standard output).
+# Create $C_TAP_BUILD/tmp for use by tests for storing temporary files and
+# return the path (via standard output).
 #
 # This macro uses puts, so don't run it using backticks inside double quotes
 # or bizarre quoting behavior will happen with Solaris sh.
 test_tmpdir () {
-    if [ -z "$BUILD" ] ; then
+    if [ -z "$C_TAP_BUILD" ] ; then
         tap_tmpdir="./tmp"
     else
-        tap_tmpdir="$BUILD"/tmp
+        tap_tmpdir="$C_TAP_BUILD"/tmp
     fi
     if [ ! -d "$tap_tmpdir" ] ; then
         mkdir "$tap_tmpdir" || bail "Error creating $tap_tmpdir"
index 04cc420ddc76b7b08cd89fc00693251d8b9362d5..2cd1e87a127edd4cc30bcb61dc69cbeab79b33cf 100644 (file)
@@ -6,9 +6,9 @@
  * everyone can pull them in.
  *
  * This file is part of C TAP Harness.  The current version plus supporting
- * documentation is at <http://www.eyrie.org/~eagle/software/c-tap-harness/>.
+ * documentation is at <https://www.eyrie.org/~eagle/software/c-tap-harness/>.
  *
- * Copyright 2008, 2012, 2013 Russ Allbery <eagle@eyrie.org>
+ * Copyright 2008, 2012, 2013, 2015 Russ Allbery <eagle@eyrie.org>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
  * variadic macro support.
  */
 #if !defined(__attribute__) && !defined(__alloc_size__)
-# if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 3)
-#  define __alloc_size__(spec, args...) /* empty */
+# if defined(__GNUC__) && !defined(__clang__)
+#  if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 3)
+#   define __alloc_size__(spec, args...) /* empty */
+#  endif
 # endif
 #endif
 
index 12be88bcab25373632cf4f9644b88e3f4c362876..bcd653240f4676ae102f4694385450db00dc81bf 100644 (file)
@@ -5,31 +5,6 @@
 # by both C packages with Automake and by stand-alone Perl modules.  See
 # Test::RRA::Automake for additional functions specifically for C Automake
 # distributions.
-#
-# The canonical version of this file is maintained in the rra-c-util package,
-# which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
-#
-# Written by Russ Allbery <eagle@eyrie.org>
-# Copyright 2013, 2014
-#     The Board of Trustees of the Leland Stanford Junior University
-#
-# Permission is hereby granted, free of charge, to any person obtaining a
-# copy of this software and associated documentation files (the "Software"),
-# to deal in the Software without restriction, including without limitation
-# the rights to use, copy, modify, merge, publish, distribute, sublicense,
-# and/or sell copies of the Software, and to permit persons to whom the
-# Software is furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
-# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-# DEALINGS IN THE SOFTWARE.
 
 package Test::RRA;
 
@@ -38,6 +13,7 @@ use strict;
 use warnings;
 
 use Exporter;
+use File::Temp;
 use Test::More;
 
 # For Perl 5.006 compatibility.
@@ -51,12 +27,56 @@ our (@EXPORT_OK, @ISA, $VERSION);
 # consistency is good).
 BEGIN {
     @ISA       = qw(Exporter);
-    @EXPORT_OK = qw(skip_unless_author skip_unless_automated use_prereq);
+    @EXPORT_OK = qw(
+      is_file_contents skip_unless_author skip_unless_automated use_prereq
+    );
 
     # This version should match the corresponding rra-c-util release, but with
     # two digits for the minor version, including a leading zero if necessary,
     # so that it will sort properly.
-    $VERSION = '5.04';
+    $VERSION = '6.02';
+}
+
+# Compare a string to the contents of a file, similar to the standard is()
+# function, but to show the line-based unified diff between them if they
+# differ.
+#
+# $got      - The output that we received
+# $expected - The path to the file containing the expected output
+# $message  - The message to use when reporting the test results
+#
+# Returns: undef
+#  Throws: Exception on failure to read or write files or run diff
+sub is_file_contents {
+    my ($got, $expected, $message) = @_;
+
+    # If they're equal, this is simple.
+    open(my $fh, '<', $expected) or BAIL_OUT("Cannot open $expected: $!\n");
+    my $data = do { local $/ = undef; <$fh> };
+    close($fh) or BAIL_OUT("Cannot close $expected: $!\n");
+    if ($got eq $data) {
+        is($got, $data, $message);
+        return;
+    }
+
+    # Otherwise, we show a diff, but only if we have IPC::System::Simple.
+    eval { require IPC::System::Simple };
+    if ($@) {
+        ok(0, $message);
+        return;
+    }
+
+    # They're not equal.  Write out what we got so that we can run diff.
+    my $tmp     = File::Temp->new();
+    my $tmpname = $tmp->filename;
+    print {$tmp} $got or BAIL_OUT("Cannot write to $tmpname: $!\n");
+    my @command = ('diff', '-u', $expected, $tmpname);
+    my $diff = IPC::System::Simple::capturex([0 .. 1], @command);
+    diag($diff);
+
+    # Remove the temporary file and report failure.
+    ok(0, $message);
+    return;
 }
 
 # Skip this test unless author tests are requested.  Takes a short description
@@ -153,7 +173,7 @@ __END__
 
 =for stopwords
 Allbery Allbery's DESC bareword sublicense MERCHANTABILITY NONINFRINGEMENT
-rra-c-util
+rra-c-util CPAN
 
 =head1 NAME
 
@@ -176,46 +196,45 @@ Test::RRA - Support functions for Perl tests
 
 =head1 DESCRIPTION
 
-This module collects utility functions that are useful for Perl test
-scripts.  It assumes Russ Allbery's Perl module layout and test
-conventions and will only be useful for other people if they use the
-same conventions.
+This module collects utility functions that are useful for Perl test scripts.
+It assumes Russ Allbery's Perl module layout and test conventions and will
+only be useful for other people if they use the same conventions.
 
 =head1 FUNCTIONS
 
-None of these functions are imported by default.  The ones used by a
-script should be explicitly imported.
+None of these functions are imported by default.  The ones used by a script
+should be explicitly imported.
 
 =over 4
 
 =item skip_unless_author(DESC)
 
-Checks whether AUTHOR_TESTING is set in the environment and skips the
-whole test (by calling C<plan skip_all> from Test::More) if it is not.
-DESC is a description of the tests being skipped.  A space and C<only run
-for author> will be appended to it and used as the skip reason.
+Checks whether AUTHOR_TESTING is set in the environment and skips the whole
+test (by calling C<plan skip_all> from Test::More) if it is not.  DESC is a
+description of the tests being skipped.  A space and C<only run for author>
+will be appended to it and used as the skip reason.
 
 =item skip_unless_automated(DESC)
 
-Checks whether AUTHOR_TESTING, AUTOMATED_TESTING, or RELEASE_TESTING are
-set in the environment and skips the whole test (by calling C<plan
-skip_all> from Test::More) if they are not.  This should be used by tests
-that should not run during end-user installs of the module, but which
-should run as part of CPAN smoke testing and release testing.
+Checks whether AUTHOR_TESTING, AUTOMATED_TESTING, or RELEASE_TESTING are set
+in the environment and skips the whole test (by calling C<plan skip_all> from
+Test::More) if they are not.  This should be used by tests that should not run
+during end-user installs of the module, but which should run as part of CPAN
+smoke testing and release testing.
 
 DESC is a description of the tests being skipped.  A space and C<normally
 skipped> will be appended to it and used as the skip reason.
 
 =item use_prereq(MODULE[, VERSION][, IMPORT ...])
 
-Attempts to load MODULE with the given VERSION and import arguments.  If
-this fails for any reason, the test will be skipped (by calling C<plan
-skip_all> from Test::More) with a skip reason saying that MODULE is
-required for the test.
+Attempts to load MODULE with the given VERSION and import arguments.  If this
+fails for any reason, the test will be skipped (by calling C<plan skip_all>
+from Test::More) with a skip reason saying that MODULE is required for the
+test.
 
 VERSION will be passed to C<use> as a version bareword if it looks like a
-version number.  The remaining IMPORT arguments will be passed as the
-value of an array.
+version number.  The remaining IMPORT arguments will be passed as the value of
+an array.
 
 =back
 
@@ -228,33 +247,33 @@ Russ Allbery <eagle@eyrie.org>
 Copyright 2013, 2014 The Board of Trustees of the Leland Stanford Junior
 University
 
-Permission is hereby granted, free of charge, to any person obtaining a
-copy of this software and associated documentation files (the "Software"),
-to deal in the Software without restriction, including without limitation
-the rights to use, copy, modify, merge, publish, distribute, sublicense,
-and/or sell copies of the Software, and to permit persons to whom the
-Software is furnished to do so, subject to the following conditions:
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
 
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
 
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
-THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-DEALINGS IN THE SOFTWARE.
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
 
 =head1 SEE ALSO
 
 Test::More(3), Test::RRA::Automake(3), Test::RRA::Config(3)
 
-This module is maintained in the rra-c-util package.  The current version
-is available from L<http://www.eyrie.org/~eagle/software/rra-c-util/>.
+This module is maintained in the rra-c-util package.  The current version is
+available from L<https://www.eyrie.org/~eagle/software/rra-c-util/>.
 
-The functions to control when tests are run use environment variables
-defined by the L<Lancaster
+The functions to control when tests are run use environment variables defined
+by the L<Lancaster
 Consensus|https://github.com/Perl-Toolchain-Gang/toolchain-site/blob/master/lancaster-consensus.md>.
 
 =cut
index db293fa8a72c4420c2b425ab38df830e8eff9527..429666790eda6e148a5ff0970da7ca780a7cfc10 100644 (file)
@@ -7,33 +7,9 @@
 # require closely following the conventions implemented by the rra-c-util
 # utility collection.
 #
-# All the functions here assume that BUILD and SOURCE are set in the
-# environment.  This is normally done via the C TAP Harness runtests wrapper.
-#
-# The canonical version of this file is maintained in the rra-c-util package,
-# which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
-#
-# Written by Russ Allbery <eagle@eyrie.org>
-# Copyright 2013
-#     The Board of Trustees of the Leland Stanford Junior University
-#
-# Permission is hereby granted, free of charge, to any person obtaining a
-# copy of this software and associated documentation files (the "Software"),
-# to deal in the Software without restriction, including without limitation
-# the rights to use, copy, modify, merge, publish, distribute, sublicense,
-# and/or sell copies of the Software, and to permit persons to whom the
-# Software is furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
-# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-# DEALINGS IN THE SOFTWARE.
+# All the functions here assume that C_TAP_BUILD and C_TAP_SOURCE are set in
+# the environment.  This is normally done via the C TAP Harness runtests
+# wrapper.
 
 package Test::RRA::Automake;
 
@@ -45,6 +21,7 @@ use warnings;
 ## no critic (ClassHierarchies::ProhibitExplicitISA)
 
 use Exporter;
+use File::Find qw(find);
 use File::Spec;
 use Test::More;
 use Test::RRA::Config qw($LIBRARY_PATH);
@@ -59,9 +36,9 @@ BEGIN {
     $PERL_BLIB_ARCH = File::Spec->catdir(qw(perl blib arch));
     $PERL_BLIB_LIB  = File::Spec->catdir(qw(perl blib lib));
 
-    # If BUILD is set, we can come up with better values.
-    if (defined($ENV{BUILD})) {
-        my ($vol, $dirs) = File::Spec->splitpath($ENV{BUILD}, 1);
+    # If C_TAP_BUILD is set, we can come up with better values.
+    if (defined($ENV{C_TAP_BUILD})) {
+        my ($vol, $dirs) = File::Spec->splitpath($ENV{C_TAP_BUILD}, 1);
         my @dirs = File::Spec->splitdir($dirs);
         pop(@dirs);
         $PERL_BLIB_ARCH = File::Spec->catdir(@dirs, qw(perl blib arch));
@@ -82,59 +59,111 @@ our (@EXPORT_OK, @ISA, $VERSION);
 # consistency is good).
 BEGIN {
     @ISA       = qw(Exporter);
-    @EXPORT_OK = qw(automake_setup perl_dirs test_file_path test_tmpdir);
+    @EXPORT_OK = qw(
+      all_files automake_setup perl_dirs test_file_path test_tmpdir
+    );
 
     # This version should match the corresponding rra-c-util release, but with
     # two digits for the minor version, including a leading zero if necessary,
     # so that it will sort properly.
-    $VERSION = '5.04';
+    $VERSION = '6.02';
 }
 
-# Perl directories to skip globally for perl_dirs.  We ignore the perl
-# directory if it exists since, in my packages, it is treated as a Perl module
-# distribution and has its own standalone test suite.
-my @GLOBAL_SKIP = qw(.git perl);
+# Directories to skip globally when looking for all files, or for directories
+# that could contain Perl files.
+my @GLOBAL_SKIP = qw(.git _build autom4te.cache build-aux);
+
+# Additional paths to skip when building a list of all files in the
+# distribution.  This primarily skips build artifacts that aren't interesting
+# to any of the tests.  These match any path component.
+my @FILES_SKIP = qw(.deps .dirstamp .libs config.h.in~ configure);
 
 # The temporary directory created by test_tmpdir, if any.  If this is set,
 # attempt to remove the directory stored here on program exit (but ignore
 # failure to do so).
 my $TMPDIR;
 
+# Returns a list of all files in the distribution.
+#
+# Returns: List of files
+sub all_files {
+    my @files;
+
+    # Turn the skip lists into hashes for ease of querying.
+    my %skip       = map { $_ => 1 } @GLOBAL_SKIP;
+    my %files_skip = map { $_ => 1 } @FILES_SKIP;
+
+    # Wanted function for find.  Prune anything matching either of the skip
+    # lists, or *.lo files, and then add all regular files to the list.
+    my $wanted = sub {
+        my $file = $_;
+        my $path = $File::Find::name;
+        $path =~ s{ \A [.]/ }{}xms;
+        if ($skip{$path} or $files_skip{$file} or $file =~ m{ [.] lo \z }xms) {
+            $File::Find::prune = 1;
+            return;
+        }
+        if (-f $file) {
+            push(@files, $path);
+        }
+    };
+
+    # Do the recursive search and return the results.
+    find($wanted, q{.});
+    return @files;
+}
+
 # Perform initial test setup for running a Perl test in an Automake package.
-# This verifies that BUILD and SOURCE are set and then changes directory to
-# the SOURCE directory by default.  Sets LD_LIBRARY_PATH if the $LIBRARY_PATH
-# configuration option is set.  Calls BAIL_OUT if BUILD or SOURCE are missing
-# or if anything else fails.
+# This verifies that C_TAP_BUILD and C_TAP_SOURCE are set and then changes
+# directory to the C_TAP_SOURCE directory by default.  Sets LD_LIBRARY_PATH if
+# the $LIBRARY_PATH configuration option is set.  Calls BAIL_OUT if
+# C_TAP_BUILD or C_TAP_SOURCE are missing or if anything else fails.
 #
 # $args_ref - Reference to a hash of arguments to configure behavior:
-#   chdir_build - If set to a true value, changes to BUILD instead of SOURCE
+#   chdir_build - If set to a true value, changes to C_TAP_BUILD instead of
+#                 C_TAP_SOURCE
 #
 # Returns: undef
 sub automake_setup {
     my ($args_ref) = @_;
 
-    # Bail if BUILD or SOURCE are not set.
-    if (!$ENV{BUILD}) {
-        BAIL_OUT('BUILD not defined (run under runtests)');
+    # Bail if C_TAP_BUILD or C_TAP_SOURCE are not set.
+    if (!$ENV{C_TAP_BUILD}) {
+        BAIL_OUT('C_TAP_BUILD not defined (run under runtests)');
     }
-    if (!$ENV{SOURCE}) {
-        BAIL_OUT('SOURCE not defined (run under runtests)');
+    if (!$ENV{C_TAP_SOURCE}) {
+        BAIL_OUT('C_TAP_SOURCE not defined (run under runtests)');
     }
 
-    # BUILD or SOURCE will be the test directory.  Change to the parent.
-    my $start = $args_ref->{chdir_build} ? $ENV{BUILD} : $ENV{SOURCE};
+    # C_TAP_BUILD or C_TAP_SOURCE will be the test directory.  Change to the
+    # parent.
+    my $start;
+    if ($args_ref->{chdir_build}) {
+        $start = $ENV{C_TAP_BUILD};
+    } else {
+        $start = $ENV{C_TAP_SOURCE};
+    }
     my ($vol, $dirs) = File::Spec->splitpath($start, 1);
     my @dirs = File::Spec->splitdir($dirs);
     pop(@dirs);
-    if ($dirs[-1] eq File::Spec->updir) {
+
+    # Simplify relative paths at the end of the directory.
+    my $ups = 0;
+    my $i   = $#dirs;
+    while ($i > 2 && $dirs[$i] eq File::Spec->updir) {
+        $ups++;
+        $i--;
+    }
+    for (1 .. $ups) {
         pop(@dirs);
         pop(@dirs);
     }
     my $root = File::Spec->catpath($vol, File::Spec->catdir(@dirs), q{});
     chdir($root) or BAIL_OUT("cannot chdir to $root: $!");
 
-    # If BUILD is a subdirectory of SOURCE, add it to the global ignore list.
-    my ($buildvol, $builddirs) = File::Spec->splitpath($ENV{BUILD}, 1);
+    # If C_TAP_BUILD is a subdirectory of C_TAP_SOURCE, add it to the global
+    # ignore list.
+    my ($buildvol, $builddirs) = File::Spec->splitpath($ENV{C_TAP_BUILD}, 1);
     my @builddirs = File::Spec->splitdir($builddirs);
     pop(@builddirs);
     if ($buildvol eq $vol && @builddirs == @dirs + 1) {
@@ -179,9 +208,11 @@ sub automake_setup {
 sub perl_dirs {
     my ($args_ref) = @_;
 
-    # Add the global skip list.
+    # Add the global skip list.  We also ignore the perl directory if it
+    # exists since, in my packages, it is treated as a Perl module
+    # distribution and has its own standalone test suite.
     my @skip = $args_ref->{skip} ? @{ $args_ref->{skip} } : ();
-    push(@skip, @GLOBAL_SKIP);
+    push(@skip, @GLOBAL_SKIP, 'perl');
 
     # Separate directories to skip under tests from top-level directories.
     my @skip_tests = grep { m{ \A tests/ }xms } @skip;
@@ -196,7 +227,7 @@ sub perl_dirs {
 
     # Build the list of top-level directories to test.
     opendir(my $rootdir, q{.}) or BAIL_OUT("cannot open .: $!");
-    my @dirs = grep { -d $_ && !$skip{$_} } readdir($rootdir);
+    my @dirs = grep { -d && !$skip{$_} } readdir($rootdir);
     closedir($rootdir);
     @dirs = File::Spec->no_upwards(@dirs);
 
@@ -223,9 +254,9 @@ sub perl_dirs {
     return @dirs;
 }
 
-# Find a configuration file for the test suite.  Searches relative to BUILD
-# first and then SOURCE and returns whichever is found first.  Calls BAIL_OUT
-# if the file could not be found.
+# Find a configuration file for the test suite.  Searches relative to
+# C_TAP_BUILD first and then C_TAP_SOURCE and returns whichever is found
+# first.  Calls BAIL_OUT if the file could not be found.
 #
 # $file - Partial path to the file
 #
@@ -233,7 +264,7 @@ sub perl_dirs {
 sub test_file_path {
     my ($file) = @_;
   BASE:
-    for my $base ($ENV{BUILD}, $ENV{SOURCE}) {
+    for my $base ($ENV{C_TAP_BUILD}, $ENV{C_TAP_SOURCE}) {
         next if !defined($base);
         if (-f "$base/$file") {
             return "$base/$file";
@@ -253,11 +284,16 @@ sub test_tmpdir {
     my $path;
 
     # If we already figured out what directory to use, reuse the same path.
-    # Otherwise, create a directory relative to BUILD if set.
+    # Otherwise, create a directory relative to C_TAP_BUILD if set.
     if (defined($TMPDIR)) {
         $path = $TMPDIR;
     } else {
-        my $base = defined($ENV{BUILD}) ? $ENV{BUILD} : File::Spec->curdir;
+        my $base;
+        if (defined($ENV{C_TAP_BUILD})) {
+            $base = $ENV{C_TAP_BUILD};
+        } else {
+            $base = File::Spec->curdir;
+        }
         $path = File::Spec->catdir($base, 'tmp');
     }
 
@@ -288,8 +324,8 @@ END {
 __END__
 
 =for stopwords
-Allbery Automake Automake-aware Automake-based rra-c-util ARGS
-subdirectories sublicense MERCHANTABILITY NONINFRINGEMENT umask
+Allbery Automake Automake-aware Automake-based rra-c-util ARGS subdirectories
+sublicense MERCHANTABILITY NONINFRINGEMENT umask
 
 =head1 NAME
 
@@ -309,75 +345,96 @@ Test::RRA::Automake - Automake-aware support functions for Perl tests
 =head1 DESCRIPTION
 
 This module collects utility functions that are useful for test scripts
-written in Perl and included in a C Automake-based package.  They assume
-the layout of a package that uses rra-c-util and C TAP Harness for the
-test structure.
+written in Perl and included in a C Automake-based package.  They assume the
+layout of a package that uses rra-c-util and C TAP Harness for the test
+structure.
 
 Loading this module will also add the directories C<perl/blib/arch> and
-C<perl/blib/lib> to the Perl library search path, relative to BUILD if
-that environment variable is set.  This is harmless for C Automake
-projects that don't contain an embedded Perl module, and for those
-projects that do, this will allow subsequent C<use> calls to find modules
-that are built as part of the package build process.
+C<perl/blib/lib> to the Perl library search path, relative to C_TAP_BUILD if
+that environment variable is set.  This is harmless for C Automake projects
+that don't contain an embedded Perl module, and for those projects that do,
+this will allow subsequent C<use> calls to find modules that are built as part
+of the package build process.
 
 The automake_setup() function should be called before calling any other
 functions provided by this module.
 
 =head1 FUNCTIONS
 
-None of these functions are imported by default.  The ones used by a
-script should be explicitly imported.  On failure, all of these functions
-call BAIL_OUT (from Test::More).
+None of these functions are imported by default.  The ones used by a script
+should be explicitly imported.  On failure, all of these functions call
+BAIL_OUT (from Test::More).
 
 =over 4
 
+=item all_files()
+
+Returns a list of all "interesting" files in the distribution that a test
+suite may want to look at.  This excludes various products of the build system,
+the build directory if it's under the source directory, and a few other
+uninteresting directories like F<.git>.  The returned paths will be paths
+relative to the root of the package.
+
 =item automake_setup([ARGS])
 
-Verifies that the BUILD and SOURCE environment variables are set and
-then changes directory to the top of the source tree (which is one
-directory up from the SOURCE path, since SOURCE points to the top of
-the tests directory).
+Verifies that the C_TAP_BUILD and C_TAP_SOURCE environment variables are set
+and then changes directory to the top of the source tree (which is one
+directory up from the C_TAP_SOURCE path, since C_TAP_SOURCE points to the top
+of the tests directory).
 
-If ARGS is given, it should be a reference to a hash of configuration
-options.  Only one option is supported: C<chdir_build>.  If it is set
-to a true value, automake_setup() changes directories to the top of
-the build tree instead.
+If ARGS is given, it should be a reference to a hash of configuration options.
+Only one option is supported: C<chdir_build>.  If it is set to a true value,
+automake_setup() changes directories to the top of the build tree instead.
 
 =item perl_dirs([ARGS])
 
 Returns a list of directories that may contain Perl scripts that should be
-tested by test scripts that test all Perl in the source tree (such as
-syntax or coding style checks).  The paths will be simple directory names
-relative to the current directory or two-part directory names under the
-F<tests> directory.  (Directories under F<tests> are broken out separately
-since it's common to want to apply different policies to different
-subdirectories of F<tests>.)
-
-If ARGS is given, it should be a reference to a hash of configuration
-options.  Only one option is supported: C<skip>, whose value should be a
-reference to an array of additional top-level directories or directories
-starting with C<tests/> that should be skipped.
+tested by test scripts that test all Perl in the source tree (such as syntax
+or coding style checks).  The paths will be simple directory names relative to
+the current directory or two-part directory names under the F<tests>
+directory.  (Directories under F<tests> are broken out separately since it's
+common to want to apply different policies to different subdirectories of
+F<tests>.)
+
+If ARGS is given, it should be a reference to a hash of configuration options.
+Only one option is supported: C<skip>, whose value should be a reference to an
+array of additional top-level directories or directories starting with
+C<tests/> that should be skipped.
 
 =item test_file_path(FILE)
 
-Given FILE, which should be a relative path, locates that file relative to
-the test directory in either the source or build tree.  FILE will be
-checked for relative to the environment variable BUILD first, and then
-relative to SOURCE.  test_file_path() returns the full path to FILE or
-calls BAIL_OUT if FILE could not be found.
+Given FILE, which should be a relative path, locates that file relative to the
+test directory in either the source or build tree.  FILE will be checked for
+relative to the environment variable C_TAP_BUILD first, and then relative to
+C_TAP_SOURCE.  test_file_path() returns the full path to FILE or calls
+BAIL_OUT if FILE could not be found.
 
 =item test_tmpdir()
 
-Create a temporary directory for tests to use for transient files and
-return the path to that directory.  The directory is created relative to
-the BUILD environment variable, which must be set.  Permissions on the
+Create a temporary directory for tests to use for transient files and return
+the path to that directory.  The directory is created relative to the
+C_TAP_BUILD environment variable, which must be set.  Permissions on the
 directory are set using the current umask.  test_tmpdir() returns the full
-path to the temporary directory or calls BAIL_OUT if it could not be
-created.
+path to the temporary directory or calls BAIL_OUT if it could not be created.
+
+The directory is automatically removed if possible on program exit.  Failure
+to remove the directory on exit is reported with diag() and otherwise ignored.
+
+=back
+
+=head1 ENVIRONMENT
 
-The directory is automatically removed if possible on program exit.
-Failure to remove the directory on exit is reported with diag() and
-otherwise ignored.
+=over 4
+
+=item C_TAP_BUILD
+
+The root of the tests directory in Automake build directory for this package,
+used to find files as documented above.
+
+=item C_TAP_SOURCE
+
+The root of the tests directory in the source tree for this package, used to
+find files as documented above.
 
 =back
 
@@ -387,35 +444,36 @@ Russ Allbery <eagle@eyrie.org>
 
 =head1 COPYRIGHT AND LICENSE
 
-Copyright 2013 The Board of Trustees of the Leland Stanford Junior
-University
+Copyright 2014, 2015 Russ Allbery <eagle@eyrie.org>
+
+Copyright 2013 The Board of Trustees of the Leland Stanford Junior University
 
-Permission is hereby granted, free of charge, to any person obtaining a
-copy of this software and associated documentation files (the "Software"),
-to deal in the Software without restriction, including without limitation
-the rights to use, copy, modify, merge, publish, distribute, sublicense,
-and/or sell copies of the Software, and to permit persons to whom the
-Software is furnished to do so, subject to the following conditions:
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
 
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
 
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
-THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-DEALINGS IN THE SOFTWARE.
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
 
 =head1 SEE ALSO
 
 Test::More(3), Test::RRA(3), Test::RRA::Config(3)
 
-The C TAP Harness test driver and libraries for TAP-based C testing are
-available from L<http://www.eyrie.org/~eagle/software/c-tap-harness/>.
+This module is maintained in the rra-c-util package.  The current version is
+available from L<https://www.eyrie.org/~eagle/software/rra-c-util/>.
 
-This module is maintained in the rra-c-util package.  The current version
-is available from L<http://www.eyrie.org/~eagle/software/rra-c-util/>.
+The C TAP Harness test driver and libraries for TAP-based C testing are
+available from L<https://www.eyrie.org/~eagle/software/c-tap-harness/>.
 
 =cut
index 6d413164d1b86455f1276745bfc9afe4f720c647..bdb31e60c0f31513c49730ec9ee58834c40cc49d 100644 (file)
@@ -4,9 +4,6 @@
 # configuration file to store some package-specific data.  This module loads
 # that configuration and provides the namespace for the configuration
 # settings.
-#
-# The canonical version of this file is maintained in the rra-c-util package,
-# which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
 
 package Test::RRA::Config;
 
@@ -30,22 +27,23 @@ BEGIN {
     @ISA       = qw(Exporter);
     @EXPORT_OK = qw(
       $COVERAGE_LEVEL @COVERAGE_SKIP_TESTS @CRITIC_IGNORE $LIBRARY_PATH
-      $MINIMUM_VERSION %MINIMUM_VERSION @POD_COVERAGE_EXCLUDE @STRICT_IGNORE
-      @STRICT_PREREQ
+      $MINIMUM_VERSION %MINIMUM_VERSION @MODULE_VERSION_IGNORE
+      @POD_COVERAGE_EXCLUDE @STRICT_IGNORE @STRICT_PREREQ
     );
 
     # This version should match the corresponding rra-c-util release, but with
     # two digits for the minor version, including a leading zero if necessary,
     # so that it will sort properly.
-    $VERSION = '5.04';
+    $VERSION = '6.02';
 }
 
-# If BUILD or SOURCE are set in the environment, look for data/perl.conf under
-# those paths for a C Automake package.  Otherwise, look in t/data/perl.conf
-# for a standalone Perl module.  Don't use Test::RRA::Automake since it may
-# not exist.
+# If C_TAP_BUILD or C_TAP_SOURCE are set in the environment, look for
+# data/perl.conf under those paths for a C Automake package.  Otherwise, look
+# in t/data/perl.conf for a standalone Perl module or tests/data/perl.conf for
+# Perl tests embedded in a larger distribution.  Don't use Test::RRA::Automake
+# since it may not exist.
 our $PATH;
-for my $base ($ENV{BUILD}, $ENV{SOURCE}, 't') {
+for my $base ($ENV{C_TAP_BUILD}, $ENV{C_TAP_SOURCE}, './t', './tests') {
     next if !defined($base);
     my $path = "$base/data/perl.conf";
     if (-r $path) {
@@ -64,6 +62,7 @@ our @CRITIC_IGNORE;
 our $LIBRARY_PATH;
 our $MINIMUM_VERSION = '5.008';
 our %MINIMUM_VERSION;
+our @MODULE_VERSION_IGNORE;
 our @POD_COVERAGE_EXCLUDE;
 our @STRICT_IGNORE;
 our @STRICT_PREREQ;
@@ -71,15 +70,15 @@ our @STRICT_PREREQ;
 # Load the configuration.
 if (!do($PATH)) {
     my $error = $@ || $! || 'loading file did not return true';
-    BAIL_OUT("cannot load data/perl.conf: $error");
+    BAIL_OUT("cannot load $PATH: $error");
 }
 
 1;
 __END__
 
 =for stopwords
-Allbery rra-c-util Automake perlcritic .libs namespace subdirectory
-sublicense MERCHANTABILITY NONINFRINGEMENT
+Allbery rra-c-util Automake perlcritic .libs namespace subdirectory sublicense
+MERCHANTABILITY NONINFRINGEMENT regexes
 
 =head1 NAME
 
@@ -92,19 +91,17 @@ Test::RRA::Config - Perl test configuration
 
 =head1 DESCRIPTION
 
-Test::RRA::Config encapsulates per-package configuration for generic Perl
-test programs that are shared between multiple packages using the
-rra-c-util infrastructure.  It handles locating and loading the test
-configuration file for both C Automake packages and stand-alone Perl
-modules.
+Test::RRA::Config encapsulates per-package configuration for generic Perl test
+programs that are shared between multiple packages using the rra-c-util
+infrastructure.  It handles locating and loading the test configuration file
+for both C Automake packages and stand-alone Perl modules.
 
 Test::RRA::Config looks for a file named F<data/perl.conf> relative to the
-root of the test directory.  That root is taken from the environment
-variables BUILD or SOURCE (in that order) if set, which will be the case
-for C Automake packages using C TAP Harness.  If neither is set, it
-expects the root of the test directory to be a directory named F<t>
-relative to the current directory, which will be the case for stand-alone
-Perl modules.
+root of the test directory.  That root is taken from the environment variables
+C_TAP_BUILD or C_TAP_SOURCE (in that order) if set, which will be the case for
+C Automake packages using C TAP Harness.  If neither is set, it expects the
+root of the test directory to be a directory named F<t> relative to the
+current directory, which will be the case for stand-alone Perl modules.
 
 The following variables are supported:
 
@@ -112,70 +109,75 @@ The following variables are supported:
 
 =item $COVERAGE_LEVEL
 
-The coverage level achieved by the test suite for Perl test coverage
-testing using Test::Strict, as a percentage.  The test will fail if test
-coverage less than this percentage is achieved.  If not given, defaults
-to 100.
+The coverage level achieved by the test suite for Perl test coverage testing
+using Test::Strict, as a percentage.  The test will fail if test coverage less
+than this percentage is achieved.  If not given, defaults to 100.
 
 =item @COVERAGE_SKIP_TESTS
 
 Directories under F<t> whose tests should be skipped when doing coverage
-testing.  This can be tests that won't contribute to coverage or tests
-that don't run properly under Devel::Cover for some reason (such as ones
-that use taint checking).  F<docs> and F<style> will always be skipped
-regardless of this setting.
+testing.  This can be tests that won't contribute to coverage or tests that
+don't run properly under Devel::Cover for some reason (such as ones that use
+taint checking).  F<docs> and F<style> will always be skipped regardless of
+this setting.
 
 =item @CRITIC_IGNORE
 
-Additional directories to ignore when doing recursive perlcritic testing.
-The contents of this directory must be either top-level directory names or
+Additional directories to ignore when doing recursive perlcritic testing.  The
+contents of this directory must be either top-level directory names or
 directory names starting with F<tests/>.
 
 =item $LIBRARY_PATH
 
 Add this directory (or a F<.libs> subdirectory) relative to the top of the
-source tree to LD_LIBRARY_PATH when checking the syntax of Perl modules.
-This may be required to pick up libraries that are used by in-tree Perl
-modules so that Perl scripts can pass a syntax check.
+source tree to LD_LIBRARY_PATH when checking the syntax of Perl modules.  This
+may be required to pick up libraries that are used by in-tree Perl modules so
+that Perl scripts can pass a syntax check.
 
 =item $MINIMUM_VERSION
 
-Default minimum version requirement for included Perl scripts.  If not
-given, defaults to 5.008.
+Default minimum version requirement for included Perl scripts.  If not given,
+defaults to 5.008.
 
 =item %MINIMUM_VERSION
 
 Minimum version exceptions for specific directories.  The keys should be
 minimum versions of Perl to enforce.  The value for each key should be a
-reference to an array of either top-level directory names or directory
-names starting with F<tests/>.  All files in those directories will have
-that minimum Perl version constraint imposed instead of $MINIMUM_VERSION.
+reference to an array of either top-level directory names or directory names
+starting with F<tests/>.  All files in those directories will have that
+minimum Perl version constraint imposed instead of $MINIMUM_VERSION.
+
+=item @MODULE_VERSION_IGNORE
+
+File names to ignore when checking that all modules in a distribution have the
+same version.  Sometimes, some specific modules need separate, special version
+handling, such as modules defining database schemata for DBIx::Class, and
+can't follow the version of the larger package.
 
 =item @POD_COVERAGE_EXCLUDE
 
 Regexes that match method names that should be excluded from POD coverage
-testing.  Normally, all methods have to be documented in the POD for a
-Perl module, but methods matching any of these regexes will be considered
-private and won't require documentation.
+testing.  Normally, all methods have to be documented in the POD for a Perl
+module, but methods matching any of these regexes will be considered private
+and won't require documentation.
 
 =item @STRICT_IGNORE
 
-Additional directories to ignore when doing recursive Test::Strict testing
-for C<use strict> and C<use warnings>.  The contents of this directory
-must be either top-level directory names or directory names starting with
-F<tests/>.
+Additional directories to ignore when doing recursive Test::Strict testing for
+C<use strict> and C<use warnings>.  The contents of this directory must be
+either top-level directory names or directory names starting with F<tests/>.
 
 =item @STRICT_PREREQ
 
 A list of Perl modules that have to be available in order to do meaningful
 Test::Strict testing.  If any of the modules cannot be loaded via C<use>,
-Test::Strict checking will be skipped.  There is currently no way to
-require specific versions of the modules.
+Test::Strict checking will be skipped.  There is currently no way to require
+specific versions of the modules.
 
 =back
 
-No variables are exported by default, but the variables can be imported
-into the local namespace to avoid long variable names.
+No variables are exported by default, but the variables can be imported into
+the local namespace to avoid long variable names.
 
 =head1 AUTHOR
 
@@ -183,36 +185,38 @@ Russ Allbery <eagle@eyrie.org>
 
 =head1 COPYRIGHT AND LICENSE
 
+Copyright 2015, 2016 Russ Allbery <eagle@eyrie.org>
+
 Copyright 2013, 2014 The Board of Trustees of the Leland Stanford Junior
 University
 
-Permission is hereby granted, free of charge, to any person obtaining a
-copy of this software and associated documentation files (the "Software"),
-to deal in the Software without restriction, including without limitation
-the rights to use, copy, modify, merge, publish, distribute, sublicense,
-and/or sell copies of the Software, and to permit persons to whom the
-Software is furnished to do so, subject to the following conditions:
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
 
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
 
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
-THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-DEALINGS IN THE SOFTWARE.
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
 
 =head1 SEE ALSO
 
-perlcritic(1), Test::MinimumVersion(3), Test::RRA(3),
-Test::RRA::Automake(3), Test::Strict(3)
+perlcritic(1), Test::MinimumVersion(3), Test::RRA(3), Test::RRA::Automake(3),
+Test::Strict(3)
 
-This module is maintained in the rra-c-util package.  The current version
-is available from L<http://www.eyrie.org/~eagle/software/rra-c-util/>.
+This module is maintained in the rra-c-util package.  The current version is
+available from L<https://www.eyrie.org/~eagle/software/rra-c-util/>.
 
 The C TAP Harness test driver and libraries for TAP-based C testing are
-available from L<http://www.eyrie.org/~eagle/software/c-tap-harness/>.
+available from L<https://www.eyrie.org/~eagle/software/c-tap-harness/>.
 
 =cut
index 54e714aa999a8c5f03894e9853a3e38f7bc7dbdc..45bbe468e1d391c879ff58b6e8e95e48064f7f09 100644 (file)
  * mkstemp.
  *
  * The canonical version of this file is maintained in the rra-c-util package,
- * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+ * which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
  *
  * Written by Russ Allbery <eagle@eyrie.org>
- * Copyright 2002, 2004, 2005, 2013 Russ Allbery <eagle@eyrie.org>
+ * Copyright 2002, 2004, 2005, 2013, 2016 Russ Allbery <eagle@eyrie.org>
  * Copyright 2009, 2010, 2011, 2013, 2014
  *     The Board of Trustees of the Leland Stanford Junior University
  *
 # include <sys/select.h>
 #endif
 #include <sys/stat.h>
-#include <sys/time.h>
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+#endif
 #include <sys/wait.h>
+#include <time.h>
 
 #include <tests/tap/basic.h>
 #include <tests/tap/process.h>
@@ -131,6 +134,8 @@ run_child_function(test_function_type function, void *data, int *status,
         count = 0;
         do {
             ret = read(fds[0], buf + count, buflen - count - 1);
+            if (SSIZE_MAX - count <= ret)
+                bail("maximum output size exceeded in run_child_function");
             if (ret > 0)
                 count += ret;
             if (count >= buflen - 1) {
@@ -138,7 +143,7 @@ run_child_function(test_function_type function, void *data, int *status,
                 buf = brealloc(buf, buflen);
             }
         } while (ret > 0);
-        buf[count < 0 ? 0 : count] = '\0';
+        buf[count] = '\0';
         if (waitpid(child, &rval, 0) == (pid_t) -1)
             sysbail("waitpid failed");
         close(fds[0]);
@@ -229,6 +234,10 @@ process_free(struct process *process)
 {
     struct process **prev;
 
+    /* Do nothing if called with a NULL argument. */
+    if (process == NULL)
+        return;
+
     /* Remove the process from the global list. */
     prev = &processes;
     while (*prev != NULL && *prev != process)
@@ -392,7 +401,7 @@ static struct process *
 process_start_internal(const char *const argv[], const char *pidfile,
                        bool fakeroot)
 {
-    size_t i, size;
+    size_t i;
     int log_fd;
     const char *name;
     struct timeval tv;
@@ -422,8 +431,7 @@ process_start_internal(const char *const argv[], const char *pidfile,
     if (fakeroot) {
         for (i = 0; argv[i] != NULL; i++)
             ;
-        size = 2 + i + 1;
-        fakeroot_argv = bmalloc(size * sizeof(const char *));
+        fakeroot_argv = bcalloc(2 + i + 1, sizeof(const char *));
         fakeroot_argv[0] = path_fakeroot;
         fakeroot_argv[1] = "--";
         for (i = 0; argv[i] != NULL; i++)
index 8137d5d26fb485b8ed70c0aa29609185677b91a9..7e008bece9299f4c9144823b0e537e89fa558d0a 100644 (file)
@@ -2,7 +2,7 @@
  * Utility functions for tests that use subprocesses.
  *
  * The canonical version of this file is maintained in the rra-c-util package,
- * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+ * which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
  *
  * Written by Russ Allbery <eagle@eyrie.org>
  * Copyright 2009, 2010, 2013
index 6ed7e68dc7c3f4b162de7e6dacf4c359c2df49a7..56450294ddebdcd33813fd2a5b94e77ec9104aba 100644 (file)
@@ -5,7 +5,7 @@
  * because they rely on additional portability code from rra-c-util.
  *
  * The canonical version of this file is maintained in the rra-c-util package,
- * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+ * which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
  *
  * Copyright 2011, 2012 Russ Allbery <eagle@eyrie.org>
  *
index cc51945da6f27d06c25a292d18a9fb4afd82b6c3..73e34eef7c92778ebc28d540522793998b13ba2e 100644 (file)
@@ -5,7 +5,7 @@
  * because they rely on additional portability code from rra-c-util.
  *
  * The canonical version of this file is maintained in the rra-c-util package,
- * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+ * which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
  *
  * Copyright 2011, 2012 Russ Allbery <eagle@eyrie.org>
  *
@@ -42,7 +42,7 @@ BEGIN_DECLS
 void basprintf(char **, const char *, ...)
     __attribute__((__nonnull__, __format__(printf, 2, 3)));
 void bvasprintf(char **, const char *, va_list)
-    __attribute__((__nonnull__));
+    __attribute__((__nonnull__, __format__(printf, 2, 0)));
 
 END_DECLS
 
index 8015c4e62943f952667f0923f0d8525a99a9a873..8113198473d38d27536a019578bf24b1b9815e5a 100644 (file)
@@ -2,10 +2,10 @@
  * Test suite for Kerberos error handling routines.
  *
  * The canonical version of this file is maintained in the rra-c-util package,
- * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+ * which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
  *
  * Written by Russ Allbery <eagle@eyrie.org>
- * Copyright 2010, 2011, 2013
+ * Copyright 2010, 2011, 2013, 2014
  *     The Board of Trustees of the Leland Stanford Junior University
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  */
 
 #include <config.h>
-#include <portable/krb5.h>
+#ifdef HAVE_KRB5
+# include <portable/krb5.h>
+#endif
 #include <portable/system.h>
 
 #include <tests/tap/basic.h>
 #include <tests/tap/process.h>
 #include <util/macros.h>
-#include <util/messages-krb5.h>
+#ifdef HAVE_KRB5
+# include <util/messages-krb5.h>
+#endif
 #include <util/messages.h>
 #include <util/xmalloc.h>
 
 
+/* Skip the whole test if not built with Kerberos support. */
+#ifndef HAVE_KRB5
+int
+main(void)
+{
+    skip_all("not built with Kerberos support");
+    return 0;
+}
+#else
+
 /*
  * Test functions.
  */
@@ -120,3 +134,5 @@ main(void)
     krb5_free_context(ctx);
     return 0;
 }
+
+#endif /* HAVE_KRB5 */
index f60fa6a9698af051b0977903116bff426a407559..eb4ef5f155c2d034f3c542ffae1e6618205ea091 100644 (file)
@@ -2,10 +2,10 @@
  * Test suite for error handling routines.
  *
  * The canonical version of this file is maintained in the rra-c-util package,
- * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+ * which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
  *
  * Written by Russ Allbery <eagle@eyrie.org>
- * Copyright 2002, 2004, 2005 Russ Allbery <eagle@eyrie.org>
+ * Copyright 2002, 2004, 2005, 2015 Russ Allbery <eagle@eyrie.org>
  * Copyright 2009, 2010, 2011, 2012
  *     The Board of Trustees of the Leland Stanford Junior University
  *
@@ -92,7 +92,8 @@ static void test11(void *data UNUSED) {
     sysdie("fatal");
 }
 
-static void log_msg(size_t len, const char *format, va_list args, int error) {
+static void __attribute__((__format__(printf, 2, 0)))
+log_msg(size_t len, const char *format, va_list args, int error) {
     fprintf(stderr, "%lu %d ", (unsigned long) len, error);
     vfprintf(stderr, format, args);
     fprintf(stderr, "\n");
index c47c644aebd096d5c86c4e02a109deda2af6b594..e8fdd74c2950aa57f7aea787e857f8f7cb71d03c 100755 (executable)
@@ -3,10 +3,10 @@
 # Test suite for xmalloc and friends.
 #
 # The canonical version of this file is maintained in the rra-c-util package,
-# which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+# which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
 #
 # Written by Russ Allbery <eagle@eyrie.org>
-# Copyright 2000, 2001, 2006, 2014 Russ Allbery <eagle@eyrie.org>
+# Copyright 2000, 2001, 2006, 2014, 2016 Russ Allbery <eagle@eyrie.org>
 # Copyright 2008, 2009, 2010, 2012
 #     The Board of Trustees of the Leland Stanford Junior University
 #
@@ -28,8 +28,8 @@
 # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 # DEALINGS IN THE SOFTWARE.
 
-. "$SOURCE/tap/libtap.sh"
-cd "$BUILD/util"
+. "$C_TAP_SOURCE/tap/libtap.sh"
+cd "$C_TAP_BUILD/util"
 
 # Run an xmalloc test.  Takes the description, the expectd exit status, the
 # output, and the arguments.
@@ -64,26 +64,28 @@ if [ -z "$AUTHOR_TESTING" ] ; then
 fi
 
 # Total tests.
-plan 36
+plan 41
 
 # First run the tests expected to succeed.
-ok_xmalloc "malloc small"    0 "" "m" "21"      "0"
-ok_xmalloc "malloc large"    0 "" "m" "5500000" "0"
-ok_xmalloc "malloc zero"     0 "" "m" "0"       "0"
-ok_xmalloc "realloc small"   0 "" "r" "21"      "0"
-ok_xmalloc "realloc large"   0 "" "r" "5500000" "0"
-ok_xmalloc "strdup small"    0 "" "s" "21"      "0"
-ok_xmalloc "strdup large"    0 "" "s" "5500000" "0"
-ok_xmalloc "strndup small"   0 "" "n" "21"      "0"
-ok_xmalloc "strndup large"   0 "" "n" "5500000" "0"
-ok_xmalloc "calloc small"    0 "" "c" "24"      "0"
-ok_xmalloc "calloc large"    0 "" "c" "5500000" "0"
-ok_xmalloc "asprintf small"  0 "" "a" "24"      "0"
-ok_xmalloc "asprintf large"  0 "" "a" "5500000" "0"
-ok_xmalloc "vasprintf small" 0 "" "v" "24"      "0"
-ok_xmalloc "vasprintf large" 0 "" "v" "5500000" "0"
+ok_xmalloc "malloc small"       0 "" "m" "21"       "0"
+ok_xmalloc "malloc large"       0 "" "m" "30000000" "0"
+ok_xmalloc "malloc zero"        0 "" "m" "0"        "0"
+ok_xmalloc "realloc small"      0 "" "r" "21"       "0"
+ok_xmalloc "realloc large"      0 "" "r" "30000000" "0"
+ok_xmalloc "reallocarray small" 0 "" "y" "20"       "0"
+ok_xmalloc "reallocarray large" 0 "" "y" "30000000" "0"
+ok_xmalloc "strdup small"       0 "" "s" "21"       "0"
+ok_xmalloc "strdup large"       0 "" "s" "30000000" "0"
+ok_xmalloc "strndup small"      0 "" "n" "21"       "0"
+ok_xmalloc "strndup large"      0 "" "n" "30000000" "0"
+ok_xmalloc "calloc small"       0 "" "c" "24"       "0"
+ok_xmalloc "calloc large"       0 "" "c" "30000000" "0"
+ok_xmalloc "asprintf small"     0 "" "a" "24"       "0"
+ok_xmalloc "asprintf large"     0 "" "a" "30000000" "0"
+ok_xmalloc "vasprintf small"    0 "" "v" "24"       "0"
+ok_xmalloc "vasprintf large"    0 "" "v" "30000000" "0"
 
-# Now limit our memory to 5.5MB and then try the large ones again, all of
+# Now limit our memory to 30MB and then try the large ones again, all of
 # which should fail.
 #
 # The exact memory limits used here are essentially black magic.  They need to
@@ -91,53 +93,60 @@ ok_xmalloc "vasprintf large" 0 "" "v" "5500000" "0"
 # but not so large that we can't reasonably expect to allocate that much
 # memory normally.  The amount of memory required varies a lot based on what
 # shared libraries are loaded, and if it's too small, all memory allocations
-# fail.  5.5MB seems to work reasonably well on both Solaris and Linux.
+# fail.  30MB seems to work reasonably well on both Solaris and Linux, even
+# when the program is linked with additional libraries.
 #
 # We assume that there are enough miscellaneous allocations that an allocation
 # exactly as large as the limit will always fail.
 ok_xmalloc "malloc fail" 1 \
-    "failed to malloc 5500000 bytes at xmalloc.c line 38" \
-    "m" "5500000" "5500000"
+    "failed to malloc 30000000 bytes at xmalloc.c line 41" \
+    "m" "30000000" "30000000"
 ok_xmalloc "realloc fail" 1 \
-    "failed to realloc 5500000 bytes at xmalloc.c line 66" \
-    "r" "5500000" "5500000"
+    "failed to realloc 30000000 bytes at xmalloc.c line 69" \
+    "r" "30000000" "30000000"
+ok_xmalloc "reallocarray fail" 1 \
+    "failed to reallocarray 30000000 bytes at xmalloc.c line 99" \
+    "y" "30000000" "30000000"
 ok_xmalloc "strdup fail" 1 \
-    "failed to strdup 5500000 bytes at xmalloc.c line 97" \
-    "s" "5500000" "5500000"
+    "failed to strdup 30000000 bytes at xmalloc.c line 130" \
+    "s" "30000000" "30000000"
 ok_xmalloc "strndup fail" 1 \
-    "failed to strndup 5500000 bytes at xmalloc.c line 143" \
-    "n" "5500000" "5500000"
+    "failed to strndup 30000000 bytes at xmalloc.c line 176" \
+    "n" "30000000" "30000000"
 ok_xmalloc "calloc fail" 1 \
-    "failed to calloc 5500000 bytes at xmalloc.c line 167" \
-    "c" "5500000" "5500000"
+    "failed to calloc 30000000 bytes at xmalloc.c line 200" \
+    "c" "30000000" "30000000"
 ok_xmalloc "asprintf fail" 1 \
-    "failed to asprintf 5500000 bytes at xmalloc.c line 191" \
-    "a" "5500000" "5500000"
+    "failed to asprintf 30000000 bytes at xmalloc.c line 224" \
+    "a" "30000000" "30000000"
 ok_xmalloc "vasprintf fail" 1 \
-    "failed to vasprintf 5500000 bytes at xmalloc.c line 210" \
-    "v" "5500000" "5500000"
+    "failed to vasprintf 30000000 bytes at xmalloc.c line 243" \
+    "v" "30000000" "30000000"
 
 # Check our custom error handler.
-ok_xmalloc "malloc custom"    1 "malloc 5500000 xmalloc.c 38" \
-    "M" "5500000" "5500000"
-ok_xmalloc "realloc custom"   1 "realloc 5500000 xmalloc.c 66" \
-    "R" "5500000" "5500000"
-ok_xmalloc "strdup custom"    1 "strdup 5500000 xmalloc.c 97" \
-    "S" "5500000" "5500000"
-ok_xmalloc "strndup custom"   1 "strndup 5500000 xmalloc.c 143" \
-    "N" "5500000" "5500000"
-ok_xmalloc "calloc custom"    1 "calloc 5500000 xmalloc.c 167" \
-    "C" "5500000" "5500000"
-ok_xmalloc "asprintf custom"  1 "asprintf 5500000 xmalloc.c 191" \
-    "A" "5500000" "5500000"
-ok_xmalloc "vasprintf custom" 1 "vasprintf 5500000 xmalloc.c 210" \
-    "V" "5500000" "5500000"
+ok_xmalloc "malloc custom"       1 "malloc 30000000 xmalloc.c 41" \
+    "M" "30000000" "30000000"
+ok_xmalloc "realloc custom"      1 "realloc 30000000 xmalloc.c 69" \
+    "R" "30000000" "30000000"
+ok_xmalloc "reallocarray custom" 1 "reallocarray 30000000 xmalloc.c 99" \
+    "Y" "30000000" "30000000"
+ok_xmalloc "strdup custom"       1 "strdup 30000000 xmalloc.c 130" \
+    "S" "30000000" "30000000"
+ok_xmalloc "strndup custom"      1 "strndup 30000000 xmalloc.c 176" \
+    "N" "30000000" "30000000"
+ok_xmalloc "calloc custom"       1 "calloc 30000000 xmalloc.c 200" \
+    "C" "30000000" "30000000"
+ok_xmalloc "asprintf custom"     1 "asprintf 30000000 xmalloc.c 224" \
+    "A" "30000000" "30000000"
+ok_xmalloc "vasprintf custom"    1 "vasprintf 30000000 xmalloc.c 243" \
+    "V" "30000000" "30000000"
 
 # Check the smaller ones again just for grins.
-ok_xmalloc "malloc retry"    0 "" "m" "21" "5500000"
-ok_xmalloc "realloc retry"   0 "" "r" "32" "5500000"
-ok_xmalloc "strdup retry"    0 "" "s" "64" "5500000"
-ok_xmalloc "strndup retry"   0 "" "n" "20" "5500000"
-ok_xmalloc "calloc retry"    0 "" "c" "24" "5500000"
-ok_xmalloc "asprintf retry"  0 "" "a" "30" "5500000"
-ok_xmalloc "vasprintf retry" 0 "" "v" "35" "5500000"
+ok_xmalloc "malloc retry"       0 "" "m" "21" "30000000"
+ok_xmalloc "realloc retry"      0 "" "r" "32" "30000000"
+ok_xmalloc "reallocarray retry" 0 "" "y" "32" "30000000"
+ok_xmalloc "strdup retry"       0 "" "s" "64" "30000000"
+ok_xmalloc "strndup retry"      0 "" "n" "20" "30000000"
+ok_xmalloc "calloc retry"       0 "" "c" "24" "30000000"
+ok_xmalloc "asprintf retry"     0 "" "a" "30" "30000000"
+ok_xmalloc "vasprintf retry"    0 "" "v" "35" "30000000"
index a415614cdd6b52e3f18834c995518f82d1d2256c..a5c0b944179fa352787e087e9d49301df8948c67 100644 (file)
@@ -2,10 +2,10 @@
  * Test suite for xmalloc and family.
  *
  * The canonical version of this file is maintained in the rra-c-util package,
- * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+ * which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
  *
  * Copyright 2000, 2001, 2006 Russ Allbery <eagle@eyrie.org>
- * Copyright 2008, 2012, 2013
+ * Copyright 2008, 2012, 2013, 2014
  *     The Board of Trustees of the Leland Stanford Junior University
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
 
 #include <ctype.h>
 #include <errno.h>
-#include <sys/time.h>
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+#endif
+#include <time.h>
 
 /* Linux requires sys/time.h be included before sys/resource.h. */
 #include <sys/resource.h>
@@ -109,6 +112,36 @@ test_realloc(size_t size)
 }
 
 
+/*
+ * Like test_realloc, but test allocating an array instead.  Returns true on
+ * success, false on any failure.
+ */
+static int
+test_reallocarray(size_t n, size_t size)
+{
+    char *buffer;
+    size_t i;
+
+    buffer = xmalloc(10);
+    if (buffer == NULL)
+        return 0;
+    memset(buffer, 1, 10);
+    buffer = xreallocarray(buffer, n, size);
+    if (buffer == NULL)
+        return 0;
+    if (n > 0 && size > 0)
+        memset(buffer + 10, 2, (n * size) - 10);
+    for (i = 0; i < 10; i++)
+        if (buffer[i] != 1)
+            return 0;
+    for (i = 10; i < n * size; i++)
+        if (buffer[i] != 2)
+            return 0;
+    free(buffer);
+    return 1;
+}
+
+
 /*
  * Generate a string of the size indicated, call xstrdup on it, and then
  * ensure the result matches.  Returns true on success, false on any failure.
@@ -231,7 +264,7 @@ test_asprintf(size_t size)
 
 
 /* Wrapper around vasprintf to do the va_list stuff. */
-static void
+static void __attribute__((__format__(printf, 2, 3)))
 xvasprintf_wrapper(char **strp, const char *format, ...)
 {
     va_list args;
@@ -330,8 +363,8 @@ main(int argc, char *argv[])
             syswarn("Can't set data limit to %lu", (unsigned long) limit);
             exit(2);
         }
-        if (size < limit || code == 'r') {
-            test_size = code == 'r' ? 10 : size;
+        if (size < limit || code == 'r' || code == 'y') {
+            test_size = (code == 'r' || code == 'y') ? 10 : size;
             if (test_size == 0)
                 test_size = 1;
             tmp = malloc(test_size);
@@ -352,6 +385,7 @@ main(int argc, char *argv[])
     case 'c': exit(test_calloc(size) ? willfail : 1);
     case 'm': exit(test_malloc(size) ? willfail : 1);
     case 'r': exit(test_realloc(size) ? willfail : 1);
+    case 'y': exit(test_reallocarray(4, size / 4) ? willfail : 1);
     case 's': exit(test_strdup(size) ? willfail : 1);
     case 'n': exit(test_strndup(size) ? willfail : 1);
     case 'a': exit(test_asprintf(size) ? willfail : 1);
index e7c1bd753f6b75b4590c2f2b49afcafe51c81ccf..93ae31cbe8cca8de5eafec6e57a5d30587cf950e 100644 (file)
@@ -182,7 +182,7 @@ describes the interface that this program implements and how to configure
 Heimdal to use it.
 
 The current version of this program is available from its web page at
-L<http://www.eyrie.org/~eagle/software/krb5-strength/> as part of the
+L<https://www.eyrie.org/~eagle/software/krb5-strength/> as part of the
 krb5-strength package.
 
 =head1 AUTHOR
@@ -191,6 +191,8 @@ Russ Allbery <eagle@eyrie.org>
 
 =head1 COPYRIGHT AND LICENSE
 
+Copyright 2016 Russ Allbery <eagle@eyrie.org>
+
 Copyright 2010, 2013, 2014 The Board of Trustees of the Leland Stanford
 Junior University
 
index 49bac55251bf66d8c6630766350090402b77a071..16e0c38a91185c4b897a3839c8efb0d1ed1083d4 100755 (executable)
@@ -428,6 +428,8 @@ Russ Allbery <eagle@eyrie.org>
 
 =head1 COPYRIGHT AND LICENSE
 
+Copyright 2016 Russ Allbery <eagle@eyrie.org>
+
 Copyright 2013, 2014 The Board of Trustees of the Leland Stanford Junior
 University
 
@@ -456,7 +458,7 @@ cdb(1), L<DBI>, L<DBD::SQLite>
 The cdb file format is defined at L<http://cr.yp.to/cdb.html>.
 
 The current version of this program is available from its web page at
-L<http://www.eyrie.org/~eagle/software/krb5-strength/> as part of the
+L<https://www.eyrie.org/~eagle/software/krb5-strength/> as part of the
 krb5-strength package.
 
 =cut
index d071793a807580cf2ecf190cc2ba3f86a5f9bd53..8b82d56107ed3b8d7db4d8c35f0ffb3530b84043 100644 (file)
@@ -2,7 +2,7 @@
  * Some standard helpful macros.
  *
  * The canonical version of this file is maintained in the rra-c-util package,
- * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+ * which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
  *
  * Written by Russ Allbery <eagle@eyrie.org>
  *
 #define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0]))
 #define ARRAY_END(array)  (&(array)[ARRAY_SIZE(array)])
 
+/* Used to name the elements of the array passed to pipe. */
+#define PIPE_READ  0
+#define PIPE_WRITE 1
+
 /* Used for unused parameters to silence gcc warnings. */
 #define UNUSED __attribute__((__unused__))
 
index 961ea1d18fec80e2a9f922243b29b52b647b6b28..341ac1a4eb714fb6277573cfb34b04e2c8e7e818 100644 (file)
@@ -6,7 +6,7 @@
  * formatted message.
  *
  * The canonical version of this file is maintained in the rra-c-util package,
- * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+ * which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
  *
  * Written by Russ Allbery <eagle@eyrie.org>
  * Copyright 2006, 2007, 2008, 2009, 2010, 2013
index 3fc08620bf89e2b5765d9ecf5af15e29c9effbf2..63e72ec410abc673f66f872eb52bd28e9f07fbce 100644 (file)
@@ -2,7 +2,7 @@
  * Prototypes for error handling for Kerberos.
  *
  * The canonical version of this file is maintained in the rra-c-util package,
- * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+ * which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
  *
  * Written by Russ Allbery <eagle@eyrie.org>
  * Copyright 2006, 2007, 2008, 2009, 2010, 2013
@@ -44,9 +44,9 @@ BEGIN_DECLS
  * an error code to get the Kerberos error.
  */
 void die_krb5(krb5_context, krb5_error_code, const char *, ...)
-    __attribute__((__nonnull__, __noreturn__, __format__(printf, 3, 4)));
+    __attribute__((__nonnull__(3), __noreturn__, __format__(printf, 3, 4)));
 void warn_krb5(krb5_context, krb5_error_code, const char *, ...)
-    __attribute__((__nonnull__, __format__(printf, 3, 4)));
+    __attribute__((__nonnull__(3), __format__(printf, 3, 4)));
 
 /* Undo default visibility change. */
 #pragma GCC visibility pop
index 4dac8236ca030cc3e5eee756ad4e3e1a3925eb21..836c4b151435b9cc9f003b19668c90ac8c730766 100644 (file)
  * va_list, and the applicable errno value (if any).
  *
  * The canonical version of this file is maintained in the rra-c-util package,
- * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+ * which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
  *
  * Written by Russ Allbery <eagle@eyrie.org>
- * Copyright 2008, 2009, 2010, 2013
+ * Copyright 2015, 2016 Russ Allbery <eagle@eyrie.org>
+ * Copyright 2008, 2009, 2010, 2013, 2014
  *     The Board of Trustees of the Leland Stanford Junior University
  * Copyright (c) 2004, 2005, 2006
  *     by Internet Systems Consortium, Inc. ("ISC")
@@ -131,7 +132,7 @@ message_handlers(message_handler_func **list, unsigned int count, va_list args)
 
     if (*list != stdout_handlers && *list != stderr_handlers)
         free(*list);
-    *list = xmalloc(sizeof(message_handler_func) * (count + 1));
+    *list = xcalloc(count + 1, sizeof(message_handler_func));
     for (i = 0; i < count; i++)
         (*list)[i] = (message_handler_func) va_arg(args, message_handler_func);
     (*list)[count] = NULL;
@@ -225,7 +226,7 @@ message_log_stderr(size_t len UNUSED, const char *fmt, va_list args, int err)
  * This needs further attention on Windows.  For example, it currently doesn't
  * log the errno information.
  */
-static void
+static void __attribute__((__format__(printf, 3, 0)))
 message_log_syslog(int pri, size_t len, const char *fmt, va_list args, int err)
 {
     char *buffer;
@@ -238,7 +239,7 @@ message_log_syslog(int pri, size_t len, const char *fmt, va_list args, int err)
         exit(message_fatal_cleanup ? (*message_fatal_cleanup)() : 1);
     }
     status = vsnprintf(buffer, len + 1, fmt, args);
-    if (status < 0) {
+    if (status < 0 || (size_t) status >= len + 1) {
         warn("failed to format output with vsnprintf in syslog handler");
         free(buffer);
         return;
index 8c731b7169aabe4058f0d089b61bbb2c46cdf29f..555792bcf1476f2c8811d1f3f309a61093b4220d 100644 (file)
@@ -2,8 +2,10 @@
  * Prototypes for message and error reporting (possibly fatal).
  *
  * The canonical version of this file is maintained in the rra-c-util package,
- * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+ * which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
  *
+ * Written by Russ Allbery <eagle@eyrie.org>
+ * Copyright 2015 Russ Allbery <eagle@eyrie.org>
  * Copyright 2008, 2010, 2013, 2014
  *     The Board of Trustees of the Leland Stanford Junior University
  * Copyright (c) 2004, 2005, 2006
@@ -84,24 +86,25 @@ void message_handlers_reset(void);
  * argument list, and the errno setting if any.
  */
 void message_log_stdout(size_t, const char *, va_list, int)
-    __attribute__((__nonnull__));
+    __attribute__((__format__(printf, 2, 0), __nonnull__));
 void message_log_stderr(size_t, const char *, va_list, int)
-    __attribute__((__nonnull__));
+    __attribute__((__format__(printf, 2, 0), __nonnull__));
 void message_log_syslog_debug(size_t, const char *, va_list, int)
-    __attribute__((__nonnull__));
+    __attribute__((__format__(printf, 2, 0), __nonnull__));
 void message_log_syslog_info(size_t, const char *, va_list, int)
-    __attribute__((__nonnull__));
+    __attribute__((__format__(printf, 2, 0), __nonnull__));
 void message_log_syslog_notice(size_t, const char *, va_list, int)
-    __attribute__((__nonnull__));
+    __attribute__((__format__(printf, 2, 0), __nonnull__));
 void message_log_syslog_warning(size_t, const char *, va_list, int)
-    __attribute__((__nonnull__));
+    __attribute__((__format__(printf, 2, 0), __nonnull__));
 void message_log_syslog_err(size_t, const char *, va_list, int)
-    __attribute__((__nonnull__));
+    __attribute__((__format__(printf, 2, 0), __nonnull__));
 void message_log_syslog_crit(size_t, const char *, va_list, int)
-    __attribute__((__nonnull__));
+    __attribute__((__format__(printf, 2, 0), __nonnull__));
 
 /* The type of a message handler. */
-typedef void (*message_handler_func)(size_t, const char *, va_list, int);
+typedef void (*message_handler_func)(size_t, const char *, va_list, int)
+    __attribute__((__format__(printf, 2, 0)));
 
 /* If non-NULL, called before exit and its return value passed to exit. */
 extern int (*message_fatal_cleanup)(void);
index 5bfd5558589f2290a8c221a5747194a950dfac5c..889bd1ee6e29656ea9ed0fc2dc04b14af34a08bb 100644 (file)
@@ -12,7 +12,7 @@
  *      buffer = xmalloc(1024);
  *      xrealloc(buffer, 2048);
  *      free(buffer);
- *      buffer = xcalloc(1024);
+ *      buffer = xcalloc(1, 1024);
  *      free(buffer);
  *      buffer = xstrdup(string);
  *      free(buffer);
  * allocation function will try its allocation again (calling the handler
  * again if it still fails).
  *
+ * xreallocarray behaves the same as the OpenBSD reallocarray function but for
+ * the same error checking, which in turn is the same as realloc but with
+ * calloc-style arguments and size overflow checking.
+ *
  * xstrndup behaves like xstrdup but only copies the given number of
  * characters.  It allocates an additional byte over its second argument and
  * always nul-terminates the string.
  * line number to these functions.
  *
  * The canonical version of this file is maintained in the rra-c-util package,
- * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+ * which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
  *
- * Copyright 2012, 2013
+ * Copyright 2015 Russ Allbery <eagle@eyrie.org>
+ * Copyright 2012, 2013, 2014
  *     The Board of Trustees of the Leland Stanford Junior University
  * Copyright (c) 2004, 2005, 2006
  *     by Internet Systems Consortium, Inc. ("ISC")
@@ -152,6 +157,20 @@ x_realloc(void *p, size_t size, const char *file, int line)
 }
 
 
+void *
+x_reallocarray(void *p, size_t n, size_t size, const char *file, int line)
+{
+    void *newp;
+
+    newp = reallocarray(p, n, size);
+    while (newp == NULL && size > 0 && n > 0) {
+        (*xmalloc_error_handler)("reallocarray", n * size, file, line);
+        newp = reallocarray(p, n, size);
+    }
+    return newp;
+}
+
+
 char *
 x_strdup(const char *s, const char *file, int line)
 {
@@ -240,6 +259,7 @@ x_asprintf(char **strp, const char *file, int line, const char *fmt, ...)
         status = vasprintf(strp, fmt, args_copy);
         va_end(args_copy);
     }
+    va_end(args);
 }
 #else /* !(HAVE_C99_VAMACROS || HAVE_GNU_VAMACROS) */
 void
@@ -262,5 +282,6 @@ x_asprintf(char **strp, const char *fmt, ...)
         status = vasprintf(strp, fmt, args_copy);
         va_end(args_copy);
     }
+    va_end(args);
 }
 #endif /* !(HAVE_C99_VAMACROS || HAVE_GNU_VAMACROS) */
index ac4d79629c0d302376ab01768b58526f1102a9a5..fc159b405f53976d1c2fc6bf26a2ffd7df811ab8 100644 (file)
@@ -2,9 +2,9 @@
  * Prototypes for malloc routines with failure handling.
  *
  * The canonical version of this file is maintained in the rra-c-util package,
- * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+ * which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
  *
- * Copyright 2010, 2012, 2013
+ * Copyright 2010, 2012, 2013, 2014
  *     The Board of Trustees of the Leland Stanford Junior University
  * Copyright (c) 2004, 2005, 2006
  *     by Internet Systems Consortium, Inc. ("ISC")
@@ -47,6 +47,8 @@
 #define xstrdup(p)              x_strdup((p), __FILE__, __LINE__)
 #define xstrndup(p, size)       x_strndup((p), (size), __FILE__, __LINE__)
 #define xvasprintf(p, f, a)     x_vasprintf((p), (f), (a), __FILE__, __LINE__)
+#define xreallocarray(p, n, size) \
+    x_reallocarray((p), (n), (size), __FILE__, __LINE__)
 
 /*
  * asprintf is a special case since it takes variable arguments.  If we have
@@ -81,12 +83,14 @@ void *x_malloc(size_t, const char *, int)
     __attribute__((__alloc_size__(1), __malloc__, __nonnull__));
 void *x_realloc(void *, size_t, const char *, int)
     __attribute__((__alloc_size__(2), __malloc__, __nonnull__(3)));
+void *x_reallocarray(void *, size_t, size_t, const char *, int)
+    __attribute__((__alloc_size__(2, 3), __malloc__, __nonnull__(4)));
 char *x_strdup(const char *, const char *, int)
     __attribute__((__malloc__, __nonnull__));
 char *x_strndup(const char *, size_t, const char *, int)
     __attribute__((__malloc__, __nonnull__));
 void x_vasprintf(char **, const char *, va_list, const char *, int)
-    __attribute__((__nonnull__));
+    __attribute__((__nonnull__, __format__(printf, 2, 0)));
 
 /* asprintf special case. */
 #if HAVE_C99_VAMACROS || HAVE_GNU_VAMACROS