[openssl-commits] [openssl] master update

Richard Levitte levitte at openssl.org
Mon Apr 24 16:10:06 UTC 2017


The branch master has been updated
       via  f044cd05a1d28c998731108dfcd25ba580cdda07 (commit)
       via  a9c6d221055c3a85edb23b1364cd60baafed4b9f (commit)
       via  b3e5db40eca1b53fc37a95163feba0da82426142 (commit)
       via  4db40c94c38ee94fbef820a9816ac2d68f65506e (commit)
       via  20626cfd5870e80838010cddf99dd6297eceaa26 (commit)
       via  331058180aba047ac6b25da781eebc08b7267d2f (commit)
      from  a68d35057ba2676bc9b9a16f4952791eef4b9905 (commit)


- Log -----------------------------------------------------------------
commit f044cd05a1d28c998731108dfcd25ba580cdda07
Author: Richard Levitte <levitte at openssl.org>
Date:   Wed Apr 19 13:06:08 2017 +0200

    Avoid using BIO streams in bioprinttest.c
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3243)

commit a9c6d221055c3a85edb23b1364cd60baafed4b9f
Author: Richard Levitte <levitte at openssl.org>
Date:   Tue Apr 18 16:47:11 2017 +0200

    Adapt all test programs
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3243)

commit b3e5db40eca1b53fc37a95163feba0da82426142
Author: Richard Levitte <levitte at openssl.org>
Date:   Wed Apr 19 12:32:42 2017 +0200

    VMS: Make sure to include MAIN from static libraries if needed
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3243)

commit 4db40c94c38ee94fbef820a9816ac2d68f65506e
Author: Richard Levitte <levitte at openssl.org>
Date:   Tue Apr 18 16:27:27 2017 +0200

    Refactor the test framework testutil
    
    It's now built as a static library, and greatly simplified for test
    programs, which no longer need to include test_main_custom.h or
    test_main.h and link with the corresponding object files.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3243)

commit 20626cfd5870e80838010cddf99dd6297eceaa26
Author: Richard Levitte <levitte at openssl.org>
Date:   Wed Apr 19 12:51:06 2017 +0200

    Add CRYPTO_mem_leaks_cb
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3243)

commit 331058180aba047ac6b25da781eebc08b7267d2f
Author: Richard Levitte <levitte at openssl.org>
Date:   Tue Apr 18 16:24:23 2017 +0200

    Make it possible to build static-only libraries
    
    The trick is to use the .a extension explicitely in the build.info files.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3243)

-----------------------------------------------------------------------

Summary of changes:
 Configurations/common.tmpl                   |  20 +-
 Configurations/descrip.mms.tmpl              |  63 ++++--
 Configurations/unix-Makefile.tmpl            |  20 +-
 Configurations/windows-makefile.tmpl         |  33 ++-
 Configure                                    |  16 +-
 crypto/mem_dbg.c                             |  43 ++--
 doc/man3/OPENSSL_malloc.pod                  |   9 +-
 include/openssl/crypto.h                     |   2 +
 test/README                                  |   5 +-
 test/asn1_encode_test.c                      |   1 -
 test/asn1_internal_test.c                    |   1 -
 test/asynciotest.c                           |   1 -
 test/bad_dtls_test.c                         |   1 -
 test/bftest.c                                |   1 -
 test/bio_enc_test.c                          |   1 -
 test/bioprinttest.c                          |  62 +++++-
 test/bntest.c                                |   1 -
 test/build.info                              | 301 ++++++++++++++-------------
 test/casttest.c                              |   1 -
 test/chacha_internal_test.c                  |   1 -
 test/cipher_overhead_test.c                  |   3 +-
 test/cipherbytes_test.c                      |   1 -
 test/cipherlist_test.c                       |   1 -
 test/clienthellotest.c                       |   1 -
 test/constant_time_test.c                    |   1 -
 test/crltest.c                               |   1 -
 test/ct_test.c                               |   1 -
 test/d2i_test.c                              |   1 -
 test/destest.c                               |   1 -
 test/dhtest.c                                |   1 -
 test/dsatest.c                               |   1 -
 test/dtlstest.c                              |   1 -
 test/ecdsatest.c                             |   1 -
 test/enginetest.c                            |   1 -
 test/evp_extra_test.c                        |   1 -
 test/exdatatest.c                            |   1 -
 test/gmdifftest.c                            |   1 -
 test/hmactest.c                              |   1 -
 test/ideatest.c                              |   1 -
 test/lhash_test.c                            |   1 -
 test/md2test.c                               |   1 -
 test/mdc2_internal_test.c                    |   1 -
 test/mdc2test.c                              |   1 -
 test/modes_internal_test.c                   |   1 -
 test/packettest.c                            |   1 -
 test/pbelutest.c                             |   1 -
 test/pkey_meth_test.c                        |   1 -
 test/poly1305_internal_test.c                |   3 +-
 test/randtest.c                              |   1 -
 test/rc2test.c                               |   1 -
 test/rc4test.c                               |   1 -
 test/rc5test.c                               |   1 -
 test/recordlentest.c                         |   1 -
 test/rsa_test.c                              |   1 -
 test/sanitytest.c                            |   1 -
 test/secmemtest.c                            |   1 -
 test/sha1test.c                              |   1 -
 test/sha256t.c                               |   1 -
 test/sha512t.c                               |   1 -
 test/siphash_internal_test.c                 |   5 +-
 test/srptest.c                               |   1 -
 test/ssl_test.c                              |   1 -
 test/ssl_test_ctx_test.c                     |   1 -
 test/sslapitest.c                            |   1 -
 test/sslcorrupttest.c                        |   1 -
 test/stack_test.c                            |   1 -
 test/test_main.h                             |  18 --
 test/test_main_custom.h                      |  20 --
 test/test_test.c                             |   1 -
 test/testutil.h                              |  52 ++++-
 test/testutil/basic_output.c                 |  80 +++++++
 test/testutil/driver.c                       | 167 +++++++++++++++
 test/{test_main_custom.c => testutil/main.c} |   8 +-
 test/{ => testutil}/test_main.c              |  15 +-
 test/{testutil.c => testutil/tests.c}        | 177 +++-------------
 test/threadstest.c                           |   1 -
 test/tls13encryptiontest.c                   |   9 +-
 test/tls13secretstest.c                      |   1 -
 test/uitest.c                                |  24 +--
 test/v3ext.c                                 |   1 -
 test/v3nametest.c                            |   1 -
 test/verify_extra_test.c                     |   1 -
 test/wpackettest.c                           |   1 -
 test/x509_dup_cert_test.c                    |   1 -
 test/x509_internal_test.c                    |   1 -
 test/x509_time_test.c                        |   1 -
 test/x509aux.c                               |   2 -
 util/libcrypto.num                           |   1 +
 88 files changed, 700 insertions(+), 520 deletions(-)
 delete mode 100644 test/test_main.h
 delete mode 100644 test/test_main_custom.h
 create mode 100644 test/testutil/basic_output.c
 create mode 100644 test/testutil/driver.c
 rename test/{test_main_custom.c => testutil/main.c} (71%)
 rename test/{ => testutil}/test_main.c (51%)
 rename test/{testutil.c => testutil/tests.c} (71%)

diff --git a/Configurations/common.tmpl b/Configurations/common.tmpl
index 5e9cb36..70adf23 100644
--- a/Configurations/common.tmpl
+++ b/Configurations/common.tmpl
@@ -18,7 +18,8 @@
      my $thing = shift;
      my $extensionlessthing = extensionlesslib($thing);
      my @listsofar = @_;    # to check if we're looping
-     my @list = @{$unified_info{depends}->{$extensionlessthing}};
+     my @list = @{$unified_info{depends}->{$thing} //
+                      $unified_info{depends}->{$extensionlessthing}};
      my @newlist = ();
      if (scalar @list) {
          foreach my $item (@list) {
@@ -33,13 +34,22 @@
  sub reducedepends {
      my @list = @_;
      my @newlist = ();
+     my %replace = ();
      while (@list) {
          my $item = shift @list;
          my $extensionlessitem = extensionlesslib($item);
-         push @newlist, $item
-             unless grep { $extensionlessitem eq extensionlesslib($_) } @list;
+         if (grep { $extensionlessitem eq extensionlesslib($_) } @list) {
+             if ($item ne $extensionlessitem) {
+                 # If this instance of the library is explicitely static, we
+                 # prefer that to any shared library name, since it must have
+                 # been done on purpose.
+                 $replace{$extensionlessitem} = $item;
+             }
+         } else {
+             push @newlist, $item;
+         }
      }
-     @newlist;
+     map { $replace{$_} // $_; } @newlist;
  }
 
  # is_installed checks if a given file will be installed (i.e. they are
@@ -113,7 +123,7 @@
  sub dolib {
      my $lib = shift;
      return "" if $cache{$lib};
-     unless ($disabled{shared}) {
+     unless ($disabled{shared} || $lib =~ /\.a$/) {
          my %ordinals =
              $unified_info{ordinals}->{$lib}
              ? (ordinals => $unified_info{ordinals}->{$lib}) : ();
diff --git a/Configurations/descrip.mms.tmpl b/Configurations/descrip.mms.tmpl
index cbec11c..e0ded0b 100644
--- a/Configurations/descrip.mms.tmpl
+++ b/Configurations/descrip.mms.tmpl
@@ -42,8 +42,18 @@
 
   # Because we need to make two computations of these data,
   # we store them in arrays for reuse
-  our @shlibs = map { $unified_info{sharednames}->{$_} || () } @{$unified_info{libraries}};
-  our @install_shlibs = map { $unified_info{sharednames}->{$_} || () } @{$unified_info{install}->{libraries}};
+  our @libs =
+      map { (my $x = $_) =~ s/\.a$//; $x }
+      @{$unified_info{libraries}};
+  our @shlibs =
+      map { $unified_info{sharednames}->{$_} || () }
+      grep(!/\.a$/, @{$unified_info{libraries}});
+  our @install_libs =
+      map { (my $x = $_) =~ s/\.a$//; $x }
+      @{$unified_info{install}->{libraries}};
+  our @install_shlibs =
+      map { $unified_info{sharednames}->{$_} || () }
+      grep(!/\.a$/, @{$unified_info{install}->{libraries}});
   our @generated = ( ( map { (my $x = $_) =~ s|\.S$|\.s|; $x }
                        grep { defined $unified_info{generate}->{$_} }
                        map { @{$unified_info{sources}->{$_}} }
@@ -113,7 +123,7 @@ SHLIB_EXT=.EXE
 OBJ_EXT=.OBJ
 DEP_EXT=.D
 
-LIBS={- join(", ", map { "-\n\t".$_.".OLB" } @{$unified_info{libraries}}) -}
+LIBS={- join(", ", map { "-\n\t".$_.".OLB" } @libs) -}
 SHLIBS={- join(", ", map { "-\n\t".$_.".EXE" } @shlibs) -}
 ENGINES={- join(", ", map { "-\n\t".$_.".EXE" } @{$unified_info{engines}}) -}
 PROGRAMS={- join(", ", map { "-\n\t".$_.".EXE" } @{$unified_info{programs}}) -}
@@ -127,7 +137,7 @@ DEPS={- our @deps = map { (my $x = $_) =~ s|\.o$|\$(DEP_EXT)|; $x; }
 GENERATED_MANDATORY={- join(", ", map { "-\n\t".$_ } @{$unified_info{depends}->{""}} ) -}
 GENERATED={- join(", ", map { "-\n\t".$_ } @generated) -}
 
-INSTALL_LIBS={- join(", ", map { "-\n\t".$_.".OLB" } @{$unified_info{install}->{libraries}}) -}
+INSTALL_LIBS={- join(", ", map { "-\n\t".$_.".OLB" } @install_libs) -}
 INSTALL_SHLIBS={- join(", ", map { "-\n\t".$_.".EXE" } @install_shlibs) -}
 INSTALL_ENGINES={- join(", ", map { "-\n\t".$_.".EXE" } @{$unified_info{install}->{engines}}) -}
 INSTALL_PROGRAMS={- join(", ", map { "-\n\t".$_.".EXE" } @{$unified_info{install}->{programs}}) -}
@@ -230,10 +240,10 @@ NODEBUG=@
         $(NODEBUG) ! Set up logical names for the libraries, so LINK and
         $(NODEBUG) ! running programs can use them.
         $(NODEBUG) !
-        $(NODEBUG) {- join("\n\t\$(NODEBUG) ", map { "DEFINE ".uc($_)." 'F\$ENV(\"DEFAULT\")'".uc($_)."\$(SHLIB_EXT)" } map { $unified_info{sharednames}->{$_} || () } @{$unified_info{libraries}}) || "!" -}
+        $(NODEBUG) {- join("\n\t\$(NODEBUG) ", map { "DEFINE ".uc($_)." 'F\$ENV(\"DEFAULT\")'".uc($_)."\$(SHLIB_EXT)" } @shlibs) || "!" -}
 
 .LAST :
-        $(NODEBUG) {- join("\n\t\$(NODEBUG) ", map { "DEASSIGN ".uc($_) } map { $unified_info{sharednames}->{$_} || () } @{$unified_info{libraries}}) || "!" -}
+        $(NODEBUG) {- join("\n\t\$(NODEBUG) ", map { "DEASSIGN ".uc($_) } @shlibs) || "!" -}
         $(NODEBUG) DEASSIGN ossl_dataroot
         $(NODEBUG) DEASSIGN ossl_installroot
         $(NODEBUG) DEASSIGN internal
@@ -317,7 +327,7 @@ uninstall : uninstall_docs uninstall_sw
 # Because VMS wants the generation number (or *) to delete files, we can't
 # use $(LIBS), $(PROGRAMS), $(GENERATED) and $(ENGINES)directly.
 libclean :
-        {- join("\n\t", map { "- DELETE $_.OLB;*" } @{$unified_info{libraries}}) || "@ !" -}
+        {- join("\n\t", map { "- DELETE $_.OLB;*" } @libs) || "@ !" -}
         {- join("\n\t", map { "- DELETE $_.EXE;*,$_.MAP;*,$_.OPT;*" } @shlibs) || "@ !" -}
 
 clean : libclean
@@ -407,7 +417,7 @@ _install_dev_ns : check_INSTALLTOP
         - CREATE/DIR ossl_installroot:[LIB.'arch']
         {- join("\n        ",
                 map { "COPY/PROT=W:R $_.OLB ossl_installroot:[LIB.'arch']" }
-                @{$unified_info{install}->{libraries}}) -}
+                @install_libs) -}
 
 install_dev : install_shared _install_dev_ns
 
@@ -729,7 +739,7 @@ EOF
   }
   sub obj2lib {
       my %args = @_;
-      my $lib = $args{lib};
+      (my $lib = $args{lib}) =~ s/\.a$//;
       my $objs = join(", -\n\t\t", map { $_.".OBJ" } (@{$args{objs}}));
       my $fill_lib = join("\n\t", (map { "LIBRARY/REPLACE $lib.OLB $_.OBJ" }
                                     @{$args{objs}}));
@@ -746,21 +756,38 @@ EOF
       my $bind = dirname($bin);
       my $binn = basename($bin);
       my @objs = map { "$_.OBJ" } @{$args{objs}};
+      my $objs = join(",", @objs);
       my @deps = compute_lib_depends(@{$args{deps}});
       my $deps = join(", -\n\t\t", @objs, @deps);
+
+      my $olb_count = scalar grep(m|\.OLB$|, @deps);
+      my $analyse_objs = "@ !";
+      if ($olb_count > 0) {
+          my $analyse_quals =
+              $config{target} =~ m|alpha| ? "/GSD" : "/SECTIONS=SYMTAB";
+          $analyse_objs = "- pipe ANALYSE/OBJECT$analyse_quals $objs | SEARCH SYS\$INPUT \"\"\"main\"\"\" ; nomain = \$severity .NE. 1"
+      }
       # The "[]" hack is because in .OPT files, each line inherits the
       # previous line's file spec as default, so if no directory spec
       # is present in the current line and the previous line has one that
       # doesn't apply, you're in for a surprise.
       my $write_opt1 =
           join(",-\"\n\t", map { my $x = $_ =~ /\[/ ? $_ : "[]".$_;
-                                 "WRITE OPT_FILE \"$x" } @objs).
+                                 "\@ WRITE OPT_FILE \"$x" } @objs).
           "\"";
       my $write_opt2 =
-          join("\n\t", map { my $x = $_ =~ /\[/ ? $_ : "[]".$_;
-                             $x =~ s|(\.EXE)|$1/SHARE|;
-                             $x =~ s|(\.OLB)|$1/LIB|;
-                             "WRITE OPT_FILE \"$x\"" } @deps)
+          join("\n\t", map { my @lines = ();
+                             my $x = $_ =~ /\[/ ? $_ : "[]".$_;
+                             if ($x =~ m|\.EXE$|) {
+                                 push @lines, "\@ WRITE OPT_FILE \"$x/SHARE\"";
+                             } elsif ($x =~ m|\.OLB$|) {
+                                 (my $l = $x) =~ s/\W/_/g;
+                                 push @lines, 
+                                     "\@ IF nomain THEN WRITE OPT_FILE \"$x/LIB\$(INCLUDE_MAIN_$l)\"",
+                                     "\@ IF .NOT. nomain THEN WRITE OPT_FILE \"$x/LIB\""
+                             }
+                             @lines
+                           } @deps)
           || "\@ !";
       # The linking commands looks a bit complex, but it's for good reason.
       # When you link, say, foo.obj, bar.obj and libsomething.exe/share, and
@@ -782,10 +809,12 @@ EOF
       # and let it break the build.
       return <<"EOF"
 $bin.EXE : $deps
-        OPEN/WRITE/SHARE=READ OPT_FILE $bin.OPT
+        $analyse_objs
+        @ OPEN/WRITE/SHARE=READ OPT_FILE $bin.OPT
         $write_opt1
         $write_opt2
-        CLOSE OPT_FILE
+        @ CLOSE OPT_FILE
+        TYPE $bin.opt ! For debugging
         - pipe SPAWN/WAIT/NOLOG/OUT=$bin.LINKLOG -
                     LINK \$(LDFLAGS)/EXEC=\$\@ $bin.OPT/OPT \$(EX_LIBS) ; -
                link_status = \$status ; link_severity = link_status .AND. 7
@@ -807,7 +836,7 @@ $bin.EXE : $deps
         @ IF .NOT. link_severity THEN SPAWN/WAIT/NOLOG EXIT 'link_status'
         - PURGE $bin.EXE,$bin.OPT
 EOF
-        . ($config{target} =~ m|alpha| ? "" : <<"EOF"
+      . ($config{target} =~ m|alpha| ? "" : <<"EOF"
         SET IMAGE/FLAGS=(NOCALL_DEBUG) \$\@
 EOF
         );
diff --git a/Configurations/unix-Makefile.tmpl b/Configurations/unix-Makefile.tmpl
index 0070fbf..132b83c 100644
--- a/Configurations/unix-Makefile.tmpl
+++ b/Configurations/unix-Makefile.tmpl
@@ -38,20 +38,26 @@
      # removed.  On some systems, they may therefore return the exact same
      # string.
      sub shlib {
-         return () if $disabled{shared};
          my $lib = shift;
+         return () if $disabled{shared} || $lib =~ /\.a$/;
          return $unified_info{sharednames}->{$lib} . $shlibext;
      }
      sub shlib_simple {
-         return () if $disabled{shared};
-
          my $lib = shift;
+         return () if $disabled{shared} || $lib =~ /\.a$/;
+
          if (windowsdll()) {
              return $lib . $shlibextimport;
          }
          return $lib .  $shlibextsimple;
      }
 
+     # Easy fixing of static library names
+     sub lib {
+         (my $lib = shift) =~ s/\.a$//;
+         return $lib . $libext;
+     }
+
      # dso is a complement to shlib / shlib_simple that returns the
      # given libname with the simple shared extension (possible SO version
      # removed).  This differs from shlib_simple() by being unconditional.
@@ -84,7 +90,7 @@ SHLIB_MAJOR={- $config{shlib_major} -}
 SHLIB_MINOR={- $config{shlib_minor} -}
 SHLIB_TARGET={- $target{shared_target} -}
 
-LIBS={- join(" ", map { $_.$libext } @{$unified_info{libraries}}) -}
+LIBS={- join(" ", map { lib($_) } @{$unified_info{libraries}}) -}
 SHLIBS={- join(" ", map { shlib($_) } @{$unified_info{libraries}}) -}
 SHLIB_INFO={- join(" ", map { "\"".shlib($_).";".shlib_simple($_)."\"" } @{$unified_info{libraries}}) -}
 ENGINES={- join(" ", map { dso($_) } @{$unified_info{engines}}) -}
@@ -103,7 +109,7 @@ GENERATED={- join(" ",
                     grep { /\.o$/ } keys %{$unified_info{sources}} ),
                   ( grep { /\.h$/ } keys %{$unified_info{generate}} )) -}
 
-INSTALL_LIBS={- join(" ", map { $_.$libext } @{$unified_info{install}->{libraries}}) -}
+INSTALL_LIBS={- join(" ", map { lib($_) } @{$unified_info{install}->{libraries}}) -}
 INSTALL_SHLIBS={- join(" ", map { shlib($_) } @{$unified_info{install}->{libraries}}) -}
 INSTALL_SHLIB_INFO={- join(" ", map { "\"".shlib($_).";".shlib_simple($_)."\"" } @{$unified_info{install}->{libraries}}) -}
 INSTALL_ENGINES={- join(" ", map { dso($_) } @{$unified_info{install}->{engines}}) -}
@@ -769,7 +775,7 @@ configdata.pm: $(SRCDIR)/Configure $(SRCDIR)/config {- join(" ", @{$config{build
   # It takes a list of library names and outputs a list of dependencies
   sub compute_lib_depends {
       if ($disabled{shared}) {
-          return map { $_ =~ /\.a$/ ? $`.$libext : $_.$libext } @_;
+          return map { lib($_) } @_;
       }
 
       # Depending on shared libraries:
@@ -983,7 +989,7 @@ EOF
   }
   sub obj2lib {
       my %args = @_;
-      my $lib = $args{lib};
+      (my $lib = $args{lib}) =~ s/\.a$//;
       my $objs = join(" ", map { $_.$objext } @{$args{objs}});
       return <<"EOF";
 $lib$libext: $objs
diff --git a/Configurations/windows-makefile.tmpl b/Configurations/windows-makefile.tmpl
index f16df75..87ad389 100644
--- a/Configurations/windows-makefile.tmpl
+++ b/Configurations/windows-makefile.tmpl
@@ -31,14 +31,20 @@
  $win_commonroot = $ENV{$win_commonroot};
 
  sub shlib {
-     return () if $disabled{shared};
      my $lib = shift;
+     return () if $disabled{shared} || $lib =~ /\.a$/;
+     return () unless defined $unified_info{sharednames}->{$lib};
      return $unified_info{sharednames}->{$lib} . $shlibext;
  }
 
+ sub lib {
+     (my $lib = shift) =~ s/\.a$//;
+     return $lib . $libext;
+ }
+
  sub shlib_import {
-     return () if $disabled{shared};
      my $lib = shift;
+     return () if $disabled{shared} || $lib =~ /\.a$/;
      return $lib . $shlibextimport;
  }
 
@@ -67,7 +73,7 @@ MINOR={- $config{minor} -}
 
 SHLIB_VERSION_NUMBER={- $config{shlib_version_number} -}
 
-LIBS={- join(" ", map { $_.$libext } @{$unified_info{libraries}}) -}
+LIBS={- join(" ", map { lib($_) } @{$unified_info{libraries}}) -}
 SHLIBS={- join(" ", map { shlib($_) } @{$unified_info{libraries}}) -}
 SHLIBPDBS={- join(" ", map { local $shlibext = ".pdb"; shlib($_) } @{$unified_info{libraries}}) -}
 ENGINES={- join(" ", map { dso($_) } @{$unified_info{engines}}) -}
@@ -88,7 +94,7 @@ GENERATED={- join(" ",
                     grep { /\.o$/ } keys %{$unified_info{sources}} ),
                   ( grep { /\.h$/ } keys %{$unified_info{generate}} )) -}
 
-INSTALL_LIBS={- join(" ", map { $_.$libext } @{$unified_info{install}->{libraries}}) -}
+INSTALL_LIBS={- join(" ", map { lib($_) } @{$unified_info{install}->{libraries}}) -}
 INSTALL_SHLIBS={- join(" ", map { shlib($_) } @{$unified_info{install}->{libraries}}) -}
 INSTALL_SHLIBPDBS={- join(" ", map { local $shlibext = ".pdb"; shlib($_) } @{$unified_info{install}->{libraries}}) -}
 INSTALL_ENGINES={- join(" ", map { dso($_) } @{$unified_info{install}->{engines}}) -}
@@ -352,11 +358,14 @@ configdata.pm: "$(SRCDIR)\Configure" {- join(" ", map { '"'.$_.'"' } @{$config{b
  # It takes a list of library names and outputs a list of dependencies
  sub compute_lib_depends {
      if ($disabled{shared}) {
-	 return map { $_ =~ /\.a$/ ? $`.$libext : $_.$libext } @_;
+	 return map { lib($_) } @_;
      }
-     die "Linking with static OpenSSL libraries is not supported in this configuration\n"
-         if grep /\.a$/, @_;
-     return map { shlib_import($_) } @_;
+     foreach (@_) {
+         (my $l = $_) =~ s/\.a$//;
+         die "Linking with static variants of shared libraries is not supported in this configuration\n"
+             if $l ne $_ && shlib($l);
+     }
+     return map { shlib_import($_) or lib($_) } @_;
  }
 
   sub generatesrc {
@@ -530,13 +539,15 @@ $objs$linklibs \$(EX_LIBS)
 EOF
  }
  sub obj2lib {
+     my %args = @_;
+     my $lib = $args{lib};
+
      # Because static libs and import libs are both named the same in native
      # Windows, we can't have both.  We skip the static lib in that case,
      # as the shared libs are what we use anyway.
-     return "" unless $disabled{"shared"};
+     return "" unless $disabled{"shared"} || $lib =~ /\.a$/;
 
-     my %args = @_;
-     my $lib = $args{lib};
+     $lib =~ s/\.a$//;
      my $objs = join("\n", map { $_.$objext } @{$args{objs}});
      my $deps = join(" ", map { $_.$objext } @{$args{objs}});
      return <<"EOF";
diff --git a/Configure b/Configure
index 66541be..c699ae0 100755
--- a/Configure
+++ b/Configure
@@ -1732,12 +1732,24 @@ EOF
             }
 
             # Additionally, we set up sharednames for libraries that don't
-            # have any, as themselves.
-            foreach (keys %{$unified_info{libraries}}) {
+            # have any, as themselves.  Only for libraries that aren't
+            # explicitely static.
+            foreach (grep !/\.a$/, keys %{$unified_info{libraries}}) {
                 if (!defined $unified_info{sharednames}->{$_}) {
                     $unified_info{sharednames}->{$_} = $_
                 }
             }
+
+            # Check that we haven't defined any library as both shared and
+            # explicitely static.  That is forbidden.
+            my @doubles = ();
+            foreach (grep /\.a$/, keys %{$unified_info{libraries}}) {
+                (my $l = $_) =~ s/\.a$//;
+                push @doubles, $l if defined $unified_info{sharednames}->{$l};
+            }
+            die "these libraries are both explicitely static and shared:\n  ",
+                join(" ", @doubles), "\n"
+                if @doubles;
         }
 
         foreach (keys %ordinals) {
diff --git a/crypto/mem_dbg.c b/crypto/mem_dbg.c
index dc3f8ff..4c4e7d3 100644
--- a/crypto/mem_dbg.c
+++ b/crypto/mem_dbg.c
@@ -443,7 +443,8 @@ void CRYPTO_mem_debug_realloc(void *addr1, void *addr2, size_t num,
 }
 
 typedef struct mem_leak_st {
-    BIO *bio;
+    int (*print_cb) (const char *str, size_t len, void *u);
+    void *print_cb_arg;
     int chunks;
     long bytes;
 } MEM_LEAK;
@@ -486,7 +487,7 @@ static void print_leak(const MEM *m, MEM_LEAK *l)
                  m->num, m->addr);
     bufp += strlen(bufp);
 
-    BIO_puts(l->bio, buf);
+    l->print_cb(buf, strlen(buf), l->print_cb_arg);
 
     l->chunks++;
     l->bytes += m->num;
@@ -520,7 +521,7 @@ static void print_leak(const MEM *m, MEM_LEAK *l)
             }
             BIO_snprintf(buf + buf_len, sizeof buf - buf_len, "\"\n");
 
-            BIO_puts(l->bio, buf);
+            l->print_cb(buf, strlen(buf), l->print_cb_arg);
 
             amip = amip->next;
         }
@@ -541,16 +542,11 @@ static void print_leak(const MEM *m, MEM_LEAK *l)
 
 IMPLEMENT_LHASH_DOALL_ARG_CONST(MEM, MEM_LEAK);
 
-int CRYPTO_mem_leaks(BIO *b)
+int CRYPTO_mem_leaks_cb(int (*cb) (const char *str, size_t len, void *u),
+                        void *u)
 {
     MEM_LEAK ml;
 
-    /*
-     * OPENSSL_cleanup() will free the ex_data locks so we can't have any
-     * ex_data hanging around
-     */
-    bio_free_ex_data(b);
-
     /* Ensure all resources are released */
     OPENSSL_cleanup();
 
@@ -559,14 +555,19 @@ int CRYPTO_mem_leaks(BIO *b)
 
     CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE);
 
-    ml.bio = b;
+    ml.print_cb = cb;
+    ml.print_cb_arg = u;
     ml.bytes = 0;
     ml.chunks = 0;
     if (mh != NULL)
         lh_MEM_doall_MEM_LEAK(mh, print_leak, &ml);
 
     if (ml.chunks != 0) {
-        BIO_printf(b, "%ld bytes leaked in %d chunks\n", ml.bytes, ml.chunks);
+        char buf[256];
+
+        BIO_snprintf(buf, sizeof(buf), "%ld bytes leaked in %d chunks\n",
+                     ml.bytes, ml.chunks);
+        cb(buf, strlen(buf), u);
     } else {
         /*
          * Make sure that, if we found no leaks, memory-leak debugging itself
@@ -603,6 +604,22 @@ int CRYPTO_mem_leaks(BIO *b)
     return ml.chunks == 0 ? 1 : 0;
 }
 
+static int print_bio(const char *str, size_t len, void *b)
+{
+    return BIO_write((BIO *)b, str, len);
+}
+
+int CRYPTO_mem_leaks(BIO *b)
+{
+    /*
+     * OPENSSL_cleanup() will free the ex_data locks so we can't have any
+     * ex_data hanging around
+     */
+    bio_free_ex_data(b);
+
+    return CRYPTO_mem_leaks_cb(print_bio, b);
+}
+
 # ifndef OPENSSL_NO_STDIO
 int CRYPTO_mem_leaks_fp(FILE *fp)
 {
@@ -620,7 +637,7 @@ int CRYPTO_mem_leaks_fp(FILE *fp)
     if (b == NULL)
         return -1;
     BIO_set_fp(b, fp, BIO_NOCLOSE);
-    ret = CRYPTO_mem_leaks(b);
+    ret = CRYPTO_mem_leaks_cb(print_bio, b);
     BIO_free(b);
     return ret;
 }
diff --git a/doc/man3/OPENSSL_malloc.pod b/doc/man3/OPENSSL_malloc.pod
index 2914143..afcdb55 100644
--- a/doc/man3/OPENSSL_malloc.pod
+++ b/doc/man3/OPENSSL_malloc.pod
@@ -15,7 +15,7 @@ CRYPTO_mem_debug_push, CRYPTO_mem_debug_pop,
 CRYPTO_clear_realloc, CRYPTO_clear_free,
 CRYPTO_get_mem_functions, CRYPTO_set_mem_functions,
 CRYPTO_set_mem_debug, CRYPTO_mem_ctrl,
-CRYPTO_mem_leaks, CRYPTO_mem_leaks_fp
+CRYPTO_mem_leaks, CRYPTO_mem_leaks_fp, CRYPTO_mem_leaks_cb,
 OPENSSL_MALLOC_FAILURES,
 OPENSSL_MALLOC_FD
 - Memory allocation functions
@@ -76,6 +76,8 @@ OPENSSL_MALLOC_FD
 
  void CRYPTO_mem_leaks(BIO *b);
  void CRYPTO_mem_leaks_fp(FILE *fp);
+ void CRYPTO_mem_leaks_cb(int (*cb)(const char *str, size_t len, void *u),
+                          void *u);
 
 =head1 DESCRIPTION
 
@@ -190,6 +192,11 @@ CRYPTO_mem_leaks_fp() will report all "leaked" memory, writing it
 to the specified BIO B<b> or FILE B<fp>. These functions return 1 if
 there are no leaks, 0 if there are leaks and -1 if an error occurred.
 
+CRYPTO_mem_leaks_cb() does the same as CRYPTO_mem_leaks(), but instead
+of writing to a given BIO, the callback function is called for each
+output string with the string, length, and userdata B<u> as the callback
+parameters.
+
 =head1 RETURN VALUES
 
 OPENSSL_malloc_init(), OPENSSL_free(), OPENSSL_clear_free()
diff --git a/include/openssl/crypto.h b/include/openssl/crypto.h
index a8b8dc1..42e888d 100644
--- a/include/openssl/crypto.h
+++ b/include/openssl/crypto.h
@@ -314,6 +314,8 @@ void CRYPTO_mem_debug_realloc(void *addr1, void *addr2, size_t num, int flag,
 void CRYPTO_mem_debug_free(void *addr, int flag,
         const char *file, int line);
 
+int CRYPTO_mem_leaks_cb(int (*cb) (const char *str, size_t len, void *u),
+                        void *u);
 #  ifndef OPENSSL_NO_STDIO
 int CRYPTO_mem_leaks_fp(FILE *);
 #  endif
diff --git a/test/README b/test/README
index 7831c86..fc9f7d0 100644
--- a/test/README
+++ b/test/README
@@ -99,14 +99,13 @@ test):
 to modify the include paths and source files if you don't want to use the
 basic test framework:
 
-    SOURCE[{name}]={name}.c testutil.c test_main.c
+    SOURCE[{name}]={name}.c
     INCLUDE[{name}]=.. ../include
-    DEPEND[{name}]=../libcrypto
+    DEPEND[{name}]=../libcrypto libtestutil.a
 
 Generic form of C test executables
 ==================================
 
-    #include "test_main.h"
     #include "testutil.h"
 
     static int my_test(void)
diff --git a/test/asn1_encode_test.c b/test/asn1_encode_test.c
index a24b284..7d762ae 100644
--- a/test/asn1_encode_test.c
+++ b/test/asn1_encode_test.c
@@ -13,7 +13,6 @@
 #include <openssl/rand.h>
 #include <openssl/asn1t.h>
 #include "internal/numbers.h"
-#include "test_main.h"
 #include "testutil.h"
 
 #ifdef __GNUC__
diff --git a/test/asn1_internal_test.c b/test/asn1_internal_test.c
index f936098..f9fdeef 100644
--- a/test/asn1_internal_test.c
+++ b/test/asn1_internal_test.c
@@ -15,7 +15,6 @@
 #include <openssl/asn1.h>
 #include <openssl/evp.h>
 #include <openssl/objects.h>
-#include "test_main.h"
 #include "testutil.h"
 #include "e_os.h"
 
diff --git a/test/asynciotest.c b/test/asynciotest.c
index f78b86f..ee450da 100644
--- a/test/asynciotest.c
+++ b/test/asynciotest.c
@@ -17,7 +17,6 @@
 
 #include "ssltestlib.h"
 #include "testutil.h"
-#include "test_main_custom.h"
 
 /* Should we fragment records or not? 0 = no, !0 = yes*/
 static int fragment = 0;
diff --git a/test/bad_dtls_test.c b/test/bad_dtls_test.c
index 0bfbebf..9745ff8 100644
--- a/test/bad_dtls_test.c
+++ b/test/bad_dtls_test.c
@@ -41,7 +41,6 @@
 #include "../ssl/packet_locl.h"
 #include "../e_os.h" /* for OSSL_NELEM() */
 
-#include "test_main.h"
 #include "testutil.h"
 
 /* For DTLS1_BAD_VER packets the MAC doesn't include the handshake header */
diff --git a/test/bftest.c b/test/bftest.c
index eea9fcb..a7e0bf1 100644
--- a/test/bftest.c
+++ b/test/bftest.c
@@ -17,7 +17,6 @@
 #include <stdlib.h>
 #include <openssl/opensslconf.h> /* To see if OPENSSL_NO_BF is defined */
 
-#include "test_main_custom.h"
 #include "testutil.h"
 
 #include "../e_os.h"
diff --git a/test/bio_enc_test.c b/test/bio_enc_test.c
index 9b0dd6d..bc49a79 100644
--- a/test/bio_enc_test.c
+++ b/test/bio_enc_test.c
@@ -12,7 +12,6 @@
 #include <openssl/bio.h>
 #include <openssl/rand.h>
 
-#include "test_main.h"
 #include "testutil.h"
 
 #define ENCRYPT  1
diff --git a/test/bioprinttest.c b/test/bioprinttest.c
index ca0f1aa..56aa0b0 100644
--- a/test/bioprinttest.c
+++ b/test/bioprinttest.c
@@ -7,13 +7,19 @@
  * https://www.openssl.org/source/license.html
  */
 
+#define TESTUTIL_NO_size_t_COMPARISON
+
 #include <stdio.h>
 #include <string.h>
+#include <openssl/e_os2.h>
+#ifdef OPENSSL_SYS_WINDOWS
+# include <winsock.h>
+#else
+# include OPENSSL_UNISTD
+#endif
 #include <openssl/bio.h>
 #include "internal/numbers.h"
 #include "testutil.h"
-#include "test_main.h"
-#include "test_main_custom.h"
 
 #define nelem(x) (int)(sizeof(x) / sizeof((x)[0]))
 
@@ -247,3 +253,55 @@ int test_main(int argc, char **argv)
 
     return run_tests(argv[0]);
 }
+
+/*
+ * Replace testutil output routines.  We do this to eliminate possible sources
+ * of BIO error
+ */
+void test_open_streams(void)
+{
+}
+
+void test_close_streams(void)
+{
+}
+
+int test_puts_stdout(const char *str)
+{
+    return write(1, str, strlen(str));
+}
+
+int test_puts_stderr(const char *str)
+{
+    return write(2, str, strlen(str));
+}
+
+static char vprint_buf[10240];
+
+int test_vprintf_stdout(const char *fmt, va_list ap)
+{
+    size_t len = vsnprintf(vprint_buf, sizeof(vprint_buf), fmt, ap);
+
+    if (len >= sizeof(vprint_buf))
+        return -1;
+    return test_puts_stdout(vprint_buf);
+}
+
+int test_vprintf_stderr(const char *fmt, va_list ap)
+{
+    size_t len = vsnprintf(vprint_buf, sizeof(vprint_buf), fmt, ap);
+
+    if (len >= sizeof(vprint_buf))
+        return -1;
+    return test_puts_stderr(vprint_buf);
+}
+
+int test_flush_stdout(void)
+{
+    return 0;
+}
+
+int test_flush_stderr(void)
+{
+    return 0;
+}
diff --git a/test/bntest.c b/test/bntest.c
index 449b3a4..0410e07 100644
--- a/test/bntest.c
+++ b/test/bntest.c
@@ -19,7 +19,6 @@
 #include <openssl/err.h>
 #include <openssl/rand.h>
 #include "testutil.h"
-#include "test_main_custom.h"
 
 /*
  * In bn_lcl.h, bn_expand() is defined as a static ossl_inline function.
diff --git a/test/build.info b/test/build.info
index 5a2e03e..83a83c4 100644
--- a/test/build.info
+++ b/test/build.info
@@ -5,11 +5,23 @@
          my ($base, $files) = @_;
          return join(" ", map { "$base/$_" } split(/\s+/, $files));
      }
-     our $apps_extra =
-         $config{target} =~ /^vms-/ ? "../apps/vms_term_sock.c" : "";
      ""
 -}
 IF[{- !$disabled{tests} -}]
+  LIBS_NO_INST=libtestutil.a
+  SOURCE[libtestutil.a]=testutil/basic_output.c testutil/driver.c \
+          testutil/tests.c testutil/test_main.c testutil/main.c \
+          {- rebase_files("../apps", $target{apps_aux_src}) -}
+  INCLUDE[libtestutil.a]=../include
+  DEPEND[libtestutil.a]=../libcrypto
+
+  # Special hack for descrip.mms to include the MAIN object module
+  # explicitely.  This will only be done if there isn't a MAIN in the
+  # program's object modules already.
+  BEGINRAW[descrip.mms]
+INCLUDE_MAIN___test_libtestutil_OLB = /INCLUDE=MAIN
+  ENDRAW[descrip.mms]
+
   PROGRAMS_NO_INST=\
           aborttest test_test \
           sanitytest exdatatest bntest \
@@ -35,270 +47,270 @@ IF[{- !$disabled{tests} -}]
   INCLUDE[aborttest]=../include
   DEPEND[aborttest]=../libcrypto
 
-  SOURCE[sanitytest]=sanitytest.c testutil.c test_main.c
+  SOURCE[sanitytest]=sanitytest.c
   INCLUDE[sanitytest]=../include
-  DEPEND[sanitytest]=../libcrypto
+  DEPEND[sanitytest]=../libcrypto libtestutil.a
 
-  SOURCE[test_test]=test_test.c testutil.c test_main.c
+  SOURCE[test_test]=test_test.c
   INCLUDE[test_test]=.. ../include
-  DEPEND[test_test]=../libcrypto
+  DEPEND[test_test]=../libcrypto libtestutil.a
 
-  SOURCE[exdatatest]=exdatatest.c testutil.c test_main.c
+  SOURCE[exdatatest]=exdatatest.c
   INCLUDE[exdatatest]=../include
-  DEPEND[exdatatest]=../libcrypto
+  DEPEND[exdatatest]=../libcrypto libtestutil.a
 
-  SOURCE[bntest]=bntest.c testutil.c test_main_custom.c
+  SOURCE[bntest]=bntest.c
   INCLUDE[bntest]=.. ../crypto/include ../include
-  DEPEND[bntest]=../libcrypto
+  DEPEND[bntest]=../libcrypto libtestutil.a
 
   SOURCE[ectest]=ectest.c
   INCLUDE[ectest]=.. ../include
   DEPEND[ectest]=../libcrypto
 
-  SOURCE[ecdsatest]=ecdsatest.c testutil.c test_main.c
+  SOURCE[ecdsatest]=ecdsatest.c
   INCLUDE[ecdsatest]=../include
-  DEPEND[ecdsatest]=../libcrypto
+  DEPEND[ecdsatest]=../libcrypto libtestutil.a
 
-  SOURCE[gmdifftest]=gmdifftest.c testutil.c test_main.c
+  SOURCE[gmdifftest]=gmdifftest.c
   INCLUDE[gmdifftest]=../include
-  DEPEND[gmdifftest]=../libcrypto
+  DEPEND[gmdifftest]=../libcrypto libtestutil.a
 
-  SOURCE[pbelutest]=pbelutest.c testutil.c test_main.c
+  SOURCE[pbelutest]=pbelutest.c
   INCLUDE[pbelutest]=../include
-  DEPEND[pbelutest]=../libcrypto
+  DEPEND[pbelutest]=../libcrypto libtestutil.a
 
-  SOURCE[ideatest]=ideatest.c testutil.c test_main.c
+  SOURCE[ideatest]=ideatest.c
   INCLUDE[ideatest]=../include
-  DEPEND[ideatest]=../libcrypto
+  DEPEND[ideatest]=../libcrypto libtestutil.a
 
-  SOURCE[md2test]=md2test.c testutil.c test_main.c
+  SOURCE[md2test]=md2test.c
   INCLUDE[md2test]=../include
-  DEPEND[md2test]=../libcrypto
+  DEPEND[md2test]=../libcrypto libtestutil.a
 
-  SOURCE[hmactest]=hmactest.c testutil.c test_main.c
+  SOURCE[hmactest]=hmactest.c
   INCLUDE[hmactest]=../include
-  DEPEND[hmactest]=../libcrypto
+  DEPEND[hmactest]=../libcrypto libtestutil.a
 
-  SOURCE[rc2test]=rc2test.c testutil.c test_main.c
+  SOURCE[rc2test]=rc2test.c
   INCLUDE[rc2test]=../include
-  DEPEND[rc2test]=../libcrypto
+  DEPEND[rc2test]=../libcrypto libtestutil.a
 
-  SOURCE[rc4test]=rc4test.c testutil.c test_main.c
+  SOURCE[rc4test]=rc4test.c
   INCLUDE[rc4test]=../include
-  DEPEND[rc4test]=../libcrypto
+  DEPEND[rc4test]=../libcrypto libtestutil.a
 
-  SOURCE[rc5test]=rc5test.c testutil.c test_main.c
+  SOURCE[rc5test]=rc5test.c
   INCLUDE[rc5test]=../include
-  DEPEND[rc5test]=../libcrypto
+  DEPEND[rc5test]=../libcrypto libtestutil.a
 
-  SOURCE[destest]=destest.c testutil.c test_main.c
+  SOURCE[destest]=destest.c
   INCLUDE[destest]=../include
-  DEPEND[destest]=../libcrypto
+  DEPEND[destest]=../libcrypto libtestutil.a
 
-  SOURCE[sha1test]=sha1test.c testutil.c test_main.c
+  SOURCE[sha1test]=sha1test.c
   INCLUDE[sha1test]=../include
-  DEPEND[sha1test]=../libcrypto
+  DEPEND[sha1test]=../libcrypto libtestutil.a
 
-  SOURCE[sha256t]=sha256t.c testutil.c test_main.c
+  SOURCE[sha256t]=sha256t.c
   INCLUDE[sha256t]=../include
-  DEPEND[sha256t]=../libcrypto
+  DEPEND[sha256t]=../libcrypto libtestutil.a
 
-  SOURCE[sha512t]=sha512t.c testutil.c test_main.c
+  SOURCE[sha512t]=sha512t.c
   INCLUDE[sha512t]=../include
-  DEPEND[sha512t]=../libcrypto
+  DEPEND[sha512t]=../libcrypto libtestutil.a
 
-  SOURCE[mdc2test]=mdc2test.c testutil.c test_main.c
+  SOURCE[mdc2test]=mdc2test.c
   INCLUDE[mdc2test]=../include
-  DEPEND[mdc2test]=../libcrypto
+  DEPEND[mdc2test]=../libcrypto libtestutil.a
 
-  SOURCE[randtest]=randtest.c testutil.c test_main.c
+  SOURCE[randtest]=randtest.c
   INCLUDE[randtest]=../include
-  DEPEND[randtest]=../libcrypto
+  DEPEND[randtest]=../libcrypto libtestutil.a
 
-  SOURCE[dhtest]=dhtest.c testutil.c test_main.c
+  SOURCE[dhtest]=dhtest.c
   INCLUDE[dhtest]=.. ../include
-  DEPEND[dhtest]=../libcrypto
+  DEPEND[dhtest]=../libcrypto libtestutil.a
 
-  SOURCE[enginetest]=enginetest.c testutil.c test_main.c
+  SOURCE[enginetest]=enginetest.c
   INCLUDE[enginetest]=../include
-  DEPEND[enginetest]=../libcrypto
+  DEPEND[enginetest]=../libcrypto libtestutil.a
 
-  SOURCE[casttest]=casttest.c testutil.c test_main.c
+  SOURCE[casttest]=casttest.c
   INCLUDE[casttest]=.. ../include
-  DEPEND[casttest]=../libcrypto
+  DEPEND[casttest]=../libcrypto libtestutil.a
 
-  SOURCE[bftest]=bftest.c testutil.c test_main_custom.c
+  SOURCE[bftest]=bftest.c
   INCLUDE[bftest]=../include
-  DEPEND[bftest]=../libcrypto
+  DEPEND[bftest]=../libcrypto libtestutil.a
 
   SOURCE[ssltest_old]=ssltest_old.c
   INCLUDE[ssltest_old]=.. ../include
   DEPEND[ssltest_old]=../libcrypto ../libssl
 
-  SOURCE[dsatest]=dsatest.c testutil.c test_main.c
+  SOURCE[dsatest]=dsatest.c
   INCLUDE[dsatest]=.. ../include
-  DEPEND[dsatest]=../libcrypto
+  DEPEND[dsatest]=../libcrypto libtestutil.a
 
   SOURCE[exptest]=exptest.c
   INCLUDE[exptest]=../include
   DEPEND[exptest]=../libcrypto
 
-  SOURCE[rsa_test]=rsa_test.c testutil.c test_main.c
+  SOURCE[rsa_test]=rsa_test.c
   INCLUDE[rsa_test]=.. ../include
-  DEPEND[rsa_test]=../libcrypto
+  DEPEND[rsa_test]=../libcrypto libtestutil.a
 
   SOURCE[evp_test]=evp_test.c
   INCLUDE[evp_test]=../include
   DEPEND[evp_test]=../libcrypto
 
-  SOURCE[evp_extra_test]=evp_extra_test.c testutil.c test_main.c
+  SOURCE[evp_extra_test]=evp_extra_test.c
   INCLUDE[evp_extra_test]=../include
-  DEPEND[evp_extra_test]=../libcrypto
+  DEPEND[evp_extra_test]=../libcrypto libtestutil.a
 
   SOURCE[igetest]=igetest.c
   INCLUDE[igetest]=.. ../include
   DEPEND[igetest]=../libcrypto
 
-  SOURCE[v3nametest]=v3nametest.c testutil.c test_main.c
+  SOURCE[v3nametest]=v3nametest.c
   INCLUDE[v3nametest]=.. ../include
-  DEPEND[v3nametest]=../libcrypto
+  DEPEND[v3nametest]=../libcrypto libtestutil.a
 
-  SOURCE[crltest]=crltest.c testutil.c test_main.c
+  SOURCE[crltest]=crltest.c
   INCLUDE[crltest]=../include
-  DEPEND[crltest]=../libcrypto
+  DEPEND[crltest]=../libcrypto libtestutil.a
 
-  SOURCE[v3ext]=v3ext.c testutil.c test_main_custom.c
+  SOURCE[v3ext]=v3ext.c
   INCLUDE[v3ext]=../include
-  DEPEND[v3ext]=../libcrypto
+  DEPEND[v3ext]=../libcrypto libtestutil.a
 
   SOURCE[danetest]=danetest.c
   INCLUDE[danetest]=../include
   DEPEND[danetest]=../libcrypto ../libssl
 
-  SOURCE[constant_time_test]=constant_time_test.c testutil.c test_main.c
+  SOURCE[constant_time_test]=constant_time_test.c
   INCLUDE[constant_time_test]=.. ../include
-  DEPEND[constant_time_test]=../libcrypto
+  DEPEND[constant_time_test]=../libcrypto libtestutil.a
 
-  SOURCE[verify_extra_test]=verify_extra_test.c testutil.c test_main_custom.c
+  SOURCE[verify_extra_test]=verify_extra_test.c
   INCLUDE[verify_extra_test]=../include
-  DEPEND[verify_extra_test]=../libcrypto
+  DEPEND[verify_extra_test]=../libcrypto libtestutil.a
 
-  SOURCE[clienthellotest]=clienthellotest.c testutil.c test_main_custom.c
+  SOURCE[clienthellotest]=clienthellotest.c
   INCLUDE[clienthellotest]=../include
-  DEPEND[clienthellotest]=../libcrypto ../libssl
+  DEPEND[clienthellotest]=../libcrypto ../libssl libtestutil.a
 
-  SOURCE[bad_dtls_test]=bad_dtls_test.c testutil.c test_main.c
+  SOURCE[bad_dtls_test]=bad_dtls_test.c
   INCLUDE[bad_dtls_test]=../include
-  DEPEND[bad_dtls_test]=../libcrypto ../libssl
+  DEPEND[bad_dtls_test]=../libcrypto ../libssl libtestutil.a
 
-  SOURCE[packettest]=packettest.c testutil.c test_main.c
+  SOURCE[packettest]=packettest.c
   INCLUDE[packettest]=../include
-  DEPEND[packettest]=../libcrypto
+  DEPEND[packettest]=../libcrypto libtestutil.a
 
   SOURCE[asynctest]=asynctest.c
   INCLUDE[asynctest]=.. ../include
   DEPEND[asynctest]=../libcrypto
 
-  SOURCE[secmemtest]=secmemtest.c testutil.c test_main.c
+  SOURCE[secmemtest]=secmemtest.c
   INCLUDE[secmemtest]=../include
-  DEPEND[secmemtest]=../libcrypto
+  DEPEND[secmemtest]=../libcrypto libtestutil.a
 
-  SOURCE[srptest]=srptest.c testutil.c test_main.c
+  SOURCE[srptest]=srptest.c
   INCLUDE[srptest]=../include
-  DEPEND[srptest]=../libcrypto
+  DEPEND[srptest]=../libcrypto libtestutil.a
 
-  SOURCE[memleaktest]=memleaktest.c testutil.c
+  SOURCE[memleaktest]=memleaktest.c
   INCLUDE[memleaktest]=../include
-  DEPEND[memleaktest]=../libcrypto
+  DEPEND[memleaktest]=../libcrypto libtestutil.a
 
-  SOURCE[stack_test]=stack_test.c testutil.c test_main.c
+  SOURCE[stack_test]=stack_test.c
   INCLUDE[stack_test]=.. ../include
-  DEPEND[stack_test]=../libcrypto
+  DEPEND[stack_test]=../libcrypto libtestutil.a
 
-  SOURCE[lhash_test]=lhash_test.c testutil.c test_main.c
+  SOURCE[lhash_test]=lhash_test.c
   INCLUDE[lhash_test]=.. ../include
-  DEPEND[lhash_test]=../libcrypto
+  DEPEND[lhash_test]=../libcrypto libtestutil.a
 
   SOURCE[dtlsv1listentest]=dtlsv1listentest.c
   INCLUDE[dtlsv1listentest]=.. ../include
   DEPEND[dtlsv1listentest]=../libssl
 
-  SOURCE[ct_test]=ct_test.c testutil.c test_main_custom.c
+  SOURCE[ct_test]=ct_test.c
   INCLUDE[ct_test]=../crypto/include ../include
-  DEPEND[ct_test]=../libcrypto
+  DEPEND[ct_test]=../libcrypto libtestutil.a
 
-  SOURCE[threadstest]=threadstest.c testutil.c test_main.c
+  SOURCE[threadstest]=threadstest.c
   INCLUDE[threadstest]=.. ../include
-  DEPEND[threadstest]=../libcrypto
+  DEPEND[threadstest]=../libcrypto libtestutil.a
 
-  SOURCE[afalgtest]=afalgtest.c testutil.c
+  SOURCE[afalgtest]=afalgtest.c
   INCLUDE[afalgtest]=.. ../include
-  DEPEND[afalgtest]=../libcrypto
+  DEPEND[afalgtest]=../libcrypto libtestutil.a
 
-  SOURCE[d2i_test]=d2i_test.c testutil.c test_main_custom.c
+  SOURCE[d2i_test]=d2i_test.c
   INCLUDE[d2i_test]=.. ../include
-  DEPEND[d2i_test]=../libcrypto
+  DEPEND[d2i_test]=../libcrypto libtestutil.a
 
-  SOURCE[ssl_test_ctx_test]=ssl_test_ctx_test.c ssl_test_ctx.c testutil.c test_main_custom.c
+  SOURCE[ssl_test_ctx_test]=ssl_test_ctx_test.c ssl_test_ctx.c
   INCLUDE[ssl_test_ctx_test]=.. ../include
-  DEPEND[ssl_test_ctx_test]=../libcrypto ../libssl
+  DEPEND[ssl_test_ctx_test]=../libcrypto ../libssl libtestutil.a
 
-  SOURCE[ssl_test]=ssl_test.c ssl_test_ctx.c testutil.c handshake_helper.c test_main_custom.c
+  SOURCE[ssl_test]=ssl_test.c ssl_test_ctx.c handshake_helper.c
   INCLUDE[ssl_test]=.. ../include
-  DEPEND[ssl_test]=../libcrypto ../libssl
+  DEPEND[ssl_test]=../libcrypto ../libssl libtestutil.a
 
-  SOURCE[cipherlist_test]=cipherlist_test.c testutil.c test_main.c
+  SOURCE[cipherlist_test]=cipherlist_test.c
   INCLUDE[cipherlist_test]=.. ../include
-  DEPEND[cipherlist_test]=../libcrypto ../libssl
+  DEPEND[cipherlist_test]=../libcrypto ../libssl libtestutil.a
 
   INCLUDE[testutil.o]=..
   INCLUDE[ssl_test_ctx.o]=../include
   INCLUDE[handshake_helper.o]=../include
   INCLUDE[ssltestlib.o]=.. ../include
 
-  SOURCE[x509aux]=x509aux.c testutil.c test_main_custom.c
+  SOURCE[x509aux]=x509aux.c
   INCLUDE[x509aux]=.. ../include
-  DEPEND[x509aux]=../libcrypto
+  DEPEND[x509aux]=../libcrypto libtestutil.a
 
-  SOURCE[asynciotest]=asynciotest.c ssltestlib.c testutil.c test_main_custom.c
+  SOURCE[asynciotest]=asynciotest.c ssltestlib.c
   INCLUDE[asynciotest]=../include
-  DEPEND[asynciotest]=../libcrypto ../libssl
+  DEPEND[asynciotest]=../libcrypto ../libssl libtestutil.a
 
-  SOURCE[bioprinttest]=bioprinttest.c testutil.c test_main_custom.c
+  SOURCE[bioprinttest]=bioprinttest.c
   INCLUDE[bioprinttest]=../ ../include
-  DEPEND[bioprinttest]=../libcrypto
+  DEPEND[bioprinttest]=../libcrypto libtestutil.a
 
-  SOURCE[sslapitest]=sslapitest.c ssltestlib.c testutil.c test_main_custom.c
+  SOURCE[sslapitest]=sslapitest.c ssltestlib.c
   INCLUDE[sslapitest]=../include ..
-  DEPEND[sslapitest]=../libcrypto ../libssl
+  DEPEND[sslapitest]=../libcrypto ../libssl libtestutil.a
 
-  SOURCE[dtlstest]=dtlstest.c ssltestlib.c testutil.c test_main_custom.c
+  SOURCE[dtlstest]=dtlstest.c ssltestlib.c
   INCLUDE[dtlstest]=../include .
-  DEPEND[dtlstest]=../libcrypto ../libssl
+  DEPEND[dtlstest]=../libcrypto ../libssl libtestutil.a
 
-  SOURCE[sslcorrupttest]=sslcorrupttest.c ssltestlib.c testutil.c test_main_custom.c
+  SOURCE[sslcorrupttest]=sslcorrupttest.c ssltestlib.c
   INCLUDE[sslcorrupttest]=../include .
-  DEPEND[sslcorrupttest]=../libcrypto ../libssl
+  DEPEND[sslcorrupttest]=../libcrypto ../libssl libtestutil.a
 
-  SOURCE[bio_enc_test]=bio_enc_test.c testutil.c test_main.c
+  SOURCE[bio_enc_test]=bio_enc_test.c
   INCLUDE[bio_enc_test]=../include
-  DEPEND[bio_enc_test]=../libcrypto
+  DEPEND[bio_enc_test]=../libcrypto libtestutil.a
 
-  SOURCE[pkey_meth_test]=pkey_meth_test.c testutil.c test_main.c
+  SOURCE[pkey_meth_test]=pkey_meth_test.c
   INCLUDE[pkey_meth_test]=../include
-  DEPEND[pkey_meth_test]=../libcrypto
+  DEPEND[pkey_meth_test]=../libcrypto libtestutil.a
 
-  SOURCE[x509_time_test]=x509_time_test.c testutil.c test_main.c
+  SOURCE[x509_time_test]=x509_time_test.c
   INCLUDE[x509_time_test]=.. ../include
-  DEPEND[x509_time_test]=../libcrypto
+  DEPEND[x509_time_test]=../libcrypto libtestutil.a
 
-  SOURCE[recordlentest]=recordlentest.c ssltestlib.c testutil.c test_main_custom.c
+  SOURCE[recordlentest]=recordlentest.c ssltestlib.c
   INCLUDE[recordlentest]=../include .
-  DEPEND[recordlentest]=../libcrypto ../libssl
+  DEPEND[recordlentest]=../libcrypto ../libssl libtestutil.a
 
-  SOURCE[x509_dup_cert_test]=x509_dup_cert_test.c testutil.c test_main_custom.c
+  SOURCE[x509_dup_cert_test]=x509_dup_cert_test.c
   INCLUDE[x509_dup_cert_test]=../include
-  DEPEND[x509_dup_cert_test]=../libcrypto
+  DEPEND[x509_dup_cert_test]=../libcrypto libtestutil.a
 
   IF[{- !$disabled{psk} -}]
     PROGRAMS_NO_INST=dtls_mtu_test
@@ -315,23 +327,22 @@ IF[{- !$disabled{tests} -}]
 
   IF[{- $disabled{shared} -}]
     PROGRAMS_NO_INST=cipher_overhead_test
-    SOURCE[cipher_overhead_test]=cipher_overhead_test.c testutil.c test_main.c
+    SOURCE[cipher_overhead_test]=cipher_overhead_test.c
     INCLUDE[cipher_overhead_test]=.. ../include
-    DEPEND[cipher_overhead_test]=../libcrypto ../libssl
+    DEPEND[cipher_overhead_test]=../libcrypto ../libssl libtestutil.a
   ENDIF
 
-  SOURCE[uitest]=uitest.c testutil.c test_main_custom.c \
-    ../apps/apps.c ../apps/opt.c {- $apps_extra -}
+  SOURCE[uitest]=uitest.c ../apps/apps.c ../apps/opt.c
   INCLUDE[uitest]=.. ../include
-  DEPEND[uitest]=../libcrypto ../libssl
+  DEPEND[uitest]=../libcrypto ../libssl libtestutil.a
 
-  SOURCE[cipherbytes_test]=cipherbytes_test.c testutil.c test_main_custom.c
+  SOURCE[cipherbytes_test]=cipherbytes_test.c
   INCLUDE[cipherbytes_test]=.. ../include
-  DEPEND[cipherbytes_test]=../libcrypto ../libssl
+  DEPEND[cipherbytes_test]=../libcrypto ../libssl libtestutil.a
 
-  SOURCE[asn1_encode_test]=asn1_encode_test.c testutil.c test_main.c
+  SOURCE[asn1_encode_test]=asn1_encode_test.c
   INCLUDE[asn1_encode_test]=../include
-  DEPEND[asn1_encode_test]=../libcrypto
+  DEPEND[asn1_encode_test]=../libcrypto libtestutil.a
 
   # Internal test programs.  These are essentially a collection of internal
   # test routines.  Some of them need to reach internal symbols that aren't
@@ -354,56 +365,56 @@ IF[{- !$disabled{tests} -}]
       PROGRAMS_NO_INST=siphash_internal_test
     ENDIF
 
-    SOURCE[poly1305_internal_test]=poly1305_internal_test.c testutil.c test_main_custom.c
+    SOURCE[poly1305_internal_test]=poly1305_internal_test.c
     INCLUDE[poly1305_internal_test]=.. ../include ../crypto/include
-    DEPEND[poly1305_internal_test]=../libcrypto.a
+    DEPEND[poly1305_internal_test]=../libcrypto.a libtestutil.a
 
-    SOURCE[chacha_internal_test]=chacha_internal_test.c testutil.c test_main.c
+    SOURCE[chacha_internal_test]=chacha_internal_test.c
     INCLUDE[chacha_internal_test]=.. ../include ../crypto/include
-    DEPEND[chacha_internal_test]=../libcrypto.a
+    DEPEND[chacha_internal_test]=../libcrypto.a libtestutil.a
 
-    SOURCE[asn1_internal_test]=asn1_internal_test.c testutil.c test_main.c
+    SOURCE[asn1_internal_test]=asn1_internal_test.c
     INCLUDE[asn1_internal_test]=.. ../include ../crypto/include
-    DEPEND[asn1_internal_test]=../libcrypto.a
+    DEPEND[asn1_internal_test]=../libcrypto.a libtestutil.a
 
-    SOURCE[modes_internal_test]=modes_internal_test.c testutil.c test_main_custom.c
+    SOURCE[modes_internal_test]=modes_internal_test.c
     INCLUDE[modes_internal_test]=.. ../include
-    DEPEND[modes_internal_test]=../libcrypto.a
+    DEPEND[modes_internal_test]=../libcrypto.a libtestutil.a
 
-    SOURCE[x509_internal_test]=x509_internal_test.c testutil.c test_main.c
+    SOURCE[x509_internal_test]=x509_internal_test.c
     INCLUDE[x509_internal_test]=.. ../include
-    DEPEND[x509_internal_test]=../libcrypto.a
+    DEPEND[x509_internal_test]=../libcrypto.a libtestutil.a
 
-    SOURCE[tls13encryptiontest]=tls13encryptiontest.c testutil.c test_main.c
+    SOURCE[tls13encryptiontest]=tls13encryptiontest.c
     INCLUDE[tls13encryptiontest]=.. ../include
-    DEPEND[tls13encryptiontest]=../libcrypto ../libssl.a
+    DEPEND[tls13encryptiontest]=../libcrypto ../libssl.a libtestutil.a
 
-    SOURCE[wpackettest]=wpackettest.c testutil.c test_main_custom.c
+    SOURCE[wpackettest]=wpackettest.c
     INCLUDE[wpackettest]=../include
-    DEPEND[wpackettest]=../libcrypto ../libssl.a
+    DEPEND[wpackettest]=../libcrypto ../libssl.a libtestutil.a
 
-    SOURCE[siphash_internal_test]=siphash_internal_test.c testutil.c test_main_custom.c
+    SOURCE[siphash_internal_test]=siphash_internal_test.c
     INCLUDE[siphash_internal_test]=.. ../include ../crypto/include
-    DEPEND[siphash_internal_test]=../libcrypto.a
+    DEPEND[siphash_internal_test]=../libcrypto.a libtestutil.a
   ENDIF
 
   IF[{- !$disabled{mdc2} -}]
     PROGRAMS_NO_INST=mdc2_internal_test
   ENDIF
 
-  SOURCE[mdc2_internal_test]=mdc2_internal_test.c testutil.c test_main.c
+  SOURCE[mdc2_internal_test]=mdc2_internal_test.c
   INCLUDE[mdc2_internal_test]=.. ../include
-  DEPEND[mdc2_internal_test]=../libcrypto
+  DEPEND[mdc2_internal_test]=../libcrypto libtestutil.a
 
   # We disable this test completely in a shared build because it deliberately
   # redefines some internal libssl symbols. This doesn't work in a non-shared
   # build
   IF[{- !$disabled{shared} -}]
     PROGRAMS_NO_INST=tls13secretstest
-    SOURCE[tls13secretstest]=tls13secretstest.c testutil.c test_main.c
+    SOURCE[tls13secretstest]=tls13secretstest.c
     SOURCE[tls13secretstest]= ../ssl/tls13_enc.c ../ssl/packet.c
     INCLUDE[tls13secretstest]=.. ../include
-    DEPEND[tls13secretstest]=../libcrypto ../libssl
+    DEPEND[tls13secretstest]=../libcrypto ../libssl libtestutil.a
   ENDIF
 ENDIF
 
diff --git a/test/casttest.c b/test/casttest.c
index fc0c700..24cfbfd 100644
--- a/test/casttest.c
+++ b/test/casttest.c
@@ -13,7 +13,6 @@
 
 #include <openssl/opensslconf.h> /* To see if OPENSSL_NO_CAST is defined */
 #include "e_os.h"
-#include "test_main.h"
 #include "testutil.h"
 
 #ifndef OPENSSL_NO_CAST
diff --git a/test/chacha_internal_test.c b/test/chacha_internal_test.c
index 0c0be9b..de8e4b2 100644
--- a/test/chacha_internal_test.c
+++ b/test/chacha_internal_test.c
@@ -14,7 +14,6 @@
 
 #include <string.h>
 #include <openssl/opensslconf.h>
-#include "test_main.h"
 #include "testutil.h"
 #include "internal/chacha.h"
 
diff --git a/test/cipher_overhead_test.c b/test/cipher_overhead_test.c
index 98d44bd..6bf74a5 100644
--- a/test/cipher_overhead_test.c
+++ b/test/cipher_overhead_test.c
@@ -9,7 +9,6 @@
 
 #include "e_os.h"
 #include "testutil.h"
-#include "test_main.h"
 
 #ifdef __VMS
 # pragma names save
@@ -36,7 +35,7 @@ static int cipher_overhead(void)
             TEST_info("Failed getting %s", ciph->name);
             ret = 0;
         } else {
-            TEST_info("Cipher %s: %"OSSLzu" %"OSSLzu" %"OSSLzu" %"OSSLzu,
+            TEST_info("Cipher %s: %zu %zu %zu %zu",
                       ciph->name, mac, in, blk, ex);
         }
     }
diff --git a/test/cipherbytes_test.c b/test/cipherbytes_test.c
index 00e361b..bc3051e 100644
--- a/test/cipherbytes_test.c
+++ b/test/cipherbytes_test.c
@@ -20,7 +20,6 @@
 
 #include "e_os.h"
 #include "testutil.h"
-#include "test_main_custom.h"
 
 static SSL_CTX *ctx;
 static SSL *s;
diff --git a/test/cipherlist_test.c b/test/cipherlist_test.c
index 31063e6..61551d9 100644
--- a/test/cipherlist_test.c
+++ b/test/cipherlist_test.c
@@ -18,7 +18,6 @@
 #include <openssl/tls1.h>
 
 #include "e_os.h"
-#include "test_main.h"
 #include "testutil.h"
 
 typedef struct cipherlist_test_fixture {
diff --git a/test/clienthellotest.c b/test/clienthellotest.c
index a5d3ad3..2de8512 100644
--- a/test/clienthellotest.c
+++ b/test/clienthellotest.c
@@ -20,7 +20,6 @@
 #include "../ssl/packet_locl.h"
 
 #include "testutil.h"
-#include "test_main_custom.h"
 
 #define CLIENT_VERSION_LEN      2
 
diff --git a/test/constant_time_test.c b/test/constant_time_test.c
index d34e386..3e3542e 100644
--- a/test/constant_time_test.c
+++ b/test/constant_time_test.c
@@ -13,7 +13,6 @@
 #include "e_os.h"
 #include "internal/constant_time_locl.h"
 #include "testutil.h"
-#include "test_main.h"
 #include "internal/numbers.h"
 
 static const unsigned int CONSTTIME_TRUE = (unsigned)(~0);
diff --git a/test/crltest.c b/test/crltest.c
index e633fd3..790fc5f 100644
--- a/test/crltest.c
+++ b/test/crltest.c
@@ -17,7 +17,6 @@
 #include <openssl/x509.h>
 
 #include "testutil.h"
-#include "test_main.h"
 
 #define PARAM_TIME 1474934400 /* Sep 27th, 2016 */
 
diff --git a/test/ct_test.c b/test/ct_test.c
index e96eab0..583db44 100644
--- a/test/ct_test.c
+++ b/test/ct_test.c
@@ -19,7 +19,6 @@
 #include <openssl/x509.h>
 #include <openssl/x509v3.h>
 #include "testutil.h"
-#include "test_main_custom.h"
 
 #ifndef OPENSSL_NO_CT
 /* Used when declaring buffers to read text files into */
diff --git a/test/d2i_test.c b/test/d2i_test.c
index 0413ceb..8126ace 100644
--- a/test/d2i_test.c
+++ b/test/d2i_test.c
@@ -13,7 +13,6 @@
 #include <string.h>
 
 #include "testutil.h"
-#include "test_main_custom.h"
 
 #include <openssl/asn1.h>
 #include <openssl/asn1t.h>
diff --git a/test/destest.c b/test/destest.c
index b863ee8..2aae1ca 100644
--- a/test/destest.c
+++ b/test/destest.c
@@ -10,7 +10,6 @@
 #include <openssl/e_os2.h>
 #include <string.h>
 
-#include "test_main.h"
 #include "testutil.h"
 
 #ifndef OPENSSL_NO_DES
diff --git a/test/dhtest.c b/test/dhtest.c
index eb6ec0e..618b84e 100644
--- a/test/dhtest.c
+++ b/test/dhtest.c
@@ -17,7 +17,6 @@
 #include <openssl/bn.h>
 #include <openssl/rand.h>
 #include <openssl/err.h>
-#include "test_main.h"
 #include "testutil.h"
 
 #ifdef OPENSSL_NO_DH
diff --git a/test/dsatest.c b/test/dsatest.c
index bff0b96..e4ed8eb 100644
--- a/test/dsatest.c
+++ b/test/dsatest.c
@@ -18,7 +18,6 @@
 #include <openssl/bn.h>
 #include <openssl/dsa.h>
 
-#include "test_main.h"
 #include "testutil.h"
 #include "e_os.h"
 
diff --git a/test/dtlstest.c b/test/dtlstest.c
index cb58b18..b766802 100644
--- a/test/dtlstest.c
+++ b/test/dtlstest.c
@@ -14,7 +14,6 @@
 
 #include "ssltestlib.h"
 #include "testutil.h"
-#include "test_main_custom.h"
 
 static char *cert = NULL;
 static char *privkey = NULL;
diff --git a/test/ecdsatest.c b/test/ecdsatest.c
index 8b1e566..561ff0c 100644
--- a/test/ecdsatest.c
+++ b/test/ecdsatest.c
@@ -46,7 +46,6 @@ int main(int argc, char *argv[])
 # include <openssl/err.h>
 # include <openssl/rand.h>
 # include "testutil.h"
-# include "test_main.h"
 
 static const char rnd_seed[] = "string to make the random number generator "
     "think it has entropy";
diff --git a/test/enginetest.c b/test/enginetest.c
index 89107a3..55bb4e0 100644
--- a/test/enginetest.c
+++ b/test/enginetest.c
@@ -23,7 +23,6 @@ int main(int argc, char *argv[])
 # include <openssl/engine.h>
 # include <openssl/err.h>
 # include "testutil.h"
-# include "test_main.h"
 
 static void display_engine_list(void)
 {
diff --git a/test/evp_extra_test.c b/test/evp_extra_test.c
index b8cfc0d..80737f9 100644
--- a/test/evp_extra_test.c
+++ b/test/evp_extra_test.c
@@ -16,7 +16,6 @@
 #include <openssl/rsa.h>
 #include <openssl/x509.h>
 #include "testutil.h"
-#include "test_main.h"
 
 /*
  * kExampleRSAKeyDER is an RSA private key in ASN.1, DER format. Of course, you
diff --git a/test/exdatatest.c b/test/exdatatest.c
index fb1694d..8880f6f 100644
--- a/test/exdatatest.c
+++ b/test/exdatatest.c
@@ -12,7 +12,6 @@
 #include <stdlib.h>
 #include <openssl/crypto.h>
 
-#include "test_main.h"
 #include "testutil.h"
 
 static long saved_argl;
diff --git a/test/gmdifftest.c b/test/gmdifftest.c
index 462436f..1d508c0 100644
--- a/test/gmdifftest.c
+++ b/test/gmdifftest.c
@@ -9,7 +9,6 @@
 
 #include <openssl/crypto.h>
 
-#include "test_main.h"
 #include "testutil.h"
 
 #define SECS_PER_DAY (24 * 60 * 60)
diff --git a/test/hmactest.c b/test/hmactest.c
index d7e68b4..db1b7af 100644
--- a/test/hmactest.c
+++ b/test/hmactest.c
@@ -23,7 +23,6 @@
 #  include <openssl/ebcdic.h>
 # endif
 
-#include "test_main.h"
 #include "testutil.h"
 
 # ifndef OPENSSL_NO_MD5
diff --git a/test/ideatest.c b/test/ideatest.c
index a208334..14d69dc 100644
--- a/test/ideatest.c
+++ b/test/ideatest.c
@@ -10,7 +10,6 @@
 #include <string.h>
 
 #include "../e_os.h"
-#include "test_main.h"
 #include "testutil.h"
 
 #ifndef OPENSSL_NO_IDEA
diff --git a/test/lhash_test.c b/test/lhash_test.c
index 1761efd..b812796 100644
--- a/test/lhash_test.c
+++ b/test/lhash_test.c
@@ -20,7 +20,6 @@
 #include <openssl/crypto.h>
 
 #include "e_os.h"
-#include "test_main.h"
 #include "testutil.h"
 
 /*
diff --git a/test/md2test.c b/test/md2test.c
index 81a1760..7a1436d 100644
--- a/test/md2test.c
+++ b/test/md2test.c
@@ -10,7 +10,6 @@
 #include <string.h>
 
 #include "../e_os.h"
-#include "test_main.h"
 #include "testutil.h"
 
 #ifndef OPENSSL_NO_MD2
diff --git a/test/mdc2_internal_test.c b/test/mdc2_internal_test.c
index 7deaf26..d696ea7 100644
--- a/test/mdc2_internal_test.c
+++ b/test/mdc2_internal_test.c
@@ -14,7 +14,6 @@
 
 #include <openssl/mdc2.h>
 #include "testutil.h"
-#include "test_main.h"
 #include "e_os.h"
 
 typedef struct {
diff --git a/test/mdc2test.c b/test/mdc2test.c
index fb513e1..724d6d3 100644
--- a/test/mdc2test.c
+++ b/test/mdc2test.c
@@ -10,7 +10,6 @@
 #include <string.h>
 
 #include "../e_os.h"
-#include "test_main.h"
 #include "testutil.h"
 
 #if defined(OPENSSL_NO_DES) && !defined(OPENSSL_NO_MDC2)
diff --git a/test/modes_internal_test.c b/test/modes_internal_test.c
index 087115b..b3a2b10 100644
--- a/test/modes_internal_test.c
+++ b/test/modes_internal_test.c
@@ -16,7 +16,6 @@
 #include <openssl/modes.h>
 #include "../crypto/modes/modes_lcl.h"
 #include "testutil.h"
-#include "test_main_custom.h"
 #include "e_os.h"
 
 typedef struct {
diff --git a/test/packettest.c b/test/packettest.c
index 7ee4a08..4866d27 100644
--- a/test/packettest.c
+++ b/test/packettest.c
@@ -9,7 +9,6 @@
 
 #include "../ssl/packet_locl.h"
 #include "testutil.h"
-#include "test_main.h"
 
 #define BUF_LEN 255
 
diff --git a/test/pbelutest.c b/test/pbelutest.c
index 11189b4..c6ce586 100644
--- a/test/pbelutest.c
+++ b/test/pbelutest.c
@@ -9,7 +9,6 @@
 
 #include <openssl/evp.h>
 #include "testutil.h"
-#include "test_main.h"
 
 /*
  * Password based encryption (PBE) table ordering test.
diff --git a/test/pkey_meth_test.c b/test/pkey_meth_test.c
index 8876537..adff232 100644
--- a/test/pkey_meth_test.c
+++ b/test/pkey_meth_test.c
@@ -14,7 +14,6 @@
 
 #include <openssl/evp.h>
 #include "testutil.h"
-#include "test_main.h"
 
 /**********************************************************************
  *
diff --git a/test/poly1305_internal_test.c b/test/poly1305_internal_test.c
index 03b0fa9..a6825d2 100644
--- a/test/poly1305_internal_test.c
+++ b/test/poly1305_internal_test.c
@@ -13,7 +13,6 @@
 #include <string.h>
 
 #include "testutil.h"
-#include "test_main_custom.h"
 #include "internal/poly1305.h"
 #include "../crypto/poly1305/poly1305_local.h"
 #include "e_os.h"
@@ -1600,7 +1599,7 @@ static int test_poly1305(int idx)
             Poly1305_Final(&poly1305, out);
 
             if (!TEST_mem_eq(out, expectedlen, expected, expectedlen)) {
-                TEST_info("Poly1305 test #%d/%" OSSLzu "+%" OSSLzu " failed.",
+                TEST_info("Poly1305 test #%d/%zu+%zu failed.",
                           idx, half, inlen-half);
                 return 0;
             }
diff --git a/test/randtest.c b/test/randtest.c
index e1d84c3..8ef5943 100644
--- a/test/randtest.c
+++ b/test/randtest.c
@@ -9,7 +9,6 @@
 
 #include <openssl/rand.h>
 #include "testutil.h"
-#include "test_main.h"
 
 /* some FIPS 140-1 random number test */
 /* some simple tests */
diff --git a/test/rc2test.c b/test/rc2test.c
index 2553c91..0561576 100644
--- a/test/rc2test.c
+++ b/test/rc2test.c
@@ -8,7 +8,6 @@
  */
 
 #include "../e_os.h"
-#include "test_main.h"
 #include "testutil.h"
 
 #ifndef OPENSSL_NO_RC2
diff --git a/test/rc4test.c b/test/rc4test.c
index e6d4ccf..bf2ec31 100644
--- a/test/rc4test.c
+++ b/test/rc4test.c
@@ -10,7 +10,6 @@
 #include <string.h>
 
 #include "../e_os.h"
-#include "test_main.h"
 #include "testutil.h"
 
 #ifndef OPENSSL_NO_RC4
diff --git a/test/rc5test.c b/test/rc5test.c
index bc2cd97..bd02f72 100644
--- a/test/rc5test.c
+++ b/test/rc5test.c
@@ -10,7 +10,6 @@
 #include <string.h>
 
 #include "../e_os.h"
-#include "test_main.h"
 #include "testutil.h"
 
 #ifndef OPENSSL_NO_RC5
diff --git a/test/recordlentest.c b/test/recordlentest.c
index 7063149..57c4648 100644
--- a/test/recordlentest.c
+++ b/test/recordlentest.c
@@ -11,7 +11,6 @@
 
 #include "ssltestlib.h"
 #include "testutil.h"
-#include "test_main_custom.h"
 
 static char *cert = NULL;
 static char *privkey = NULL;
diff --git a/test/rsa_test.c b/test/rsa_test.c
index ea10c8e..47be258 100644
--- a/test/rsa_test.c
+++ b/test/rsa_test.c
@@ -19,7 +19,6 @@
 #include <openssl/rand.h>
 #include <openssl/bn.h>
 
-#include "test_main.h"
 #include "testutil.h"
 
 #ifdef OPENSSL_NO_RSA
diff --git a/test/sanitytest.c b/test/sanitytest.c
index 3ef0a37..5a9e6bb 100644
--- a/test/sanitytest.c
+++ b/test/sanitytest.c
@@ -10,7 +10,6 @@
 #include <string.h>
 #include <internal/numbers.h>
 
-#include "test_main.h"
 #include "testutil.h"
 
 static int test_sanity_null_zero(void)
diff --git a/test/secmemtest.c b/test/secmemtest.c
index 9fd0235..3244d06 100644
--- a/test/secmemtest.c
+++ b/test/secmemtest.c
@@ -9,7 +9,6 @@
 
 #include <openssl/crypto.h>
 
-#include "test_main.h"
 #include "testutil.h"
 
 static int test_sec_mem(void)
diff --git a/test/sha1test.c b/test/sha1test.c
index 25c7f10..6a8b304 100644
--- a/test/sha1test.c
+++ b/test/sha1test.c
@@ -11,7 +11,6 @@
 #include <string.h>
 
 #include "../e_os.h"
-#include "test_main.h"
 #include "testutil.h"
 
 #include <openssl/evp.h>
diff --git a/test/sha256t.c b/test/sha256t.c
index 29e65d5..c6ce1ae 100644
--- a/test/sha256t.c
+++ b/test/sha256t.c
@@ -10,7 +10,6 @@
 #include <openssl/sha.h>
 #include <openssl/evp.h>
 
-#include "test_main.h"
 #include "testutil.h"
 
 static const unsigned char app_b1[SHA256_DIGEST_LENGTH] = {
diff --git a/test/sha512t.c b/test/sha512t.c
index 91efa32..2a1bd1b 100644
--- a/test/sha512t.c
+++ b/test/sha512t.c
@@ -10,7 +10,6 @@
 #include <openssl/sha.h>
 #include <openssl/evp.h>
 
-#include "test_main.h"
 #include "testutil.h"
 
 static const unsigned char app_c1[SHA512_DIGEST_LENGTH] = {
diff --git a/test/siphash_internal_test.c b/test/siphash_internal_test.c
index fd097e0..0114af1 100644
--- a/test/siphash_internal_test.c
+++ b/test/siphash_internal_test.c
@@ -14,7 +14,6 @@
 
 #include <openssl/bio.h>
 #include "testutil.h"
-#include "test_main_custom.h"
 #include "internal/siphash.h"
 #include "../crypto/siphash/siphash_local.h"
 #include "e_os.h"
@@ -226,7 +225,7 @@ static int test_siphash(int idx)
 
     if (expectedlen != SIPHASH_MIN_DIGEST_SIZE &&
         expectedlen != SIPHASH_MAX_DIGEST_SIZE) {
-        TEST_info("size %" OSSLzu " vs %d and %d", expectedlen,
+        TEST_info("size %zu vs %d and %d", expectedlen,
                   SIPHASH_MIN_DIGEST_SIZE, SIPHASH_MAX_DIGEST_SIZE);
         return 0;
     }
@@ -286,7 +285,7 @@ static int test_siphash(int idx)
                 return 0;
 
             if (!TEST_mem_eq(out, expectedlen, expected, expectedlen)) {
-                TEST_info("SipHash test #%d/%" OSSLzu "+%" OSSLzu " failed.",
+                TEST_info("SipHash test #%d/%zu+%zu failed.",
                           idx, half, inlen-half);
                 return 0;
             }
diff --git a/test/srptest.c b/test/srptest.c
index 6d14571..c908c39 100644
--- a/test/srptest.c
+++ b/test/srptest.c
@@ -24,7 +24,6 @@ int main(int argc, char *argv[])
 # include <openssl/rand.h>
 # include <openssl/err.h>
 # include "testutil.h"
-# include "test_main.h"
 
 static void showbn(const char *name, const BIGNUM *bn)
 {
diff --git a/test/ssl_test.c b/test/ssl_test.c
index 9406f94..092e755 100644
--- a/test/ssl_test.c
+++ b/test/ssl_test.c
@@ -17,7 +17,6 @@
 #include "handshake_helper.h"
 #include "ssl_test_ctx.h"
 #include "testutil.h"
-#include "test_main_custom.h"
 
 static CONF *conf = NULL;
 
diff --git a/test/ssl_test_ctx_test.c b/test/ssl_test_ctx_test.c
index 6f277e5..2a633f9 100644
--- a/test/ssl_test_ctx_test.c
+++ b/test/ssl_test_ctx_test.c
@@ -18,7 +18,6 @@
 #include "e_os.h"
 #include "ssl_test_ctx.h"
 #include "testutil.h"
-#include "test_main_custom.h"
 #include <openssl/e_os2.h>
 #include <openssl/err.h>
 #include <openssl/conf.h>
diff --git a/test/sslapitest.c b/test/sslapitest.c
index 3b4d01a..436fbbb 100644
--- a/test/sslapitest.c
+++ b/test/sslapitest.c
@@ -17,7 +17,6 @@
 
 #include "ssltestlib.h"
 #include "testutil.h"
-#include "test_main_custom.h"
 #include "e_os.h"
 
 static char *cert = NULL;
diff --git a/test/sslcorrupttest.c b/test/sslcorrupttest.c
index 98e5bb3..c480f23 100644
--- a/test/sslcorrupttest.c
+++ b/test/sslcorrupttest.c
@@ -10,7 +10,6 @@
 #include <string.h>
 #include "ssltestlib.h"
 #include "testutil.h"
-#include "test_main_custom.h"
 
 static int docorrupt = 0;
 
diff --git a/test/stack_test.c b/test/stack_test.c
index 25b2e00..6d1cd91 100644
--- a/test/stack_test.c
+++ b/test/stack_test.c
@@ -20,7 +20,6 @@
 #include <openssl/crypto.h>
 
 #include "e_os.h"
-#include "test_main.h"
 #include "testutil.h"
 
 /* The macros below generate unused functions which error out one of the clang
diff --git a/test/test_main.h b/test/test_main.h
deleted file mode 100644
index ce0d06a..0000000
--- a/test/test_main.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
- *
- * Licensed under the OpenSSL license (the "License").  You may not use
- * this file except in compliance with the License.  You can obtain a copy
- * in the file LICENSE in the source distribution or at
- * https://www.openssl.org/source/license.html
- */
-
-#ifndef HEADER_TEST_MAIN_H
-# define HEADER_TEST_MAIN_H
-
-/*
- * Simple unit tests should implement register_tests() and link to test_main.c.
- */
-extern void register_tests(void);
-
-#endif  /* HEADER_TEST_MAIN_H */
diff --git a/test/test_main_custom.h b/test/test_main_custom.h
deleted file mode 100644
index 22bc8f5..0000000
--- a/test/test_main_custom.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
- *
- * Licensed under the OpenSSL license (the "License").  You may not use
- * this file except in compliance with the License.  You can obtain a copy
- * in the file LICENSE in the source distribution or at
- * https://www.openssl.org/source/license.html
- */
-
-#ifndef HEADER_TEST_MAIN_CUSTOM_H
-# define HEADER_TEST_MAIN_CUSTOM_H
-
-/*
- * Unit tests that need a custom main() should implement test_main and link to
- * test_main_custom.c
- * test_main() should return the result of run_tests().
- */
-extern int test_main(int argc, char *argv[]);
-
-#endif  /* HEADER_TEST_MAIN_CUSTOM_H */
diff --git a/test/test_test.c b/test/test_test.c
index a154289..879a051 100644
--- a/test/test_test.c
+++ b/test/test_test.c
@@ -19,7 +19,6 @@
 #include <openssl/crypto.h>
 
 #include "e_os.h"
-#include "test_main.h"
 #include "testutil.h"
 
 #define C(l, b, t)                                      \
diff --git a/test/testutil.h b/test/testutil.h
index e7478a8..5d96ddd 100644
--- a/test/testutil.h
+++ b/test/testutil.h
@@ -16,12 +16,9 @@
 #include <openssl/e_os2.h>
 
 /*-
- * Simple unit tests should implement register_tests() from test_main.h
- * and link against test_main.c.
+ * Simple unit tests should implement register_tests().
  * To register tests, call ADD_TEST or ADD_ALL_TESTS:
  *
- * #include "test_main.h"
- *
  * void register_tests(void)
  * {
  *     ADD_TEST(test_foo);
@@ -29,8 +26,7 @@
  * }
  *
  * Tests that need to perform custom setup or read command-line arguments should
- * implement test_main() from test_main_custom.h and link against
- * test_main_custom.c:
+ * implement test_main():
  *
  * int test_main(int argc, char *argv[])
  * {
@@ -139,13 +135,26 @@ void add_all_tests(const char *test_case_name, int (*test_fn)(int idx), int num)
 __owur int run_tests(const char *test_prog_name);
 
 /*
+ * Declarations for user defined functions
+ */
+void register_tests(void);
+int test_main(int argc, char *argv[]);
+
+
+/*
  *  Test assumption verification helpers.
  */
 
-# if defined(__GNUC__)
-#define PRINTF_FORMAT(a, b)   __attribute__ ((format(printf, a, b)))
-# else
 #define PRINTF_FORMAT(a, b)
+#if defined(__GNUC__) && defined(__STDC_VERSION__)
+  /*
+   * Because we support the 'z' modifier, which made its appearance in C99,
+   * we can't use __attribute__ with pre C99 dialects.
+   */
+# if __STDC_VERSION__ >= 199901L
+#  undef PRINTF_FORMAT
+#  define PRINTF_FORMAT(a, b)   __attribute__ ((format(printf, a, b)))
+# endif
 #endif
 
 #  define DECLARE_COMPARISON(type, name, opname)                        \
@@ -167,7 +176,13 @@ DECLARE_COMPARISONS(char, char)
 DECLARE_COMPARISONS(unsigned char, uchar)
 DECLARE_COMPARISONS(long, long)
 DECLARE_COMPARISONS(unsigned long, ulong)
+/*
+ * Because this comparison uses a printf format specifier that's not
+ * universally known (yet), we provide an option to not have it declared.
+ */
+# ifndef TESTUTIL_NO_size_t_COMPARISON
 DECLARE_COMPARISONS(size_t, size_t)
+# endif
 
 /*
  * Pointer comparisons against other pointers and null.
@@ -335,3 +350,22 @@ void test_info_c90(const char *desc, ...) PRINTF_FORMAT(1, 2);
         }                                       \
     } while (0)
 #endif                          /* HEADER_TESTUTIL_H */
+
+
+/*
+ * The basic I/O functions used by the test framework.  These can be
+ * overriden when needed. Note that if one is, then all must be.
+ */
+void test_open_streams(void);
+void test_close_streams(void);
+/* The following ALL return the number of characters written */
+int test_puts_stdout(const char *str);
+int test_puts_stderr(const char *str);
+int test_vprintf_stdout(const char *fmt, va_list ap);
+int test_vprintf_stderr(const char *fmt, va_list ap);
+/* These return failure or success */
+int test_flush_stdout(void);
+int test_flush_stderr(void);
+
+extern BIO *bio_out;
+extern BIO *bio_err;
diff --git a/test/testutil/basic_output.c b/test/testutil/basic_output.c
new file mode 100644
index 0000000..ac413a6
--- /dev/null
+++ b/test/testutil/basic_output.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2017 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include "../testutil.h"
+
+#include <openssl/crypto.h>
+#include <openssl/bio.h>
+
+BIO *bio_out = NULL;
+BIO *bio_err = NULL;
+
+#ifdef OPENSSL_USE_APPLINK
+/*
+ * Using BIO_new_fd() obligates the use of applinks on platforms where it's
+ * relevant.  Because it becomes a module of the libtestutil library and would
+ * be disregarded if not actively referred to, we have this dummy that does
+ * exactly this.  For any module that uses the rest of the routines here,
+ * OPENSSL_Applink should tag along for sure.
+ */
+void Applink_dummy(void);
+void Applink_dummy(void)
+{
+    OPENSSL_EXTERN void OPENSSL_Applink(void);
+
+    OPENSSL_Applink();
+}
+/* Generate an error for anyone who tries to actually use this dummy */
+# define Applink_dummy "DON'T USE THIS"
+#endif
+
+void test_open_streams(void)
+{
+    bio_out = BIO_new_fd(1, 0);
+    bio_err = BIO_new_fd(2, 0);
+
+    OPENSSL_assert(bio_out != NULL);
+    OPENSSL_assert(bio_err != NULL);
+}
+
+void test_close_streams(void)
+{
+    BIO_free(bio_out);
+    BIO_free(bio_err);
+}
+
+int test_puts_stdout(const char *str)
+{
+    return BIO_puts(bio_out, str);
+}
+
+int test_puts_stderr(const char *str)
+{
+    return BIO_puts(bio_err, str);
+}
+
+int test_vprintf_stdout(const char *fmt, va_list ap)
+{
+    return BIO_vprintf(bio_out, fmt, ap);
+}
+
+int test_vprintf_stderr(const char *fmt, va_list ap)
+{
+    return BIO_vprintf(bio_err, fmt, ap);
+}
+
+int test_flush_stdout(void)
+{
+    return BIO_flush(bio_out);
+}
+
+int test_flush_stderr(void)
+{
+    return BIO_flush(bio_err);
+}
diff --git a/test/testutil/driver.c b/test/testutil/driver.c
new file mode 100644
index 0000000..e70fd21
--- /dev/null
+++ b/test/testutil/driver.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2016-2017 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include "../testutil.h"
+
+#include <string.h>
+#include <assert.h>
+
+#include "../../e_os.h"
+#include <openssl/bio.h>
+
+/*
+ * Declares the structures needed to register each test case function.
+ */
+typedef struct test_info {
+    const char *test_case_name;
+    int (*test_fn) ();
+    int (*param_test_fn)(int idx);
+    int num;
+} TEST_INFO;
+
+static TEST_INFO all_tests[1024];
+static int num_tests = 0;
+/*
+ * A parameterised tests runs a loop of test cases.
+ * |num_test_cases| counts the total number of test cases
+ * across all tests.
+ */
+static int num_test_cases = 0;
+
+void add_test(const char *test_case_name, int (*test_fn) ())
+{
+    assert(num_tests != OSSL_NELEM(all_tests));
+    all_tests[num_tests].test_case_name = test_case_name;
+    all_tests[num_tests].test_fn = test_fn;
+    all_tests[num_tests].num = -1;
+    ++num_tests;
+    ++num_test_cases;
+}
+
+void add_all_tests(const char *test_case_name, int(*test_fn)(int idx),
+                   int num)
+{
+    assert(num_tests != OSSL_NELEM(all_tests));
+    all_tests[num_tests].test_case_name = test_case_name;
+    all_tests[num_tests].param_test_fn = test_fn;
+    all_tests[num_tests].num = num;
+    ++num_tests;
+    num_test_cases += num;
+}
+
+#ifndef OPENSSL_NO_CRYPTO_MDEBUG
+static int should_report_leaks()
+{
+    /*
+     * When compiled with enable-crypto-mdebug, OPENSSL_DEBUG_MEMORY=0
+     * can be used to disable leak checking at runtime.
+     * Note this only works when running the test binary manually;
+     * the test harness always enables OPENSSL_DEBUG_MEMORY.
+     */
+    char *mem_debug_env = getenv("OPENSSL_DEBUG_MEMORY");
+
+    return mem_debug_env == NULL
+        || (strcmp(mem_debug_env, "0") && strcmp(mem_debug_env, ""));
+}
+#endif
+
+
+static int err_cb(const char *str, size_t len, void *u)
+{
+    return test_puts_stderr(str);
+}
+
+void setup_test()
+{
+    test_open_streams();
+
+#ifndef OPENSSL_NO_CRYPTO_MDEBUG
+    if (should_report_leaks()) {
+        CRYPTO_set_mem_debug(1);
+        CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
+    }
+#endif
+}
+
+int finish_test(int ret)
+{
+#ifndef OPENSSL_NO_CRYPTO_MDEBUG
+    if (should_report_leaks() && CRYPTO_mem_leaks_cb(err_cb, NULL) <= 0)
+        return EXIT_FAILURE;
+#endif
+
+    test_close_streams();
+
+    return ret;
+}
+
+static void finalize(int success)
+{
+    if (success)
+        ERR_clear_error();
+    else
+        ERR_print_errors_cb(err_cb, NULL);
+}
+
+static void helper_printf_stdout(const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start(ap, fmt);
+    test_vprintf_stdout(fmt, ap);
+    va_end(ap);
+}
+
+int run_tests(const char *test_prog_name)
+{
+    int num_failed = 0;
+    int i, j;
+
+    helper_printf_stdout("%s: %d test case%s\n", test_prog_name, num_test_cases,
+                         num_test_cases == 1 ? "" : "s");
+    test_flush_stdout();
+
+    for (i = 0; i != num_tests; ++i) {
+        if (all_tests[i].num == -1) {
+            int ret = all_tests[i].test_fn();
+
+            if (!ret) {
+                helper_printf_stdout("** %s failed **\n--------\n",
+                                     all_tests[i].test_case_name);
+                test_flush_stdout();
+                ++num_failed;
+            }
+            finalize(ret);
+        } else {
+            for (j = 0; j < all_tests[i].num; j++) {
+                int ret = all_tests[i].param_test_fn(j);
+
+                if (!ret) {
+                    helper_printf_stdout("** %s failed test %d\n--------\n",
+                                         all_tests[i].test_case_name, j);
+                    test_flush_stdout();
+                    ++num_failed;
+                }
+                finalize(ret);
+            }
+        }
+    }
+
+    if (num_failed != 0) {
+        helper_printf_stdout("%s: %d test%s failed (out of %d)\n",
+                             test_prog_name, num_failed,
+                             num_failed != 1 ? "s" : "", num_test_cases);
+        test_flush_stdout();
+        return EXIT_FAILURE;
+    }
+    helper_printf_stdout("  All tests passed.\n");
+    test_flush_stdout();
+    return EXIT_SUCCESS;
+}
+
diff --git a/test/test_main_custom.c b/test/testutil/main.c
similarity index 71%
rename from test/test_main_custom.c
rename to test/testutil/main.c
index e10f279..435a358 100644
--- a/test/test_main_custom.c
+++ b/test/testutil/main.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2016-2017 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the OpenSSL license (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -7,11 +7,7 @@
  * https://www.openssl.org/source/license.html
  */
 
-#include "test_main_custom.h"
-#include "testutil.h"
-
-#include <stdio.h>
-#include <stdlib.h>
+#include "../testutil.h"
 
 int main(int argc, char *argv[])
 {
diff --git a/test/test_main.c b/test/testutil/test_main.c
similarity index 51%
rename from test/test_main.c
rename to test/testutil/test_main.c
index 99b21ac..0152421 100644
--- a/test/test_main.c
+++ b/test/testutil/test_main.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2016-2017 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the OpenSSL license (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -7,20 +7,15 @@
  * https://www.openssl.org/source/license.html
  */
 
-#include "test_main.h"
-#include "testutil.h"
+#include "../testutil.h"
 
 #include <stdio.h>
 
-int main(int argc, char *argv[])
+int test_main(int argc, char *argv[])
 {
-    int ret;
     if (argc > 1)
-        printf("Warning: ignoring extra command-line arguments.\n");
+        test_puts_stderr("Warning: ignoring extra command-line arguments.\n");
 
-    setup_test();
     register_tests();
-    ret = run_tests(argv[0]);
-
-    return finish_test(ret);
+    return run_tests(argv[0]);
 }
diff --git a/test/testutil.c b/test/testutil/tests.c
similarity index 71%
rename from test/testutil.c
rename to test/testutil/tests.c
index ae98e10..f00ec6c 100644
--- a/test/testutil.c
+++ b/test/testutil/tests.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2014-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2017 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the OpenSSL license (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -7,153 +7,15 @@
  * https://www.openssl.org/source/license.html
  */
 
-#include "testutil.h"
+#include "../testutil.h"
 
-#include <assert.h>
-#include <stdlib.h>
-#include <stdio.h>
 #include <string.h>
-#include "e_os.h"
-
-#include <openssl/opensslconf.h>
-#include <openssl/crypto.h>
-#include <openssl/err.h>
+#include "../../e_os.h"
 
 /* The size of memory buffers to display on failure */
 #define MEM_BUFFER_SIZE     (21)
 
 /*
- * Declares the structures needed to register each test case function.
- */
-typedef struct test_info {
-    const char *test_case_name;
-    int (*test_fn) ();
-    int (*param_test_fn)(int idx);
-    int num;
-} TEST_INFO;
-
-static TEST_INFO all_tests[1024];
-static int num_tests = 0;
-/*
- * A parameterised tests runs a loop of test cases.
- * |num_test_cases| counts the total number of test cases
- * across all tests.
- */
-static int num_test_cases = 0;
-
-void add_test(const char *test_case_name, int (*test_fn) ())
-{
-    assert(num_tests != OSSL_NELEM(all_tests));
-    all_tests[num_tests].test_case_name = test_case_name;
-    all_tests[num_tests].test_fn = test_fn;
-    all_tests[num_tests].num = -1;
-    ++num_test_cases;
-    ++num_tests;
-}
-
-void add_all_tests(const char *test_case_name, int(*test_fn)(int idx),
-                   int num)
-{
-    assert(num_tests != OSSL_NELEM(all_tests));
-    all_tests[num_tests].test_case_name = test_case_name;
-    all_tests[num_tests].param_test_fn = test_fn;
-    all_tests[num_tests].num = num;
-    ++num_tests;
-    num_test_cases += num;
-}
-
-#ifndef OPENSSL_NO_CRYPTO_MDEBUG
-static int should_report_leaks()
-{
-    /*
-     * When compiled with enable-crypto-mdebug, OPENSSL_DEBUG_MEMORY=0
-     * can be used to disable leak checking at runtime.
-     * Note this only works when running the test binary manually;
-     * the test harness always enables OPENSSL_DEBUG_MEMORY.
-     */
-    char *mem_debug_env = getenv("OPENSSL_DEBUG_MEMORY");
-
-    return mem_debug_env == NULL
-        || (strcmp(mem_debug_env, "0") && strcmp(mem_debug_env, ""));
-}
-#endif
-
-
-void setup_test()
-{
-#ifndef OPENSSL_NO_CRYPTO_MDEBUG
-    if (should_report_leaks()) {
-        CRYPTO_set_mem_debug(1);
-        CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
-    }
-#endif
-}
-
-int finish_test(int ret)
-{
-#ifndef OPENSSL_NO_CRYPTO_MDEBUG
-    if (should_report_leaks() && CRYPTO_mem_leaks_fp(stderr) <= 0)
-        return EXIT_FAILURE;
-#endif
-    return ret;
-}
-
-static void finalize(int success)
-{
-    if (success)
-        ERR_clear_error();
-    else
-        ERR_print_errors_fp(stderr);
-}
-
-int run_tests(const char *test_prog_name)
-{
-    int num_failed = 0;
-
-    int i, j;
-
-    printf("%s: %d test case%s\n", test_prog_name, num_test_cases,
-           num_test_cases == 1 ? "" : "s");
-    fflush(stdout);
-
-    for (i = 0; i != num_tests; ++i) {
-        if (all_tests[i].num == -1) {
-            int ret = all_tests[i].test_fn();
-
-            if (!ret) {
-                printf("** %s failed **\n--------\n",
-                       all_tests[i].test_case_name);
-                fflush(stdout);
-                ++num_failed;
-            }
-            finalize(ret);
-        } else {
-            for (j = 0; j < all_tests[i].num; j++) {
-                int ret = all_tests[i].param_test_fn(j);
-
-                if (!ret) {
-                    printf("** %s failed test %d\n--------\n",
-                           all_tests[i].test_case_name, j);
-                    fflush(stdout);
-                    ++num_failed;
-                }
-                finalize(ret);
-            }
-        }
-    }
-
-    if (num_failed != 0) {
-        printf("%s: %d test%s failed (out of %d)\n", test_prog_name,
-               num_failed, num_failed != 1 ? "s" : "", num_test_cases);
-        fflush(stdout);
-        return EXIT_FAILURE;
-    }
-    printf("  All tests passed.\n");
-    fflush(stdout);
-    return EXIT_SUCCESS;
-}
-
-/*
  * A common routine to output test failure messages.  Generally this should not
  * be called directly, rather it should be called by the following functions.
  *
@@ -182,27 +44,38 @@ static void test_fail_message(const char *prefix, const char *file, int line,
                               const char *type, const char *fmt, ...)
             PRINTF_FORMAT(5, 6);
 
+static void helper_printf_stderr(const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start(ap, fmt);
+    test_vprintf_stderr(fmt, ap);
+    va_end(ap);
+}
+
 static void test_fail_message_va(const char *prefix, const char *file, int line,
                                  const char *type, const char *fmt, va_list ap)
 {
-    fputs(prefix != NULL ? prefix : "ERROR", stderr);
-    fputs(":", stderr);
+    test_puts_stderr(prefix != NULL ? prefix : "ERROR");
+    test_puts_stderr(":");
     if (type)
-        fprintf(stderr, " (%s)", type);
+        helper_printf_stderr(" (%s)", type);
     if (fmt != NULL) {
-        fputc(' ', stderr);
-        vfprintf(stderr, fmt, ap);
+        test_puts_stderr(" ");
+        test_vprintf_stderr(fmt, ap);
     }
     if (file != NULL) {
-        fprintf(stderr, " @ %s:%d", file, line);
+        helper_printf_stderr(" @ %s:%d", file, line);
     }
-    fputc('\n', stderr);
+    test_puts_stderr("\n");
+    test_flush_stderr();
 }
 
 static void test_fail_message(const char *prefix, const char *file, int line,
                               const char *type, const char *fmt, ...)
 {
     va_list ap;
+
     va_start(ap, fmt);
     test_fail_message_va(prefix, file, line, type, fmt, ap);
     va_end(ap);
@@ -293,7 +166,7 @@ DEFINE_COMPARISONS(char, char, "%c")
 DEFINE_COMPARISONS(unsigned char, uchar, "%u")
 DEFINE_COMPARISONS(long, long, "%ld")
 DEFINE_COMPARISONS(unsigned long, ulong, "%lu")
-DEFINE_COMPARISONS(size_t, size_t, "%" OSSLzu)
+DEFINE_COMPARISONS(size_t, size_t, "%zu")
 
 DEFINE_COMPARISON(void *, ptr, eq, ==, "%p")
 DEFINE_COMPARISON(void *, ptr, ne, !=, "%p")
@@ -434,14 +307,14 @@ int test_mem_eq(const char *file, int line, const char *st1, const char *st2,
         return 1;
     if (n1 != n2) {
         test_fail_message(NULL, file, line, "memory",
-                          "size mismatch %s %s [%"OSSLzu"] != %s %s [%"OSSLzu"]",
+                          "size mismatch %s %s [%zu] != %s %s [%zu]",
                           st1, print_mem_maybe_null(s1, n1, b1), n1,
                           st2, print_mem_maybe_null(s2, n2, b2), n2);
         return 0;
     }
     if (s1 == NULL || s2 == NULL || memcmp(s1, s2, n1) != 0) {
         test_fail_message(NULL, file, line, "memory",
-                          "%s %s [%"OSSLzu"] != %s %s [%"OSSLzu"]",
+                          "%s %s [%zu] != %s %s [%zu]",
                           st1, print_mem_maybe_null(s1, n1, b1), n1,
                           st2, print_mem_maybe_null(s2, n2, b2), n2);
         return 0;
@@ -460,7 +333,7 @@ int test_mem_ne(const char *file, int line, const char *st1, const char *st2,
         return 1;
     if (s1 == NULL || memcmp(s1, s2, n1) == 0) {
         test_fail_message(NULL, file, line, "memory",
-                          "%s %s [%"OSSLzu"] != %s %s [%"OSSLzu"]",
+                          "%s %s [%zu] != %s %s [%zu]",
                           st1, print_mem_maybe_null(s1, n1, b1), n1,
                           st2, print_mem_maybe_null(s2, n2, b2), n2);
         return 0;
diff --git a/test/threadstest.c b/test/threadstest.c
index 9c735ff..60064d6 100644
--- a/test/threadstest.c
+++ b/test/threadstest.c
@@ -12,7 +12,6 @@
 #endif
 
 #include <openssl/crypto.h>
-#include "test_main.h"
 #include "testutil.h"
 
 #if !defined(OPENSSL_THREADS) || defined(CRYPTO_TDEBUG)
diff --git a/test/tls13encryptiontest.c b/test/tls13encryptiontest.c
index c60d3b6..861a815 100644
--- a/test/tls13encryptiontest.c
+++ b/test/tls13encryptiontest.c
@@ -23,7 +23,6 @@
 #endif
 
 #include "testutil.h"
-#include "test_main.h"
 
 /*
  * Based on the test vectors provided in:
@@ -358,21 +357,21 @@ static int test_tls13_encryption(void)
 
         /* Encrypt it */
         if (!TEST_size_t_eq(tls13_enc(s, &rec, 1, 1), 1)) {
-            TEST_info("Failed to encrypt record %"OSSLzu"", ctr);
+            TEST_info("Failed to encrypt record %zu", ctr);
             goto err;
         }
         if (!TEST_true(test_record(&rec, &refdata[ctr], 1))) {
-            TEST_info("Record %"OSSLzu" encryption test failed", ctr);
+            TEST_info("Record %zu encryption test failed", ctr);
             goto err;
         }
 
         /* Decrypt it */
         if (!TEST_int_eq(tls13_enc(s, &rec, 1, 0), 1)) {
-            TEST_info("Failed to decrypt record %"OSSLzu"", ctr);
+            TEST_info("Failed to decrypt record %zu", ctr);
             goto err;
         }
         if (!TEST_true(test_record(&rec, &refdata[ctr], 0))) {
-            TEST_info("Record %"OSSLzu" decryption test failed", ctr);
+            TEST_info("Record %zu decryption test failed", ctr);
             goto err;
         }
 
diff --git a/test/tls13secretstest.c b/test/tls13secretstest.c
index e74c486..2904ba9 100644
--- a/test/tls13secretstest.c
+++ b/test/tls13secretstest.c
@@ -22,7 +22,6 @@
 #endif
 
 #include "testutil.h"
-#include "test_main.h"
 
 #define IVLEN   12
 #define KEYLEN  16
diff --git a/test/uitest.c b/test/uitest.c
index 574412d..855dc45 100644
--- a/test/uitest.c
+++ b/test/uitest.c
@@ -11,22 +11,11 @@
 #include <string.h>
 #include <openssl/opensslconf.h>
 #include <openssl/err.h>
-
-/*
- * The VMS build does stdio via a socketpair.
- */
-#ifdef __VMS
-# include "../apps/vms_term_sock.h"
-#endif
-
 #include "../apps/apps.h"
-
 #include "testutil.h"
-#include "test_main_custom.h"
 
 /* apps/apps.c depend on these */
 char *default_config_file = NULL;
-BIO *bio_err = NULL;
 
 #ifndef OPENSSL_NO_UI
 # include <openssl/ui.h>
@@ -102,21 +91,10 @@ static int test_new_ui()
 
 #endif
 
-int test_main(int argc, char *argv[])
+void register_tests(void)
 {
-    int ret;
-
-    bio_err = dup_bio_err(FORMAT_TEXT);
-
 #ifndef OPENSSL_NO_UI
     ADD_TEST(test_old);
     ADD_TEST(test_new_ui);
 #endif
-
-    ret = run_tests(argv[0]);
-
-    (void)BIO_flush(bio_err);
-    BIO_free(bio_err);
-
-    return ret;
 }
diff --git a/test/v3ext.c b/test/v3ext.c
index f4cb568..9fbdfd2 100644
--- a/test/v3ext.c
+++ b/test/v3ext.c
@@ -13,7 +13,6 @@
 #include <openssl/pem.h>
 #include <openssl/err.h>
 
-#include "test_main_custom.h"
 #include "testutil.h"
 
 static const char *infile;
diff --git a/test/v3nametest.c b/test/v3nametest.c
index 39dcfe8..cb7b799 100644
--- a/test/v3nametest.c
+++ b/test/v3nametest.c
@@ -12,7 +12,6 @@
 #include <openssl/x509.h>
 #include <openssl/x509v3.h>
 #include "testutil.h"
-#include "test_main.h"
 
 static const char *const names[] = {
     "a", "b", ".", "*", "@",
diff --git a/test/verify_extra_test.c b/test/verify_extra_test.c
index d528fa5..a0df29d 100644
--- a/test/verify_extra_test.c
+++ b/test/verify_extra_test.c
@@ -14,7 +14,6 @@
 #include <openssl/pem.h>
 #include <openssl/err.h>
 #include "testutil.h"
-#include "test_main_custom.h"
 
 static STACK_OF(X509) *load_certs_from_file(const char *filename)
 {
diff --git a/test/wpackettest.c b/test/wpackettest.c
index a37fab7..a0872c5 100644
--- a/test/wpackettest.c
+++ b/test/wpackettest.c
@@ -22,7 +22,6 @@
 #endif
 
 #include "testutil.h"
-#include "test_main_custom.h"
 
 const static unsigned char simple1[] = { 0xff };
 const static unsigned char simple2[] = { 0x01, 0xff };
diff --git a/test/x509_dup_cert_test.c b/test/x509_dup_cert_test.c
index 05899aa..adeb8ea 100644
--- a/test/x509_dup_cert_test.c
+++ b/test/x509_dup_cert_test.c
@@ -15,7 +15,6 @@
 #include <openssl/err.h>
 #include <openssl/x509_vfy.h>
 
-#include "test_main_custom.h"
 #include "testutil.h"
 
 static int test_509_dup_cert(const char *cert_f)
diff --git a/test/x509_internal_test.c b/test/x509_internal_test.c
index 0a3a9be..10cb0b1 100644
--- a/test/x509_internal_test.c
+++ b/test/x509_internal_test.c
@@ -15,7 +15,6 @@
 #include <openssl/x509.h>
 #include <openssl/x509v3.h>
 #include "testutil.h"
-#include "test_main.h"
 #include "e_os.h"
 
 /**********************************************************************
diff --git a/test/x509_time_test.c b/test/x509_time_test.c
index d9a7f50..b73e655 100644
--- a/test/x509_time_test.c
+++ b/test/x509_time_test.c
@@ -15,7 +15,6 @@
 #include <openssl/asn1.h>
 #include <openssl/x509.h>
 #include "testutil.h"
-#include "test_main.h"
 #include "e_os.h"
 
 typedef struct {
diff --git a/test/x509aux.c b/test/x509aux.c
index 7030a13..44a9db1 100644
--- a/test/x509aux.c
+++ b/test/x509aux.c
@@ -17,8 +17,6 @@
 #include <openssl/conf.h>
 #include <openssl/err.h>
 #include "e_os.h"
-#include "test_main.h"
-#include "test_main_custom.h"
 #include "testutil.h"
 
 
diff --git a/util/libcrypto.num b/util/libcrypto.num
index 1a19273..725e075 100644
--- a/util/libcrypto.num
+++ b/util/libcrypto.num
@@ -4270,3 +4270,4 @@ UINT32_it                               4214	1_1_0f	EXIST:!EXPORT_VAR_AS_FUNCTIO
 UINT32_it                               4214	1_1_0f	EXIST:EXPORT_VAR_AS_FUNCTION:FUNCTION:
 ZINT64_it                               4215	1_1_0f	EXIST:!EXPORT_VAR_AS_FUNCTION:VARIABLE:
 ZINT64_it                               4215	1_1_0f	EXIST:EXPORT_VAR_AS_FUNCTION:FUNCTION:
+CRYPTO_mem_leaks_cb                     4216	1_1_1	EXIST::FUNCTION:CRYPTO_MDEBUG


More information about the openssl-commits mailing list