Add malloc test support to unit tests.

Currently far from passing and I haven't even tried with a leak checker yet.
Also bn_test is slow.

Change-Id: I4fe2783aa5f7897839ca846062ae7e4a367d2469
Reviewed-on: https://boringssl-review.googlesource.com/4794
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/CMakeLists.txt b/crypto/CMakeLists.txt
index 7430b62..6858cbb 100644
--- a/crypto/CMakeLists.txt
+++ b/crypto/CMakeLists.txt
@@ -207,6 +207,8 @@
   constant_time_test
 
   constant_time_test.c
+
+  $<TARGET_OBJECTS:test_support>
 )
 
 target_link_libraries(constant_time_test crypto)
@@ -215,6 +217,8 @@
   thread_test
 
   thread_test.c
+
+  $<TARGET_OBJECTS:test_support>
 )
 
 target_link_libraries(thread_test crypto)
diff --git a/crypto/base64/CMakeLists.txt b/crypto/base64/CMakeLists.txt
index 8bc531a..42037a5 100644
--- a/crypto/base64/CMakeLists.txt
+++ b/crypto/base64/CMakeLists.txt
@@ -12,6 +12,8 @@
   base64_test
 
   base64_test.cc
+
+  $<TARGET_OBJECTS:test_support>
 )
 
 target_link_libraries(base64_test crypto)
diff --git a/crypto/bio/CMakeLists.txt b/crypto/bio/CMakeLists.txt
index f4122c4..dbf5951 100644
--- a/crypto/bio/CMakeLists.txt
+++ b/crypto/bio/CMakeLists.txt
@@ -22,6 +22,8 @@
   bio_test
 
   bio_test.cc
+
+  $<TARGET_OBJECTS:test_support>
 )
 
 target_link_libraries(bio_test crypto)
diff --git a/crypto/bn/CMakeLists.txt b/crypto/bn/CMakeLists.txt
index 4a33f7e..2e0cb45 100644
--- a/crypto/bn/CMakeLists.txt
+++ b/crypto/bn/CMakeLists.txt
@@ -70,6 +70,8 @@
   bn_test
 
   bn_test.cc
+
+  $<TARGET_OBJECTS:test_support>
 )
 
 target_link_libraries(bn_test crypto)
diff --git a/crypto/bytestring/CMakeLists.txt b/crypto/bytestring/CMakeLists.txt
index d1f0441..cbbacf2 100644
--- a/crypto/bytestring/CMakeLists.txt
+++ b/crypto/bytestring/CMakeLists.txt
@@ -14,6 +14,8 @@
   bytestring_test
 
   bytestring_test.cc
+
+  $<TARGET_OBJECTS:test_support>
 )
 
 target_link_libraries(bytestring_test crypto)
diff --git a/crypto/dh/CMakeLists.txt b/crypto/dh/CMakeLists.txt
index 9e487d5..d0c1da7 100644
--- a/crypto/dh/CMakeLists.txt
+++ b/crypto/dh/CMakeLists.txt
@@ -16,6 +16,8 @@
   dh_test
 
   dh_test.cc
+
+  $<TARGET_OBJECTS:test_support>
 )
 
 target_link_libraries(dh_test crypto)
diff --git a/crypto/digest/CMakeLists.txt b/crypto/digest/CMakeLists.txt
index 8cab46a..816d116 100644
--- a/crypto/digest/CMakeLists.txt
+++ b/crypto/digest/CMakeLists.txt
@@ -13,6 +13,8 @@
   digest_test
 
   digest_test.cc
+
+  $<TARGET_OBJECTS:test_support>
 )
 
 target_link_libraries(digest_test crypto)
diff --git a/crypto/dsa/CMakeLists.txt b/crypto/dsa/CMakeLists.txt
index dab2c4c..1bb8b63 100644
--- a/crypto/dsa/CMakeLists.txt
+++ b/crypto/dsa/CMakeLists.txt
@@ -14,6 +14,8 @@
   dsa_test
 
   dsa_test.c
+
+  $<TARGET_OBJECTS:test_support>
 )
 
 target_link_libraries(dsa_test crypto)
diff --git a/crypto/ec/CMakeLists.txt b/crypto/ec/CMakeLists.txt
index a218c0d..b5ebefa 100644
--- a/crypto/ec/CMakeLists.txt
+++ b/crypto/ec/CMakeLists.txt
@@ -20,12 +20,16 @@
   example_mul
 
   example_mul.c
+
+  $<TARGET_OBJECTS:test_support>
 )
 
 add_executable(
   ec_test
 
   ec_test.cc
+
+  $<TARGET_OBJECTS:test_support>
 )
 
 target_link_libraries(example_mul crypto)
diff --git a/crypto/ecdsa/CMakeLists.txt b/crypto/ecdsa/CMakeLists.txt
index c8645d1..f431e59 100644
--- a/crypto/ecdsa/CMakeLists.txt
+++ b/crypto/ecdsa/CMakeLists.txt
@@ -14,6 +14,8 @@
   ecdsa_test
 
   ecdsa_test.cc
+
+  $<TARGET_OBJECTS:test_support>
 )
 
 target_link_libraries(ecdsa_test crypto)
diff --git a/crypto/err/CMakeLists.txt b/crypto/err/CMakeLists.txt
index 89f96bd..5215eec 100644
--- a/crypto/err/CMakeLists.txt
+++ b/crypto/err/CMakeLists.txt
@@ -44,6 +44,8 @@
   err_test
 
   err_test.cc
+
+  $<TARGET_OBJECTS:test_support>
 )
 
 target_link_libraries(err_test crypto)
diff --git a/crypto/evp/CMakeLists.txt b/crypto/evp/CMakeLists.txt
index 6db9752..5769fa4 100644
--- a/crypto/evp/CMakeLists.txt
+++ b/crypto/evp/CMakeLists.txt
@@ -26,12 +26,15 @@
   evp_extra_test
 
   evp_extra_test.cc
+
+  $<TARGET_OBJECTS:test_support>
 )
 
 add_executable(
   evp_test
 
   evp_test.cc
+
   $<TARGET_OBJECTS:test_support>
 )
 
@@ -39,6 +42,8 @@
   pbkdf_test
 
   pbkdf_test.cc
+
+  $<TARGET_OBJECTS:test_support>
 )
 
 target_link_libraries(evp_extra_test crypto)
diff --git a/crypto/hkdf/CMakeLists.txt b/crypto/hkdf/CMakeLists.txt
index f8dd748..66d680a 100644
--- a/crypto/hkdf/CMakeLists.txt
+++ b/crypto/hkdf/CMakeLists.txt
@@ -12,6 +12,8 @@
   hkdf_test
 
   hkdf_test.c
+
+  $<TARGET_OBJECTS:test_support>
 )
 
 target_link_libraries(hkdf_test crypto)
diff --git a/crypto/hmac/CMakeLists.txt b/crypto/hmac/CMakeLists.txt
index 1a08c55..11d267f 100644
--- a/crypto/hmac/CMakeLists.txt
+++ b/crypto/hmac/CMakeLists.txt
@@ -13,6 +13,7 @@
   hmac_test
 
   hmac_test.cc
+
   $<TARGET_OBJECTS:test_support>
 )
 
diff --git a/crypto/lhash/CMakeLists.txt b/crypto/lhash/CMakeLists.txt
index 0eaabed..c71b8a1 100644
--- a/crypto/lhash/CMakeLists.txt
+++ b/crypto/lhash/CMakeLists.txt
@@ -12,6 +12,8 @@
   lhash_test
 
   lhash_test.c
+
+  $<TARGET_OBJECTS:test_support>
 )
 
 target_link_libraries(lhash_test crypto)
diff --git a/crypto/modes/CMakeLists.txt b/crypto/modes/CMakeLists.txt
index d50e97b..ffb29b6 100644
--- a/crypto/modes/CMakeLists.txt
+++ b/crypto/modes/CMakeLists.txt
@@ -58,6 +58,8 @@
   gcm_test
 
   gcm_test.c
+
+  $<TARGET_OBJECTS:test_support>
 )
 
 target_link_libraries(gcm_test crypto)
diff --git a/crypto/pkcs8/CMakeLists.txt b/crypto/pkcs8/CMakeLists.txt
index c0f2746..4426f1e 100644
--- a/crypto/pkcs8/CMakeLists.txt
+++ b/crypto/pkcs8/CMakeLists.txt
@@ -15,6 +15,8 @@
   pkcs12_test
 
   pkcs12_test.cc
+
+  $<TARGET_OBJECTS:test_support>
 )
 
 target_link_libraries(pkcs12_test crypto)
diff --git a/crypto/rsa/CMakeLists.txt b/crypto/rsa/CMakeLists.txt
index c438e1d..0ea12c8 100644
--- a/crypto/rsa/CMakeLists.txt
+++ b/crypto/rsa/CMakeLists.txt
@@ -16,6 +16,8 @@
   rsa_test
 
   rsa_test.c
+
+  $<TARGET_OBJECTS:test_support>
 )
 
 target_link_libraries(rsa_test crypto)
diff --git a/crypto/test/CMakeLists.txt b/crypto/test/CMakeLists.txt
index 0d5ca81..84a6174 100644
--- a/crypto/test/CMakeLists.txt
+++ b/crypto/test/CMakeLists.txt
@@ -4,4 +4,5 @@
   OBJECT
 
   file_test.cc
+  malloc.cc
 )
diff --git a/ssl/test/malloc.cc b/crypto/test/malloc.cc
similarity index 100%
rename from ssl/test/malloc.cc
rename to crypto/test/malloc.cc
diff --git a/crypto/x509/CMakeLists.txt b/crypto/x509/CMakeLists.txt
index 96cf35c..3bb5704 100644
--- a/crypto/x509/CMakeLists.txt
+++ b/crypto/x509/CMakeLists.txt
@@ -59,6 +59,8 @@
   pkcs7_test
 
   pkcs7_test.c
+
+  $<TARGET_OBJECTS:test_support>
 )
 
 target_link_libraries(pkcs7_test crypto)
diff --git a/crypto/x509v3/CMakeLists.txt b/crypto/x509v3/CMakeLists.txt
index ffa5a4a..c7e6054 100644
--- a/crypto/x509v3/CMakeLists.txt
+++ b/crypto/x509v3/CMakeLists.txt
@@ -47,6 +47,8 @@
   v3name_test
 
   v3nametest.c
+
+  $<TARGET_OBJECTS:test_support>
 )
 
 target_link_libraries(v3name_test crypto)
@@ -55,6 +57,8 @@
   tab_test
 
   tabtest.c
+
+  $<TARGET_OBJECTS:test_support>
 )
 
 target_link_libraries(tab_test crypto)
diff --git a/ssl/CMakeLists.txt b/ssl/CMakeLists.txt
index f016046..cf5a29d 100644
--- a/ssl/CMakeLists.txt
+++ b/ssl/CMakeLists.txt
@@ -40,6 +40,8 @@
   ssl_test
 
   ssl_test.cc
+
+  $<TARGET_OBJECTS:test_support>
 )
 
 target_link_libraries(ssl_test ssl crypto)
diff --git a/ssl/pqueue/CMakeLists.txt b/ssl/pqueue/CMakeLists.txt
index 9f14020..53d2a8b 100644
--- a/ssl/pqueue/CMakeLists.txt
+++ b/ssl/pqueue/CMakeLists.txt
@@ -12,6 +12,8 @@
   pqueue_test
 
   pqueue_test.c
+
+  $<TARGET_OBJECTS:test_support>
 )
 
 target_link_libraries(pqueue_test ssl crypto)
diff --git a/ssl/test/CMakeLists.txt b/ssl/test/CMakeLists.txt
index a0d7a5e..3b07903 100644
--- a/ssl/test/CMakeLists.txt
+++ b/ssl/test/CMakeLists.txt
@@ -5,9 +5,10 @@
 
   async_bio.cc
   bssl_shim.cc
-  malloc.cc
   packeted_bio.cc
   test_config.cc
+
+  $<TARGET_OBJECTS:test_support>
 )
 
 target_link_libraries(bssl_shim ssl crypto)
diff --git a/util/all_tests.go b/util/all_tests.go
index 5b6dd88..49954df 100644
--- a/util/all_tests.go
+++ b/util/all_tests.go
@@ -22,16 +22,21 @@
 	"os"
 	"os/exec"
 	"path"
+	"strconv"
 	"strings"
+	"syscall"
 	"time"
 )
 
 // TODO(davidben): Link tests with the malloc shim and port -malloc-test to this runner.
 
 var (
-	useValgrind = flag.Bool("valgrind", false, "If true, run code under valgrind")
-	buildDir    = flag.String("build-dir", "build", "The build directory to run the tests from.")
-	jsonOutput  = flag.String("json-output", "", "The file to output JSON results to.")
+	useValgrind     = flag.Bool("valgrind", false, "If true, run code under valgrind")
+	useGDB          = flag.Bool("gdb", false, "If true, run BoringSSL code under gdb")
+	buildDir        = flag.String("build-dir", "build", "The build directory to run the tests from.")
+	jsonOutput      = flag.String("json-output", "", "The file to output JSON results to.")
+	mallocTest      = flag.Int64("malloc-test", -1, "If non-negative, run each test with each malloc in turn failing from the given number onwards.")
+	mallocTestDebug = flag.Bool("malloc-test-debug", false, "If true, ask each test to abort rather than fail a malloc. This can be used with a specific value for --malloc-test to identity the malloc failing that is causing problems.")
 )
 
 type test []string
@@ -157,25 +162,59 @@
 	return exec.Command("valgrind", valgrindArgs...)
 }
 
-func runTest(test test) (passed bool, err error) {
+func gdbOf(path string, args ...string) *exec.Cmd {
+	xtermArgs := []string{"-e", "gdb", "--args"}
+	xtermArgs = append(xtermArgs, path)
+	xtermArgs = append(xtermArgs, args...)
+
+	return exec.Command("xterm", xtermArgs...)
+}
+
+type moreMallocsError struct{}
+
+func (moreMallocsError) Error() string {
+	return "child process did not exhaust all allocation calls"
+}
+
+var errMoreMallocs = moreMallocsError{}
+
+func runTestOnce(test test, mallocNumToFail int64) (passed bool, err error) {
 	prog := path.Join(*buildDir, test[0])
 	args := test[1:]
 	var cmd *exec.Cmd
 	if *useValgrind {
 		cmd = valgrindOf(false, prog, args...)
+	} else if *useGDB {
+		cmd = gdbOf(prog, args...)
 	} else {
 		cmd = exec.Command(prog, args...)
 	}
 	var stdoutBuf bytes.Buffer
+	var stderrBuf bytes.Buffer
 	cmd.Stdout = &stdoutBuf
-	cmd.Stderr = os.Stderr
+	cmd.Stderr = &stderrBuf
+	if mallocNumToFail >= 0 {
+		cmd.Env = os.Environ()
+		cmd.Env = append(cmd.Env, "MALLOC_NUMBER_TO_FAIL="+strconv.FormatInt(mallocNumToFail, 10))
+		if *mallocTestDebug {
+			cmd.Env = append(cmd.Env, "MALLOC_ABORT_ON_FAIL=1")
+		}
+		cmd.Env = append(cmd.Env, "_MALLOC_CHECK=1")
+	}
 
 	if err := cmd.Start(); err != nil {
 		return false, err
 	}
 	if err := cmd.Wait(); err != nil {
+		if exitError, ok := err.(*exec.ExitError); ok {
+			if exitError.Sys().(syscall.WaitStatus).ExitStatus() == 88 {
+				return false, errMoreMallocs
+			}
+		}
+		fmt.Print(string(stderrBuf.Bytes()))
 		return false, err
 	}
+	fmt.Print(string(stderrBuf.Bytes()))
 
 	// Account for Windows line-endings.
 	stdout := bytes.Replace(stdoutBuf.Bytes(), []byte("\r\n"), []byte("\n"), -1)
@@ -187,6 +226,21 @@
 	return false, nil
 }
 
+func runTest(test test) (bool, error) {
+	if *mallocTest < 0 {
+		return runTestOnce(test, -1)
+	}
+
+	for mallocNumToFail := int64(*mallocTest); ; mallocNumToFail++ {
+		if passed, err := runTestOnce(test, mallocNumToFail); err != errMoreMallocs {
+			if err != nil {
+				err = fmt.Errorf("at malloc %d: %s", mallocNumToFail, err)
+			}
+			return passed, err
+		}
+	}
+}
+
 // shortTestName returns the short name of a test. Except for evp_test, it
 // assumes that any argument which ends in .txt is a path to a data file and not
 // relevant to the test's uniqueness.