Add an idle timeout to runner.go.

If a Read or Write blocks for too long, time out the operation. Otherwise, some
kinds of test failures result in hangs, which prevent the test harness from
progressing. (Notably, OpenSSL currently has a lot of those failure modes and
upstream expressed interest in being able to run the tests to completion.)

Go's APIs want you to send an absolute timeout, to avoid problems when a Read
is split into lots of little Reads. But we actively want the timer to reset in
that case, so this needs a trivial adapter.

The default timeout is set at 15 seconds for now. If this becomes a problem, we
can extend it or build a more robust deadlock detector given an out-of-band
channel (shim tells runner when it's waiting on data, abort if we're also
waiting on data at the same time). But I don't think we'll need that
complexity. 15 seconds appears fine for both valgrind and running tests on a
Nexus 4.

BUG=460189

Change-Id: I6463fd36058427d883b526044da1bbefba851785
Reviewed-on: https://boringssl-review.googlesource.com/7380
Reviewed-by: Steven Valdez <svaldez@google.com>
Reviewed-by: David Benjamin <davidben@google.com>
This commit is contained in:
David Benjamin 2016-03-08 12:50:21 -05:00
parent 3d38c03a8e
commit 3ed5977cbb

View File

@ -39,6 +39,7 @@ var (
resourceDir = flag.String("resource-dir", ".", "The directory in which to find certificate and key files.") resourceDir = flag.String("resource-dir", ".", "The directory in which to find certificate and key files.")
fuzzer = flag.Bool("fuzzer", false, "If true, tests against a BoringSSL built in fuzzer mode.") fuzzer = flag.Bool("fuzzer", false, "If true, tests against a BoringSSL built in fuzzer mode.")
transcriptDir = flag.String("transcript-dir", "", "The directory in which to write transcripts.") transcriptDir = flag.String("transcript-dir", "", "The directory in which to write transcripts.")
timeout = flag.Int("timeout", 15, "The number of seconds to wait for a read or write to bssl_shim.")
) )
const ( const (
@ -279,8 +280,28 @@ func writeTranscript(test *testCase, isResume bool, data []byte) {
} }
} }
// A timeoutConn implements an idle timeout on each Read and Write operation.
type timeoutConn struct {
net.Conn
timeout time.Duration
}
func (t *timeoutConn) Read(b []byte) (int, error) {
if err := t.SetReadDeadline(time.Now().Add(t.timeout)); err != nil {
return 0, err
}
return t.Conn.Read(b)
}
func (t *timeoutConn) Write(b []byte) (int, error) {
if err := t.SetWriteDeadline(time.Now().Add(t.timeout)); err != nil {
return 0, err
}
return t.Conn.Write(b)
}
func doExchange(test *testCase, config *Config, conn net.Conn, isResume bool) error { func doExchange(test *testCase, config *Config, conn net.Conn, isResume bool) error {
var connDamage *damageAdaptor conn = &timeoutConn{conn, time.Duration(*timeout) * time.Second}
if test.protocol == dtls { if test.protocol == dtls {
config.Bugs.PacketAdaptor = newPacketAdaptor(conn) config.Bugs.PacketAdaptor = newPacketAdaptor(conn)
@ -317,6 +338,7 @@ func doExchange(test *testCase, config *Config, conn net.Conn, isResume bool) er
conn = newReplayAdaptor(conn) conn = newReplayAdaptor(conn)
} }
var connDamage *damageAdaptor
if test.damageFirstWrite { if test.damageFirstWrite {
connDamage = newDamageAdaptor(conn) connDamage = newDamageAdaptor(conn)
conn = connDamage conn = connDamage